Merge remote branch 'refs/remotes/origin/fruitiex/racefixes'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / verbstack.qc
1 /// Some default stacks.
2 .entity verbs_idle;
3 .entity verbs_attack;
4 .entity verbs_move;
5 //.entity vchain;
6
7 /// This global gets set to the verb in question each time the stack manager calls verb_call
8 entity verb;
9 //.entity current_verb;
10 //.float verb_done;
11
12 /// Execure this verb
13 #define VCM_DO     0
14 /// Return the value of this verb. Return VS_CALL_REMOVE to delete it.
15 #define VCM_EVAL   1
16 /// This verb is beeing removed NOW (not sent when verb_call returns VS_CALL_REMOVE)
17 #define VCM_REMOVE 2
18
19 /// Verb callback
20 .float(float message) verb_call;
21
22 /// Points to this verb's stack.
23 .entity  verbstack;
24
25 /// Static value of this verb
26 .float verb_static_value;
27
28 /// verb_call returns this when a verb in not doable
29 #define VS_CALL_NO        0
30 /// verb_call(VCM_DO) returns this when a verb is executing
31 #define VS_CALL_YES_DOING -1
32 /// verb_call(VCM_DO) returns this when a verb did execure and is done
33 #define VS_CALL_YES_DONE  -2
34 /// verb_call(VCM_DO) returns this when a verb should be deleted by the stack manager
35 #define VS_CALL_REMOVE    -3
36
37 /*
38 void verbstack_updatechain(entity stack)
39 {
40     entity vrb, v;
41     if not (stack)
42         return;
43
44     dprint("verbstack_updatechain\n");
45
46     vrb = findchainentity(verbstack, stack);
47     if not (vrb)
48     {
49         stack.vchain = world;
50         return;
51     }
52
53     stack.vchain = vrb;
54     v = vrb;
55
56     while(vrb)
57     {
58         vrb = vrb.chain;
59
60
61     }
62 }
63
64 void verbstack_remove(entity vverb)
65 {
66     entity vstack;
67     dprint("verbstack_remove\n");
68
69     vstack = verb.verbstack;
70     remove(vverb);
71     vverb.verbstack = world;
72     verbstack_updatechain(vstack);
73
74     //vverb.think = SUB_Remove;
75     //vverb.nextthink = time;
76 }
77
78 void verbstack_thinkremove()
79 {
80     dprint("verbstack_thinkremove\n");
81     verbstack_remove(self);
82 }
83 */
84
85 /**
86     Push a new verb onto the specified stack. Set vrb_life to make it time-limited.
87 **/
88 entity verbstack_push(entity stack, float(float eval) vrb_call, float val_static, float vrb_life,entity verb_owner)
89 {
90     entity vrb;
91
92     if not(stack)
93         return world;
94
95     if not(vrb_call)
96         return world;
97
98     vrb                   = spawn();
99     vrb.owner             = verb_owner;
100     vrb.verbstack         = stack;
101     vrb.verb_call         = vrb_call;
102     vrb.verb_static_value = val_static;
103
104     vrb.classname         = "verb";
105     stack.classname       = "verbstack";
106
107     if(vrb_life)
108     {
109         //vrb.think     = verbstack_thinkremove;
110         vrb.think     = SUB_Remove;
111         vrb.nextthink = time + vrb_life;
112     }
113
114     //verbstack_updatechain(stack);
115
116     return vrb;
117 }
118
119 /**
120     Find the best verb in this stack and execurte it.
121     ALso remove any verbs returning VS_CALL_REMOVE on VCM_EVAL or VCM_DO
122 **/
123 float verbstack_pop(entity stack)
124 {
125     entity vrb, bestverb, oldself;
126     float  value, bestvalue;
127
128     oldself = self;
129
130     vrb = findchainentity(verbstack,stack);
131     //vrb = stack.vchain;
132     //dprint("owner:", stack.owner.classname, " vsn:", stack.classname,"\n");
133     while(vrb)
134     {
135         //dprint("vn:", vrb.classname,"\n");
136         verb  = vrb;
137         vrb   = vrb.chain;
138         self  = verb.owner;
139         value = verb.verb_call(VCM_EVAL);
140
141         if(value < 0)
142         {
143             if(value == VS_CALL_REMOVE)
144                 remove(verb);
145         }
146         else
147         {
148             if(value > bestvalue)
149             {
150                 bestverb  = verb;
151                 bestvalue = value;
152             }
153         }
154     }
155
156     if(bestverb)
157     {
158         verb  = bestverb;
159         self  = verb.owner;
160         value = verb.verb_call(VCM_DO);
161
162         if(value == VS_CALL_REMOVE)
163             remove(bestverb);
164     }
165
166     self = oldself;
167
168     return value;
169 }
170
171 float verbstack_popfifo(entity stack)
172 {
173     entity oldself;
174     float ret;
175
176     oldself = self;
177     verb = findentity(stack,verbstack,stack);
178     if not (verb)
179         ret = 0;
180     else
181     {
182         self = verb.owner;
183         ret = verb.verb_call(VCM_DO);
184
185         if(ret == VS_CALL_REMOVE)
186             remove(verb);
187     }
188
189     self = oldself;
190     return ret;
191 }
192
193 /**
194     Find the best verb in this stack and return it.
195     ALso remove any verbs returning VS_CALL_REMOVE on VCM_EVAL.
196 **/
197 entity verbstack_pull(entity stack)
198 {
199     entity vrb;
200     entity bestverb, oldself;
201     float  value, bestvalue;
202
203     oldself = self;
204
205     vrb = findchainentity(verbstack,stack);
206     while(vrb)
207     {
208         self = vrb.owner;
209
210         verb  = vrb;
211         vrb   = vrb.chain;
212         value = verb.verb_call(VCM_EVAL);
213
214         if(value < 0)
215         {
216             if(value == VS_CALL_REMOVE)
217                 remove(verb);
218         }
219         else
220         {
221             if(value > bestvalue)
222             {
223                 bestverb = verb;
224                 bestvalue = value;
225             }
226         }
227     }
228
229     self = oldself;
230
231     return bestverb;
232 }
233
234 entity verbstack_pullfifo(entity stack)
235 {
236     return findentity(stack,verbstack,stack);
237 }
238
239 /**
240     Delete every verb on this stack, signaling them with VCM_REMOVE first.
241 **/
242 void verbstack_flush(entity stack)
243 {
244     entity vrb, oldself;
245
246     oldself = self;
247
248     vrb = findchainentity(verbstack,stack);
249     while(vrb)
250     {
251         self = vrb.owner;
252
253         verb = vrb;
254         vrb  = vrb.chain;
255         verb.verb_call(VCM_REMOVE);
256         remove(verb);
257     }
258
259     self = oldself;
260
261     //stack.vchain = world;
262 }
263
264 void verbstack_doverb(entity vrb)
265 {
266     float value;
267
268     verb  = vrb;
269     self  = verb.owner;
270     value = verb.verb_call(VCM_DO);
271
272     if(value == VS_CALL_REMOVE)
273         remove(vrb);
274 }