CGameRules: Now incorporates DamageApply and DamageRadius, thus making you

able to have gamerule specific logic for inflicting damage to entities.
This commit is contained in:
Marco Cawthorne 2021-10-07 23:30:21 +02:00
parent dd94d7d75f
commit 574980bb1d
Signed by: eukara
GPG Key ID: C196CD8BA993248A
3 changed files with 153 additions and 128 deletions

View File

@ -18,145 +18,22 @@
void
Damage_Apply(entity t, entity c, float dmg, int w, damageType_t type)
{
base_player tp = (base_player)t;
CGameRules rules = (CGameRules)g_grMode;
/* player god mode */
if (t.flags & FL_CLIENT && t.flags & FL_GODMODE)
return;
/* already dead, please avoid recursion */
if (t.health <= 0)
return;
/* only clients have armor */
if (t.flags & FL_CLIENT) {
/* skip armor */
if not (type & DMG_SKIP_ARMOR)
if (tp.armor && dmg > 0) {
float flArmor;
float flNewDamage;
flNewDamage = dmg * 0.2;
flArmor = (dmg - flNewDamage) * 0.5;
if (flArmor > tp.armor) {
flArmor = tp.armor;
flArmor *= (1/0.5);
flNewDamage = dmg - flArmor;
tp.armor = 0;
} else {
tp.armor -= flArmor;
}
dmg = flNewDamage;
}
}
dmg = rint(dmg);
t.health -= dmg;
/* the globals... */
g_dmg_eAttacker = c;
g_dmg_eTarget = t;
g_dmg_iDamage = dmg;
g_dmg_iHitBody = trace_surface_id;
g_dmg_iFlags = type;
g_dmg_iWeapon = w;
if (dmg > 0) {
t.dmg_take = dmg;
t.dmg_inflictor = c;
} else if (t.max_health && t.health > t.max_health) {
t.health = t.max_health;
}
CBaseEntity s = (CBaseEntity)t;
if (s.health <= 0) {
if (s.flags & FL_CLIENT) {
rules.PlayerDeath((player)s);
} else {
s.Death();
}
} else {
if (s.flags & FL_CLIENT) {
rules.PlayerPain((player)s);
} else {
s.Pain();
}
}
rules.DamageApply(t, c, dmg, w, type);
}
/* physical check of whether or not we can trace important parts of an ent */
float
Damage_CheckTrace(entity t, vector vecHitPos)
{
/* We're lazy. Who cares */
if (t.solid == SOLID_BSP) {
return (1);
}
traceline(vecHitPos, t.origin, 1, self);
if (trace_fraction == 1) {
return (1);
}
traceline(vecHitPos, t.origin + [15,15,0], 1, self);
if (trace_fraction == 1) {
return (1);
}
traceline(vecHitPos, t.origin + [-15,-15,0], 1, self);
if (trace_fraction == 1) {
return (1);
}
traceline(vecHitPos, t.origin + [-15,15,0], 1, self);
if (trace_fraction == 1) {
return (1);
}
traceline(vecHitPos, t.origin + [15,-15,0], 1, self);
if (trace_fraction == 1) {
return (1);
}
return (0);
CGameRules rules = (CGameRules)g_grMode;
return rules.DamageCheckTrace(t, vecHitPos);
}
/* even more pain and suffering, mostly used for explosives */
void
Damage_Radius(vector org, entity attacker, float dmg, float r, int check, int w)
{
float new_dmg;
float dist;
float diff;
vector pos;
for (entity e = world; (e = findfloat(e, ::takedamage, DAMAGE_YES));) {
pos[0] = e.absmin[0] + (0.5 * (e.absmax[0] - e.absmin[0]));
pos[1] = e.absmin[1] + (0.5 * (e.absmax[1] - e.absmin[1]));
pos[2] = e.absmin[2] + (0.5 * (e.absmax[2] - e.absmin[2]));
/* don't bother if it's not anywhere near us */
dist = vlen(org - pos);
if (dist > r)
continue;
/* can we physically hit this thing? */
if (check == TRUE)
if (Damage_CheckTrace(e, org) == FALSE)
continue;
/* calculate new damage values */
diff = (r - dist) / r;
new_dmg = rint(dmg * diff);
if (diff > 0) {
Damage_Apply(e, attacker, new_dmg, w, DMG_EXPLODE);
/* approximate, feel free to tweak */
if (e.movetype == MOVETYPE_WALK) {
makevectors(vectoangles(e.origin - org));
e.velocity += v_forward * (new_dmg * 5);
}
}
}
CGameRules rules = (CGameRules)g_grMode;
rules.DamageRadius(org, attacker, dmg, r, check, w);
}

View File

@ -42,8 +42,12 @@ class CGameRules
virtual void(void) LevelNewParms;
virtual void(base_player) LevelChangeParms;
/* Entities/Item manipulation */
virtual int(int) MaxItemPerSlot;
virtual int(void) MonstersSpawn;
virtual void(entity,entity,float,int,damageType_t) DamageApply;
virtual int(entity, vector) DamageCheckTrace;
virtual void(vector,entity,float,float,int,int) DamageRadius;
/* end of a game */
virtual void(void) IntermissionStart;

View File

@ -177,6 +177,150 @@ CGameRules::MonstersSpawn(void)
return (TRUE);
}
void
CGameRules::DamageApply(entity t, entity c, float dmg, int w, damageType_t type)
{
/* Damage */
base_player tp = (base_player)t;
/* player god mode */
if (t.flags & FL_CLIENT && t.flags & FL_GODMODE)
return;
/* already dead, please avoid recursion */
if (t.health <= 0)
return;
/* only clients have armor */
if (t.flags & FL_CLIENT) {
/* skip armor */
if not (type & DMG_SKIP_ARMOR)
if (tp.armor && dmg > 0) {
float flArmor;
float flNewDamage;
flNewDamage = dmg * 0.2;
flArmor = (dmg - flNewDamage) * 0.5;
if (flArmor > tp.armor) {
flArmor = tp.armor;
flArmor *= (1/0.5);
flNewDamage = dmg - flArmor;
tp.armor = 0;
} else {
tp.armor -= flArmor;
}
dmg = flNewDamage;
}
}
dmg = rint(dmg);
t.health -= dmg;
/* the globals... */
g_dmg_eAttacker = c;
g_dmg_eTarget = t;
g_dmg_iDamage = dmg;
g_dmg_iHitBody = trace_surface_id;
g_dmg_iFlags = type;
g_dmg_iWeapon = w;
if (dmg > 0) {
t.dmg_take = dmg;
t.dmg_inflictor = c;
} else if (t.max_health && t.health > t.max_health) {
t.health = t.max_health;
}
CBaseEntity s = (CBaseEntity)t;
if (s.health <= 0) {
if (s.flags & FL_CLIENT) {
PlayerDeath((player)s);
} else {
s.Death();
}
} else {
if (s.flags & FL_CLIENT) {
PlayerPain((player)s);
} else {
s.Pain();
}
}
}
/* checks if we can hit an entity at 5 of the same spots */
int
CGameRules::DamageCheckTrace(entity t, vector vecHitPos)
{
/* We're lazy. Who cares */
if (t.solid == SOLID_BSP) {
return (TRUE);
}
traceline(vecHitPos, t.origin, 1, self);
if (trace_fraction == 1) {
return (TRUE);
}
traceline(vecHitPos, t.origin + [15,15,0], 1, self);
if (trace_fraction == 1) {
return (TRUE);
}
traceline(vecHitPos, t.origin + [-15,-15,0], 1, self);
if (trace_fraction == 1) {
return (TRUE);
}
traceline(vecHitPos, t.origin + [-15,15,0], 1, self);
if (trace_fraction == 1) {
return (TRUE);
}
traceline(vecHitPos, t.origin + [15,-15,0], 1, self);
if (trace_fraction == 1) {
return (TRUE);
}
return (FALSE);
}
void
CGameRules::DamageRadius(vector org, entity attacker, float dmg, float r, int check, int w)
{
float new_dmg;
float dist;
float diff;
vector pos;
for (entity e = world; (e = findfloat(e, ::takedamage, DAMAGE_YES));) {
pos[0] = e.absmin[0] + (0.5 * (e.absmax[0] - e.absmin[0]));
pos[1] = e.absmin[1] + (0.5 * (e.absmax[1] - e.absmin[1]));
pos[2] = e.absmin[2] + (0.5 * (e.absmax[2] - e.absmin[2]));
/* don't bother if it's not anywhere near us */
dist = vlen(org - pos);
if (dist > r)
continue;
/* can we physically hit this thing? */
if (check == TRUE)
if (DamageCheckTrace(e, org) == FALSE)
continue;
/* calculate new damage values */
diff = (r - dist) / r;
new_dmg = rint(dmg * diff);
if (diff > 0) {
DamageApply(e, attacker, new_dmg, w, DMG_EXPLODE);
/* approximate, feel free to tweak */
if (e.movetype == MOVETYPE_WALK) {
makevectors(vectoangles(e.origin - org));
e.velocity += v_forward * (new_dmg * 5);
}
}
}
}
void
CGameRules::IntermissionEnd(void)
{