]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/target_spawn.qc
Reclaim the `new` keyword for entity classes
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / target_spawn.qc
1 #if defined(CSQC)
2 #elif defined(MENUQC)
3 #elif defined(SVQC)
4         #include "../dpdefs/progsdefs.qh"
5     #include "../dpdefs/dpextensions.qh"
6     #include "../common/util.qh"
7     #include "defs.qh"
8 #endif
9
10 // spawner entity
11 // "classname" "target_spawn"
12 // "message" "fieldname value fieldname value ..."
13 // "spawnflags"
14 //   1 = call the spawn function
15 //   2 = trigger on map load
16
17 float target_spawn_initialized;
18 .void() target_spawn_spawnfunc;
19 float target_spawn_spawnfunc_field;
20 .entity target_spawn_activator;
21 .float target_spawn_id;
22 float target_spawn_count;
23
24 void target_spawn_helper_setmodel()
25 {
26         setmodel(self, self.model);
27 }
28
29 void target_spawn_helper_setsize()
30 {
31         setsize(self, self.mins, self.maxs);
32 }
33
34 void target_spawn_edit_entity(entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act)
35 {
36         float i, n, valuefieldpos;
37         string key, value, valuefield, valueoffset, valueoffsetrandom;
38         entity valueent;
39         vector data, data2;
40         entity oldself;
41         entity oldactivator;
42
43         n = tokenize_console(msg);
44
45         for(i = 0; i < n-1; i += 2)
46         {
47                 key = argv(i);
48                 value = argv(i+1);
49                 if(key == "$")
50                 {
51                         data.x = -1;
52                         data.y = FIELD_STRING;
53                 }
54                 else
55                 {
56                         data = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", key)));
57                         if(data.y == 0) // undefined field, i.e., invalid type
58                         {
59                                 print("target_spawn: invalid/unknown entity key ", key, " specified, ignored!\n");
60                                 continue;
61                         }
62                 }
63                 if(substring(value, 0, 1) == "$")
64                 {
65                         value = substring(value, 1, strlen(value) - 1);
66                         if(substring(value, 0, 1) == "$")
67                         {
68                                 // deferred replacement
69                                 // do nothing
70                                 // useful for creating target_spawns with this!
71                         }
72                         else
73                         {
74                                 // replace me!
75                                 valuefieldpos = strstrofs(value, "+", 0);
76                                 valueoffset = "";
77                                 if(valuefieldpos != -1)
78                                 {
79                                         valueoffset = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
80                                         value = substring(value, 0, valuefieldpos);
81                                 }
82
83                                 valuefieldpos = strstrofs(valueoffset, "+", 0);
84                                 valueoffsetrandom = "";
85                                 if(valuefieldpos != -1)
86                                 {
87                                         valueoffsetrandom = substring(valueoffset, valuefieldpos + 1, strlen(valueoffset) - valuefieldpos - 1);
88                                         valueoffset = substring(valueoffset, 0, valuefieldpos);
89                                 }
90
91                                 valuefieldpos = strstrofs(value, ".", 0);
92                                 valuefield = "";
93                                 if(valuefieldpos != -1)
94                                 {
95                                         valuefield = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
96                                         value = substring(value, 0, valuefieldpos);
97                                 }
98
99                                 if(value == "self")
100                                 {
101                                         valueent = self;
102                                         value = "";
103                                 }
104                                 else if(value == "activator")
105                                 {
106                                         valueent = act;
107                                         value = "";
108                                 }
109                                 else if(value == "other")
110                                 {
111                                         valueent = other;
112                                         value = "";
113                                 }
114                                 else if(value == "pusher")
115                                 {
116                                         if(time < act.pushltime)
117                                                 valueent = act.pusher;
118                                         else
119                                                 valueent = world;
120                                         value = "";
121                                 }
122                                 else if(value == "target")
123                                 {
124                                         valueent = e;
125                                         value = "";
126                                 }
127                                 else if(value == "killtarget")
128                                 {
129                                         valueent = kt;
130                                         value = "";
131                                 }
132                                 else if(value == "target2")
133                                 {
134                                         valueent = t2;
135                                         value = "";
136                                 }
137                                 else if(value == "target3")
138                                 {
139                                         valueent = t3;
140                                         value = "";
141                                 }
142                                 else if(value == "target4")
143                                 {
144                                         valueent = t4;
145                                         value = "";
146                                 }
147                                 else if(value == "time")
148                                 {
149                                         valueent = world;
150                                         value = ftos(time);
151                                 }
152                                 else
153                                 {
154                                         print("target_spawn: invalid/unknown variable replacement ", value, " specified, ignored!\n");
155                                         continue;
156                                 }
157
158                                 if(valuefield == "")
159                                 {
160                                         if(value == "")
161                                                 value = ftos(num_for_edict(valueent));
162                                 }
163                                 else
164                                 {
165                                         if(value != "")
166                                         {
167                                                 print("target_spawn: try to get a field of a non-entity, ignored!\n");
168                                                 continue;
169                                         }
170                                         data2 = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", valuefield)));
171                                         if(data2_y == 0) // undefined field, i.e., invalid type
172                                         {
173                                                 print("target_spawn: invalid/unknown entity key replacement ", valuefield, " specified, ignored!\n");
174                                                 continue;
175                                         }
176                                         value = getentityfieldstring(data2_x, valueent);
177                                 }
178
179                                 if(valueoffset != "")
180                                 {
181                                         switch(data.y)
182                                         {
183                                                 case FIELD_STRING:
184                                                         value = strcat(value, valueoffset);
185                                                         break;
186                                                 case FIELD_FLOAT:
187                                                         value = ftos(stof(value) + stof(valueoffset));
188                                                         break;
189                                                 case FIELD_VECTOR:
190                                                         value = vtos(stov(value) + stov(valueoffset));
191                                                         break;
192                                                 default:
193                                                         print("target_spawn: only string, float and vector fields can do calculations, calculation ignored!\n");
194                                                         break;
195                                         }
196                                 }
197
198                                 if(valueoffsetrandom != "")
199                                 {
200                                         switch(data.y)
201                                         {
202                                                 case FIELD_FLOAT:
203                                                         value = ftos(stof(value) + random() * stof(valueoffsetrandom));
204                                                         break;
205                                                 case FIELD_VECTOR:
206                                                         data2 = stov(valueoffsetrandom);
207                                                         value = vtos(stov(value) + random() * data2_x * '1 0 0' + random() * data2_y * '0 1 0' + random() * data2_z * '0 0 1');
208                                                         break;
209                                                 default:
210                                                         print("target_spawn: only float and vector fields can do random calculations, calculation ignored!\n");
211                                                         break;
212                                         }
213                                 }
214                         }
215                 }
216                 if(key == "$")
217                 {
218                         if(substring(value, 0, 1) == "_")
219                                 value = strcat("target_spawn_helper", value);
220                         putentityfieldstring(target_spawn_spawnfunc_field, e, value);
221
222                         oldself = self;
223                         oldactivator = activator;
224
225                         self = e;
226                         activator = act;
227
228                         self.target_spawn_spawnfunc();
229
230                         self = oldself;
231                         activator = oldactivator;
232
233                         // We called an external function, so we have to re-tokenize msg.
234                         n = tokenize_console(msg);
235                 }
236                 else
237                 {
238                         if(data.y == FIELD_VECTOR)
239                                 value = strreplace("'", "", value); // why?!?
240                         putentityfieldstring(data.x, e, value);
241                 }
242         }
243 }
244
245 void target_spawn_useon(entity e)
246 {
247         self.target_spawn_activator = activator;
248         target_spawn_edit_entity(
249                 e,
250                 self.message,
251                 find(world, targetname, self.killtarget),
252                 find(world, targetname, self.target2),
253                 find(world, targetname, self.target3),
254                 find(world, targetname, self.target4),
255                 activator
256         );
257 }
258
259 float target_spawn_cancreate()
260 {
261         float c;
262         entity e;
263
264         c = self.count;
265         if(c == 0) // no limit?
266                 return 1;
267
268         ++c; // increase count to not include MYSELF
269         for(e = world; (e = findfloat(e, target_spawn_id, self.target_spawn_id)); --c)
270                 ;
271
272         // if c now is 0, we have AT LEAST the given count (maybe more), so don't spawn any more
273         if(c == 0)
274                 return 0;
275         return 1;
276 }
277
278 void target_spawn_use()
279 {
280         entity e;
281
282         if(self.target == "")
283         {
284                 // spawn new entity
285                 if(!target_spawn_cancreate())
286                         return;
287                 e = spawn();
288                 target_spawn_useon(e);
289                 e.target_spawn_id = self.target_spawn_id;
290         }
291         else if(self.target == "*activator")
292         {
293                 // edit entity
294                 if(activator)
295                         target_spawn_useon(activator);
296         }
297         else
298         {
299                 // edit entity
300                 for(e = world; (e = find(e, targetname, self.target)); )
301                         target_spawn_useon(e);
302         }
303 }
304
305 void target_spawn_spawnfirst()
306 {
307         activator = self.target_spawn_activator;
308         if(self.spawnflags & 2)
309                 target_spawn_use();
310 }
311
312 void initialize_field_db()
313 {
314         if(!target_spawn_initialized)
315         {
316                 float n, i;
317                 string fn;
318                 vector prev, next;
319                 float ft;
320
321                 n = numentityfields();
322                 for(i = 0; i < n; ++i)
323                 {
324                         fn = entityfieldname(i);
325                         ft = entityfieldtype(i);
326                         next = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
327                         prev = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", fn)));
328                         if(prev.y == 0)
329                         {
330                                 db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(next));
331                                 if(fn == "target_spawn_spawnfunc")
332                                         target_spawn_spawnfunc_field = i;
333                         }
334                 }
335
336                 target_spawn_initialized = 1;
337         }
338 }
339
340 void spawnfunc_target_spawn()
341 {
342         initialize_field_db();
343         self.use = target_spawn_use;
344         self.message = strzone(strreplace("'", "\"", self.message));
345         self.target_spawn_id = ++target_spawn_count;
346         InitializeEntity(self, target_spawn_spawnfirst, INITPRIO_LAST);
347 }
348
349
350 void trigger_relay_if_use()
351 {
352         float n;
353         n = self.count;
354
355         // TODO make this generic AND faster than nextent()ing through all, if somehow possible
356         n = (cvar_string(self.netname) == cvar_string(self.message));
357         if(self.spawnflags & 1)
358                 n = !n;
359
360         if(n)
361                 SUB_UseTargets();
362 }
363
364 void spawnfunc_trigger_relay_if()
365 {
366         self.use = trigger_relay_if_use;
367 }