1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
21 */
22 //
23
24 #include "g_local.h"
25
G_SpawnString(const char * key,const char * defaultString,char ** out)26 qboolean G_SpawnString( const char *key, const char *defaultString, char **out ) {
27 int i;
28
29 if ( !level.spawning ) {
30 *out = (char *)defaultString;
31 // G_Error( "G_SpawnString() called while not spawning" );
32 }
33
34 for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
35 if ( !Q_stricmp( key, level.spawnVars[i][0] ) ) {
36 *out = level.spawnVars[i][1];
37 return qtrue;
38 }
39 }
40
41 *out = (char *)defaultString;
42 return qfalse;
43 }
44
G_SpawnFloat(const char * key,const char * defaultString,float * out)45 qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out ) {
46 char *s;
47 qboolean present;
48
49 present = G_SpawnString( key, defaultString, &s );
50 *out = atof( s );
51 return present;
52 }
53
G_SpawnInt(const char * key,const char * defaultString,int * out)54 qboolean G_SpawnInt( const char *key, const char *defaultString, int *out ) {
55 char *s;
56 qboolean present;
57
58 present = G_SpawnString( key, defaultString, &s );
59 *out = atoi( s );
60 return present;
61 }
62
G_SpawnVector(const char * key,const char * defaultString,float * out)63 qboolean G_SpawnVector( const char *key, const char *defaultString, float *out ) {
64 char *s;
65 qboolean present;
66
67 present = G_SpawnString( key, defaultString, &s );
68 sscanf( s, "%f %f %f", &out[0], &out[1], &out[2] );
69 return present;
70 }
71
72
73
74 //
75 // fields are needed for spawning from the entity string
76 //
77 typedef enum {
78 F_INT,
79 F_FLOAT,
80 F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
81 F_GSTRING, // string on disk, pointer in memory, TAG_GAME
82 F_VECTOR,
83 F_ANGLEHACK,
84 F_ENTITY, // index on disk, pointer in memory
85 F_ITEM, // index on disk, pointer in memory
86 F_CLIENT, // index on disk, pointer in memory
87 F_IGNORE
88 } fieldtype_t;
89
90 typedef struct
91 {
92 char *name;
93 int ofs;
94 fieldtype_t type;
95 int flags;
96 } field_t;
97
98 field_t fields[] = {
99 {"classname", FOFS(classname), F_LSTRING},
100 {"origin", FOFS(s.origin), F_VECTOR},
101 {"model", FOFS(model), F_LSTRING},
102 {"model2", FOFS(model2), F_LSTRING},
103 {"spawnflags", FOFS(spawnflags), F_INT},
104 {"speed", FOFS(speed), F_FLOAT},
105 {"target", FOFS(target), F_LSTRING},
106 {"targetname", FOFS(targetname), F_LSTRING},
107 {"message", FOFS(message), F_LSTRING},
108 {"team", FOFS(team), F_LSTRING},
109 {"wait", FOFS(wait), F_FLOAT},
110 {"random", FOFS(random), F_FLOAT},
111 {"count", FOFS(count), F_INT},
112 {"health", FOFS(health), F_INT},
113 {"light", 0, F_IGNORE},
114 {"dmg", FOFS(damage), F_INT},
115 {"angles", FOFS(s.angles), F_VECTOR},
116 {"angle", FOFS(s.angles), F_ANGLEHACK},
117 {"targetShaderName", FOFS(targetShaderName), F_LSTRING},
118 {"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING},
119
120 {NULL}
121 };
122
123
124 typedef struct {
125 char *name;
126 void (*spawn)(gentity_t *ent);
127 } spawn_t;
128
129 void SP_info_player_start (gentity_t *ent);
130 void SP_info_player_deathmatch (gentity_t *ent);
131 void SP_info_player_intermission (gentity_t *ent);
132 void SP_info_firstplace(gentity_t *ent);
133 void SP_info_secondplace(gentity_t *ent);
134 void SP_info_thirdplace(gentity_t *ent);
135 void SP_info_podium(gentity_t *ent);
136
137 void SP_func_plat (gentity_t *ent);
138 void SP_func_static (gentity_t *ent);
139 void SP_func_rotating (gentity_t *ent);
140 void SP_func_bobbing (gentity_t *ent);
141 void SP_func_pendulum( gentity_t *ent );
142 void SP_func_button (gentity_t *ent);
143 void SP_func_door (gentity_t *ent);
144 void SP_func_train (gentity_t *ent);
145 void SP_func_timer (gentity_t *self);
146
147 void SP_trigger_always (gentity_t *ent);
148 void SP_trigger_multiple (gentity_t *ent);
149 void SP_trigger_push (gentity_t *ent);
150 void SP_trigger_teleport (gentity_t *ent);
151 void SP_trigger_hurt (gentity_t *ent);
152
153 void SP_target_remove_powerups( gentity_t *ent );
154 void SP_target_give (gentity_t *ent);
155 void SP_target_delay (gentity_t *ent);
156 void SP_target_speaker (gentity_t *ent);
157 void SP_target_print (gentity_t *ent);
158 void SP_target_laser (gentity_t *self);
159 void SP_target_character (gentity_t *ent);
160 void SP_target_score( gentity_t *ent );
161 void SP_target_teleporter( gentity_t *ent );
162 void SP_target_relay (gentity_t *ent);
163 void SP_target_kill (gentity_t *ent);
164 void SP_target_position (gentity_t *ent);
165 void SP_target_location (gentity_t *ent);
166 void SP_target_push (gentity_t *ent);
167
168 void SP_light (gentity_t *self);
169 void SP_info_null (gentity_t *self);
170 void SP_info_notnull (gentity_t *self);
171 void SP_info_camp (gentity_t *self);
172 void SP_path_corner (gentity_t *self);
173
174 void SP_misc_teleporter_dest (gentity_t *self);
175 void SP_misc_model(gentity_t *ent);
176 void SP_misc_portal_camera(gentity_t *ent);
177 void SP_misc_portal_surface(gentity_t *ent);
178
179 void SP_shooter_rocket( gentity_t *ent );
180 void SP_shooter_plasma( gentity_t *ent );
181 void SP_shooter_grenade( gentity_t *ent );
182
183 void SP_team_CTF_redplayer( gentity_t *ent );
184 void SP_team_CTF_blueplayer( gentity_t *ent );
185
186 void SP_team_CTF_redspawn( gentity_t *ent );
187 void SP_team_CTF_bluespawn( gentity_t *ent );
188
189 #ifdef MISSIONPACK
190 void SP_team_blueobelisk( gentity_t *ent );
191 void SP_team_redobelisk( gentity_t *ent );
192 void SP_team_neutralobelisk( gentity_t *ent );
193 #endif
SP_item_botroam(gentity_t * ent)194 void SP_item_botroam( gentity_t *ent ) { }
195
196 spawn_t spawns[] = {
197 // info entities don't do anything at all, but provide positional
198 // information for things controlled by other processes
199 {"info_player_start", SP_info_player_start},
200 {"info_player_deathmatch", SP_info_player_deathmatch},
201 {"info_player_intermission", SP_info_player_intermission},
202 {"info_null", SP_info_null},
203 {"info_notnull", SP_info_notnull}, // use target_position instead
204 {"info_camp", SP_info_camp},
205
206 {"func_plat", SP_func_plat},
207 {"func_button", SP_func_button},
208 {"func_door", SP_func_door},
209 {"func_static", SP_func_static},
210 {"func_rotating", SP_func_rotating},
211 {"func_bobbing", SP_func_bobbing},
212 {"func_pendulum", SP_func_pendulum},
213 {"func_train", SP_func_train},
214 {"func_group", SP_info_null},
215 {"func_timer", SP_func_timer}, // rename trigger_timer?
216
217 // Triggers are brush objects that cause an effect when contacted
218 // by a living player, usually involving firing targets.
219 // While almost everything could be done with
220 // a single trigger class and different targets, triggered effects
221 // could not be client side predicted (push and teleport).
222 {"trigger_always", SP_trigger_always},
223 {"trigger_multiple", SP_trigger_multiple},
224 {"trigger_push", SP_trigger_push},
225 {"trigger_teleport", SP_trigger_teleport},
226 {"trigger_hurt", SP_trigger_hurt},
227
228 // targets perform no action by themselves, but must be triggered
229 // by another entity
230 {"target_give", SP_target_give},
231 {"target_remove_powerups", SP_target_remove_powerups},
232 {"target_delay", SP_target_delay},
233 {"target_speaker", SP_target_speaker},
234 {"target_print", SP_target_print},
235 {"target_laser", SP_target_laser},
236 {"target_score", SP_target_score},
237 {"target_teleporter", SP_target_teleporter},
238 {"target_relay", SP_target_relay},
239 {"target_kill", SP_target_kill},
240 {"target_position", SP_target_position},
241 {"target_location", SP_target_location},
242 {"target_push", SP_target_push},
243
244 {"light", SP_light},
245 {"path_corner", SP_path_corner},
246
247 {"misc_teleporter_dest", SP_misc_teleporter_dest},
248 {"misc_model", SP_misc_model},
249 {"misc_portal_surface", SP_misc_portal_surface},
250 {"misc_portal_camera", SP_misc_portal_camera},
251
252 {"shooter_rocket", SP_shooter_rocket},
253 {"shooter_grenade", SP_shooter_grenade},
254 {"shooter_plasma", SP_shooter_plasma},
255
256 {"team_CTF_redplayer", SP_team_CTF_redplayer},
257 {"team_CTF_blueplayer", SP_team_CTF_blueplayer},
258
259 {"team_CTF_redspawn", SP_team_CTF_redspawn},
260 {"team_CTF_bluespawn", SP_team_CTF_bluespawn},
261
262 #ifdef MISSIONPACK
263 {"team_redobelisk", SP_team_redobelisk},
264 {"team_blueobelisk", SP_team_blueobelisk},
265 {"team_neutralobelisk", SP_team_neutralobelisk},
266 #endif
267 {"item_botroam", SP_item_botroam},
268
269 {NULL, 0}
270 };
271
272 /*
273 ===============
274 G_CallSpawn
275
276 Finds the spawn function for the entity and calls it,
277 returning qfalse if not found
278 ===============
279 */
G_CallSpawn(gentity_t * ent)280 qboolean G_CallSpawn( gentity_t *ent ) {
281 spawn_t *s;
282 gitem_t *item;
283
284 if ( !ent->classname ) {
285 G_Printf ("G_CallSpawn: NULL classname\n");
286 return qfalse;
287 }
288
289 // check item spawn functions
290 for ( item=bg_itemlist+1 ; item->classname ; item++ ) {
291 if ( !strcmp(item->classname, ent->classname) ) {
292 G_SpawnItem( ent, item );
293 return qtrue;
294 }
295 }
296
297 // check normal spawn functions
298 for ( s=spawns ; s->name ; s++ ) {
299 if ( !strcmp(s->name, ent->classname) ) {
300 // found it
301 s->spawn(ent);
302 return qtrue;
303 }
304 }
305 G_Printf ("%s doesn't have a spawn function\n", ent->classname);
306 return qfalse;
307 }
308
309 /*
310 =============
311 G_NewString
312
313 Builds a copy of the string, translating \n to real linefeeds
314 so message texts can be multi-line
315 =============
316 */
G_NewString(const char * string)317 char *G_NewString( const char *string ) {
318 char *newb, *new_p;
319 int i,l;
320
321 l = strlen(string) + 1;
322
323 newb = G_Alloc( l );
324
325 new_p = newb;
326
327 // turn \n into a real linefeed
328 for ( i=0 ; i< l ; i++ ) {
329 if (string[i] == '\\' && i < l-1) {
330 i++;
331 if (string[i] == 'n') {
332 *new_p++ = '\n';
333 } else {
334 *new_p++ = '\\';
335 }
336 } else {
337 *new_p++ = string[i];
338 }
339 }
340
341 return newb;
342 }
343
344
345
346
347 /*
348 ===============
349 G_ParseField
350
351 Takes a key/value pair and sets the binary values
352 in a gentity
353 ===============
354 */
G_ParseField(const char * key,const char * value,gentity_t * ent)355 void G_ParseField( const char *key, const char *value, gentity_t *ent ) {
356 field_t *f;
357 byte *b;
358 float v;
359 vec3_t vec;
360
361 for ( f=fields ; f->name ; f++ ) {
362 if ( !Q_stricmp(f->name, key) ) {
363 // found it
364 b = (byte *)ent;
365
366 switch( f->type ) {
367 case F_LSTRING:
368 *(char **)(b+f->ofs) = G_NewString (value);
369 break;
370 case F_VECTOR:
371 sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
372 ((float *)(b+f->ofs))[0] = vec[0];
373 ((float *)(b+f->ofs))[1] = vec[1];
374 ((float *)(b+f->ofs))[2] = vec[2];
375 break;
376 case F_INT:
377 *(int *)(b+f->ofs) = atoi(value);
378 break;
379 case F_FLOAT:
380 *(float *)(b+f->ofs) = atof(value);
381 break;
382 case F_ANGLEHACK:
383 v = atof(value);
384 ((float *)(b+f->ofs))[0] = 0;
385 ((float *)(b+f->ofs))[1] = v;
386 ((float *)(b+f->ofs))[2] = 0;
387 break;
388 default:
389 case F_IGNORE:
390 break;
391 }
392 return;
393 }
394 }
395 }
396
397
398
399
400 /*
401 ===================
402 G_SpawnGEntityFromSpawnVars
403
404 Spawn an entity and fill in all of the level fields from
405 level.spawnVars[], then call the class specfic spawn function
406 ===================
407 */
G_SpawnGEntityFromSpawnVars(void)408 void G_SpawnGEntityFromSpawnVars( void ) {
409 int i;
410 gentity_t *ent;
411 char *s, *value, *gametypeName;
412 static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester", "teamtournament"};
413
414 // get the next free entity
415 ent = G_Spawn();
416
417 for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
418 G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );
419 }
420
421 // check for "notsingle" flag
422 if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
423 G_SpawnInt( "notsingle", "0", &i );
424 if ( i ) {
425 G_FreeEntity( ent );
426 return;
427 }
428 }
429 // check for "notteam" flag (GT_FFA, GT_TOURNAMENT, GT_SINGLE_PLAYER)
430 if ( g_gametype.integer >= GT_TEAM ) {
431 G_SpawnInt( "notteam", "0", &i );
432 if ( i ) {
433 G_FreeEntity( ent );
434 return;
435 }
436 } else {
437 G_SpawnInt( "notfree", "0", &i );
438 if ( i ) {
439 G_FreeEntity( ent );
440 return;
441 }
442 }
443
444 #ifdef MISSIONPACK
445 G_SpawnInt( "notta", "0", &i );
446 if ( i ) {
447 G_FreeEntity( ent );
448 return;
449 }
450 #else
451 G_SpawnInt( "notq3a", "0", &i );
452 if ( i ) {
453 G_FreeEntity( ent );
454 return;
455 }
456 #endif
457
458 if( G_SpawnString( "gametype", NULL, &value ) ) {
459 if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {
460 gametypeName = gametypeNames[g_gametype.integer];
461
462 s = strstr( value, gametypeName );
463 if( !s ) {
464 G_FreeEntity( ent );
465 return;
466 }
467 }
468 }
469
470 // move editor origin to pos
471 VectorCopy( ent->s.origin, ent->s.pos.trBase );
472 VectorCopy( ent->s.origin, ent->r.currentOrigin );
473
474 // if we didn't get a classname, don't bother spawning anything
475 if ( !G_CallSpawn( ent ) ) {
476 G_FreeEntity( ent );
477 }
478 }
479
480
481
482 /*
483 ====================
484 G_AddSpawnVarToken
485 ====================
486 */
G_AddSpawnVarToken(const char * string)487 char *G_AddSpawnVarToken( const char *string ) {
488 int l;
489 char *dest;
490
491 l = strlen( string );
492 if ( level.numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) {
493 G_Error( "G_AddSpawnVarToken: MAX_SPAWN_CHARS" );
494 }
495
496 dest = level.spawnVarChars + level.numSpawnVarChars;
497 memcpy( dest, string, l+1 );
498
499 level.numSpawnVarChars += l + 1;
500
501 return dest;
502 }
503
504 /*
505 ====================
506 G_ParseSpawnVars
507
508 Parses a brace bounded set of key / value pairs out of the
509 level's entity strings into level.spawnVars[]
510
511 This does not actually spawn an entity.
512 ====================
513 */
G_ParseSpawnVars(void)514 qboolean G_ParseSpawnVars( void ) {
515 char keyname[MAX_TOKEN_CHARS];
516 char com_token[MAX_TOKEN_CHARS];
517
518 level.numSpawnVars = 0;
519 level.numSpawnVarChars = 0;
520
521 // parse the opening brace
522 if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
523 // end of spawn string
524 return qfalse;
525 }
526 if ( com_token[0] != '{' ) {
527 G_Error( "G_ParseSpawnVars: found %s when expecting {",com_token );
528 }
529
530 // go through all the key / value pairs
531 while ( 1 ) {
532 // parse key
533 if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) {
534 G_Error( "G_ParseSpawnVars: EOF without closing brace" );
535 }
536
537 if ( keyname[0] == '}' ) {
538 break;
539 }
540
541 // parse value
542 if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
543 G_Error( "G_ParseSpawnVars: EOF without closing brace" );
544 }
545
546 if ( com_token[0] == '}' ) {
547 G_Error( "G_ParseSpawnVars: closing brace without data" );
548 }
549 if ( level.numSpawnVars == MAX_SPAWN_VARS ) {
550 G_Error( "G_ParseSpawnVars: MAX_SPAWN_VARS" );
551 }
552 level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( keyname );
553 level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( com_token );
554 level.numSpawnVars++;
555 }
556
557 return qtrue;
558 }
559
560
561
562 /*QUAKED worldspawn (0 0 0) ?
563
564 Every map should have exactly one worldspawn.
565 "music" music wav file
566 "gravity" 800 is default gravity
567 "message" Text to print during connection process
568 */
SP_worldspawn(void)569 void SP_worldspawn( void ) {
570 char *s;
571
572 G_SpawnString( "classname", "", &s );
573 if ( Q_stricmp( s, "worldspawn" ) ) {
574 G_Error( "SP_worldspawn: The first entity isn't 'worldspawn'" );
575 }
576
577 // make some data visible to connecting client
578 trap_SetConfigstring( CS_GAME_VERSION, GAME_VERSION );
579
580 trap_SetConfigstring( CS_LEVEL_START_TIME, va("%i", level.startTime ) );
581
582 G_SpawnString( "music", "", &s );
583 trap_SetConfigstring( CS_MUSIC, s );
584
585 G_SpawnString( "message", "", &s );
586 trap_SetConfigstring( CS_MESSAGE, s ); // map specific message
587
588 trap_SetConfigstring( CS_MOTD, g_motd.string ); // message of the day
589
590 G_SpawnString( "gravity", "800", &s );
591 trap_Cvar_Set( "g_gravity", s );
592
593 G_SpawnString( "enableDust", "0", &s );
594 trap_Cvar_Set( "g_enableDust", s );
595
596 G_SpawnString( "enableBreath", "0", &s );
597 trap_Cvar_Set( "g_enableBreath", s );
598
599 g_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD;
600 g_entities[ENTITYNUM_WORLD].classname = "worldspawn";
601
602 // see if we want a warmup time
603 trap_SetConfigstring( CS_WARMUP, "" );
604 if ( g_restarted.integer ) {
605 trap_Cvar_Set( "g_restarted", "0" );
606 level.warmupTime = 0;
607 } else if ( g_doWarmup.integer ) { // Turn it on
608 level.warmupTime = -1;
609 trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
610 G_LogPrintf( "Warmup:\n" );
611 }
612
613 }
614
615
616 /*
617 ==============
618 G_SpawnEntitiesFromString
619
620 Parses textual entity definitions out of an entstring and spawns gentities.
621 ==============
622 */
G_SpawnEntitiesFromString(void)623 void G_SpawnEntitiesFromString( void ) {
624 // allow calls to G_Spawn*()
625 level.spawning = qtrue;
626 level.numSpawnVars = 0;
627
628 // the worldspawn is not an actual entity, but it still
629 // has a "spawn" function to perform any global setup
630 // needed by a level (setting configstrings or cvars, etc)
631 if ( !G_ParseSpawnVars() ) {
632 G_Error( "SpawnEntities: no entities" );
633 }
634 SP_worldspawn();
635
636 // parse ents
637 while( G_ParseSpawnVars() ) {
638 G_SpawnGEntityFromSpawnVars();
639 }
640
641 level.spawning = qfalse; // any future calls to G_Spawn*() will be errors
642 }
643
644