]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/base.qc
Merge branch 'master' into Mario/showspecs
[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         order = 0;
63         for(e = cb; e.cbc_next; e = e.cbc_next)
64         {
65                 while(e.cbc_next.cbc_func == func)
66                 {
67                         // remove e.cbc_next from the chain
68                         entity e2;
69                         e2 = e.cbc_next.cbc_next;
70                         remove(e.cbc_next);
71                         e.cbc_next = e2;
72                         ++n;
73                 }
74                 // e.cbc_next is now something we want to keep
75                 order |= (e.cbc_next.cbc_order & CBC_ORDER_ANY);
76         }
77         cb.cbc_order = order;
78         return n;
79 }
80
81 float CallbackChain_Call(entity cb)
82 {
83         float r;
84         entity e;
85         r = 0;
86         for(e = cb; e.cbc_next; e = e.cbc_next)
87         {
88                 CallbackChain_ReturnValue = r;
89                 r |= e.cbc_next.cbc_func();
90         }
91         return r; // callbacks return an error status, so 0 is default return value
92 }
93
94 const float MAX_MUTATORS = 15;
95 string loaded_mutators[MAX_MUTATORS];
96 float Mutator_Add(mutatorfunc_t func, string name)
97 {
98         float i, j;
99         j = -1;
100         for(i = 0; i < MAX_MUTATORS; ++i)
101         {
102                 if(name == loaded_mutators[i])
103                         return 1; // already added
104                 if (!(loaded_mutators[i]))
105                         j = i;
106         }
107         if(j < 0)
108         {
109                 backtrace("WARNING: too many mutators, cannot add any more\n");
110                 return 0;
111         }
112         loaded_mutators[j] = name;
113
114         if(func(MUTATOR_ADDING) == 0)
115         {
116                 // good
117                 return 1;
118         }
119
120         backtrace("WARNING: when adding mutator: adding failed, rolling back\n");
121
122         if(func(MUTATOR_ROLLING_BACK) != 0)
123         {
124                 // baaaaad
125                 error("WARNING: when adding mutator: rolling back failed");
126         }
127         return 0;
128 }
129 void Mutator_Remove(float(float) func, string name)
130 {
131         float i;
132         for(i = 0; i < MAX_MUTATORS; ++i)
133                 if(name == loaded_mutators[i])
134                         break;
135         if(i >= MAX_MUTATORS)
136         {
137                 backtrace("WARNING: removing not-added mutator\n");
138                 return;
139         }
140         loaded_mutators[i] = string_null;
141
142         if(func(MUTATOR_REMOVING) != 0)
143         {
144                 // baaaaad
145                 error("Mutator_Remove: removing mutator failed");
146         }
147 }