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