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