]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/damagetext/sv_damagetext.qc
DamageText code quality changes and new DT lifetime and accumulation lifetime cvars
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / damagetext / sv_damagetext.qc
1 #include "sv_damagetext.qh"
2
3 AUTOCVAR(sv_damagetext, int, 2, "<= 0: disabled, >= 1: visible to spectators, >= 2: visible to attacker, >= 3: all players see everyone's damage");
4
5 REGISTER_MUTATOR(damagetext, true);
6
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
12 .int dent_net_flags;
13 .float dent_net_deathtype;
14 .float dent_net_health;
15 .float dent_net_armor;
16 .float dent_net_potential;
17
18 bool write_damagetext(entity this, entity client, int sf)
19 {
20         entity attacker = this.realowner;
21         entity hit = this.enemy;
22         int flags = this.dent_net_flags;
23         int deathtype = this.dent_net_deathtype;
24         float health = this.dent_net_health;
25         float armor = this.dent_net_armor;
26         float potential_damage = this.dent_net_potential;
27         if (!(
28                 (SV_DAMAGETEXT_ALL()) ||
29                 (SV_DAMAGETEXT_PLAYERS() && client == attacker) ||
30                 (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(client) && client.enemy == attacker) ||
31                 (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(client))
32         )) return false;
33
34         WriteHeader(MSG_ENTITY, damagetext);
35         WriteByte(MSG_ENTITY, etof(hit));
36         WriteInt24_t(MSG_ENTITY, deathtype);
37         WriteByte(MSG_ENTITY, flags);
38
39         // we need to send a few decimal places to minimize errors when accumulating damage
40         // sending them multiplied saves bandwidth compared to using WriteCoord,
41         // however if the multiplied damage would be too much for (signed) short, we send an int24
42         if (flags & DTFLAG_BIG_HEALTH) WriteInt24_t(MSG_ENTITY, health * DAMAGETEXT_PRECISION_MULTIPLIER);
43         else WriteShort(MSG_ENTITY, health * DAMAGETEXT_PRECISION_MULTIPLIER);
44         if (!(flags & DTFLAG_NO_ARMOR))
45         {
46                 if (flags & DTFLAG_BIG_ARMOR) WriteInt24_t(MSG_ENTITY, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
47                 else WriteShort(MSG_ENTITY, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
48         }
49         if (!(flags & DTFLAG_NO_POTENTIAL))
50         {
51                 if (flags & DTFLAG_BIG_POTENTIAL) WriteInt24_t(MSG_ENTITY, potential_damage * DAMAGETEXT_PRECISION_MULTIPLIER);
52                 else WriteShort(MSG_ENTITY, potential_damage * DAMAGETEXT_PRECISION_MULTIPLIER);
53         }
54         return true;
55 }
56
57 MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
58         if (SV_DAMAGETEXT_DISABLED()) return;
59         entity attacker = M_ARGV(0, entity);
60         entity hit = M_ARGV(1, entity); if (hit == attacker) return;
61         float health = M_ARGV(2, float);
62         float armor = M_ARGV(3, float);
63         int deathtype = M_ARGV(5, int);
64         float potential_damage = M_ARGV(6, float);
65         if(DEATH_WEAPONOF(deathtype) == WEP_VAPORIZER) return;
66
67         int flags = 0;
68         if (SAME_TEAM(hit, attacker)) flags |= DTFLAG_SAMETEAM;
69         if (health >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_HEALTH;
70         if (armor >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_ARMOR;
71         if (potential_damage >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_POTENTIAL;
72         if (!armor) flags |= DTFLAG_NO_ARMOR;
73         if (almost_equals_eps(armor + health, potential_damage, 5)) flags |= DTFLAG_NO_POTENTIAL;
74
75         entity net_text = new_pure(net_damagetext);
76         net_text.realowner = attacker;
77         net_text.enemy = hit;
78         net_text.dent_net_flags = flags;
79         net_text.dent_net_deathtype = deathtype;
80         net_text.dent_net_health = health;
81         net_text.dent_net_armor = armor;
82         net_text.dent_net_potential = potential_damage;
83
84         setthink(net_text, SUB_Remove);
85         net_text.nextthink = (time > 10) ? (time + 0.5) : 10; // allow a buffer from start time for clients to load in
86
87         Net_LinkEntity(net_text, false, 0, write_damagetext);
88 }