fteqw/quakec/basemod/combat.qc

325 lines
6.6 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.
============
*/
BOOL(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
*/
BOOL(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
*/
BOOL(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;
}
};