Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
status_effects.qh
Go to the documentation of this file.
1#pragma once
2
3#ifdef GAMEQC
5
6REGISTER_MUTATOR(status_effects, true);
7#endif
8
9#include "all.qh"
10
11#ifdef GAMEQC
13.StatusEffect statuseffects;
15.StatusEffect statuseffects_store;
16
17REGISTER_NET_LINKED(ENT_CLIENT_STATUSEFFECTS)
18
19const int StatusEffects_groups_minor = 8; // must be a multiple of 8 (one byte) to optimize bandwidth usage
20const int StatusEffects_groups_major = 4; // must be >= ceil(REGISTRY_COUNT(StatusEffects) / StatusEffects_groups_minor)
21#endif
22
23// no need to perform these checks on both server and client
24#ifdef CSQC
25STATIC_INIT(StatusEffects)
26{
28 error("StatusEffects_groups_minor is not a multiple of 8.");
29 int min_major_value = ceil(REGISTRY_COUNT(StatusEffects) / StatusEffects_groups_minor);
30 if (StatusEffects_groups_major < min_major_value)
31 error(sprintf("StatusEffects_groups_major can not be < %d.", min_major_value));
32}
33#endif
34
35#ifdef SVQC
36#define G_MAJOR(id) (floor((id) / StatusEffects_groups_minor))
37#define G_MINOR(id) ((id) % StatusEffects_groups_minor)
38#endif
39
40#ifdef CSQC
43{
44 if(g_statuseffects == this)
46}
47
48NET_HANDLE(ENT_CLIENT_STATUSEFFECTS, bool isnew)
49{
50 make_pure(this);
51 g_statuseffects = this;
52 this.entremove = StatusEffects_entremove;
53 const int majorBits = Readbits(StatusEffects_groups_major);
54 for (int i = 0; i < StatusEffects_groups_major; ++i) {
55 if (!(majorBits & BIT(i))) {
56 continue;
57 }
58 const int minorBits = Readbits(StatusEffects_groups_minor);
59 for (int j = 0; j < StatusEffects_groups_minor; ++j) {
60 if (!(minorBits & BIT(j))) {
61 continue;
62 }
63 const StatusEffect it = REGISTRY_GET(StatusEffects, StatusEffects_groups_minor * i + j);
64 this.statuseffect_time[it.m_id] = ReadFloat();
65 this.statuseffect_flags[it.m_id] = ReadByte();
66 }
67 }
68 return true;
69}
70#endif
71
72#ifdef SVQC
75{
76 if (!data) {
78 return;
79 }
80 TC(StatusEffect, data);
81
82 for (int i = 0; i < StatusEffects_groups_major; ++i)
83 SEFminorBitsArr[i] = 0;
84
85 int majorBits = 0;
86 FOREACH(StatusEffects, true, {
87 .float fld = statuseffect_time[it.m_id];
88 .int flg = statuseffect_flags[it.m_id];
89 const bool changed = (store.(fld) != data.(fld) || store.(flg) != data.(flg));
90 store.(fld) = data.(fld);
91 store.(flg) = data.(flg);
92 if (changed) {
93 int maj = G_MAJOR(it.m_id);
94 majorBits = BITSET(majorBits, BIT(maj), true);
95 SEFminorBitsArr[maj] = BITSET(SEFminorBitsArr[maj], BIT(G_MINOR(it.m_id)), true);
96 }
97 });
98
99 Writebits(MSG_ENTITY, majorBits, StatusEffects_groups_major);
100 for (int i = 0; i < StatusEffects_groups_major; ++i)
101 {
102 if (!(majorBits & BIT(i)))
103 continue;
104
105 const int minorBits = SEFminorBitsArr[i];
106 Writebits(MSG_ENTITY, minorBits, StatusEffects_groups_minor);
107 for (int j = 0; j < StatusEffects_groups_minor; ++j)
108 {
109 if (!(minorBits & BIT(j)))
110 continue;
111
112 const entity it = REGISTRY_GET(StatusEffects, StatusEffects_groups_minor * i + j);
113 WriteFloat(MSG_ENTITY, data.statuseffect_time[it.m_id]);
115 }
116 }
117}
118#endif
119
120#undef G_MAJOR
121#undef G_MINOR
122
123#ifdef SVQC
125{
126 TC(StatusEffect, this);
127 WriteHeader(MSG_ENTITY, ENT_CLIENT_STATUSEFFECTS);
128 StatusEffects_Write(this, to.statuseffects_store);
129 return true;
130}
131
133{
134 // sends to spectators too!
135 return (client.statuseffects == this);
136}
137
139{
141 this.statuseffects = eff;
142 eff.owner = this;
143 if(this.statuseffects_store)
144 {
146 Net_LinkEntity(eff, false, 0, StatusEffects_Send);
147 }
148}
149
150void StatusEffects_delete(entity e) { delete(e.statuseffects); e.statuseffects = NULL; }
151// may be called on non-player entities, should be harmless!
152
153void StatusEffects_update(entity e) { e.statuseffects.SendFlags = 0xFFFFFF; }
154
155// this clears the storage entity instead of the statuseffects object, useful for map resets and such
157{
158 if(!store)
159 return; // safety net
160 // NOTE: you will need to perform StatusEffects_update after this to update the storage entity
161 // (unless store is the storage entity)
162 FOREACH(StatusEffects, true, {
163 store.statuseffect_time[it.m_id] = 0;
164 store.statuseffect_flags[it.m_id] = 0;
165 });
166}
167
168void StatusEffectsStorage_attach(entity e) { e.statuseffects_store = NEW(StatusEffect); e.statuseffects_store.drawonlytoclient = e; }
169void StatusEffectsStorage_delete(entity e) { delete(e.statuseffects_store); e.statuseffects_store = NULL; }
170
171// called when an entity is deleted with delete() / remove()
172// or when a player disconnects
173void ONREMOVE(entity this)
174{
175 // remove statuseffects object attached to 'this'
176 if(this.statuseffects && this.statuseffects.owner == this)
178}
179#endif
180
181#ifdef GAMEQC
183
184// runs every SV_StartFrame on the server
185// called by HUD_Powerups_add on the client
186void StatusEffects_tick(entity actor);
187
188// accesses the status effect timer, returns 0 if the entity has no statuseffects object
189// pass g_statuseffects as the actor on client side
190// pass the entity with a .statuseffects on server side
191float StatusEffects_gettime(StatusEffect this, entity actor);
192#endif
193#ifdef SVQC
194// call when applying the effect to an entity
195void StatusEffects_apply(StatusEffect this, entity actor, float eff_time, int eff_flags);
196
197// copies all the status effect fields to the specified storage entity
198// does not perform an update
199void StatusEffects_copy(StatusEffect this, entity store, float time_offset);
200
201// call when removing the effect
202void StatusEffects_remove(StatusEffect this, entity actor, int removal_type);
203
204void StatusEffects_removeall(entity actor, int removal_type);
205#endif
#define REGISTER_MUTATOR(...)
Definition base.qh:295
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition bits.qh:8
#define BITSET(var, mask, flag)
Definition bits.qh:11
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
int m_id
Definition all.qh:34
int statuseffect_flags[REGISTRY_MAX(StatusEffects)]
Definition all.qh:49
float statuseffect_time[REGISTRY_MAX(StatusEffects)]
Stores times of status effects, the id being the index.
Definition all.qh:48
#define FOREACH(list, cond, body)
Definition iter.qh:19
#define TC(T, sym)
Definition _all.inc:82
#define ReadFloat()
Definition net.qh:366
#define NET_HANDLE(id, param)
Definition net.qh:15
const int MSG_ENTITY
Definition net.qh:115
#define WriteHeader(to, id)
Definition net.qh:221
#define REGISTER_NET_LINKED(id)
Definition net.qh:55
void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
Definition net.qh:123
int ReadByte()
int Readbits(int num)
Definition net.qh:372
float ceil(float f)
void WriteShort(float data, float dest, float desto)
void WriteByte(float data, float dest, float desto)
float floor(float f)
#define NEW(cname,...)
Definition oo.qh:117
#define make_pure(e)
direct use is
Definition oo.qh:13
#define NULL
Definition post.qh:14
#define error
Definition pre.qh:6
#define REGISTRY_COUNT(id)
Definition registry.qh:18
#define REGISTRY_GET(id, i)
Definition registry.qh:43
#define setcefc(e, f)
#define STATIC_INIT(func)
during worldspawn
Definition static.qh:32
bool StatusEffects_Send(StatusEffect this, entity to, int sf)
void StatusEffects_removeall(entity actor, int removal_type)
void StatusEffectsStorage_attach(entity e)
void StatusEffects_remove(StatusEffect this, entity actor, int removal_type)
StatusEffect g_statuseffects
void StatusEffects_new(entity this)
const int StatusEffects_groups_minor
int SEFminorBitsArr[StatusEffects_groups_major]
void StatusEffects_Write(StatusEffect data, StatusEffect store)
StatusEffect statuseffects
Entity statuseffects.
#define G_MAJOR(id)
void StatusEffects_copy(StatusEffect this, entity store, float time_offset)
void StatusEffects_entremove(entity this)
float StatusEffects_gettime(StatusEffect this, entity actor)
const int StatusEffects_groups_major
bool StatusEffects_customize(entity this, entity client)
bool StatusEffects_active(StatusEffect this, entity actor)
void StatusEffects_update(entity e)
StatusEffect statuseffects_store
Player statuseffects storage (holds previous state)
#define G_MINOR(id)
void StatusEffects_apply(StatusEffect this, entity actor, float eff_time, int eff_flags)
void StatusEffects_delete(entity e)
void StatusEffectsStorage_delete(entity e)
void StatusEffects_clearall(entity store)
void ONREMOVE(entity this)
void StatusEffects_tick(entity actor)