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