mirror of
https://git.code.sf.net/p/quake/game-source
synced 2024-11-25 05:11:58 +00:00
275 lines
5.3 KiB
C++
275 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);
|
|
}
|
|
};
|