]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/base.qc
Merge branch 'maint' (early part before Transifex)
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / base.qc
1 #include "base.qh"
2 #include "../_all.qh"
3
4 .bool() cbc_func;
5 .entity cbc_next;
6 .int cbc_order;
7
8 entity CallbackChain_New(string name)
9 {
10         entity e = spawn();
11         e.classname = "callbackchain";
12         e.netname = name;
13         return e;
14 }
15
16 bool CallbackChain_Add(entity cb, bool() func, int order)
17 {
18         if (order & CBC_ORDER_FIRST) {
19                 if (order & CBC_ORDER_LAST)
20                         if (cb.cbc_order & CBC_ORDER_ANY)
21                                 return false;
22                 if (cb.cbc_order & CBC_ORDER_FIRST)
23                         return false;
24         } else if (order & CBC_ORDER_LAST) {
25                 if (cb.cbc_order & CBC_ORDER_LAST)
26                         return false;
27         }
28         entity thiscb = spawn();
29         thiscb.classname = "callback";
30         thiscb.cbc_func = func;
31         thiscb.cbc_order = order;
32         if (order & CBC_ORDER_FIRST) {
33                 thiscb.cbc_next = cb.cbc_next;
34                 cb.cbc_next = thiscb;
35         } else if (order & CBC_ORDER_LAST) {
36                 entity e = cb;
37                 while (e.cbc_next) e = e.cbc_next;
38                 e.cbc_next = thiscb;
39         } else {
40                 // by default we execute last, but before a possible CBC_ORDER_LAST callback
41                 entity e = cb;
42                 // we must make sure that we insert BEFORE an CBC_ORDER_LAST mutator!
43                 while (e.cbc_next && !(e.cbc_next.cbc_order & CBC_ORDER_LAST)) e = e.cbc_next;
44                 thiscb.cbc_next = e.cbc_next;
45                 e.cbc_next = thiscb;
46         }
47         cb.cbc_order |= (order | CBC_ORDER_ANY);
48         return true;
49 }
50
51 int CallbackChain_Remove(entity cb, bool() func)
52 {
53         int n = 0, order = 0;
54         for (entity e = cb; e.cbc_next; e = e.cbc_next) {
55                 while (e.cbc_next.cbc_func == func) {
56                         // remove e.cbc_next from the chain
57                         entity e2 = e.cbc_next.cbc_next;
58                         remove(e.cbc_next);
59                         e.cbc_next = e2;
60                         ++n;
61                 }
62                 // e.cbc_next is now something we want to keep
63                 order |= (e.cbc_next.cbc_order & CBC_ORDER_ANY);
64         }
65         cb.cbc_order = order;
66         return n;
67 }
68
69 bool CallbackChain_Call(entity cb)
70 {
71         bool r = false;
72         for (entity e = cb; e.cbc_next; e = e.cbc_next) {
73                 CallbackChain_ReturnValue = r;
74                 r |= e.cbc_next.cbc_func();
75         }
76         return r; // callbacks return an error status, so 0 is default return value
77 }
78
79 const int MAX_MUTATORS = 15;
80 string loaded_mutators[MAX_MUTATORS];
81 bool Mutator_Add(mutatorfunc_t func, string name)
82 {
83         int j = -1;
84         for (int i = 0; i < MAX_MUTATORS; ++i) {
85                 if (name == loaded_mutators[i])
86                         return true; // already added
87                 if (!(loaded_mutators[i]))
88                         j = i;
89         }
90         if (j < 0) {
91                 backtrace("WARNING: too many mutators, cannot add any more\n");
92                 return false;
93         }
94         loaded_mutators[j] = name;
95
96         if (!func(MUTATOR_ADDING)) {
97                 // good
98                 return true;
99         }
100
101         backtrace("WARNING: when adding mutator: adding failed, rolling back\n");
102
103         if (func(MUTATOR_ROLLING_BACK)) {
104                 // baaaaad
105                 error("WARNING: when adding mutator: rolling back failed");
106         }
107         return false;
108 }
109 void Mutator_Remove(mutatorfunc_t func, string name)
110 {
111         int i;
112         for (i = 0; i < MAX_MUTATORS; ++i)
113                 if (name == loaded_mutators[i])
114                         break;
115         if (i >= MAX_MUTATORS) {
116                 backtrace("WARNING: removing not-added mutator\n");
117                 return;
118         }
119         loaded_mutators[i] = string_null;
120
121         if (func(MUTATOR_REMOVING) != 0) {
122                 // baaaaad
123                 error("Mutator_Remove: removing mutator failed");
124         }
125 }