1 #include "sv_damagetext.qh"
3 AUTOCVAR(sv_damagetext, int, 2, "<= 0: disabled, >= 1: visible to spectators, >= 2: visible to attacker, >= 3: all players see everyone's damage");
5 REGISTER_MUTATOR(damagetext, true);
7 #define SV_DAMAGETEXT_DISABLED() (autocvar_sv_damagetext <= 0)
8 #define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1)
9 #define SV_DAMAGETEXT_PLAYERS() (autocvar_sv_damagetext >= 2)
10 #define SV_DAMAGETEXT_ALL() (autocvar_sv_damagetext >= 3)
11 MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
12 if (SV_DAMAGETEXT_DISABLED()) return;
13 entity attacker = M_ARGV(0, entity);
14 entity hit = M_ARGV(1, entity); if (hit == attacker) return;
15 float health = M_ARGV(2, float);
16 float armor = M_ARGV(3, float);
17 int deathtype = M_ARGV(5, int);
18 float potential_damage = M_ARGV(6, float);
19 if(DEATH_WEAPONOF(deathtype) == WEP_VAPORIZER) return;
20 if(deathtype == DEATH_FIRE.m_id || deathtype == DEATH_BUFF.m_id) return; // TODO: exclude damage over time and thorn effects
21 FOREACH_CLIENT(IS_REAL_CLIENT(it), {
23 (SV_DAMAGETEXT_ALL()) ||
24 (SV_DAMAGETEXT_PLAYERS() && it == attacker) ||
25 (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(it) && it.enemy == attacker) ||
26 (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(it))
29 if (SAME_TEAM(hit, attacker)) flags |= DTFLAG_SAMETEAM;
30 if (health >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_HEALTH;
31 if (armor >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_ARMOR;
32 if (potential_damage >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_POTENTIAL;
33 if (!armor) flags |= DTFLAG_NO_ARMOR;
34 if (almost_equals_eps(armor + health, potential_damage, 5)) flags |= DTFLAG_NO_POTENTIAL;
37 WriteHeader(MSG_ONE, damagetext);
38 WriteByte(MSG_ONE, etof(hit));
39 WriteInt24_t(MSG_ONE, deathtype);
40 WriteByte(MSG_ONE, flags);
42 // we need to send a few decimal places to minimize errors when accumulating damage
43 // sending them multiplied saves bandwidth compared to using WriteCoord,
44 // however if the multiplied damage would be too much for (signed) short, we send an int24
45 if (flags & DTFLAG_BIG_HEALTH) WriteInt24_t(MSG_ONE, health * DAMAGETEXT_PRECISION_MULTIPLIER);
46 else WriteShort(MSG_ONE, health * DAMAGETEXT_PRECISION_MULTIPLIER);
47 if (!(flags & DTFLAG_NO_ARMOR))
49 if (flags & DTFLAG_BIG_ARMOR) WriteInt24_t(MSG_ONE, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
50 else WriteShort(MSG_ONE, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
52 if (!(flags & DTFLAG_NO_POTENTIAL))
54 if (flags & DTFLAG_BIG_POTENTIAL) WriteInt24_t(MSG_ONE, potential_damage * DAMAGETEXT_PRECISION_MULTIPLIER);
55 else WriteShort(MSG_ONE, potential_damage * DAMAGETEXT_PRECISION_MULTIPLIER);