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