X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fclient%2Fdamage.qc;h=662c8fddb9ee7076a2609eb905aa6cfcf01bd458;hb=74506d6244b1a6e2a02e7f44e5732085826954a9;hp=6ff989e4a6ed598d55e0da35ad71d535f33bfa2d;hpb=2e44f19e0c92cf7fab9e7d21f15abda16118765b;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/client/damage.qc b/qcsrc/client/damage.qc index 6ff989e4a..662c8fddb 100644 --- a/qcsrc/client/damage.qc +++ b/qcsrc/client/damage.qc @@ -1,6 +1,7 @@ +void DamageEffect(float dmg, float type, float specnum1, float entnumber); 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; @@ -67,6 +69,7 @@ void Ent_DamageInfo(float isNew) if(self.event_damage) self.event_damage(thisdmg, w_deathtype, w_org, thisforce); } + DamageEffect(dmg, w_deathtype, species, self.entnum); self = oldself; @@ -88,33 +91,33 @@ void Ent_DamageInfo(float isNew) case DEATH_SBMINIGUN: string _snd; _snd = strcat("weapons/ric", ftos(1 + rint(random() * 2)), ".waw"); - sound(self, CHAN_PROJECTILE, _snd, VOL_BASE, ATTN_NORM); + sound(self, CH_SHOTS, _snd, VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("spiderbot_minigun_impact"), self.origin, w_backoff * 1000, 1); break; case DEATH_SBROCKET: - sound(self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); + 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: - sound(self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_MIN); + 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: - sound(self, CHAN_PROJECTILE, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM); + 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: - sound(self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); + 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: - sound(self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_MIN); + 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: - sound(self, CHAN_PROJECTILE, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM); + 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: @@ -128,15 +131,15 @@ void Ent_DamageInfo(float isNew) } - sound(self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); + 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: - sound(self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); + 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: - sound(self, CHAN_PROJECTILE, "weapons/laserimpact.wav", VOL_BASE, ATTN_MIN); + sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_MIN); pointparticles(particleeffectnum("explosion_big"), self.origin, w_backoff * 1000, 1); break; } @@ -145,6 +148,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; @@ -156,46 +160,38 @@ void Ent_DamageInfo(float isNew) switch(w_deathtype) { case DEATH_TURRET_EWHEEL: - sound(self, CHAN_PROJECTILE, "weapons/laserimpact.wav", VOL_BASE, ATTN_MIN); - pointparticles(particleeffectnum("electro_impact"), self.origin, w_backoff * 1000, 1); + sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_MIN); + 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, CHAN_PROJECTILE, "weapons/hagexp1.wav", VOL_BASE, ATTN_NORM); - else if (w_random<0.7) - sound(self, CHAN_PROJECTILE, "weapons/hagexp2.wav", VOL_BASE, ATTN_NORM); - else - sound(self, CHAN_PROJECTILE, "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: case DEATH_TURRET_HK: case DEATH_TURRET_WALKER_ROCKET: case DEATH_TURRET_HELLION: - sound(self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_MIN); + 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: - string _snd; _snd = strcat("weapons/ric", ftos(1 + rint(random() * 2)), ".waw"); - sound(self, CHAN_PROJECTILE, _snd, VOL_BASE, ATTN_NORM); + sound(self, CH_SHOTS, _snd, VOL_BASE, ATTN_NORM); pointparticles(particleeffectnum("machinegun_impact"), self.origin, w_backoff * 1000, 1); break; case DEATH_TURRET_PLASMA: - sound(self, CHAN_PROJECTILE, "weapons/electro_impact.wav", VOL_BASE, ATTN_MIN); + sound(self, CH_SHOTS, "weapons/electro_impact.wav", VOL_BASE, ATTN_MIN); pointparticles(particleeffectnum("electro_impact"), self.origin, w_backoff * 1000, 1); break; case DEATH_TURRET_WALKER_MEELE: - sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_MIN); + sound(self, CH_SHOTS, "weapons/ric1.wav", VOL_BASE, ATTN_MIN); pointparticles(particleeffectnum("TE_SPARK"), self.origin, w_backoff * 1000, 1); break; @@ -234,3 +230,103 @@ void DamageInfo_Precache() for(i = WEP_FIRST; i <= WEP_LAST; ++i) (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) + { + remove(self); + self = world; + return; + } + if(self.dmgtime > time) + return; + org = getplayerorigin(self.team); + if(org == GETPLAYERORIGIN_ERROR) + 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 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; +} + +void DamageEffect(float dmg, float type, float specnum1, float entnumber) +{ + float specnum2, life; + string specstr, effectnum; + entity e; + + if(!autocvar_cl_damageeffect_player && !autocvar_cl_damageeffect_gibs) + return; + if(autocvar_cl_gentle || autocvar_cl_gentle_damage) + 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); + + 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(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 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(head.team == entnumber - 1) + { + head.dmgpartnum = particleeffectnum(effectnum); + head.lifetime += life; + return; + } + } + + entity e; + e = spawn(); + e.classname = "damageeffect"; + e.team = entnumber - 1; + e.dmgpartnum = particleeffectnum(effectnum); + e.lifetime = time + life; + e.think = DamageEffect_Think; + e.nextthink = time; +}