game-source/klik/damage.qc

276 lines
5.3 KiB
C++

#include "common.qh"
#include "misc.qh"
#include "damage.qh"
#include "server.qh"
.entity dmg_attacker;
.void () deathmsg;
.string deathmsg1, deathmsg2, deathmsg3, deathmsg4, deathmsg5, deathmsg6;
// You _MUST_ have th_takedamage if you .takedamage!
// Return TRUE if you were damaged, FALSE otherwise.
.float (float dmg) th_takedamage;
/* Allows you to globally override damage you deal */
/* self = you, other = target */
/* returns new amount of damage, or < 0 for don't */
.float (float dmg) th_dealdamage;
.void (entity missile) th_attack;
/* Update frags in these. */
.void () th_die;
.void () th_kill;
.float (entity missile) th_projectile;
entity ghost_inflictor;
void ()
damage_init =
{
ghost_inflictor = spawn ("GHOST_INFLICTOR");
};
void (entity from, entity to)
deathmsg_copy =
{
to.deathmsg1 = from.deathmsg1;
to.deathmsg2 = from.deathmsg2;
to.deathmsg3 = from.deathmsg3;
to.deathmsg4 = from.deathmsg4;
to.deathmsg5 = from.deathmsg5;
to.deathmsg6 = from.deathmsg6;
};
string (entity e, string s) _deathmsg_custom_str = {
if (s == "name(self)")
return name(self);
if (s == "name(attacker)")
return name (self.dmg_attacker);
if (s == "name(inflictor)")
return name (self.dmg_inflictor);
return s;
};
void ()
_deathmsg_custom =
{
local string s1, s2, s3, s4, s5, s6;
s1 = s2 = s3 = s4 = s5 = s6 = "";
s1 = _deathmsg_custom_str (self, self.deathmsg1);
if (s1)
s2 = _deathmsg_custom_str (self, self.deathmsg2);
if (s2)
s3 = _deathmsg_custom_str (self, self.deathmsg3);
if (s3)
s4 = _deathmsg_custom_str (self, self.deathmsg4);
if (s4)
s5 = _deathmsg_custom_str (self, self.deathmsg5);
if (s5)
s6 = _deathmsg_custom_str (self, self.deathmsg6);
// I don't use separate bprints, because iD in all its wisdom
// made them unreliable -- I'd rather lose the whole thing than parts.
bprint (PRINT_DEATH, s1, s2, s3, s4, s5, s6);
};
void ()
deathmsg_nodisplay =
{
// refcount_dec (self.dmg_attacker);
// refcount_dec (self.dmg_inflictor);
self.dmg_attacker = world;
self.dmg_inflictor = world;
self.deathmsg = NOTHING_function;
};
void ()
deathmsg_display =
{
if (self.th_die)
self.th_die ();
if (other.th_kill) {
local entity oldself, oldother;
oldself = self;
oldother = other;
self = oldother;
other = oldself;
self.th_kill ();
self = oldself;
other = oldother;
}
self.deathmsg ();
deathmsg_nodisplay ();
};
float (float d)
damage_armor = {
local float adamg, rest;
adamg = d * self.armortype;
if (self.armorvalue < adamg)
adamg = self.armorvalue;
rest = d - adamg;
self.armorvalue = self.armorvalue - adamg;
if (self.armorvalue <= 0) {
self.armorvalue = 0;
self.armortype = 0.0;
}
return rest;
};
void (float d)
damage_push =
{
local vector vel;
if (self.mass == 0) {
d = 0;
} else {
if (self.dmg_attacker == self)
d = (self.dmg_inflictor.mass + d * rocket_jump) / self.mass;
else
d = self.dmg_inflictor.mass / self.mass;
}
if (self.dmg_inflictor.velocity == '0 0 0') {
vel = normalize (self.origin - self.dmg_inflictor.origin);
vel *= self.dmg_inflictor.speed;
} else {
vel = self.dmg_inflictor.velocity;
}
self.velocity += d * vel;
};
// deathmessage _IS_ overridden if inflictor.deathmsg1
float (entity ent, entity attacker, entity inflictor, float d,
void() deathmessage)
damage =
{
local entity oldself, oldother;
local float wasdamaged;
if (!ent.takedamage)
return FALSE;
oldself = self;
oldother = other;
ent.dmg_attacker = attacker;
ent.dmg_inflictor = inflictor;
// refcount_inc (ent.dmg_attacker);
// refcount_inc (ent.dmg_inflictor);
if (inflictor.deathmsg1)
ent.deathmsg = _deathmsg_custom;
else
ent.deathmsg = deathmessage;
if (attacker.th_dealdamage) {
self = attacker;
other = ent;
d = self.th_dealdamage(d);
self = oldself;
other = oldother;
if (d < 0)
return FALSE;
}
self = ent;
other = attacker;
wasdamaged = self.th_takedamage(d);
self = oldself;
other = oldother;
return wasdamaged;
};
float (vector org, entity e)
_damage_radius_can_hit =
{
if (e.movetype == MOVETYPE_PUSH) {
traceline (org, center (e), TRUE, world);
if (trace_fraction == 1 || trace_ent == e)
return TRUE;
return FALSE;
}
traceline (org, e.origin, TRUE, self);
if (trace_fraction == 1)
return TRUE;
traceline (org, e.origin + '15 15 0', TRUE, self);
if (trace_fraction == 1)
return TRUE;
traceline (org, e.origin + '15 -15 0', TRUE, self);
if (trace_fraction == 1)
return TRUE;
traceline (org, e.origin + '-15 15 0', TRUE, self);
if (trace_fraction == 1)
return TRUE;
traceline (org, e.origin + '-15 -15 0', TRUE, self);
if (trace_fraction == 1)
return TRUE;
return FALSE;
};
void (entity ignore, entity attacker, entity inflictor, void () deathmessage)
damage_radius =
{
local entity head;
local vector iorg, org;
local float points, d, m, r;
d = inflictor.dmg;
m = inflictor.mass;
r = inflictor.lip;
iorg = center (inflictor);
for (head = findradius (iorg, r + 40); head; head = head.chain) {
if (head == ignore)
continue;
if (!_damage_radius_can_hit (iorg, head))
continue;
org = center(head);
points = r - (0.5 * vlen (iorg - org));
if (points <= 0)
continue;
if (head == attacker)
points *= 0.5;
inflictor.dmg = (points * d) / r;
inflictor.mass = (points * m) / r;
damage (head, attacker, inflictor, inflictor.dmg, deathmessage);
}
};