/*====================================================== COMBAT.QC Custom TeamFortress v3.2 (c) TeamFortress Software Pty Ltd 29/2/97 (c) William Kerney 5/19/00 ======================================================== All the functions pertaining to killing people ======================================================*/ #include "defs.qh" #include "jobs.qh" void(string gibname, float dm) ThrowGib; void() T_MissileTouch; void() info_player_start; void(entity targ, entity attacker) ClientObituary; // TeamFortress Prototypes void(entity Goal, entity AP, float addb) DoResults; float(entity Goal, entity AP) Activated; void() monster_death_use; float (entity targ, entity attacker, float damage) TeamEqualiseDamage; void(entity bastard,float threshold) createBastard; void (entity targ,float pain) RevealThief; //WK void() GuerillaExplode; float(entity tester) IsBuilding; //float(entity happyboy,float newtime) makeImmune; //- OfN - float(entity thing) IsMonster; void(entity body) ExpBody; string(entity thebuilding) GetBuildingName; string(entity thething) GetEnemyName; void(entity tfield, vector where, entity thing) FieldExplosion; void(entity field) PutFieldWork; #ifndef COOP_MODE /*================ monster_death_use (from monsters.qc) When a monster dies, it fires all of its targets with the current enemy as activator. ================ */ void() monster_death_use = { // fall to ground if (self.flags & FL_FLY) self.flags = self.flags - FL_FLY; if (self.flags & FL_SWIM) self.flags = self.flags - FL_SWIM; if (!self.target) return; activator = self.enemy; SUB_UseTargets (); }; #endif //============================================================================ /* ============ CanDamage Returns true if the inflictor can directly damage the target. Used for explosions and melee attacks. ============ */ float(entity targ, entity inflictor) CanDamage = { local vector soffset; // - OfN - hackish fix for turretized sentry guns soffset='0 0 0'; // 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; } if (targ.classname == "building_sentrygun" && (targ.tf_items & NIT_TURRET)) soffset='0 0 -20'; // OfN - Force field traceline(inflictor.origin, targ.origin + soffset, FALSE, self); if (trace_ent.classname == "force_field") { FieldExplosion(trace_ent,trace_endpos,trace_ent); PutFieldWork(trace_ent); return FALSE; } traceline(inflictor.origin, targ.origin + soffset, TRUE, self); if (trace_fraction == 1) return TRUE; /*traceline(inflictor.origin, targ.origin + '15 15 0' + soffset, TRUE, self); if (trace_fraction == 1) return TRUE; traceline(inflictor.origin, targ.origin + '-15 -15 0' + soffset, TRUE, self); if (trace_fraction == 1) return TRUE; traceline(inflictor.origin, targ.origin + '-15 15 0' + soffset, TRUE, self); if (trace_fraction == 1) return TRUE; traceline(inflictor.origin, targ.origin + '15 -15 0' + soffset, TRUE, self); if (trace_fraction == 1) return TRUE;*/ // OfN - Fixes dets thru wall? return FALSE; }; /* ============ Killed ============ */ void(entity targ, entity attacker) Killed = { // SOLVES BUG ???? // Stack overflow? if (targ.is_killed == TRUE) { if (IsBuilding(targ)) { local string st; RPrint("(OfN WARNING:) Building: '"); st=GetBuildingName(targ); RPrint(st); RPrint("' was going to be Killed() again!\n"); RPrint("Attacker: '"); st=GetEnemyName(attacker); RPrint(st); RPrint("\n"); return; } if (targ.classname == "player") { local string st; RPrint("(OfN WARNING:) Player: '"); RPrint(targ.netname); if (targ.cutf_items & CUTF_EXPBODY) { RPrint(" (with expbody) "); } else { RPrint(" (without expbody) "); } RPrint("' is Killed() again!\n"); RPrint("Attacker: '"); st=GetEnemyName(attacker); RPrint(st); if (attacker.classname == "player" && attacker.cutf_items & CUTF_EXPBODY) { RPrint(" (with expbody) "); } else { RPrint(" (without expbody) "); } RPrint("\n"); } else { // NOT BUGS, HAPPEN OFTEN WITH BUTTONS ETC.. /*RPrint("(OfN WARNING:) Object: '"); RPrint(targ.classname); RPrint("' is Killed() again!\n"); RPrint("Attacker: '"); st=GetEnemyName(attacker); RPrint(st); if (attacker.classname == "player" && attacker.cutf_items & CUTF_EXPBODY) { RPrint(" (with expbody) "); } else { RPrint(" (without expbody) "); } RPrint("\n"); */ } } targ.is_killed = TRUE; ///////////////////////////////////// local entity oself; //WK Have cursed person respawn immediately if (targ.classname == "player") { if (targ.penance_time > time) { targ.real_frags = targ.real_frags - 1; if (!(toggleflags & TFLAG_TEAMFRAGS)) targ.frags = targ.real_frags; targ.health = 50; //Give em a little so they can die again targ.is_killed = FALSE; return; } } oself = self; self = targ; // don't let sbar look bad if a player if (self.health < -99) self.health = -99; // doors, triggers, etc // - ofn added sensor, it now calls clientobituary when dead if ((self.movetype == MOVETYPE_PUSH || self.movetype == MOVETYPE_NONE) && self.classname != "building_camera" && self.classname!="building_sensor") //CH stop bug. { self.th_die (); self = oself; return; } self.enemy = attacker; // bump the monster counter if (self.flags & FL_MONSTER) { killed_monsters = killed_monsters + 1; WriteByte (MSG_ALL, SVC_KILLEDMONSTER); } ClientObituary(self, attacker); self.takedamage = DAMAGE_NO; self.touch = SUB_Null; monster_death_use(); self.th_die (); self = oself; }; /* ============ 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) T_Damage = { //WK Just call TF_T_Damage instead, so no updating two functions //WK that do exactly the same thing. TF_T_Damage(targ,inflictor,attacker,damage,0,0); }; /* ============ TF_T_Damage same thing as T_Damage (see above), just with some more details T_Flags: TF_TD_IGNOREARMOUR: bypasses the armour of the target TF_TD_NOTTEAM: doesn't damage a team member TF_TD_NOTSELF: doesn't damage self The following is used to determine whether this attack is affected the type of armor the defender is wearing. T_AttackType: TF_TD_OTHER : type ignored TF_TD_SHOT : bullet damage TF_TD_NAIL : nailgun damage TF_TD_EXPLOSION : explosion damage TF_TD_ELECTRICITY : electricity damage TF_TD_FIRE : fire damage TF_TD_NOSOUND : Special Value. Health is adjusted without any sound, painframe, etc Health is _set_ to damage, not altered. ============ */ void(entity targ, entity inflictor, entity attacker, float damage, float T_flags, float T_AttackType) TF_T_Damage = { local vector dir; local entity oldself, te; local float save; local float take; local float mirror; local float dist; local string output; local float knockem; //WK -- For LPB calculation local string foo; local float ping; mirror = 0; if (infokey(world,"ceasefire")=="on") //Cyto return; if (targ == world) return; if (!targ.takedamage) return; //WK Set off land mines if (targ.classname == "grenade" && targ.netname == "land_mine") { targ.think = GuerillaExplode; targ.nextthink = time + 0.1; return; } //BOOKKEEPING //WK Store last person who shot martyr into .enemy //(This conflicts with cameraman, but hey...) //Remember last person who shot us, so we can give him a frag if (targ.cutf_items & CUTF_EXPBODY && !targ.is_abouttodie) { //if (targ.classname == "player" && attacker.classname == "player" && !Teammate(targ.team_no, attacker.team_no)) targ.martyr_enemy = attacker; targ.stored_deathmsg = deathmsg; //- OfN - UNUSED? } if (targ.classname == "player") //WK Time holding the last time we've been shot targ.last_attacked_time = time; //WK For chaplan healing purposes //BUTTON TRIGGERING if (attacker.classname == "player") { //if (targ.classname != "player" && !IsBuilding(targ) && targ.classname != "monster_demon1") if (targ.classname != "player" && !IsBuilding(targ) && !IsMonster(targ)) { if (!Activated(targ,attacker)) { // If an else goal should be activated, activate it if (targ.else_goal != 0) { te = Findgoal(targ.else_goal); if (te) DoResults(te, attacker, (targ.goal_result & TFGR_ADD_BONUSES)); } return; } } } // used by buttons and triggers to set activator for target firing damage_attacker = attacker; // INVINCIBILITY if (targ.flags & FL_GODMODE) return; if (targ.invincible_finished >= time) { if (self.invincible_sound < time) { sound (targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM); self.invincible_sound = time + 2; } return; } else if (self.aura == AURA_RESISTANCE) { if (self.invincible_sound < time) { sound (targ, CHAN_ITEM, "auras/aura1.wav", 1, ATTN_NORM); self.invincible_sound = time + 1.5; } return; } //CHAPLAIN CALCULATIONS // WK See if they're close enough to chap to get protection if (attacker.classname == "player" && attacker.tfstate & TFSTATE_INSPIRED) { dist = vlen(attacker.origin - attacker.inspirator.origin); output = ftos(dist); if (dist > CHAPLAN_RADIUS) { //We've strayed from the flock sprint(attacker,PRINT_HIGH,"You have strayed from the flock\n"); attacker.tfstate = attacker.tfstate - TFSTATE_INSPIRED; attacker.super_damage_finished = 0; attacker.items = attacker.items & ~IT_QUAD; attacker.effects = attacker.effects - (attacker.effects & EF_DIMLIGHT); } } if (targ.classname == "player" && targ.tfstate & TFSTATE_INSPIRED) { dist = vlen(targ.origin - targ.inspirator.origin); if (dist > CHAPLAN_RADIUS) { //We've strayed from the flock sprint(targ,PRINT_HIGH,"You have strayed from the flock\n"); targ.tfstate = targ.tfstate - TFSTATE_INSPIRED; targ.super_damage_finished = 0; targ.items = targ.items & ~IT_QUAD; targ.effects = targ.effects - (targ.effects & EF_DIMLIGHT); } } // QUAD DAMAGE if (attacker.super_damage_finished > time) { if (attacker.tfstate & TFSTATE_INSPIRED) damage = damage * 1.5; if (attacker.job & JOB_BERSERKER && attacker.job & JOB_ACTIVE) damage = damage * 2; else damage = damage * 4; } if (attacker.aura == AURA_POWER || (attacker.job == JOB_CRUSADER && IsMonsterNonArmy(targ))) damage = damage * 1.5; if (targ.aura == AURA_RESISTANCE || (attacker.job == JOB_CRUSADER && IsMonsterNonArmy(targ))) damage = damage * 0.66; //DAMAGE ADJUSTMENT //- OfN - if (deathmsg != DMSG_MARTYR && targ.classname != "monster_demon1" && targ.classname != "monster_shambler" && targ.classname != "monster_army") if (deathmsg != DMSG_MARTYR && !IsMonster(targ)) { if (targ.tfstate & TFSTATE_INSPIRED) //Chaplan defense damage = damage * 0.66; //WK Ping fairness code. LPB is < 200 ping if (attacker.classname == "player" && targ.classname == "player" && attacker != targ) { foo = infokey(attacker,"ping"); ping = 200; if (foo != string_null) ping = stof(foo); ping = (ping + 1000) / 1200; if (ping < 0.8) ping = 0.8; if (ping > 1.2) ping = 1.2; damage = damage * ping; } if (teamplay & (TEAMPLAY_LESSSCOREHELP | TEAMPLAY_LESSPLAYERSHELP)) damage = TeamEqualiseDamage(targ, attacker, damage); } //MIRROR DAMAGE //WK - Check to see if we hit a friend if (Teammate(targ.team_no, attacker.team_no) && (targ != attacker) && attacker.classname == "player" && targ.classname == "player") { //We just hit someone on our team! if (T_flags & TF_TD_NOTTEAM) { //Direct damage if (teamplay & TEAMPLAY_FULLMIRRORDIRECT) mirror = mirror + damage; if (teamplay & TEAMPLAY_HALFMIRRORDIRECT) mirror = mirror + damage / 2; } else { //Explosive damage if (teamplay & TEAMPLAY_FULLMIRROREXPLOSIVE) mirror = mirror + damage; if (teamplay & TEAMPLAY_HALFMIRROREXPLOSIVE) mirror = mirror + damage / 2; } //Don't inflict damage on a (teamkiller or spy)-hitter if (mirror > 0 && !(targ.is_feigning || targ.is_undercover) && !(targ.penance_time > time)) //Hurt the jerk! TF_T_Damage (attacker, attacker, attacker, mirror, 0, TF_TD_OTHER); } //WK Slight mirror demon protection //Do 2 points of damage to a friendly teammate shooting a friendly demon //SB 2 damage? no way, we're doing the full mirror damage //- Ofn- if ((targ.classname == "monster_demon1" || targ.classname == "monster_army" || targ.classname == "monster_shambler") && targ.real_owner != world) if (IsMonster(targ) && targ.real_owner != world) { targ.armorvalue = 1; if (T_flags & TF_TD_NOTTEAM) { //Direct damage if (teamplay & TEAMPLAY_FULLMIRRORDIRECT) mirror = mirror + damage; if (teamplay & TEAMPLAY_HALFMIRRORDIRECT) mirror = mirror + damage / 2; } else { //Explosive damage if (teamplay & TEAMPLAY_FULLMIRROREXPLOSIVE) mirror = mirror + damage; if (teamplay & TEAMPLAY_HALFMIRROREXPLOSIVE) mirror = mirror + damage / 2; } if (Teammate(targ.real_owner.team_no,attacker.team_no) && (targ.real_owner != attacker) && attacker.classname == "player") TF_T_Damage (attacker, attacker, attacker, mirror, 0, TF_TD_OTHER); } //WK Friendly Sentrygun protection - you can't hurt friendly sentries if (IsBuilding(targ)) { if (Teammate(targ.team_no, attacker.team_no) && (targ != attacker) && (!(targ.tf_items & NIT_SECURITY_CAMERA))) { return; } targ.armorvalue = 1; //CH so that the armors are counted } // SPECIAL ARMOR CALCULATIONS if ((targ.armorclass != 0) && (T_AttackType != 0)) { if ((targ.armorclass & AT_SAVESHOT) && (T_AttackType == TF_TD_SHOT)) { damage = floor(damage * 0.5); //WK Cap max damage you can take with kevlar on, like in Real Life(tm) //WK The purpose being to cut down on the power of snipers if(targ.classname == "player") // SB kevlar fixed so it caps damage now, also spacing much nicer :) { local float olddamage; //- OfN - special cap damage with otr! heh olddamage=damage; if (light_damage) { if (damage > 75) damage = 75; } else if (damage > 100) damage = 100; if (attacker.classname == "player" && (deathmsg == DMSG_SNIPERRIFLE || deathmsg == DMSG_SNIPERHEADSHOT || deathmsg == DMSG_SNIPERLEGSHOT)) { sprint(attacker,PRINT_HIGH,"You hit kevlar\n"); if (attacker.cutf_items & CUTF_OTR) //- OfN - { if (olddamage > 100) olddamage=olddamage - ((olddamage - 100)*0.4); damage = olddamage; } } } } else if ((targ.armorclass & AT_SAVEMELEE) && (deathmsg == DMSG_JUDOKA || deathmsg == DMSG_AXE || deathmsg == DMSG_BACKSTAB || deathmsg == DMSG_SPANNER)) { damage = floor(damage * 0.5); if ((targ.velocity_x > 0 || targ.velocity_y > 0 || targ.velocity_z > 0) && random() > 0.6) return; if (deathmsg == DMSG_BACKSTAB) T_flags = T_flags - (T_flags & TF_TD_IGNOREARMOUR); } else if ((targ.armorclass & AT_SAVEEXPLOSION) && (T_AttackType == TF_TD_EXPLOSION)) damage = floor(damage * 0.5); else if ((targ.armorclass & AT_SAVEELECTRICITY) && (T_AttackType == TF_TD_ELECTRICITY || T_AttackType == TF_TD_NAIL)) damage = floor(damage * 0.5); else if ((targ.armorclass & AT_SAVEFIRE) && (T_AttackType == TF_TD_FIRE)) damage = floor(damage * 0.5); } //ARMOR PROTECTION CALCULATION // save damage based on the target's armor level if (T_flags & TF_TD_IGNOREARMOUR) { take = damage; save = 0; } else { save = ceil(targ.armortype*damage); if (save >= targ.armorvalue) { save = targ.armorvalue; targ.armortype = 0; // lost all armor targ.armorclass = 0; // lost special armor targ.items = targ.items & ~(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3); } //WK Flags prevent armor damage too if (T_flags & TF_TD_NOTTEAM) { if (Teammate(targ.team_no,attacker.team_no) && (targ != attacker)) { if (teamplay & TEAMPLAY_NOARMORDIRECT) targ.armorvalue = targ.armorvalue; else if (teamplay & TEAMPLAY_HALFARMORDIRECT) targ.armorvalue = targ.armorvalue - save / 2; else targ.armorvalue = targ.armorvalue - save; } else targ.armorvalue = targ.armorvalue - save; } else { if (Teammate(targ.team_no, attacker.team_no) && (targ != attacker)) { if (teamplay & TEAMPLAY_NOARMOREXPLOSIVE) targ.armorvalue = targ.armorvalue; else if (teamplay & TEAMPLAY_HALFARMOREXPLOSIVE) targ.armorvalue = targ.armorvalue - save / 2; else targ.armorvalue = targ.armorvalue - save; } else targ.armorvalue = targ.armorvalue - save; } // 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; } // KNOCKATION CALCULATION if ( (inflictor != world) && (targ.movetype == MOVETYPE_WALK) ) { // Nail Gren doesn't knock ppl //WK People with Aspect of HWGUY are immune to knockation //WK Martyrs are immune to bullet damage, so AC's and Turrets // can't be annoying and just simply stop them. //SB That's annoying. They can now :) knockem = 1; if (targ.cutf_items & CUTF_HWGUY) knockem = 0; //if (targ.job & JOB_MARTYR && targ.job & JOB_ACTIVE && T_AttackType != TF_TD_SHOT) knockem = 1; if (deathmsg == DMSG_GREN_NAIL) knockem = 0; if (knockem) { // give them some immunity to cheat check //targ.immune_to_check = time + (damage / 20); makeImmune(targ,time+(damage/20)); dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; dir = normalize(dir); // Increase kickback for smaller weapons if ( (damage < 60) & ((attacker.classname == "player") & (targ.classname == "player")) & ( attacker.netname != targ.netname)) targ.velocity = targ.velocity + dir * damage * 11; else targ.velocity = targ.velocity + dir*damage*8; if ( (rj > 1) & ((attacker.classname == "player") & (targ.classname == "player")) & ( attacker.netname == targ.netname)) targ.velocity = targ.velocity + dir * damage * rj; if (targ.classname == "player" && targ.cutf_items & CUTF_GYMNAST) targ.velocity = targ.velocity + dir * damage * 8; } } // TEAMPLAY FLAGS if (attacker.classname == "player" && targ.classname == "player") { if (T_flags & TF_TD_NOTTEAM) { if (Teammate(targ.team_no, attacker.team_no) && (targ != attacker)) { if (teamplay & TEAMPLAY_NODIRECT) return; else if (teamplay & TEAMPLAY_HALFDIRECT) take = take / 2; } } else { if (Teammate(targ.team_no, attacker.team_no) && (targ != attacker)) { if (teamplay & TEAMPLAY_NOEXPLOSIVE) return; else if (teamplay & TEAMPLAY_HALFEXPLOSIVE) take = take / 2; } } } if (T_flags & TF_TD_NOTSELF) { if (targ == attacker) return; } // do the damage, min 1 if (take < 1) take = 1; //Make thief visible when he's shot if (take > 1 && targ != attacker && (targ.job & JOB_THIEF && (targ.job & JOB_ACTIVE || targ.job & JOB_FULL_HIDE))) if (!Teammate(targ.team_no, attacker.team_no)) RevealThief(targ,TRUE); targ.health = targ.health - take; if (targ.armorvalue < 1) { targ.armorclass = 0; // lost special armor targ.armorvalue = 0; } if (targ.health < 1 && targ.health > 0) //WK Stop the scoreboard coming up targ.health = 1; if (targ.health <= 0) { if (inflictor.classname == "detpack" && inflictor.weaponmode == 1 && inflictor.enemy == targ) deathmsg = DMSG_DETPACK_DIS; //WK Autotrigger martyr - OfN - Now exp.body if ((targ.cutf_items & CUTF_EXPBODY) && attacker != world && targ.is_abouttodie == FALSE) { //oldself = self; //self = targ; targ.health = 1; targ.martyr_enemy=attacker; ExpBody(targ); //self = oldself; targ.is_abouttodie = TRUE; return; }// /////// OFTEN /////////// //WK Make sure the world doesn't have a bastard level if (attacker.classname != "player" || targ.classname != "player") { //bprint(PRINT_MEDIUM,"Non player death or kill\n"); Killed(targ, attacker); return; } //WK Handle Total Bastard Checking //If they kill more than a certain number of friends in a certain period, they are booted if (Teammate(targ.team_no, attacker.team_no) && targ != attacker && !(targ.penance_time > time) && !(targ.is_undercover) && prematch < time) { //A teamkill local string st; local float threshold; threshold = 0; st = infokey(world, "curse"); if (st != string_null) threshold = stof(st); attacker.ff_count = attacker.ff_count + 1; //Increase their bastard rating if (threshold >= 1) { if (attacker.ff_count >= threshold) createBastard(attacker,threshold); if ((attacker.ff_count == threshold - 1) || (attacker.ff_count == threshold - 0.5)) { sprint (attacker, PRINT_MEDIUM, "One more teamkill and you will be cursed.\n"); } } } if (!Teammate(targ.team_no, attacker.team_no) || targ.penance_time > time) { attacker.ff_count = attacker.ff_count - 0.5; if (attacker.ff_count < 0) attacker.ff_count = 0; } if (targ.penance_time > time) //A penitent loses frags Killed(targ, targ); else Killed(targ, attacker); return; } // react to the damage oldself = self; self = targ; if (self.th_pain) { self.th_pain (attacker, take); // nightmare mode monsters don't go into pain frames often if (skill >= 3) self.pain_finished = time + 5; } self = oldself; }; /* ============ T_RadiusDamage ============ */ void(entity inflictor, entity attacker, float damage, entity ignore) T_RadiusDamage = { local float points; local entity head, te; local vector org; head = findradius(inflictor.origin, damage+40); while (head) { if (head != ignore) { //WK Set off all land mines in blast radius if (head.classname == "grenade" && head.netname == "land_mine") { if (deathmsg != DMSG_LAND_MINE) { //head.has_tesla = 2; //- ofn - ur mine explodes better than is destroyed head.think = GuerillaExplode; head.nextthink = time + 0.1; } } // Check for TeamFortress Goals that can be triggered by Detpacks else if (head.classname == "info_tfgoal") { if (inflictor.classname == "detpack") { // Don't activate timer goals if ((head.goal_activation & TFGA_TOUCH_DETPACK) && (head.search_time == 0)) { traceline (inflictor.origin, head.origin, TRUE, inflictor); if (trace_fraction == 1) { // Does the AP match the AP Criteria? if (Activated(head,attacker)) { DoResults(head, attacker, TRUE); } else { // If an else goal should be activated, activate it if (head.else_goal != 0) { te = Findgoal(head.else_goal); if (te) DoResults(te, attacker, (head.goal_result & TFGR_ADD_BONUSES)); } return; } } } } } else 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 = rint(points * 0.75); if (head.classname == "building_camera") points = 10; if (points > 0) { if (CanDamage (head, inflictor)) { TF_T_Damage (head, inflictor, attacker, points, TF_TD_NOTTEAM, TF_TD_EXPLOSION); } //Turrets have fucked up bounding boxes due to their natures //So we have to make them susceptible to blast damage here //But only 50% damage, since they are turrets... else if ((head.classname == "building_sentrygun" || head.classname == "building_tesla") && head.tf_items & NIT_TURRET) { points = rint(points / 2); TF_T_Damage (head, inflictor, attacker, points, TF_TD_NOTTEAM, TF_TD_EXPLOSION); } } } } head = head.chain; } }; /* ============ T_BeamDamage // OfN - UNUSED so.. i coment it out ============ */ /*void(entity attacker, float damage) T_BeamDamage = { local float points; local entity head; head = findradius(attacker.origin, damage+40); while (head) { if (head.takedamage) { points = 0.5*vlen (attacker.origin - head.origin); if (points < 0) points = 0; points = damage - points; if (head == attacker) points = points * 0.5; if (points > 0) { if (CanDamage (head, attacker)) { //if (head.classname == "monster_shambler") // T_Damage (head, attacker, attacker, points*0.5); //else T_Damage (head, attacker, attacker, points); } } } head = head.chain; } };*/