From 574980bb1d36a1d272357f7d64fd6bc69cf8bada Mon Sep 17 00:00:00 2001 From: Marco Hladik Date: Thu, 7 Oct 2021 23:30:21 +0200 Subject: [PATCH] CGameRules: Now incorporates DamageApply and DamageRadius, thus making you able to have gamerule specific logic for inflicting damage to entities. --- base/src/server/damage.qc | 133 ++--------------------------------- src/server/gamerules.h | 4 ++ src/server/gamerules.qc | 144 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 128 deletions(-) diff --git a/base/src/server/damage.qc b/base/src/server/damage.qc index 558f45d1..92e93115 100644 --- a/base/src/server/damage.qc +++ b/base/src/server/damage.qc @@ -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); } diff --git a/src/server/gamerules.h b/src/server/gamerules.h index d3ec1818..54322540 100644 --- a/src/server/gamerules.h +++ b/src/server/gamerules.h @@ -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; diff --git a/src/server/gamerules.qc b/src/server/gamerules.qc index a8e20cf8..3741145e 100644 --- a/src/server/gamerules.qc +++ b/src/server/gamerules.qc @@ -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) {