Xonotic
sv_damagetext.qc
Go to the documentation of this file.
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 
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) ||
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 }
float dent_net_armor
entity() spawn
#define IS_OBSERVER(v)
Definition: utils.qh:11
const int DTFLAG_NO_POTENTIAL
Definition: damagetext.qh:11
const int DTFLAG_NO_ARMOR
Definition: damagetext.qh:10
#define DAMAGETEXT_PRECISION_MULTIPLIER
Definition: damagetext.qh:3
#define DEATH_WEAPONOF(t)
Definition: all.qh:41
const int DTFLAG_BIG_POTENTIAL
Definition: damagetext.qh:9
#define IS_SPEC(v)
Definition: utils.qh:10
entity enemy
Definition: sv_ctf.qh:143
REGISTER_MUTATOR(damagetext, true)
MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged)
#define SV_DAMAGETEXT_PLAYERS()
Definition: sv_damagetext.qc:9
#define DAMAGETEXT_SHORT_LIMIT
Definition: damagetext.qh:4
float dent_net_health
#define SAME_TEAM(a, b)
Definition: teams.qh:239
#define M_ARGV(x, type)
Definition: events.qh:17
#define SV_DAMAGETEXT_ALL()
float flags
Definition: csprogsdefs.qc:129
float health
Definition: progsdefs.qc:137
float dent_net_deathtype
const int DTFLAG_SAMETEAM
Definition: damagetext.qh:6
entity realowner
Definition: common.qh:25
float dent_net_potential
AUTOCVAR(sv_damagetext, int, 2, "<= 0: disabled, >= 1: visible to spectators, >= 2: visible to attacker, >= 3: all players see everyone's damage")
#define new_pure(class)
purely logical entities (.origin doesn&#39;t work)
Definition: oo.qh:62
const int DTFLAG_BIG_HEALTH
Definition: damagetext.qh:7
#define setthink(e, f)
int dent_net_flags
#define SV_DAMAGETEXT_SPECTATORS_ONLY()
Definition: sv_damagetext.qc:8
float time
Definition: csprogsdefs.qc:16
ERASEABLE float almost_equals_eps(float a, float b, float times_eps)
Definition: math.qh:229
const int DTFLAG_BIG_ARMOR
Definition: damagetext.qh:8
#define SV_DAMAGETEXT_DISABLED()
Definition: sv_damagetext.qc:7
bool write_damagetext(entity this, entity client, int sf)