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