Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
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>
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
20.void(entity this) target_spawn_spawnfunc;
25
27{
28 _setmodel(this, this.model);
29}
30
32{
33 setsize(this, this.mins, this.maxs);
34}
35
36void 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
236void target_spawn_useon(entity e, entity this, entity actor, entity trigger)
237{
238 this.target_spawn_activator = actor;
240 this,
241 e,
242 this.message,
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
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
271void target_spawn_use(entity this, entity actor, entity trigger)
272{
273 if(this.active != ACTIVE_ACTIVE)
274 return;
275 if(this.target == "")
276 {
277 // spawn new entity
278 if(!target_spawn_cancreate(this))
279 return;
280 entity e = spawn();
281 e.spawnfunc_checked = true;
282 target_spawn_useon(e, this, actor, trigger);
283 e.target_spawn_id = this.target_spawn_id;
284 }
285 else if(this.target == "*activator")
286 {
287 // edit entity
288 if(actor)
289 target_spawn_useon(actor, this, actor, trigger);
290 }
291 else
292 {
293 // edit entity
295 {
296 target_spawn_useon(it, this, actor, trigger);
297 });
298 }
299}
300
302{
304 if(this.spawnflags & ON_MAPLOAD)
305 target_spawn_use(this, act, NULL);
306}
307
309{
311 {
312 float n, i;
313 string fn;
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")
329 }
330 }
331
333 }
334}
335
337{
338 // TODO call "spawn first" again?
339 this.active = ACTIVE_ACTIVE;
340}
341
342spawnfunc(target_spawn)
343{
345 this.use = target_spawn_use;
346 this.active = ACTIVE_ACTIVE;
347 this.reset = target_spawn_reset;
348 this.message = strzone(strreplace("'", "\"", this.message));
351}
352#endif
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
string message
Definition powerups.qc:19
float count
Definition powerups.qc:22
int spawnflags
Definition ammo.qh:15
const int INITPRIO_LAST
Definition constants.qh:100
float FIELD_VECTOR
vector mins
float FIELD_STRING
float FIELD_FLOAT
float time
vector maxs
#define spawn
#define use
int active
Definition defs.qh:34
const int ACTIVE_ACTIVE
Definition defs.qh:37
const int ON_MAPLOAD
Definition defs.qh:9
#define strstrofs
#define strlen
#define tokenize_console
model
Definition ent_cs.qc:139
prev
Definition all.qh:71
next
Definition all.qh:93
#define FOREACH_ENTITY_STRING(fld, match, body)
Definition iter.qh:184
#define LOG_INFO(...)
Definition log.qh:65
ERASEABLE string db_get(int db, string key)
Definition map.qh:91
ERASEABLE void db_put(int db, string key, string value)
Definition map.qh:101
float target_spawn_initialized
Definition spawn.qc:19
void target_spawn_helper_setsize(entity this)
Definition spawn.qc:31
void target_spawn_useon(entity e, entity this, entity actor, entity trigger)
Definition spawn.qc:236
void initialize_field_db()
Definition spawn.qc:308
float target_spawn_id
Definition spawn.qc:23
float target_spawn_spawnfunc_field
Definition spawn.qc:21
void target_spawn_helper_setmodel(entity this)
Definition spawn.qc:26
void target_spawn_edit_entity(entity this, entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act, entity trigger)
Definition spawn.qc:36
void target_spawn_use(entity this, entity actor, entity trigger)
Definition spawn.qc:271
void target_spawn_reset(entity this)
Definition spawn.qc:336
void target_spawn_spawnfirst(entity this)
Definition spawn.qc:301
bool target_spawn_cancreate(entity this)
Definition spawn.qc:252
float target_spawn_count
Definition spawn.qc:24
entity target_spawn_activator
Definition spawn.qc:22
float stof(string val,...)
string substring(string s, float start, float length)
entity find(entity start,.string field, string match)
vector stov(string s)
float random(void)
string vtos(vector v)
string ftos(float f)
string strzone(string s)
string argv(float n)
entity findfloat(entity start,.float field, float match)
#define etof(e)
Definition misc.qh:25
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
#define NULL
Definition post.qh:14
vector
Definition self.qh:92
#define spawnfunc(id)
Definition spawnfunc.qh:96
string killtarget
Definition subs.qh:48
string target4
Definition subs.qh:55
string target3
Definition subs.qh:54
string target2
string targetname
Definition triggers.qh:56
string target
Definition triggers.qh:55
void InitializeEntity(entity e, void(entity this) func, int order)
Definition world.qc:2209
float TemporaryDB
Definition world.qh:129