X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fclient%2Fdamage.qc;h=2ac4a01c138f4c7c1511a2985465ab7472350998;hb=d03bf59652dab079deef7cf35e5b80599b13df05;hp=fe2e8b67b0488a28d7f759bad87c435715ff7216;hpb=fe8fa62ddd3321825b7628645e3d4b809f07929d;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/client/damage.qc b/qcsrc/client/damage.qc index fe2e8b67b..2ac4a01c1 100644 --- a/qcsrc/client/damage.qc +++ b/qcsrc/client/damage.qc @@ -1,6 +1,7 @@ +void DamageEffect(vector hitorg, float dmg, float type, float specnum1); void Ent_DamageInfo(float isNew) { - float dmg, rad, edge, thisdmg, forcemul; + float dmg, rad, edge, thisdmg, forcemul, species; vector force, thisforce; entity oldself; @@ -18,6 +19,7 @@ void Ent_DamageInfo(float isNew) rad = ReadByte(); edge = ReadByte(); force = decompressShortVector(ReadShort()); + species = ReadByte(); if not(isNew) return; @@ -30,13 +32,16 @@ void Ent_DamageInfo(float isNew) else forcemul = 1; - for(self = findradius(w_org, rad); self; self = self.chain) + for(self = findradius(w_org, rad + MAX_DAMAGEEXTRARADIUS); self; self = self.chain) { + vector nearest = NearestPointOnBox(self, w_org); if(rad) { - thisdmg = vlen(self.origin - w_org) / rad; + 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; @@ -50,6 +55,9 @@ void Ent_DamageInfo(float isNew) } else { + if(vlen(nearest - w_org) > bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS)) + continue; + thisdmg = dmg; thisforce = forcemul * force; } @@ -66,6 +74,8 @@ void Ent_DamageInfo(float isNew) if(self.event_damage) self.event_damage(thisdmg, w_deathtype, w_org, thisforce); + + DamageEffect(w_org, thisdmg, w_deathtype, species); } self = oldself; @@ -145,6 +155,7 @@ void Ent_DamageInfo(float isNew) if(DEATH_ISTURRET(w_deathtype)) { + string _snd; traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world); if(trace_plane_normal != '0 0 0') w_backoff = trace_plane_normal; @@ -157,20 +168,13 @@ void Ent_DamageInfo(float isNew) { case DEATH_TURRET_EWHEEL: sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_MIN); - pointparticles(particleeffectnum("electro_impact"), self.origin, w_backoff * 1000, 1); + pointparticles(particleeffectnum("laser_impact"), self.origin, w_backoff * 1000, 1); break; case DEATH_TURRET_FLAC: - vector org2; - org2 = w_org + w_backoff * 6; - pointparticles(particleeffectnum("hagar_explode"), org2, '0 0 0', 1); - if (w_random<0.15) - sound(self, CH_SHOTS, "weapons/hagexp1.wav", VOL_BASE, ATTN_NORM); - else if (w_random<0.7) - sound(self, CH_SHOTS, "weapons/hagexp2.wav", VOL_BASE, ATTN_NORM); - else - sound(self, CH_SHOTS, "weapons/hagexp3.wav", VOL_BASE, ATTN_NORM); - + pointparticles(particleeffectnum("hagar_explode"), w_org, '0 0 0', 1); + _snd = strcat("weapons/hagexp", ftos(1 + rint(random() * 2)), ".waw"); + sound(self, CH_SHOTS, _snd, VOL_BASE, ATTN_NORM); break; case DEATH_TURRET_MLRS: @@ -183,7 +187,6 @@ void Ent_DamageInfo(float isNew) case DEATH_TURRET_MACHINEGUN: case DEATH_TURRET_WALKER_GUN: - string _snd; _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); @@ -235,88 +238,88 @@ void DamageInfo_Precache() (get_weaponinfo(i)).weapon_func(WR_PRECACHE); } -.entity dmgeffect; -.string dmgparticles; - -void Ent_DamageEffect_Think() +void DamageEffect_Think() { - self.nextthink = time; - - entity entcs; - entcs = entcs_receiver[self.team]; - if(!entcs) - return; - - // 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 the particles to the gibs as well. - if(autocvar_cl_damageeffect_gibs) + if(time >= self.cnt || self.owner == world || self.owner.model == "" || !self.owner.drawmask) { - entity head; - for(head = world; (head = find(head, classname, "gib")); ) - { - if(head.team == self.team) - if(random() < autocvar_cl_damageeffect_gibs) - pointparticles(particleeffectnum(self.dmgparticles), head.origin, '0 0 0', 1); - } - } - - // if we aren't in third person mode, hide our own damage effect - if(self.team == player_localentnum) - if(!autocvar_chase_active) + // time is up or the player got gibbed / disconnected + remove(self); return; + } + if(self.owner.entnum == player_localentnum && !autocvar_chase_active) + return; // if we aren't using a third person view, hide our own effects - // Now apply the effect to the actual player. - if(random() < autocvar_cl_damageeffect) - pointparticles(particleeffectnum(self.dmgparticles), entcs.origin, '0 0 0', 1); + // 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 Ent_DamageEffect() +void DamageEffect(vector hitorg, float dmg, float type, float specnum) { - float dmg, type, specnum1, specnum2, entnumber; - vector org; + // 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; - dmg = ReadByte(); // damage amount - type = ReadByte(); // damage weapon - specnum1 = ReadByte(); // player species - entnumber = ReadByte(); // player entnum - - if not(autocvar_cl_damageeffect) - 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); + // 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, replace it with the new one - entity head; - for(head = world; (head = find(head, classname, "dmgeffect")); ) + // 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) { - remove(head); - head = world; + // 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(); - e.classname = "dmgeffect"; - e.team = entnumber; - e.dmgparticles = effectnum; - e.think = Ent_DamageEffect_Think; + 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 = particleeffectnum(effectnum); + e.think = DamageEffect_Think; e.nextthink = time; }