-void DamageEffect(float dmg, float type, float specnum1, float entnumber);
+void DamageEffect(vector hitorg, float dmg, float type, float specnum1);
void Ent_DamageInfo(float isNew)
{
float dmg, rad, edge, thisdmg, forcemul, species;
thisdmg = ((vlen (nearest - w_org) - bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
if(thisdmg >= 1)
continue;
+ if(thisdmg < 0)
+ thisdmg = 0;
if(dmg)
{
thisdmg = dmg + (edge - dmg) * thisdmg;
if(self.event_damage)
self.event_damage(thisdmg, w_deathtype, w_org, thisforce);
- DamageEffect(thisdmg, w_deathtype, species, self.entnum - 1);
+ DamageEffect(w_org, thisdmg, w_deathtype, species);
}
self = oldself;
(get_weaponinfo(i)).weapon_func(WR_PRECACHE);
}
-// damage effect
-
-.entity dmgent;
-.float dmgpartnum, dmgtime;
-.float lifetime;
-
void DamageEffect_Think()
{
- self.nextthink = time;
-
- float foundgib;
- vector org;
-
- if(time >= self.lifetime)
+ if(time >= self.cnt || self.owner == world || self.owner.model == "" || !self.owner.drawmask)
{
+ // time is up or the player got gibbed / disconnected
remove(self);
- self = world;
return;
}
- if(self.dmgtime > time)
- return;
- org = getplayerorigin(self.team);
- if(org == GETPLAYERORIGIN_ERROR)
- return;
+ if(self.owner.entnum == player_localentnum && !autocvar_chase_active)
+ return; // if we aren't using a third person view, hide our own effects
- // Scan the owner of all gibs in the world. If a gib owner is the same as the player we're applying
- // the effect to, it means our player is gibbed. Therefore, apply particles to the gibs instead.
- entity head;
- for(head = world; (head = find(head, classname, "gib")); )
- {
- if(head.team == self.team)
- {
- if(autocvar_cl_damageeffect_gibs)
- {
- if(autocvar_cl_damageeffect_gibs_randomize >= random())
- pointparticles(self.dmgpartnum, head.origin, '0 0 0', 1);
- self.dmgtime = time + autocvar_cl_damageeffect_gibs;
- }
- foundgib = TRUE;
- }
- }
-
- if(foundgib || !autocvar_cl_damageeffect_player)
- return; // don't show effects on the invisible dead body if gibs exist
- if(self.team == player_localentnum - 1 && !autocvar_chase_active)
- return; // if we aren't in third person mode, hide own damage effect
-
- // Now apply the effect to actual players
- pointparticles(self.dmgpartnum, org, '0 0 0', 1);
- self.dmgtime = time + autocvar_cl_damageeffect_player;
+ // now generate the particles
+ vector org;
+ org = gettaginfo(self, 0); // origin at attached location
+ pointparticles(self.team, org, '0 0 0', 1);
+ self.nextthink = time + autocvar_cl_damageeffect_ticrate;
}
-void DamageEffect(float dmg, float type, float specnum1, float entnumber)
+void DamageEffect(vector hitorg, float dmg, float type, float specnum)
{
- float specnum2, life;
+ // particle effects for players and objects damaged by weapons (eg: flames coming out of victims shot with rockets)
+
+ float life, i;
string specstr, effectnum;
entity e;
- if(!autocvar_cl_damageeffect_player && !autocvar_cl_damageeffect_gibs)
- return;
if(autocvar_cl_gentle || autocvar_cl_gentle_damage)
return;
+ if(self == world || self.model == "" || !self.drawmask)
+ return;
- specnum2 = (specnum1 & 0x78) / 8; // blood type: using four bits (0..7, bit indexes 3,4,5)
- specstr = species_prefix(specnum2);
- life = bound(0, dmg * autocvar_cl_damageeffect_lifetime, autocvar_cl_damageeffect_lifetime_max);
-
+ // return if we reached our damage effect limit
+ for(e = world; (e = find(e, classname, "damageeffect")); )
+ if(e.owner.entnum == self.entnum)
+ i += 1;
+ if(autocvar_cl_damageeffect < 1 || (self.isplayermodel && i >= autocvar_cl_damageeffect_limit))
+ return; // allow multiple damage effects on players
+ if(autocvar_cl_damageeffect < 2 || (!self.isplayermodel && i))
+ return; // allow a single damage effect on objects
+
+ specstr = species_prefix(specnum);
+ life = bound(autocvar_cl_damageeffect_lifetime_min, dmg * autocvar_cl_damageeffect_lifetime, autocvar_cl_damageeffect_lifetime_max);
+ type = DEATH_WEAPONOF(type);
e = get_weaponinfo(type);
+
effectnum = strcat("weapondamage_", e.netname);
- // If the weapon is a bullet weapon, its damage effect is blood.
- // Since blood is species dependent, we make this effect per-species.
+ // if the weapon is a bullet weapon, its damage effect is blood
+ // since blood is species dependent, use the species tag for this effect
if(type == WEP_SHOTGUN || type == WEP_UZI || type == WEP_RIFLE)
- if(specstr != "")
{
- effectnum = strcat(effectnum, "_", specstr);
- effectnum = substring(effectnum, 0, strlen(effectnum) - 1); // remove the _ symbol at the end of the species name
+ if(self.isplayermodel)
+ {
+ effectnum = strcat(effectnum, "_", specstr);
+ effectnum = substring(effectnum, 0, strlen(effectnum) - 1); // remove the _ symbol at the end of the species tag
+ }
+ else
+ return; // objects don't bleed
}
- // if the player already has a damage effect, update it instead of spawning a new one
- entity head;
- for(head = world; (head = find(head, classname, "damageeffect")); )
+ // if this is a player, damage effects will show on the limb where damage was dealt
+ // we do this by choosing the skeletal bone closest to the impact, and attaching the effect there
+ if(self.isplayermodel)
{
- if(head.team == entnumber)
+ float closest;
+ FOR_EACH_TAG(self)
{
- head.dmgpartnum = particleeffectnum(effectnum);
- head.lifetime += life;
- return;
+ // go through all skeletal bones on the player, and choose the one closest to the damage origin
+ if(!closest || vlen(hitorg - gettaginfo(self, tagnum)) <= vlen(hitorg - gettaginfo(self, closest)))
+ closest = tagnum;
}
+ gettaginfo(self, closest); // set gettaginfo_name to our bone
}
+ else
+ gettaginfo(self, 0); // set gettaginfo_name to entity origin
- entity e;
e = spawn();
+ setmodel(e, "models/null.md3"); // necessary to attach and read origin
+ setattachment(e, self, gettaginfo_name); // attach to the given bone
+ e.owner = self;
+ e.cnt = time + life;
e.classname = "damageeffect";
- e.team = entnumber;
- e.dmgpartnum = particleeffectnum(effectnum);
- e.lifetime = time + life;
+ e.team = particleeffectnum(effectnum);
e.think = DamageEffect_Think;
e.nextthink = time;
}