if(time >= self.cnt || !self.owner || !self.owner.modelindex || !self.owner.drawmask)
{
// time is up or the player got gibbed / disconnected
- self.owner.total_damages -= 1;
+ self.owner.total_damages = max(0, self.owner.total_damages - 1);
remove(self);
return;
}
{
// if the player was dead but is now alive, it means he respawned
// if so, clear his damage effects, or damages from his dead body will be copied back
- self.owner.total_damages -= 1;
+ self.owner.total_damages = max(0, self.owner.total_damages - 1);
remove(self);
return;
}
self.state = self.owner.csqcmodel_isdead;
+#ifdef COMPAT_XON050_ENGINE
if(self.owner.isplayermodel && (self.owner.entnum == player_localentnum || self.owner.entnum == spectatee_status) && !autocvar_chase_active)
+#else
+ if(self.owner.isplayermodel && (self.owner.entnum == player_localentnum) && !autocvar_chase_active)
+#endif
return; // if we aren't using a third person camera, hide our own effects
// now generate the particles
{
// particle effects for players and objects damaged by weapons (eg: flames coming out of victims shot with rockets)
- float life, nearestbone;
- string specstr, effectnum;
+ float life, nearestbone = 0;
+ string specstr, effectname;
entity e;
- if(autocvar_cl_gentle || autocvar_cl_gentle_damage)
+ if(!autocvar_cl_damageeffect || autocvar_cl_gentle || autocvar_cl_gentle_damage)
return;
if(!self || !self.modelindex || !self.drawmask)
return;
// if there's no skeleton, object origin will automatically be selected
FOR_EACH_TAG(self)
{
+ if(!tagnum)
+ continue; // skip empty bones
// blacklist bones positioned outside the mesh, or the effect will be floating
// TODO: Do we have to do it this way? Why do these bones exist at all?
if(gettaginfo_name == "master" || gettaginfo_name == "knee_L" || gettaginfo_name == "knee_R" || gettaginfo_name == "leg_L" || gettaginfo_name == "leg_R")
continue; // player model bone blacklist
- if(gettaginfo_name == "")
- continue; // skip empty bones
// now choose the bone closest to impact origin
- if(vlen(hitorg - gettaginfo(self, tagnum)) <= vlen(hitorg - gettaginfo(self, nearestbone)))
+ if(nearestbone == 0 || vlen(hitorg - gettaginfo(self, tagnum)) <= vlen(hitorg - gettaginfo(self, nearestbone)))
nearestbone = tagnum;
}
gettaginfo(self, nearestbone); // set gettaginfo_name
// return if we reached our damage effect limit or damages are disabled
+ // TODO: When the limit is reached, it would be better if the oldest damage was removed instead of not adding a new one
if(nearestbone)
{
- if(autocvar_cl_damageeffect < 1 || self.total_damages >= autocvar_cl_damageeffect_bones)
+ if(self.total_damages >= autocvar_cl_damageeffect_bones)
return; // allow multiple damages on skeletal models
}
else
type = DEATH_WEAPONOF(type);
e = get_weaponinfo(type);
- effectnum = strcat("damage_", e.netname);
+ effectname = strcat("damage_", e.netname);
// if damage was dealt with a bullet weapon, our effect is blood
// since blood is species dependent, include the species tag
{
if(self.isplayermodel)
{
- effectnum = strcat(effectnum, "_", specstr);
- effectnum = substring(effectnum, 0, strlen(effectnum) - 1); // remove the _ symbol at the end of the species tag
+ effectname = strcat(effectname, "_", specstr);
+ effectname = substring(effectname, 0, strlen(effectname) - 1); // remove the _ symbol at the end of the species tag
}
else
return; // objects don't bleed
e.classname = "damage";
e.owner = self;
e.cnt = time + life;
- e.team = particleeffectnum(effectnum);
+ e.team = particleeffectnum(effectname);
e.think = DamageEffect_Think;
e.nextthink = time;
self.total_damages += 1;
void Ent_DamageInfo(float isNew)
{
- float dmg, rad, edge, thisdmg, forcemul, species;
+ float dmg, rad, edge, thisdmg, forcemul, species, hitplayer = FALSE;
vector force, thisforce;
entity oldself;
for(self = findradius(w_org, rad + MAX_DAMAGEEXTRARADIUS); self; self = self.chain)
{
+ // attached ents suck
+ if(self.tag_entity)
+ continue;
+
vector nearest = NearestPointOnBox(self, w_org);
if(rad)
{
self.event_damage(thisdmg, w_deathtype, w_org, thisforce);
DamageEffect(w_org, thisdmg, w_deathtype, species);
+
+ if(self.isplayermodel)
+ hitplayer = TRUE; // this impact damaged a player
}
self = oldself;
switch(w_deathtype)
{
- case DEATH_VHCRUSH:
+ case DEATH_VH_CRUSH:
break;
// spiderbot
- case DEATH_SBMINIGUN:
+ case DEATH_VH_SPID_MINIGUN:
string _snd;
_snd = strcat("weapons/ric", ftos(1 + rint(random() * 2)), ".waw");
sound(self, CH_SHOTS, _snd, VOL_BASE, ATTN_NORM);
pointparticles(particleeffectnum("spiderbot_minigun_impact"), self.origin, w_backoff * 1000, 1);
break;
- case DEATH_SBROCKET:
+ case DEATH_VH_SPID_ROCKET:
sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
pointparticles(particleeffectnum("spiderbot_rocket_explode"), self.origin, w_backoff * 1000, 1);
break;
- case DEATH_SBBLOWUP:
+ case DEATH_VH_SPID_DEATH:
sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_MIN);
pointparticles(particleeffectnum("explosion_big"), self.origin, w_backoff * 1000, 1);
break;
-
- case DEATH_WAKIGUN:
+
+ case DEATH_VH_WAKI_GUN:
sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM);
pointparticles(particleeffectnum("wakizashi_gun_impact"), self.origin, w_backoff * 1000, 1);
break;
- case DEATH_WAKIROCKET:
+ case DEATH_VH_WAKI_ROCKET:
sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
pointparticles(particleeffectnum("wakizashi_rocket_explode"), self.origin, w_backoff * 1000, 1);
break;
- case DEATH_WAKIBLOWUP:
+ case DEATH_VH_WAKI_DEATH:
sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_MIN);
pointparticles(particleeffectnum("explosion_big"), self.origin, w_backoff * 1000, 1);
break;
- case DEATH_RAPTOR_CANNON:
+ case DEATH_VH_RAPT_CANNON:
sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM);
pointparticles(particleeffectnum("raptor_cannon_impact"), self.origin, w_backoff * 1000, 1);
break;
- case DEATH_RAPTOR_BOMB_SPLIT:
+ case DEATH_VH_RAPT_FRAGMENT:
float i;
vector ang, vel;
for(i = 1; i < 4; ++i)
sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
pointparticles(particleeffectnum("raptor_bomb_spread"), self.origin, w_backoff * 1000, 1);
break;
- case DEATH_RAPTOR_BOMB:
+ case DEATH_VH_RAPT_BOMB:
sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
pointparticles(particleeffectnum("raptor_bomb_impact"), self.origin, w_backoff * 1000, 1);
break;
- case DEATH_RAPTOR_DEATH:
+ case DEATH_VH_RAPT_DEATH:
sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_MIN);
pointparticles(particleeffectnum("explosion_big"), self.origin, w_backoff * 1000, 1);
break;
+ case DEATH_VH_BUMB_GUN:
+ sound(self, CH_SHOTS, "weapons/fireball_impact2.wav", VOL_BASE, ATTN_NORM);
+ pointparticles(particleeffectnum("bigplasma_impact"), self.origin, w_backoff * 1000, 1);
+ break;
}
}
case DEATH_TURRET_MLRS:
case DEATH_TURRET_HK:
- case DEATH_TURRET_WALKER_ROCKET:
+ case DEATH_TURRET_WALK_ROCKET:
case DEATH_TURRET_HELLION:
sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_MIN);
pointparticles(particleeffectnum("rocket_explode"), self.origin, w_backoff * 1000, 1);
break;
case DEATH_TURRET_MACHINEGUN:
- case DEATH_TURRET_WALKER_GUN:
+ case DEATH_TURRET_WALK_GUN:
_snd = strcat("weapons/ric", ftos(1 + rint(random() * 2)), ".waw");
sound(self, CH_SHOTS, _snd, VOL_BASE, ATTN_NORM);
pointparticles(particleeffectnum("machinegun_impact"), self.origin, w_backoff * 1000, 1);
pointparticles(particleeffectnum("electro_impact"), self.origin, w_backoff * 1000, 1);
break;
- case DEATH_TURRET_WALKER_MEELE:
+ case DEATH_TURRET_WALK_MEELE:
sound(self, CH_SHOTS, "weapons/ric1.wav", VOL_BASE, ATTN_MIN);
pointparticles(particleeffectnum("TE_SPARK"), self.origin, w_backoff * 1000, 1);
break;
// TODO spawn particle effects and sounds based on w_deathtype
if(!DEATH_ISSPECIAL(w_deathtype))
+ if not(hitplayer && !rad) // don't show ground impacts for hitscan weapons if a player was hit
{
float hitwep;