]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/damagetext/sv_damagetext.qc
Merge branch 'Juhu/velocity_pads_cleanup' into 'master'
[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     if(deathtype == DEATH_FIRE.m_id || deathtype == DEATH_BUFF.m_id) return; // TODO: exclude damage over time and thorn effects
67
68     int flags = 0;
69     if (SAME_TEAM(hit, attacker)) flags |= DTFLAG_SAMETEAM;
70     if (health >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_HEALTH;
71     if (armor >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_ARMOR;
72     if (potential_damage >= DAMAGETEXT_SHORT_LIMIT) flags |= DTFLAG_BIG_POTENTIAL;
73     if (!armor) flags |= DTFLAG_NO_ARMOR;
74     if (almost_equals_eps(armor + health, potential_damage, 5)) flags |= DTFLAG_NO_POTENTIAL;
75
76     entity net_text = new_pure(net_damagetext);
77     net_text.realowner = attacker;
78     net_text.enemy = hit;
79     net_text.dent_net_flags = flags;
80     net_text.dent_net_deathtype = deathtype;
81     net_text.dent_net_health = health;
82     net_text.dent_net_armor = armor;
83     net_text.dent_net_potential = potential_damage;
84
85     setthink(net_text, SUB_Remove);
86     net_text.nextthink = (time > 10) ? (time + 0.5) : 10; // allow a buffer from start time for clients to load in
87
88     Net_LinkEntity(net_text, false, 0, write_damagetext);
89 }