]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/base.qh
Enable mutator calls to take parameters
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / base.qh
1 #ifndef MUTATORS_BASE_H
2 #define MUTATORS_BASE_H
3 const int CBC_ORDER_FIRST = 1;
4 const int CBC_ORDER_LAST = 2;
5 const int CBC_ORDER_EXCLUSIVE = 3;
6 const int CBC_ORDER_ANY = 4;
7
8 bool CallbackChain_ReturnValue; // read-only field of the current return value
9
10 entity CallbackChain_New(string name);
11 bool CallbackChain_Add(entity cb, bool() func, int order);
12 int CallbackChain_Remove(entity cb, bool() func);
13 // a callback function is like this:
14 // bool mycallback(entity me)
15 // {
16 //   do something
17 //   return false;
18 // }
19 bool CallbackChain_Call(entity cb);
20
21 enum {
22         MUTATOR_REMOVING,
23         MUTATOR_ADDING,
24         MUTATOR_ROLLING_BACK
25 };
26 typedef bool(int) mutatorfunc_t;
27 bool Mutator_Add(mutatorfunc_t func, string name);
28 void Mutator_Remove(mutatorfunc_t func, string name); // calls error() on fail
29
30 #define MUTATOR_ADD(name) Mutator_Add(MUTATOR_##name, #name)
31 #define MUTATOR_REMOVE(name) Mutator_Remove(MUTATOR_##name, #name)
32 #define MUTATOR_DEFINITION(name) bool MUTATOR_##name(int mode)
33 #define MUTATOR_DECLARATION(name) bool MUTATOR_##name(int mode)
34 #define MUTATOR_HOOKFUNCTION(name) bool HOOKFUNCTION_##name()
35 #define MUTATOR_HOOK(cb, func, order) do {                                                                              \
36         MUTATOR_ONADD {                                                                                                                         \
37                 if (!HOOK_##cb) HOOK_##cb = CallbackChain_New(#cb);                                     \
38                 if (!CallbackChain_Add(HOOK_##cb, HOOKFUNCTION_##func, order)) {                \
39                         print("HOOK FAILED: ", #func, "\n");                                                            \
40                         return true;                                                                                                            \
41                 }                                                                                                                                               \
42         }                                                                                                                                                       \
43         MUTATOR_ONROLLBACK_OR_REMOVE {                                                                                          \
44                 if (HOOK_##cb) CallbackChain_Remove(HOOK_##cb, HOOKFUNCTION_##func);    \
45         }                                                                                                                                                       \
46 } while(0)
47 #define MUTATOR_ONADD if (mode == MUTATOR_ADDING)
48 #define MUTATOR_ONREMOVE if (mode == MUTATOR_REMOVING)
49 #define MUTATOR_ONROLLBACK_OR_REMOVE if (mode == MUTATOR_REMOVING || mode == MUTATOR_ROLLING_BACK)
50
51 #define _MUTATOR_HOOKABLE(id, ...) entity HOOK_##id; bool __Mutator_Send_##id(__VA_ARGS__)
52 #define MUTATOR_CALLHOOK(id, ...) APPLY(__Mutator_Send_##id, 0, ##__VA_ARGS__)
53
54 #define MUTATOR_RETURNVALUE CallbackChain_ReturnValue
55
56 #define HANDLE_NOP(type, id)
57 #define HANDLE_PARAMS(type, id) , type in_##id
58 #define HANDLE_PREPARE(type, id) id = in_##id;
59 #define HANDLE_PUSHTMP(type, id) type tmp_##id = id;
60 #define HANDLE_PUSHOUT(type, id) type out_##id = id;
61 #define HANDLE_POPTMP(type, id) id = tmp_##id;
62 #define HANDLE_POPOUT(type, id) id = out_##id;
63
64 #define MUTATOR_HOOKABLE(id, params) \
65         _MUTATOR_HOOKABLE(id, int params(HANDLE_PARAMS, HANDLE_PARAMS)) { \
66                 params(HANDLE_PUSHTMP, HANDLE_NOP) \
67                 params(HANDLE_PREPARE, HANDLE_NOP) \
68                 bool ret = CallbackChain_Call(HOOK_##id); \
69                 params(HANDLE_NOP,     HANDLE_PUSHOUT) \
70                 params(HANDLE_POPTMP,  HANDLE_NOP) \
71                 params(HANDLE_NOP,     HANDLE_POPOUT) \
72                 return ret; \
73         }
74
75
76
77 // register all possible hooks here
78 // some parameters are commented to avoid duplicate declarations
79
80 #define EV_NO_ARGS(i, o)
81
82 MUTATOR_HOOKABLE(MakePlayerObserver, EV_NO_ARGS)
83         // called when a player becomes observer, after shared setup
84
85 MUTATOR_HOOKABLE(PutClientInServer, EV_NO_ARGS);
86 //      entity self; // client wanting to spawn
87
88 MUTATOR_HOOKABLE(PlayerSpawn, EV_NO_ARGS);
89         entity spawn_spot; // spot that was used, or world
90         // called when a player spawns as player, after shared setup, before his weapon is chosen (so items may be changed in here)
91
92 MUTATOR_HOOKABLE(reset_map_global, EV_NO_ARGS);
93         // called in reset_map
94
95 MUTATOR_HOOKABLE(reset_map_players, EV_NO_ARGS);
96         // called in reset_map
97
98 MUTATOR_HOOKABLE(ForbidPlayerScore_Clear, EV_NO_ARGS);
99         // returns 1 if clearing player score shall not be allowed
100
101 MUTATOR_HOOKABLE(ClientDisconnect, EV_NO_ARGS);
102         // called when a player disconnects
103
104 MUTATOR_HOOKABLE(PlayerDies, EV_NO_ARGS);
105         // called when a player dies to e.g. remove stuff he was carrying.
106         // INPUT:
107                 entity frag_inflictor;
108                 entity frag_attacker;
109                 entity frag_target; // same as self
110                 int frag_deathtype;
111
112 MUTATOR_HOOKABLE(PlayerJump, EV_NO_ARGS);
113         // called when a player presses the jump key
114         // INPUT, OUTPUT:
115                 float player_multijump;
116                 float player_jumpheight;
117
118 MUTATOR_HOOKABLE(GiveFragsForKill, EV_NO_ARGS);
119         // called when someone was fragged by "self", and is expected to change frag_score to adjust scoring for the kill
120         // INPUT:
121 //              entity frag_attacker; // same as self
122 //              entity frag_target;
123         // INPUT, OUTPUT:
124                 float frag_score;
125
126 MUTATOR_HOOKABLE(MatchEnd, EV_NO_ARGS);
127         // called when the match ends
128
129 MUTATOR_HOOKABLE(GetTeamCount, EV_NO_ARGS);
130         // should adjust ret_float to contain the team count
131         // INPUT, OUTPUT:
132                 float ret_float;
133
134 MUTATOR_HOOKABLE(SpectateCopy, EV_NO_ARGS);
135         // copies variables for spectating "other" to "self"
136         // INPUT:
137 //              entity other;
138
139 MUTATOR_HOOKABLE(ForbidThrowCurrentWeapon, EV_NO_ARGS);
140         // returns 1 if throwing the current weapon shall not be allowed
141
142 MUTATOR_HOOKABLE(WeaponRateFactor, EV_NO_ARGS);
143         // allows changing attack rate
144         // INPUT, OUTPUT:
145                 float weapon_rate;
146
147 MUTATOR_HOOKABLE(WeaponSpeedFactor, EV_NO_ARGS);
148         // allows changing weapon speed (projectiles mostly)
149         // INPUT, OUTPUT:
150                 //float ret_float;
151
152 MUTATOR_HOOKABLE(SetStartItems, EV_NO_ARGS);
153         // adjusts {warmup_}start_{items,weapons,ammo_{cells,plasma,rockets,nails,shells,fuel}}
154
155 MUTATOR_HOOKABLE(BuildMutatorsString, EV_NO_ARGS);
156         // appends ":mutatorname" to ret_string for logging
157         // INPUT, OUTPUT:
158                 string ret_string;
159
160 MUTATOR_HOOKABLE(BuildMutatorsPrettyString, EV_NO_ARGS);
161         // appends ", Mutator name" to ret_string for display
162         // INPUT, OUTPUT:
163 //              string ret_string;
164
165 MUTATOR_HOOKABLE(CustomizeWaypoint, EV_NO_ARGS);
166         // called every frame
167         // customizes the waypoint for spectators
168         // INPUT: self = waypoint, other = player, other.enemy = spectator
169
170 MUTATOR_HOOKABLE(FilterItem, EV_NO_ARGS);
171         // checks if the current item may be spawned (self.items and self.weapons may be read and written to, as well as the ammo_ fields)
172         // return error to request removal
173
174 MUTATOR_HOOKABLE(TurretSpawn, EV_NO_ARGS);
175         // return error to request removal
176         // INPUT: self - turret
177
178 MUTATOR_HOOKABLE(OnEntityPreSpawn, EV_NO_ARGS);
179         // return error to prevent entity spawn, or modify the entity
180
181 MUTATOR_HOOKABLE(PlayerPreThink, EV_NO_ARGS);
182         // runs in the event loop for players; is called for ALL player entities, also bots, also the dead, or spectators
183
184 MUTATOR_HOOKABLE(GetPressedKeys, EV_NO_ARGS);
185         // TODO change this into a general PlayerPostThink hook?
186
187 MUTATOR_HOOKABLE(PlayerPhysics, EV_NO_ARGS);
188         // called before any player physics, may adjust variables for movement,
189         // is run AFTER bot code and idle checking
190
191 MUTATOR_HOOKABLE(GetCvars, EV_NO_ARGS);
192         // is meant to call GetCvars_handle*(get_cvars_s, get_cvars_f, cvarfield, "cvarname") for cvars this mutator needs from the client
193         // INPUT:
194                 float get_cvars_f;
195                 string get_cvars_s;
196
197 MUTATOR_HOOKABLE(EditProjectile, EV_NO_ARGS);
198         // can edit any "just fired" projectile
199         // INPUT:
200 //              entity self;
201 //              entity other;
202
203 MUTATOR_HOOKABLE(MonsterSpawn, EV_NO_ARGS);
204         // called when a monster spawns
205
206 MUTATOR_HOOKABLE(MonsterDies, EV_NO_ARGS);
207         // called when a monster dies
208         // INPUT:
209 //              entity frag_attacker;
210
211 MUTATOR_HOOKABLE(MonsterRespawn, EV_NO_ARGS);
212         // called when a monster wants to respawn
213         // INPUT:
214 //              entity other;
215
216 MUTATOR_HOOKABLE(MonsterDropItem, EV_NO_ARGS);
217         // called when a monster is dropping loot
218         // INPUT, OUTPUT:
219                 .void() monster_loot;
220 //              entity other;
221
222 MUTATOR_HOOKABLE(MonsterMove, EV_NO_ARGS);
223         // called when a monster moves
224         // returning true makes the monster stop
225         // INPUT:
226                 float monster_speed_run;
227                 float monster_speed_walk;
228                 entity monster_target;
229
230 MUTATOR_HOOKABLE(MonsterFindTarget, EV_NO_ARGS);
231         // called when a monster looks for another target
232
233 MUTATOR_HOOKABLE(MonsterCheckBossFlag, EV_NO_ARGS);
234     // called to change a random monster to a miniboss
235
236 MUTATOR_HOOKABLE(AllowMobSpawning, EV_NO_ARGS);
237         // called when a player tries to spawn a monster
238         // return 1 to prevent spawning
239
240 MUTATOR_HOOKABLE(PlayerDamage_SplitHealthArmor, EV_NO_ARGS);
241         // called when a player gets damaged to e.g. remove stuff he was carrying.
242         // INPUT:
243 //              entity frag_inflictor;
244 //              entity frag_attacker;
245 //              entity frag_target; // same as self
246                 vector damage_force; // NOTE: this force already HAS been applied
247         // INPUT, OUTPUT:
248                 float damage_take;
249                 float damage_save;
250
251 MUTATOR_HOOKABLE(PlayerDamage_Calculate, EV_NO_ARGS);
252         // called to adjust damage and force values which are applied to the player, used for e.g. strength damage/force multiplier
253         // i'm not sure if I should change this around slightly (Naming of the entities, and also how they're done in g_damage).
254         // INPUT:
255 //              entity frag_attacker;
256 //              entity frag_target;
257 //              float frag_deathtype;
258         // INPUT, OUTPUT:
259                 float frag_damage;
260                 float frag_mirrordamage;
261                 vector frag_force;
262
263 MUTATOR_HOOKABLE(PlayerPowerups, EV_NO_ARGS);
264         // called at the end of player_powerups() in cl_client.qc, used for manipulating the values which are set by powerup items.
265         // INPUT
266 //      entity self;
267         int olditems; // also technically output, but since it is at the end of the function it's useless for that :P
268
269 MUTATOR_HOOKABLE(PlayerRegen, EV_NO_ARGS);
270         // called every player think frame
271         // return 1 to disable regen
272         // INPUT, OUTPUT:
273                 float regen_mod_max;
274                 float regen_mod_regen;
275                 float regen_mod_rot;
276                 float regen_mod_limit;
277
278 MUTATOR_HOOKABLE(PlayerUseKey, EV_NO_ARGS);
279         // called when the use key is pressed
280         // if MUTATOR_RETURNVALUE is 1, don't do anything
281         // return 1 if the use key actually did something
282
283 MUTATOR_HOOKABLE(SV_ParseClientCommand, EV_NO_ARGS);
284         // called when a client command is parsed
285         // NOTE: hooks MUST start with if(MUTATOR_RETURNVALUE) return 0;
286         // NOTE: return 1 if you handled the command, return 0 to continue handling
287         // NOTE: THESE HOOKS MUST NEVER EVER CALL tokenize()
288         // INPUT
289         string cmd_name; // command name
290         int cmd_argc; // also, argv() can be used
291         string cmd_string; // whole command, use only if you really have to
292         /*
293                 // example:
294                 MUTATOR_HOOKFUNCTION(foo_SV_ParseClientCommand)
295                 {
296                         if(MUTATOR_RETURNVALUE) // command was already handled?
297                                 return 0;
298                         if(cmd_name == "echocvar" && cmd_argc >= 2)
299                         {
300                                 print(cvar_string(argv(1)), "\n");
301                                 return 1;
302                         }
303                         if(cmd_name == "echostring" && cmd_argc >= 2)
304                         {
305                                 print(substring(cmd_string, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), "\n");
306                                 return 1;
307                         }
308                         return 0;
309                 }
310         */
311
312 MUTATOR_HOOKABLE(Spawn_Score, EV_NO_ARGS);
313         // called when a spawnpoint is being evaluated
314         // return 1 to make the spawnpoint unusable
315         // INPUT
316 //      entity self; // player wanting to spawn
317 //      entity spawn_spot; // spot to be evaluated
318         // IN+OUT
319         vector spawn_score; // _x is priority, _y is "distance"
320
321 MUTATOR_HOOKABLE(SV_StartFrame, EV_NO_ARGS);
322         // runs globally each server frame
323
324 MUTATOR_HOOKABLE(SetModname, EV_NO_ARGS);
325         // OUT
326 //      string modname; // name of the mutator/mod if it warrants showing as such in the server browser
327
328 MUTATOR_HOOKABLE(Item_Spawn, EV_NO_ARGS);
329         // called for each item being spawned on a map, including dropped weapons
330         // return 1 to remove an item
331         // INPUT
332 //      entity self; // the item
333
334 MUTATOR_HOOKABLE(SetWeaponreplace, EV_NO_ARGS);
335         // IN
336 //              entity self; // map entity
337 //              entity other; // weapon info
338         // IN+OUT
339 //              string ret_string;
340
341 MUTATOR_HOOKABLE(Item_RespawnCountdown, EV_NO_ARGS);
342         // called when an item is about to respawn
343         // INPUT+OUTPUT:
344         string item_name;
345         vector item_color;
346
347 MUTATOR_HOOKABLE(BotShouldAttack, EV_NO_ARGS);
348         // called when a bot checks a target to attack
349         // INPUT
350         entity checkentity;
351
352 MUTATOR_HOOKABLE(PortalTeleport, EV_NO_ARGS);
353         // called whenever a player goes through a portal gun teleport
354         // allows you to strip a player of an item if they go through the teleporter to help prevent cheating
355         // INPUT
356 //      entity self;
357
358 MUTATOR_HOOKABLE(HelpMePing, EV_NO_ARGS);
359         // called whenever a player uses impulse 33 (help me) in cl_impulse.qc
360         // normally help me ping uses self.waypointsprite_attachedforcarrier,
361         // but if your mutator uses something different then you can handle it
362         // in a special manner using this hook
363         // INPUT
364 //      entity self; // the player who pressed impulse 33
365
366 MUTATOR_HOOKABLE(VehicleSpawn, EV_NO_ARGS);
367         // called when a vehicle initializes
368         // return true to remove the vehicle
369
370 MUTATOR_HOOKABLE(VehicleEnter, EV_NO_ARGS);
371         // called when a player enters a vehicle
372         // allows mutators to set special settings in this event
373         // INPUT
374         entity vh_player; // player
375         entity vh_vehicle; // vehicle
376
377 MUTATOR_HOOKABLE(VehicleTouch, EV_NO_ARGS);
378         // called when a player touches a vehicle
379         // return true to stop player from entering the vehicle
380         // INPUT
381 //      entity self; // vehicle
382 //      entity other; // player
383
384 MUTATOR_HOOKABLE(VehicleExit, EV_NO_ARGS);
385         // called when a player exits a vehicle
386         // allows mutators to set special settings in this event
387         // INPUT
388 //      entity vh_player; // player
389 //      entity vh_vehicle; // vehicle
390
391 MUTATOR_HOOKABLE(AbortSpeedrun, EV_NO_ARGS);
392         // called when a speedrun is aborted and the player is teleported back to start position
393         // INPUT
394 //      entity self; // player
395
396 MUTATOR_HOOKABLE(ItemTouch, EV_NO_ARGS);
397         // called at when a item is touched. Called early, can edit item properties.
398 //      entity self;    // item
399 //      entity other;   // player
400 enum {
401         MUT_ITEMTOUCH_CONTINUE, // return this flag to make the function continue as normal
402         MUT_ITEMTOUCH_RETURN, // return this flag to make the function return (handled entirely by mutator)
403         MUT_ITEMTOUCH_PICKUP // return this flag to have the item "picked up" and taken even after mutator handled it
404 };
405
406 MUTATOR_HOOKABLE(ClientConnect, EV_NO_ARGS);
407         // called at when a player connect
408 //      entity self;    // player
409
410 MUTATOR_HOOKABLE(HavocBot_ChooseRole, EV_NO_ARGS);
411 //      entity self;
412
413 MUTATOR_HOOKABLE(AccuracyTargetValid, EV_NO_ARGS);
414         // called when a target is checked for accuracy
415 //      entity frag_attacker; // attacker
416 //      entity frag_target; // target
417 enum {
418         MUT_ACCADD_VALID, // return this flag to make the function continue if target is a client
419         MUT_ACCADD_INVALID, // return this flag to make the function always continue
420         MUT_ACCADD_INDIFFERENT // return this flag to make the function always return
421 };
422 #endif