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