#include "base.qh"
#include "../_all.qh"
-.float() cbc_func;
+.bool() cbc_func;
.entity cbc_next;
-.float cbc_order;
+.int cbc_order;
entity CallbackChain_New(string name)
{
- entity e;
- e = spawn();
+ entity e = spawn();
e.classname = "callbackchain";
e.netname = name;
return e;
}
-float CallbackChain_Add(entity cb, float() func, float order)
+bool CallbackChain_Add(entity cb, bool() func, int order)
{
- entity e;
- if(order & CBC_ORDER_FIRST)
- {
- if(order & CBC_ORDER_LAST)
- if(cb.cbc_order & CBC_ORDER_ANY)
- return 0;
- if(cb.cbc_order & CBC_ORDER_FIRST)
- return 0;
+ if (order & CBC_ORDER_FIRST) {
+ if (order & CBC_ORDER_LAST)
+ if (cb.cbc_order & CBC_ORDER_ANY)
+ return false;
+ if (cb.cbc_order & CBC_ORDER_FIRST)
+ return false;
+ } else if (order & CBC_ORDER_LAST) {
+ if (cb.cbc_order & CBC_ORDER_LAST)
+ return false;
}
- else if(order & CBC_ORDER_LAST)
- {
- if(cb.cbc_order & CBC_ORDER_LAST)
- return 0;
- }
- entity thiscb;
- thiscb = spawn();
+ entity thiscb = spawn();
thiscb.classname = "callback";
thiscb.cbc_func = func;
thiscb.cbc_order = order;
- if(order & CBC_ORDER_FIRST)
- {
+ if (order & CBC_ORDER_FIRST) {
thiscb.cbc_next = cb.cbc_next;
cb.cbc_next = thiscb;
- }
- else if(order & CBC_ORDER_LAST)
- {
- for(e = cb; e.cbc_next; e = e.cbc_next);
+ } else if (order & CBC_ORDER_LAST) {
+ entity e = cb;
+ while (e.cbc_next) e = e.cbc_next;
e.cbc_next = thiscb;
- }
- else
- {
+ } else {
// by default we execute last, but before a possible CBC_ORDER_LAST callback
- for(e = cb; e.cbc_next && !(e.cbc_next.cbc_order & CBC_ORDER_LAST); e = e.cbc_next); // we must make sure that we insert BEFORE an CBC_ORDER_LAST mutator!
+ entity e = cb;
+ // we must make sure that we insert BEFORE an CBC_ORDER_LAST mutator!
+ while (e.cbc_next && !(e.cbc_next.cbc_order & CBC_ORDER_LAST)) e = e.cbc_next;
thiscb.cbc_next = e.cbc_next;
e.cbc_next = thiscb;
}
cb.cbc_order |= (order | CBC_ORDER_ANY);
- return 1;
+ return true;
}
-float CallbackChain_Remove(entity cb, float() func)
+int CallbackChain_Remove(entity cb, bool() func)
{
- float order;
- entity e;
- float n;
- n = 0;
- order = 0;
- for(e = cb; e.cbc_next; e = e.cbc_next)
- {
- while(e.cbc_next.cbc_func == func)
- {
+ int n = 0, order = 0;
+ for (entity e = cb; e.cbc_next; e = e.cbc_next) {
+ while (e.cbc_next.cbc_func == func) {
// remove e.cbc_next from the chain
- entity e2;
- e2 = e.cbc_next.cbc_next;
+ entity e2 = e.cbc_next.cbc_next;
remove(e.cbc_next);
e.cbc_next = e2;
++n;
return n;
}
-float CallbackChain_Call(entity cb)
+bool CallbackChain_Call(entity cb)
{
- float r;
- entity e;
- r = 0;
- for(e = cb; e.cbc_next; e = e.cbc_next)
- {
+ bool r = false;
+ for (entity e = cb; e.cbc_next; e = e.cbc_next) {
CallbackChain_ReturnValue = r;
r |= e.cbc_next.cbc_func();
}
return r; // callbacks return an error status, so 0 is default return value
}
-const float MAX_MUTATORS = 15;
+const int MAX_MUTATORS = 15;
string loaded_mutators[MAX_MUTATORS];
-float Mutator_Add(mutatorfunc_t func, string name)
+bool Mutator_Add(mutatorfunc_t func, string name)
{
- int i, j;
- j = -1;
- for(i = 0; i < MAX_MUTATORS; ++i)
- {
- if(name == loaded_mutators[i])
- return 1; // already added
+ int j = -1;
+ for (int i = 0; i < MAX_MUTATORS; ++i) {
+ if (name == loaded_mutators[i])
+ return true; // already added
if (!(loaded_mutators[i]))
j = i;
}
- if(j < 0)
- {
+ if (j < 0) {
backtrace("WARNING: too many mutators, cannot add any more\n");
- return 0;
+ return false;
}
loaded_mutators[j] = name;
- if(func(MUTATOR_ADDING) == 0)
- {
+ if (!func(MUTATOR_ADDING)) {
// good
- return 1;
+ return true;
}
backtrace("WARNING: when adding mutator: adding failed, rolling back\n");
- if(func(MUTATOR_ROLLING_BACK) != 0)
- {
+ if (func(MUTATOR_ROLLING_BACK)) {
// baaaaad
error("WARNING: when adding mutator: rolling back failed");
}
- return 0;
+ return false;
}
-void Mutator_Remove(float(float) func, string name)
+void Mutator_Remove(mutatorfunc_t func, string name)
{
int i;
- for(i = 0; i < MAX_MUTATORS; ++i)
- if(name == loaded_mutators[i])
+ for (i = 0; i < MAX_MUTATORS; ++i)
+ if (name == loaded_mutators[i])
break;
- if(i >= MAX_MUTATORS)
- {
+ if (i >= MAX_MUTATORS) {
backtrace("WARNING: removing not-added mutator\n");
return;
}
loaded_mutators[i] = string_null;
- if(func(MUTATOR_REMOVING) != 0)
- {
+ if (func(MUTATOR_REMOVING) != 0) {
// baaaaad
error("Mutator_Remove: removing mutator failed");
}
#ifndef MUTATORS_BASE_H
#define MUTATORS_BASE_H
-const float CBC_ORDER_EXCLUSIVE = 3;
-const float CBC_ORDER_FIRST = 1;
-const float CBC_ORDER_LAST = 2;
-const float CBC_ORDER_ANY = 4;
+const int CBC_ORDER_FIRST = 1;
+const int CBC_ORDER_LAST = 2;
+const int CBC_ORDER_EXCLUSIVE = 3;
+const int CBC_ORDER_ANY = 4;
-float CallbackChain_ReturnValue; // read-only field of the current return value
+bool CallbackChain_ReturnValue; // read-only field of the current return value
entity CallbackChain_New(string name);
-float CallbackChain_Add(entity cb, float() func, float order);
-float CallbackChain_Remove(entity cb, float() func);
+bool CallbackChain_Add(entity cb, bool() func, int order);
+int CallbackChain_Remove(entity cb, bool() func);
// a callback function is like this:
-// float mycallback(entity me)
+// bool mycallback(entity me)
// {
// do something
-// return r;
+// return false;
// }
-float CallbackChain_Call(entity cb);
-
-const float MUTATOR_REMOVING = 0;
-const float MUTATOR_ADDING = 1;
-const float MUTATOR_ROLLING_BACK = 2;
-typedef float(float) mutatorfunc_t;
-float Mutator_Add(mutatorfunc_t func, string name);
+bool CallbackChain_Call(entity cb);
+
+enum {
+ MUTATOR_REMOVING,
+ MUTATOR_ADDING,
+ MUTATOR_ROLLING_BACK
+};
+typedef bool(int) mutatorfunc_t;
+bool Mutator_Add(mutatorfunc_t func, string name);
void Mutator_Remove(mutatorfunc_t func, string name); // calls error() on fail
#define MUTATOR_ADD(name) Mutator_Add(MUTATOR_##name, #name)
#define MUTATOR_REMOVE(name) Mutator_Remove(MUTATOR_##name, #name)
-#define MUTATOR_DEFINITION(name) float MUTATOR_##name(float mode)
-#define MUTATOR_DECLARATION(name) float MUTATOR_##name(float mode)
-#define MUTATOR_HOOKFUNCTION(name) float HOOKFUNCTION_##name()
-#define MUTATOR_HOOK(cb,func,order) do { if(mode == MUTATOR_ADDING) { if(!HOOK_##cb) HOOK_##cb = CallbackChain_New(#cb); if(!CallbackChain_Add(HOOK_##cb,HOOKFUNCTION_##func,order)) { print("HOOK FAILED: ", #func, "\n"); return 1; } } else if(mode == MUTATOR_REMOVING || mode == MUTATOR_ROLLING_BACK) { if(HOOK_##cb) CallbackChain_Remove(HOOK_##cb,HOOKFUNCTION_##func); } } while(0)
-#define MUTATOR_ONADD if(mode == MUTATOR_ADDING)
-#define MUTATOR_ONREMOVE if(mode == MUTATOR_REMOVING)
-#define MUTATOR_ONROLLBACK_OR_REMOVE if(mode == MUTATOR_REMOVING || mode == MUTATOR_ROLLING_BACK)
+#define MUTATOR_DEFINITION(name) bool MUTATOR_##name(int mode)
+#define MUTATOR_DECLARATION(name) bool MUTATOR_##name(int mode)
+#define MUTATOR_HOOKFUNCTION(name) bool HOOKFUNCTION_##name()
+#define MUTATOR_HOOK(cb, func, order) do { \
+ MUTATOR_ONADD { \
+ if (!HOOK_##cb) HOOK_##cb = CallbackChain_New(#cb); \
+ if (!CallbackChain_Add(HOOK_##cb, HOOKFUNCTION_##func, order)) { \
+ print("HOOK FAILED: ", #func, "\n"); \
+ return true; \
+ } \
+ } \
+ MUTATOR_ONROLLBACK_OR_REMOVE { \
+ if (HOOK_##cb) CallbackChain_Remove(HOOK_##cb, HOOKFUNCTION_##func); \
+ } \
+} while(0)
+#define MUTATOR_ONADD if (mode == MUTATOR_ADDING)
+#define MUTATOR_ONREMOVE if (mode == MUTATOR_REMOVING)
+#define MUTATOR_ONROLLBACK_OR_REMOVE if (mode == MUTATOR_REMOVING || mode == MUTATOR_ROLLING_BACK)
#define MUTATOR_HOOKABLE(cb) entity HOOK_##cb
#define MUTATOR_CALLHOOK(cb) CallbackChain_Call(HOOK_##cb)
entity frag_inflictor;
entity frag_attacker;
entity frag_target; // same as self
- float frag_deathtype;
+ int frag_deathtype;
MUTATOR_HOOKABLE(PlayerJump);
// called when a player presses the jump key
// called at the end of player_powerups() in cl_client.qc, used for manipulating the values which are set by powerup items.
// INPUT
// entity self;
- float olditems; // also technically output, but since it is at the end of the function it's useless for that :P
+ int olditems; // also technically output, but since it is at the end of the function it's useless for that :P
MUTATOR_HOOKABLE(PlayerRegen);
// called every player think frame
// NOTE: THESE HOOKS MUST NEVER EVER CALL tokenize()
// INPUT
string cmd_name; // command name
- float cmd_argc; // also, argv() can be used
+ int cmd_argc; // also, argv() can be used
string cmd_string; // whole command, use only if you really have to
/*
// example:
// called at when a item is touched. Called early, can edit item properties.
// entity self; // item
// entity other; // player
- const float MUT_ITEMTOUCH_CONTINUE = 0; // return this flag to make the function continue as normal
- const float MUT_ITEMTOUCH_RETURN = 1; // return this flag to make the function return (handled entirely by mutator)
- const float MUT_ITEMTOUCH_PICKUP = 2; // return this flag to have the item "picked up" and taken even after mutator handled it
+enum {
+ MUT_ITEMTOUCH_CONTINUE, // return this flag to make the function continue as normal
+ MUT_ITEMTOUCH_RETURN, // return this flag to make the function return (handled entirely by mutator)
+ MUT_ITEMTOUCH_PICKUP // return this flag to have the item "picked up" and taken even after mutator handled it
+};
MUTATOR_HOOKABLE(ClientConnect);
// called at when a player connect
// called when a target is checked for accuracy
// entity frag_attacker; // attacker
// entity frag_target; // target
- const float MUT_ACCADD_VALID = 0; // return this flag to make the function continue if target is a client
- const float MUT_ACCADD_INVALID = 1; // return this flag to make the function always continue
- const float MUT_ACCADD_INDIFFERENT = 2; // return this flag to make the function always return
+enum {
+ MUT_ACCADD_VALID, // return this flag to make the function continue if target is a client
+ MUT_ACCADD_INVALID, // return this flag to make the function always continue
+ MUT_ACCADD_INDIFFERENT // return this flag to make the function always return
+};
#endif