.float dent_net_health;
.float dent_net_armor;
.float dent_net_potential;
+.entity dent_attackers;
bool write_damagetext(entity this, entity client, int sf)
{
float potential_damage = M_ARGV(6, float);
if(DEATH_WEAPONOF(deathtype) == WEP_VAPORIZER) return;
+ static entity net_text_prev;
+ static float net_damagetext_prev_time;
+
+ bool multiple = (net_damagetext_prev_time == time && net_text_prev && !wasfreed(net_text_prev)
+ && net_text_prev.realowner == attacker && net_text_prev.enemy == hit
+ && net_text_prev.dent_net_deathtype == deathtype);
+
+ if (multiple)
+ {
+ // damage of multiple projectiles hitting player at the same time, e.g. shotgun
+ // is accumulated on the same damagetext entity
+ health += net_text_prev.dent_net_health;
+ armor += net_text_prev.dent_net_armor;
+ potential_damage += net_text_prev.dent_net_potential;
+ }
+
int flags = 0;
if (SAME_TEAM(hit, attacker)) flags |= DTFLAG_SAMETEAM;
if (health >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_HEALTH;
if (!armor) flags |= DTFLAG_NO_ARMOR;
if (almost_equals_eps(armor + health, potential_damage, 5)) flags |= DTFLAG_NO_POTENTIAL;
+ if (multiple)
+ {
+ net_text_prev.dent_net_flags = flags;
+ net_text_prev.dent_net_health = health;
+ net_text_prev.dent_net_armor = armor;
+ net_text_prev.dent_net_potential = potential_damage;
+ return;
+ }
+ else if (!IL_CONTAINS(hit.dent_attackers, attacker))
+ {
+ // player is hit for the first time after respawn by this attacker
+ IL_PUSH(hit.dent_attackers, attacker);
+ flags |= DTFLAG_STOP_ACCUMULATION; // forcedly stop client-side damage accumulation
+ }
+
entity net_text = new_pure(net_damagetext);
net_text.realowner = attacker;
net_text.enemy = hit;
net_text.dent_net_armor = armor;
net_text.dent_net_potential = potential_damage;
+ net_text_prev = net_text;
+ net_damagetext_prev_time = time;
+
setthink(net_text, SUB_Remove);
net_text.nextthink = (time > 10) ? (time + 0.5) : 10; // allow a buffer from start time for clients to load in
Net_LinkEntity(net_text, false, 0, write_damagetext);
}
+
+MUTATOR_HOOKFUNCTION(damagetext, ClientDisconnect)
+{
+ entity player = M_ARGV(0, entity);
+ if (player.dent_attackers)
+ IL_DELETE(player.dent_attackers);
+
+ // NOTE this player is automatically removed from dent_attackers lists of other players
+ // by intrusive list's ONREMOVE
+}
+
+MUTATOR_HOOKFUNCTION(damagetext, PlayerSpawn)
+{
+ entity player = M_ARGV(0, entity);
+ if (player.dent_attackers == NULL)
+ {
+ player.dent_attackers = IL_NEW();
+ return true;
+ }
+
+ IL_CLEAR(player.dent_attackers);
+}