mirror of
https://github.com/nzp-team/quakec.git
synced 2024-11-25 05:11:05 +00:00
159 lines
No EOL
5.9 KiB
C++
159 lines
No EOL
5.9 KiB
C++
/*
|
|
client/particles.qc
|
|
|
|
CSQC-Driven Particle Runner.
|
|
|
|
Copyright (C) 2021-2024 NZ:P Team
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
|
|
// Stored outside of struct for stack efficency.
|
|
float particle_optional_field;
|
|
float particle_optional_entity;
|
|
vector particle_position;
|
|
|
|
//
|
|
// Particles_MuzzleflashCallback()
|
|
// Executes Muzzleflash Particle effect.
|
|
// Optional: Which weapon was fired (left/right, for akimbo).
|
|
//
|
|
void() Particles_MuzzleflashCallback =
|
|
{
|
|
// Do not display Muzzleflashes if we're using a Sniper Scope or not drawing the viewmodel.
|
|
if (getstatf(STAT_WEAPONZOOM) == 2 || !cvar("r_drawviewmodel"))
|
|
return;
|
|
|
|
// Organized storage of optional_field and optional_entity.
|
|
float weapon_side = particle_optional_field;
|
|
float hit_entity = particle_optional_entity;
|
|
|
|
// Obtain our input view angles.
|
|
getinputstate(servercommandframe);
|
|
makevectors(input_angles);
|
|
|
|
vector muzzleflash_offset;
|
|
vector muzzleflash_position = getviewprop(VF_ORIGIN);
|
|
|
|
// If firing the left side of a dual-wield weapon, use the left side muzzleflash offset.
|
|
if (weapon_side == 0 && IsDualWeapon(getstatf(STAT_ACTIVEWEAPON)))
|
|
muzzleflash_offset = WepDef_GetLeftFlashOffset(getstatf(STAT_ACTIVEWEAPON))/1000;
|
|
// Otherwise, use the standard offset.
|
|
else
|
|
muzzleflash_offset = GetWeaponFlash_Offset(getstatf(STAT_ACTIVEWEAPON))/1000;
|
|
|
|
// Move to match ADS position if Zoomed in.
|
|
if(getstatf(STAT_WEAPONZOOM) == 1) {
|
|
muzzleflash_offset += GetWeaponADSOfs(getstatf(STAT_ACTIVEWEAPON))/1000;
|
|
}
|
|
|
|
muzzleflash_position += v_forward * muzzleflash_offset_z;
|
|
muzzleflash_position += v_right * muzzleflash_offset_x;
|
|
muzzleflash_position += v_up * muzzleflash_offset_y;
|
|
|
|
float muzzleflash_type = rint(random() * 2); // Choose one of three Muzzleflash variances.
|
|
|
|
// Display Muzzleflash Particle and Dynamic Light
|
|
if (IsPapWeapon(getstatf(STAT_ACTIVEWEAPON))) {
|
|
pointparticles(particleeffectnum(strcat("muzzle.muzzle_pap_part", ftos(muzzleflash_type))), muzzleflash_position, '0 0 0', 1);
|
|
|
|
// Pack-A-Punched Weapons can display either a Blue or Red light
|
|
if (random() > 0.5)
|
|
dynamiclight_add(muzzleflash_position, 256, '0.7 0 0');
|
|
else
|
|
dynamiclight_add(muzzleflash_position, 256, '0 0 0.7');
|
|
} else {
|
|
pointparticles(particleeffectnum(strcat("muzzle.muzzle_part", ftos(muzzleflash_type))), muzzleflash_position, '0 0 0', 1);
|
|
dynamiclight_add(muzzleflash_position, 256, '1.2 0.7 0.2');
|
|
}
|
|
|
|
// Grenade-Lunching weapons should not show decals.
|
|
if (GetFiretype(getstatf(STAT_ACTIVEWEAPON)) == FIRETYPE_GRENADE)
|
|
return;
|
|
|
|
if(hit_entity == 0) {
|
|
pointparticles(particleeffectnum("weapons.impact"), particle_position, '0 0 0', 1);
|
|
pointparticles(particleeffectnum("weapons.impact_decal"), particle_position, '0 0 0', 1);
|
|
}
|
|
};
|
|
|
|
// This struct must be ordered linearly for fast array lookups. Do NOT skip indexes.
|
|
var struct
|
|
{
|
|
float particle_type; // ID of Particle.
|
|
string particle_string; // String that refers to the Particle name/gamedir path. May be blank if callbacks utilized.
|
|
void() particle_func; // Callback that also gets executed on Particle_RunParticle, typically __NULL__. optional_field used here.
|
|
} csqc_particles[] =
|
|
{
|
|
{CSQC_PART_MUZZLEFLASH, "", Particles_MuzzleflashCallback}, // View Entity Muzzleflashes.
|
|
{CSQC_PART_EXPLOSION, "weapons.explode", __NULL__}, // Explosion effect.
|
|
{CSQC_PART_BLOODIMPACT, "blood.blood_particle", __NULL__}, // Blood Impact effect.
|
|
{CSQC_PART_ZOMBIEGIB, "blood.gibs", __NULL__}, // Zombie Gib effect.
|
|
{CSQC_PART_FIRE, "flames.flame_particle", __NULL__} // Fire/flame effect.
|
|
};
|
|
|
|
//
|
|
// Particles_RunParticle(particle_type, position, optional_field, optional_entity)
|
|
// Runs specific particle given it's type, location,
|
|
// and optional fields to pass to an optional callback.
|
|
//
|
|
void(float particle_type, vector position, float optional_field, float optional_entity) Particles_RunParticle =
|
|
{
|
|
// If the requested particle index does not have a callback function,
|
|
// run it outright.
|
|
if (csqc_particles[particle_type].particle_func == __NULL__)
|
|
pointparticles(particleeffectnum(csqc_particles[particle_type].particle_string), position, '0 0 0', 1);
|
|
// It has a callback -- so execute it instead.
|
|
else {
|
|
particle_optional_field = optional_field;
|
|
particle_optional_entity = optional_entity;
|
|
particle_position = position;
|
|
csqc_particles[particle_type].particle_func();
|
|
particle_optional_field = particle_optional_entity = 0;
|
|
particle_position = '0 0 0';
|
|
}
|
|
};
|
|
|
|
//
|
|
// Particles_Init()
|
|
// Particles never draw on their first run, so "allocate"
|
|
// them here. Particles only called via callbacks need
|
|
// invidiually referenced.
|
|
//
|
|
void() Particles_Init =
|
|
{
|
|
int i;
|
|
//
|
|
// Callback Particles
|
|
//
|
|
|
|
// Muzzleflashes.
|
|
for(i = 0; i < 3; i++) {
|
|
pointparticles(particleeffectnum(strcat("muzzle.muzzle_pap_part", itos(i))), '0 0 0', '0 0 0', 0);
|
|
pointparticles(particleeffectnum(strcat("muzzle.muzzle_part", itos(i))), '0 0 0', '0 0 0', 0);
|
|
}
|
|
|
|
//
|
|
// Normal References
|
|
//
|
|
for(i = 0; i < csqc_particles.length; i++) {
|
|
pointparticles(particleeffectnum(csqc_particles[i].particle_string), '0 0 0', '0 0 0', 0);
|
|
}
|
|
}; |