Xonotic
spawn.qc
Go to the documentation of this file.
1 #include "spawn.qh"
2 #if defined(CSQC)
3 #elif defined(MENUQC)
4 #elif defined(SVQC)
5  #include <common/util.qh>
6  #include <common/weapons/_all.qh>
7  #include <common/stats.qh>
8  #include <server/world.qh>
9 #endif
10 
11 #ifdef SVQC
12 
13 // spawner entity
14 // "classname" "target_spawn"
15 // "message" "fieldname value fieldname value ..."
16 // "spawnflags"
17 // ON_MAPLOAD = trigger on map load
18 
19 float target_spawn_initialized;
20 .void(entity this) target_spawn_spawnfunc;
21 float target_spawn_spawnfunc_field;
22 .entity target_spawn_activator;
23 .float target_spawn_id;
24 float target_spawn_count;
25 
26 void target_spawn_helper_setmodel(entity this)
27 {
28  _setmodel(this, this.model);
29 }
30 
31 void target_spawn_helper_setsize(entity this)
32 {
33  setsize(this, this.mins, this.maxs);
34 }
35 
36 void target_spawn_edit_entity(entity this, entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act, entity trigger)
37 {
38  float i, n, valuefieldpos;
39  string key, value, valuefield, valueoffset, valueoffsetrandom;
40  entity valueent;
41  vector data, data2;
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  LOG_INFO("target_spawn: invalid/unknown entity key ", key, " specified, ignored!");
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 = this;
102  value = "";
103  }
104  else if(value == "activator")
105  {
106  valueent = act;
107  value = "";
108  }
109  else if(value == "other")
110  {
111  valueent = trigger;
112  value = "";
113  }
114  else if(value == "pusher")
115  {
116  if(time < act.pushltime)
117  valueent = act.pusher;
118  else
119  valueent = NULL;
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 = NULL;
150  value = ftos(time);
151  }
152  else
153  {
154  LOG_INFO("target_spawn: invalid/unknown variable replacement ", value, " specified, ignored!");
155  continue;
156  }
157 
158  if(valuefield == "")
159  {
160  if(value == "")
161  value = ftos(etof(valueent));
162  }
163  else
164  {
165  if(value != "")
166  {
167  LOG_INFO("target_spawn: try to get a field of a non-entity, ignored!");
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  LOG_INFO("target_spawn: invalid/unknown entity key replacement ", valuefield, " specified, ignored!");
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  LOG_INFO("target_spawn: only string, float and vector fields can do calculations, calculation ignored!");
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  LOG_INFO("target_spawn: only float and vector fields can do random calculations, calculation ignored!");
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  e.target_spawn_spawnfunc(e);
223 
224  // We called an external function, so we have to re-tokenize msg.
225  n = tokenize_console(msg);
226  }
227  else
228  {
229  if(data.y == FIELD_VECTOR)
230  value = strreplace("'", "", value); // why?!?
231  putentityfieldstring(data.x, e, value);
232  }
233  }
234 }
235 
236 void target_spawn_useon(entity e, entity this, entity actor, entity trigger)
237 {
238  this.target_spawn_activator = actor;
239  target_spawn_edit_entity(
240  this,
241  e,
242  this.message,
243  find(NULL, targetname, this.killtarget),
244  find(NULL, targetname, this.target2),
245  find(NULL, targetname, this.target3),
246  find(NULL, targetname, this.target4),
247  actor,
248  trigger
249  );
250 }
251 
252 bool target_spawn_cancreate(entity this)
253 {
254  float c;
255  entity e;
256 
257  c = this.count;
258  if(c == 0) // no limit?
259  return true;
260 
261  ++c; // increase count to not include MYSELF
262  for(e = NULL; (e = findfloat(e, target_spawn_id, this.target_spawn_id)); --c)
263  ;
264 
265  // if c now is 0, we have AT LEAST the given count (maybe more), so don't spawn any more
266  if(c == 0)
267  return false;
268  return true;
269 }
270 
271 void target_spawn_use(entity this, entity actor, entity trigger)
272 {
273  if(this.target == "")
274  {
275  // spawn new entity
276  if(!target_spawn_cancreate(this))
277  return;
278  entity e = spawn();
279  e.spawnfunc_checked = true;
280  target_spawn_useon(e, this, actor, trigger);
281  e.target_spawn_id = this.target_spawn_id;
282  }
283  else if(this.target == "*activator")
284  {
285  // edit entity
286  if(actor)
287  target_spawn_useon(actor, this, actor, trigger);
288  }
289  else
290  {
291  // edit entity
293  {
294  target_spawn_useon(it, this, actor, trigger);
295  });
296  }
297 }
298 
299 void target_spawn_spawnfirst(entity this)
300 {
301  entity act = this.target_spawn_activator;
302  if(this.spawnflags & ON_MAPLOAD)
303  target_spawn_use(this, act, NULL);
304 }
305 
306 void initialize_field_db()
307 {
308  if(!target_spawn_initialized)
309  {
310  float n, i;
311  string fn;
312  vector prev, next;
313  float ft;
314 
315  n = numentityfields();
316  for(i = 0; i < n; ++i)
317  {
318  fn = entityfieldname(i);
319  ft = entityfieldtype(i);
320  next = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
321  prev = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", fn)));
322  if(prev.y == 0)
323  {
324  db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(next));
325  if(fn == "target_spawn_spawnfunc")
326  target_spawn_spawnfunc_field = i;
327  }
328  }
329 
330  target_spawn_initialized = 1;
331  }
332 }
333 
334 spawnfunc(target_spawn)
335 {
336  initialize_field_db();
337  this.use = target_spawn_use;
338  this.message = strzone(strreplace("'", "\"", this.message));
339  this.target_spawn_id = ++target_spawn_count;
340  InitializeEntity(this, target_spawn_spawnfirst, INITPRIO_LAST);
341 }
342 #endif
ERASEABLE void db_put(int db, string key, string value)
Definition: map.qh:101
string killtarget
Definition: subs.qh:48
string target3
Definition: subs.qh:54
entity() spawn
prev
Definition: all.qh:66
vector maxs
Definition: csprogsdefs.qc:113
spawnfunc(info_player_attacker)
Definition: sv_assault.qc:283
float FIELD_VECTOR
float spawnflags
Definition: progsdefs.qc:191
string model
Definition: csprogsdefs.qc:108
#define FOREACH_ENTITY_STRING(fld, match, body)
Definition: iter.qh:184
float TemporaryDB
Definition: world.qh:132
const int ON_MAPLOAD
Definition: defs.qh:9
vector mins
Definition: csprogsdefs.qc:113
float FIELD_FLOAT
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
string message
Definition: powerups.qc:19
#define NULL
Definition: post.qh:17
#define LOG_INFO(...)
Definition: log.qh:70
float FIELD_STRING
#define strstrofs
Definition: dpextensions.qh:42
ERASEABLE string db_get(int db, string key)
Definition: map.qh:91
string target2
Definition: sv_onslaught.qh:45
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define tokenize_console
Definition: dpextensions.qh:24
next
Definition: all.qh:88
void InitializeEntity(entity e, void(entity this) func, int order)
Definition: world.qc:2146
float count
Definition: powerups.qc:22
string targetname
Definition: progsdefs.qc:194
#define use
Definition: csprogsdefs.qh:50
string target
Definition: progsdefs.qc:193
float time
Definition: csprogsdefs.qc:16
string target4
Definition: subs.qh:55