prozac-qfcc/combat.qc

891 lines
26 KiB
C++
Raw Normal View History

2001-07-17 05:58:10 +00:00
/*======================================================
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"
2001-07-17 05:58:10 +00:00
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 =
{
local entity ent, otemp, stemp;
// 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;
2001-07-17 05:58:10 +00:00
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)
2001-07-17 05:58:10 +00:00
{
traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self);
2001-07-17 05:58:10 +00:00
if (trace_fraction == 1)
return TRUE;
2001-07-17 05:58:10 +00:00
if (trace_ent == targ)
return TRUE;
return FALSE;
2001-07-17 05:58:10 +00:00
}
if (targ.classname == "building_sentrygun" && (targ.tf_items & NIT_TURRET))
2001-07-17 05:58:10 +00:00
soffset='0 0 -20';
// OfN - Force field
traceline(inflictor.origin, targ.origin + soffset, FALSE, self);
2001-07-17 05:58:10 +00:00
if (trace_ent.classname == "force_field")
{
FieldExplosion(trace_ent,trace_endpos,trace_ent);
PutFieldWork(trace_ent);
return FALSE;
2001-07-17 05:58:10 +00:00
}
traceline(inflictor.origin, targ.origin + soffset, TRUE, self);
2001-07-17 05:58:10 +00:00
if (trace_fraction == 1)
return TRUE;
/*traceline(inflictor.origin, targ.origin + '15 15 0' + soffset, TRUE, self);
2001-07-17 05:58:10 +00:00
if (trace_fraction == 1)
return TRUE;
traceline(inflictor.origin, targ.origin + '-15 -15 0' + soffset, TRUE, self);
2001-07-17 05:58:10 +00:00
if (trace_fraction == 1)
return TRUE;
traceline(inflictor.origin, targ.origin + '-15 15 0' + soffset, TRUE, self);
2001-07-17 05:58:10 +00:00
if (trace_fraction == 1)
return TRUE;
traceline(inflictor.origin, targ.origin + '15 -15 0' + soffset, TRUE, self);
2001-07-17 05:58:10 +00:00
if (trace_fraction == 1)
return TRUE;*/ // OfN - Fixes dets thru wall?
2001-07-17 05:58:10 +00:00
return FALSE;
2001-07-17 05:58:10 +00:00
};
/*
============
Killed
============
*/
void(entity targ, entity attacker) Killed =
{
// SOLVES BUG ???? // Stack overflow?
if (targ.is_killed == TRUE)
2001-07-17 05:58:10 +00:00
{
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)
2001-07-17 05:58:10 +00:00
{
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)
2001-07-17 05:58:10 +00:00
{
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)
2001-07-17 05:58:10 +00:00
{
RPrint(" (with expbody) ");
}
else
{
RPrint(" (without expbody) ");
}
RPrint("\n"); */
}
}
targ.is_killed = TRUE;
2001-07-17 05:58:10 +00:00
/////////////////////////////////////
local entity oself;
local string db;
//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))
2001-07-17 05:58:10 +00:00
targ.frags = targ.real_frags;
targ.health = 50; //Give em a little so they can die again
targ.is_killed = FALSE;
2001-07-17 05:58:10 +00:00
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.
2001-07-17 05:58:10 +00:00
{
self.th_die ();
self = oself;
return;
}
self.enemy = attacker;
// bump the monster counter
if (self.flags & FL_MONSTER)
2001-07-17 05:58:10 +00:00
{
killed_monsters = killed_monsters + 1;
WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
2001-07-17 05:58:10 +00:00
}
ClientObituary(self, attacker);
self.takedamage = DAMAGE_NO;
2001-07-17 05:58:10 +00:00
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
2001-07-17 05:58:10 +00:00
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
2001-07-17 05:58:10 +00:00
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)
2001-07-17 05:58:10 +00:00
{
//if (targ.classname == "player" && attacker.classname == "player" && !Teammate(targ.team_no, attacker.team_no))
2001-07-17 05:58:10 +00:00
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));
2001-07-17 05:58:10 +00:00
}
return;
}
}
}
// used by buttons and triggers to set activator for target firing
damage_attacker = attacker;
// INVINCIBILITY
if (targ.flags & FL_GODMODE)
2001-07-17 05:58:10 +00:00
return;
if (targ.invincible_finished >= time)
{
if (self.invincible_sound < time)
{
sound (targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
2001-07-17 05:58:10 +00:00
self.invincible_sound = time + 2;
}
return;
}
else if (self.aura == AURA_RESISTANCE)
2001-07-17 05:58:10 +00:00
{
if (self.invincible_sound < time)
{
sound (targ, CHAN_ITEM, "auras/aura1.wav", 1, ATTN_NORM);
2001-07-17 05:58:10 +00:00
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) {
2001-07-17 05:58:10 +00:00
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;
2001-07-17 05:58:10 +00:00
attacker.super_damage_finished = 0;
attacker.items = attacker.items & ~IT_QUAD;
attacker.effects = attacker.effects - (attacker.effects & EF_DIMLIGHT);
2001-07-17 05:58:10 +00:00
}
}
if (targ.classname == "player" && targ.tfstate & TFSTATE_INSPIRED) {
2001-07-17 05:58:10 +00:00
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;
2001-07-17 05:58:10 +00:00
targ.super_damage_finished = 0;
targ.items = targ.items & ~IT_QUAD;
targ.effects = targ.effects - (targ.effects & EF_DIMLIGHT);
2001-07-17 05:58:10 +00:00
}
}
// QUAD DAMAGE
if (attacker.super_damage_finished > time) {
if (attacker.tfstate & TFSTATE_INSPIRED)
2001-07-17 05:58:10 +00:00
damage = damage * 1.5;
if (attacker.job & JOB_BERSERKER && attacker.job & JOB_ACTIVE)
2001-07-17 05:58:10 +00:00
damage = damage * 2;
else
damage = damage * 4;
}
if (attacker.aura == AURA_POWER || (attacker.job == JOB_CRUSADER && IsMonsterNonArmy(targ)))
2001-07-17 05:58:10 +00:00
damage = damage * 1.5;
if (targ.aura == AURA_RESISTANCE || (attacker.job == JOB_CRUSADER && IsMonsterNonArmy(targ)))
2001-07-17 05:58:10 +00:00
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))
2001-07-17 05:58:10 +00:00
{
if (targ.tfstate & TFSTATE_INSPIRED) //Chaplan defense
2001-07-17 05:58:10 +00:00
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))
2001-07-17 05:58:10 +00:00
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)
2001-07-17 05:58:10 +00:00
{
//Direct damage
if (teamplay & TEAMPLAY_FULLMIRRORDIRECT)
2001-07-17 05:58:10 +00:00
mirror = mirror + damage;
if (teamplay & TEAMPLAY_HALFMIRRORDIRECT)
2001-07-17 05:58:10 +00:00
mirror = mirror + damage / 2;
}
else
{
//Explosive damage
if (teamplay & TEAMPLAY_FULLMIRROREXPLOSIVE)
2001-07-17 05:58:10 +00:00
mirror = mirror + damage;
if (teamplay & TEAMPLAY_HALFMIRROREXPLOSIVE)
2001-07-17 05:58:10 +00:00
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);
2001-07-17 05:58:10 +00:00
}
//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)
2001-07-17 05:58:10 +00:00
if (IsMonster(targ) && targ.real_owner != world) {
targ.armorvalue = 1;
if (T_flags & TF_TD_NOTTEAM)
2001-07-17 05:58:10 +00:00
{
//Direct damage
if (teamplay & TEAMPLAY_FULLMIRRORDIRECT)
2001-07-17 05:58:10 +00:00
mirror = mirror + damage;
if (teamplay & TEAMPLAY_HALFMIRRORDIRECT)
2001-07-17 05:58:10 +00:00
mirror = mirror + damage / 2;
}
else
{
//Explosive damage
if (teamplay & TEAMPLAY_FULLMIRROREXPLOSIVE)
2001-07-17 05:58:10 +00:00
mirror = mirror + damage;
if (teamplay & TEAMPLAY_HALFMIRROREXPLOSIVE)
2001-07-17 05:58:10 +00:00
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);
2001-07-17 05:58:10 +00:00
}
//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))) {
2001-07-17 05:58:10 +00:00
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)) {
2001-07-17 05:58:10 +00:00
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))
2001-07-17 05:58:10 +00:00
{
sprint(attacker,PRINT_HIGH,"You hit kevlar\n");
if (attacker.cutf_items & CUTF_OTR) //- OfN -
2001-07-17 05:58:10 +00:00
{
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))
2001-07-17 05:58:10 +00:00
{
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);
2001-07-17 05:58:10 +00:00
}
else if ((targ.armorclass & AT_SAVEEXPLOSION) && (T_AttackType == TF_TD_EXPLOSION))
2001-07-17 05:58:10 +00:00
damage = floor(damage * 0.5);
else if ((targ.armorclass & AT_SAVEELECTRICITY) && (T_AttackType == TF_TD_ELECTRICITY || T_AttackType == TF_TD_NAIL))
2001-07-17 05:58:10 +00:00
damage = floor(damage * 0.5);
else if ((targ.armorclass & AT_SAVEFIRE) && (T_AttackType == TF_TD_FIRE))
2001-07-17 05:58:10 +00:00
damage = floor(damage * 0.5);
}
//ARMOR PROTECTION CALCULATION
// save damage based on the target's armor level
if (T_flags & TF_TD_IGNOREARMOUR)
2001-07-17 05:58:10 +00:00
{
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);
2001-07-17 05:58:10 +00:00
}
//WK Flags prevent armor damage too
if (T_flags & TF_TD_NOTTEAM)
2001-07-17 05:58:10 +00:00
{
if (Teammate(targ.team_no,attacker.team_no) && (targ != attacker))
{
if (teamplay & TEAMPLAY_NOARMORDIRECT)
2001-07-17 05:58:10 +00:00
targ.armorvalue = targ.armorvalue;
else if (teamplay & TEAMPLAY_HALFARMORDIRECT)
2001-07-17 05:58:10 +00:00
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)
2001-07-17 05:58:10 +00:00
targ.armorvalue = targ.armorvalue;
else if (teamplay & TEAMPLAY_HALFARMOREXPLOSIVE)
2001-07-17 05:58:10 +00:00
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)
2001-07-17 05:58:10 +00:00
{
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) )
2001-07-17 05:58:10 +00:00
{
// 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;
2001-07-17 05:58:10 +00:00
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)
2001-07-17 05:58:10 +00:00
targ.velocity = targ.velocity + dir * damage * 8;
}
}
// TEAMPLAY FLAGS
if (attacker.classname == "player" && targ.classname == "player") {
if (T_flags & TF_TD_NOTTEAM) {
2001-07-17 05:58:10 +00:00
if (Teammate(targ.team_no, attacker.team_no) && (targ != attacker)) {
if (teamplay & TEAMPLAY_NODIRECT) return;
else if (teamplay & TEAMPLAY_HALFDIRECT) take = take / 2;
2001-07-17 05:58:10 +00:00
}
}
else {
if (Teammate(targ.team_no, attacker.team_no) && (targ != attacker)) {
if (teamplay & TEAMPLAY_NOEXPLOSIVE) return;
else if (teamplay & TEAMPLAY_HALFEXPLOSIVE) take = take / 2;
2001-07-17 05:58:10 +00:00
}
}
}
if (T_flags & TF_TD_NOTSELF) {
2001-07-17 05:58:10 +00:00
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)))
2001-07-17 05:58:10 +00:00
if (!Teammate(targ.team_no, attacker.team_no))
RevealThief(targ,TRUE);
2001-07-17 05:58:10 +00:00
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;
2001-07-17 05:58:10 +00:00
//WK Autotrigger martyr - OfN - Now exp.body
if ((targ.cutf_items & CUTF_EXPBODY) && attacker != world && targ.is_abouttodie == FALSE)
2001-07-17 05:58:10 +00:00
{
//oldself = self;
//self = targ;
targ.health = 1;
targ.martyr_enemy=attacker;
ExpBody(targ);
//self = oldself;
targ.is_abouttodie = TRUE;
2001-07-17 05:58:10 +00:00
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");
2001-07-17 05:58:10 +00:00
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");
2001-07-17 05:58:10 +00:00
}
}
}
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) {
2001-07-17 05:58:10 +00:00
//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))
2001-07-17 05:58:10 +00:00
{
traceline (inflictor.origin, head.origin, TRUE, inflictor);
2001-07-17 05:58:10 +00:00
if (trace_fraction == 1)
{
// Does the AP match the AP Criteria?
if (Activated(head,attacker))
{
DoResults(head, attacker, TRUE);
2001-07-17 05:58:10 +00:00
}
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));
2001-07-17 05:58:10 +00:00
}
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);
2001-07-17 05:58:10 +00:00
}
//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) {
2001-07-17 05:58:10 +00:00
points = rint(points / 2);
TF_T_Damage (head, inflictor, attacker, points, TF_TD_NOTTEAM, TF_TD_EXPLOSION);
2001-07-17 05:58:10 +00:00
}
}
}
}
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;
}
};*/