void() info_player_start; void(entity targ, entity attacker, INTEGER mod) ClientObituary; void(entity inflictor, entity attacker, float damage, float radius, entity ignore, INTEGER mod) T_RadiusDamage; #ifdef MONSTERS void() monster_death_use; void() FoundTarget; #endif //============================================================================ /* ============ CanDamage Returns true if the inflictor can directly damage the target. Used for explosions and melee attacks. ============ */ float(entity targ, entity inflictor) CanDamage = { // bmodels need special checking because their origin is 0,0,0 if (targ.movetype == MOVETYPE_PUSH) { traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self); if (trace_fraction == 1) return TRUE; if (trace_ent == targ) return TRUE; return FALSE; } traceline(inflictor.origin, targ.origin, TRUE, self); if (trace_fraction == 1) return TRUE; traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self); if (trace_fraction == 1) return TRUE; traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self); if (trace_fraction == 1) return TRUE; traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self); if (trace_fraction == 1) return TRUE; traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self); if (trace_fraction == 1) return TRUE; return FALSE; }; /* ============ Killed ============ */ void(entity targ, entity attacker, INTEGER mod) Killed = { local entity oself; oself = self; self = targ; if (self.health < -99) self.health = -99; // don't let sbar look bad if a player self.enemy = attacker; if (self.movetype == MOVETYPE_PUSH || self.movetype == MOVETYPE_NONE) { // doors, triggers, etc self.th_die (); self = oself; return; } // bump the monster counter #ifdef MONSTERS if (self.flags & FL_MONSTER) { killed_monsters = killed_monsters + 1; WriteByte (MSG_ALL, SVC_KILLEDMONSTER); monster_death_use(); } #endif ClientObituary(self, attacker, mod); self.takedamage = DAMAGE_NO; self.touch = SUB_Null; self.effects = 0; self.th_die (); self = oself; }; /* OnSameTeam */ float(entity targ, entity attacker) OnSameTeam = { #ifndef NETQUAKE local string targteam; local string attackerteam; #endif if (attacker == targ) return TRUE; if (targ.classname != "player" || attacker.classname != "player") return FALSE; if (coop) return TRUE; if (teamplay == 0) return FALSE; #ifdef NETQUAKE // NQ team check if (!targ.team) return FALSE; if (targ.team == attacker.team) return TRUE; #else // QW team check targteam = stringclientinfokey(targ, "team"); attackerteam = stringclientinfokey(attacker, "team"); if (targteam == "") return FALSE; if (targteam == attackerteam) return TRUE; #endif return FALSE; }; /* DisallowFriendlyFire */ float(entity targ, entity attacker, INTEGER mod) DisallowFriendlyFire = { if (targ == attacker && teamplay != 1) return FALSE; if (OnSameTeam(targ, attacker) && (teamplay == 1 || teamplay == 3)) return TRUE; return FALSE; }; /* ============ T_Damage The damage is coming from inflictor, but get mad at attacker This should be the only function that ever reduces health. ============ */ void(entity targ, entity inflictor, entity attacker, float damage, INTEGER mod) T_Damage= { local vector dir; local entity oldself; local float save; local float take; if (!targ.takedamage) return; // used by buttons and triggers to set activator for target firing damage_attacker = attacker; // set mod damage_mod = mod; // check for quad damage powerup on the attacker if (attacker.super_damage_finished > time && mod != MOD_SQUISH) { if (deathmatch == 4) damage = damage * 8; else damage = damage * 4; } // save damage based on the target's armor level save = ceil(targ.armortype*damage); if (save >= targ.armorvalue) { save = targ.armorvalue; targ.armortype = 0; // lost all armor targ.items = targ.items - (targ.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)); } targ.armorvalue = targ.armorvalue - save; take = ceil(damage-save); // add to the damage total for clients, which will be sent as a single // message at the end of the frame // FIXME: remove after combining shotgun blasts? if (targ.flags & FL_CLIENT) { targ.dmg_take = targ.dmg_take + take; targ.dmg_save = targ.dmg_save + save; targ.dmg_inflictor = inflictor; } damage_inflictor = inflictor; // figure momentum add if ( (inflictor != world) && (targ.movetype == MOVETYPE_WALK) ) { dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; dir = normalize(dir); // Set kickback for smaller weapons targ.velocity = targ.velocity + dir * damage * 8; // Rocket Jump modifiers if (rj > 1 && attacker == targ) if (targ.classname == "player") targ.velocity = targ.velocity + dir * damage * rj; } // check for godmode or invincibility if (targ.flags & FL_GODMODE) return; if (targ.invincible_finished >= time) { if (targ.invincible_sound < time) { sound (targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM); targ.invincible_sound = time + 2; } return; } // team play damage avoidance if (DisallowFriendlyFire(targ, attacker, mod)) return; // do the damage targ.health = targ.health - take; if (targ.health <= 0) { Killed (targ, attacker, mod); return; } // react to the damage oldself = self; self = targ; #ifdef MONSTERS if ( (self.flags & FL_MONSTER) && attacker != world) { // get mad unless of the same class (except for soldiers) if (self != attacker && attacker != self.enemy) { if ( (self.classname != attacker.classname) || (self.classname == "monster_army" ) ) { if (self.enemy.classname == "player") self.oldenemy = self.enemy; self.enemy = attacker; FoundTarget (); } } } #endif if (self.th_pain) { self.th_pain (attacker, take); } self = oldself; }; /* ============ T_RadiusDamage ============ */ void(entity inflictor, entity attacker, float damage, float radius, entity ignore, INTEGER mod) T_RadiusDamage = { local float points; local entity head; local vector org; head = findradius(inflictor.origin, radius); while (head) { if (head != ignore) { if (head.takedamage) { org = head.origin + (head.mins + head.maxs)*0.5; points = 0.5*vlen (inflictor.origin - org); if (points < 0) points = 0; points = damage - points; if (head == attacker) points = points * 0.5; if (points > 0) { if (CanDamage (head, inflictor)) T_Damage (head, inflictor, attacker, points, mod); } } } head = head.chain; } };