1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7 
8 This file is part of the OpenJK source code.
9 
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see <http://www.gnu.org/licenses/>.
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 //		trap->Error( ERR_DROP, "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 	if ( sscanf( s, "%f %f %f", &out[0], &out[1], &out[2] ) != 3 ) {
69 		trap->Print( "G_SpawnVector: Failed sscanf on %s (default: %s)\n", key, defaultString );
70 		VectorClear( out );
71 		return qfalse;
72 	}
73 	return present;
74 }
75 
G_SpawnBoolean(const char * key,const char * defaultString,qboolean * out)76 qboolean	G_SpawnBoolean( const char *key, const char *defaultString, qboolean *out ) {
77 	char		*s;
78 	qboolean	present;
79 
80 	present = G_SpawnString( key, defaultString, &s );
81 
82 	if ( !Q_stricmp( s, "qtrue" ) || !Q_stricmp( s, "true" ) || !Q_stricmp( s, "yes" ) || !Q_stricmp( s, "1" ) )
83 		*out = qtrue;
84 	else if ( !Q_stricmp( s, "qfalse" ) || !Q_stricmp( s, "false" ) || !Q_stricmp( s, "no" ) || !Q_stricmp( s, "0" ) )
85 		*out = qfalse;
86 	else
87 		*out = qfalse;
88 
89 	return present;
90 }
91 
92 //
93 // fields are needed for spawning from the entity string
94 //
95 typedef enum {
96 	F_INT,
97 	F_FLOAT,
98 	F_STRING,			// string on disk, pointer in memory
99 	F_VECTOR,
100 	F_ANGLEHACK,
101 	F_PARM1,			// Special case for parms
102 	F_PARM2,			// Special case for parms
103 	F_PARM3,			// Special case for parms
104 	F_PARM4,			// Special case for parms
105 	F_PARM5,			// Special case for parms
106 	F_PARM6,			// Special case for parms
107 	F_PARM7,			// Special case for parms
108 	F_PARM8,			// Special case for parms
109 	F_PARM9,			// Special case for parms
110 	F_PARM10,			// Special case for parms
111 	F_PARM11,			// Special case for parms
112 	F_PARM12,			// Special case for parms
113 	F_PARM13,			// Special case for parms
114 	F_PARM14,			// Special case for parms
115 	F_PARM15,			// Special case for parms
116 	F_PARM16			// Special case for parms
117 } fieldtype_t;
118 
119 typedef struct field_s {
120 	const char	*name;
121 	size_t		ofs;
122 	fieldtype_t	type;
123 } field_t;
124 
125 field_t fields[] = {
126 	{ "alliedteam",				FOFS( alliedTeam ),						F_INT },//for misc_turrets
127 	{ "angerscript",			FOFS( behaviorSet[BSET_ANGER] ),		F_STRING },//name of script to run
128 	{ "angle",					FOFS( s.angles ),						F_ANGLEHACK },
129 	{ "angles",					FOFS( s.angles ),						F_VECTOR },
130 	{ "attackscript",			FOFS( behaviorSet[BSET_ATTACK] ),		F_STRING },//name of script to run
131 	{ "awakescript",			FOFS( behaviorSet[BSET_AWAKE] ),		F_STRING },//name of script to run
132 	{ "blockedscript",			FOFS( behaviorSet[BSET_BLOCKED] ),		F_STRING },//name of script to run
133 	{ "chunksize",				FOFS( mass ),							F_FLOAT },//for func_breakables
134 	{ "classname",				FOFS( classname ),						F_STRING },
135 	{ "closetarget",			FOFS( closetarget ),					F_STRING },//for doors
136 	{ "count",					FOFS( count ),							F_INT },
137 	{ "deathscript",			FOFS( behaviorSet[BSET_DEATH] ),		F_STRING },//name of script to run
138 	{ "delay",					FOFS( delay ),							F_INT },
139 	{ "delayscript",			FOFS( behaviorSet[BSET_DELAYED] ),		F_STRING },//name of script to run
140 	{ "delayscripttime",		FOFS( delayScriptTime ),				F_INT },//name of script to run
141 	{ "dmg",					FOFS( damage ),							F_INT },
142 	{ "ffdeathscript",			FOFS( behaviorSet[BSET_FFDEATH] ),		F_STRING },//name of script to run
143 	{ "ffirescript",			FOFS( behaviorSet[BSET_FFIRE] ),		F_STRING },//name of script to run
144 	{ "fleescript",				FOFS( behaviorSet[BSET_FLEE] ),			F_STRING },//name of script to run
145 	{ "fullname",				FOFS( fullName ),						F_STRING },
146 	{ "goaltarget",				FOFS( goaltarget ),						F_STRING },//for siege
147 	{ "healingclass",			FOFS( healingclass ),					F_STRING },
148 	{ "healingrate",			FOFS( healingrate ),					F_INT },
149 	{ "healingsound",			FOFS( healingsound ),					F_STRING },
150 	{ "health",					FOFS( health ),							F_INT },
151 	{ "idealclass",				FOFS( idealclass ),						F_STRING },//for siege spawnpoints
152 	{ "linear",					FOFS( alt_fire ),						F_INT },//for movers to use linear movement
153 	{ "lostenemyscript",		FOFS( behaviorSet[BSET_LOSTENEMY] ),	F_STRING },//name of script to run
154 	{ "message",				FOFS( message ),						F_STRING },
155 	{ "mindtrickscript",		FOFS( behaviorSet[BSET_MINDTRICK] ),	F_STRING },//name of script to run
156 	{ "model",					FOFS( model ),							F_STRING },
157 	{ "model2",					FOFS( model2 ),							F_STRING },
158 	{ "npc_target",				FOFS( NPC_target ),						F_STRING },
159 	{ "npc_target2",			FOFS( target2 ),						F_STRING },//NPC_spawner only
160 	{ "npc_target4",			FOFS( target4 ),						F_STRING },//NPC_spawner only
161 	{ "npc_targetname",			FOFS( NPC_targetname ),					F_STRING },
162 	{ "npc_type",				FOFS( NPC_type ),						F_STRING },
163 	{ "numchunks",				FOFS( radius ),							F_FLOAT },//for func_breakables
164 	{ "opentarget",				FOFS( opentarget ),						F_STRING },//for doors
165 	{ "origin",					FOFS( s.origin ),						F_VECTOR },
166 	{ "ownername",				FOFS( ownername ),						F_STRING },
167 	{ "painscript",				FOFS( behaviorSet[BSET_PAIN] ),			F_STRING },//name of script to run
168 	{ "paintarget",				FOFS( paintarget ),						F_STRING },//for doors
169 	{ "parm1",					0,										F_PARM1 },
170 	{ "parm10",					0,										F_PARM10 },
171 	{ "parm11",					0,										F_PARM11 },
172 	{ "parm12",					0,										F_PARM12 },
173 	{ "parm13",					0,										F_PARM13 },
174 	{ "parm14",					0,										F_PARM14 },
175 	{ "parm15",					0,										F_PARM15 },
176 	{ "parm16",					0,										F_PARM16 },
177 	{ "parm2",					0,										F_PARM2 },
178 	{ "parm3",					0,										F_PARM3 },
179 	{ "parm4",					0,										F_PARM4 },
180 	{ "parm5",					0,										F_PARM5 },
181 	{ "parm6",					0,										F_PARM6 },
182 	{ "parm7",					0,										F_PARM7 },
183 	{ "parm8",					0,										F_PARM8 },
184 	{ "parm9",					0,										F_PARM9 },
185 	{ "radius",					FOFS( radius ),							F_FLOAT },
186 	{ "random",					FOFS( random ),							F_FLOAT },
187 	{ "roffname",				FOFS( roffname ),						F_STRING },
188 	{ "rofftarget",				FOFS( rofftarget ),						F_STRING },
189 	{ "script_targetname",		FOFS( script_targetname ),				F_STRING },//scripts look for this when "affecting"
190 	{ "soundset",				FOFS( soundSet ),						F_STRING },
191 	{ "spawnflags",				FOFS( spawnflags ),						F_INT },
192 	{ "spawnscript",			FOFS( behaviorSet[BSET_SPAWN] ),		F_STRING },//name of script to run
193 	{ "speed",					FOFS( speed ),							F_FLOAT },
194 	{ "target",					FOFS( target ),							F_STRING },
195 	{ "target2",				FOFS( target2 ),						F_STRING },
196 	{ "target3",				FOFS( target3 ),						F_STRING },
197 	{ "target4",				FOFS( target4 ),						F_STRING },
198 	{ "target5",				FOFS( target5 ),						F_STRING },
199 	{ "target6",				FOFS( target6 ),						F_STRING },
200 	{ "targetname",				FOFS( targetname ),						F_STRING },
201 	{ "targetshadername",		FOFS( targetShaderName ),				F_STRING },
202 	{ "targetshadernewname",	FOFS( targetShaderNewName ),			F_STRING },
203 	{ "team",					FOFS( team ),							F_STRING },
204 	{ "teamnodmg",				FOFS( teamnodmg ),						F_INT },
205 	{ "teamowner",				FOFS( s.teamowner ),					F_INT },
206 	{ "teamuser",				FOFS( alliedTeam ),						F_INT },
207 	{ "usescript",				FOFS( behaviorSet[BSET_USE] ),			F_STRING },//name of script to run
208 	{ "victoryscript",			FOFS( behaviorSet[BSET_VICTORY] ),		F_STRING },//name of script to run
209 	{ "wait",					FOFS( wait ),							F_FLOAT },
210 };
211 
212 typedef struct spawn_s {
213 	const char	*name;
214 	void		(*spawn)(gentity_t *ent);
215 } spawn_t;
216 
217 void SP_info_player_start (gentity_t *ent);
218 void SP_info_player_duel( gentity_t *ent );
219 void SP_info_player_duel1( gentity_t *ent );
220 void SP_info_player_duel2( gentity_t *ent );
221 void SP_info_player_deathmatch (gentity_t *ent);
222 void SP_info_player_siegeteam1 (gentity_t *ent);
223 void SP_info_player_siegeteam2 (gentity_t *ent);
224 void SP_info_player_intermission (gentity_t *ent);
225 void SP_info_player_intermission_red (gentity_t *ent);
226 void SP_info_player_intermission_blue (gentity_t *ent);
227 void SP_info_jedimaster_start (gentity_t *ent);
228 void SP_info_player_start_red (gentity_t *ent);
229 void SP_info_player_start_blue (gentity_t *ent);
230 void SP_info_firstplace(gentity_t *ent);
231 void SP_info_secondplace(gentity_t *ent);
232 void SP_info_thirdplace(gentity_t *ent);
233 void SP_info_podium(gentity_t *ent);
234 
235 void SP_info_siege_objective (gentity_t *ent);
236 void SP_info_siege_radaricon (gentity_t *ent);
237 void SP_info_siege_decomplete (gentity_t *ent);
238 void SP_target_siege_end (gentity_t *ent);
239 void SP_misc_siege_item (gentity_t *ent);
240 
241 void SP_func_plat (gentity_t *ent);
242 void SP_func_static (gentity_t *ent);
243 void SP_func_rotating (gentity_t *ent);
244 void SP_func_bobbing (gentity_t *ent);
245 void SP_func_pendulum( gentity_t *ent );
246 void SP_func_button (gentity_t *ent);
247 void SP_func_door (gentity_t *ent);
248 void SP_func_train (gentity_t *ent);
249 void SP_func_timer (gentity_t *self);
250 void SP_func_breakable (gentity_t *ent);
251 void SP_func_glass (gentity_t *ent);
252 void SP_func_usable( gentity_t *ent);
253 void SP_func_wall( gentity_t *ent );
254 
255 void SP_trigger_lightningstrike( gentity_t *ent );
256 
257 void SP_trigger_always (gentity_t *ent);
258 void SP_trigger_multiple (gentity_t *ent);
259 void SP_trigger_once( gentity_t *ent );
260 void SP_trigger_push (gentity_t *ent);
261 void SP_trigger_teleport (gentity_t *ent);
262 void SP_trigger_hurt (gentity_t *ent);
263 void SP_trigger_space(gentity_t *self);
264 void SP_trigger_shipboundary(gentity_t *self);
265 void SP_trigger_hyperspace(gentity_t *self);
266 void SP_trigger_asteroid_field(gentity_t *self);
267 
268 void SP_target_remove_powerups( gentity_t *ent );
269 void SP_target_give (gentity_t *ent);
270 void SP_target_delay (gentity_t *ent);
271 void SP_target_speaker (gentity_t *ent);
272 void SP_target_print (gentity_t *ent);
273 void SP_target_laser (gentity_t *self);
274 void SP_target_character (gentity_t *ent);
275 void SP_target_score( gentity_t *ent );
276 void SP_target_teleporter( gentity_t *ent );
277 void SP_target_relay (gentity_t *ent);
278 void SP_target_kill (gentity_t *ent);
279 void SP_target_position (gentity_t *ent);
280 void SP_target_location (gentity_t *ent);
281 void SP_target_counter (gentity_t *self);
282 void SP_target_random (gentity_t *self);
283 void SP_target_scriptrunner( gentity_t *self );
284 void SP_target_interest (gentity_t *self);
285 void SP_target_activate (gentity_t *self);
286 void SP_target_deactivate (gentity_t *self);
287 void SP_target_level_change( gentity_t *self );
288 void SP_target_play_music( gentity_t *self );
289 void SP_target_push (gentity_t *ent);
290 
291 void SP_light (gentity_t *self);
292 void SP_info_null (gentity_t *self);
293 void SP_info_notnull (gentity_t *self);
294 void SP_info_camp (gentity_t *self);
295 void SP_path_corner (gentity_t *self);
296 
297 void SP_misc_teleporter_dest (gentity_t *self);
298 void SP_misc_model(gentity_t *ent);
299 void SP_misc_model_static(gentity_t *ent);
300 void SP_misc_model_breakable( gentity_t *ent ) ;
301 void SP_misc_G2model(gentity_t *ent);
302 void SP_misc_portal_camera(gentity_t *ent);
303 void SP_misc_portal_surface(gentity_t *ent);
304 void SP_misc_weather_zone( gentity_t *ent );
305 
306 void SP_misc_bsp (gentity_t *ent);
307 void SP_terrain (gentity_t *ent);
308 void SP_misc_skyportal_orient (gentity_t *ent);
309 void SP_misc_skyportal (gentity_t *ent);
310 
311 void SP_misc_ammo_floor_unit(gentity_t *ent);
312 void SP_misc_shield_floor_unit( gentity_t *ent );
313 void SP_misc_model_shield_power_converter( gentity_t *ent );
314 void SP_misc_model_ammo_power_converter( gentity_t *ent );
315 void SP_misc_model_health_power_converter( gentity_t *ent );
316 
317 void SP_fx_runner( gentity_t *ent );
318 
319 void SP_target_screenshake(gentity_t *ent);
320 void SP_target_escapetrig(gentity_t *ent);
321 
322 void SP_misc_maglock ( gentity_t *self );
323 
324 void SP_misc_faller(gentity_t *ent);
325 
326 void SP_misc_holocron(gentity_t *ent);
327 
328 void SP_reference_tag ( gentity_t *ent );
329 
330 void SP_misc_weapon_shooter( gentity_t *self );
331 
332 void SP_misc_cubemap( gentity_t *ent );
333 
334 void SP_NPC_spawner( gentity_t *self );
335 
336 void SP_NPC_Vehicle( gentity_t *self);
337 
338 void SP_NPC_Kyle( gentity_t *self );
339 void SP_NPC_Lando( gentity_t *self );
340 void SP_NPC_Jan( gentity_t *self );
341 void SP_NPC_Luke( gentity_t *self );
342 void SP_NPC_MonMothma( gentity_t *self );
343 void SP_NPC_Tavion( gentity_t *self );
344 void SP_NPC_Tavion_New( gentity_t *self );
345 void SP_NPC_Alora( gentity_t *self );
346 void SP_NPC_Reelo( gentity_t *self );
347 void SP_NPC_Galak( gentity_t *self );
348 void SP_NPC_Desann( gentity_t *self );
349 void SP_NPC_Bartender( gentity_t *self );
350 void SP_NPC_MorganKatarn( gentity_t *self );
351 void SP_NPC_Jedi( gentity_t *self );
352 void SP_NPC_Prisoner( gentity_t *self );
353 void SP_NPC_Rebel( gentity_t *self );
354 void SP_NPC_Human_Merc( gentity_t *self );
355 void SP_NPC_Stormtrooper( gentity_t *self );
356 void SP_NPC_StormtrooperOfficer( gentity_t *self );
357 void SP_NPC_Snowtrooper( gentity_t *self);
358 void SP_NPC_Tie_Pilot( gentity_t *self );
359 void SP_NPC_Ugnaught( gentity_t *self );
360 void SP_NPC_Jawa( gentity_t *self );
361 void SP_NPC_Gran( gentity_t *self );
362 void SP_NPC_Rodian( gentity_t *self );
363 void SP_NPC_Weequay( gentity_t *self );
364 void SP_NPC_Trandoshan( gentity_t *self );
365 void SP_NPC_Tusken( gentity_t *self );
366 void SP_NPC_Noghri( gentity_t *self );
367 void SP_NPC_SwampTrooper( gentity_t *self );
368 void SP_NPC_Imperial( gentity_t *self );
369 void SP_NPC_ImpWorker( gentity_t *self );
370 void SP_NPC_BespinCop( gentity_t *self );
371 void SP_NPC_Reborn( gentity_t *self );
372 void SP_NPC_ShadowTrooper( gentity_t *self );
373 void SP_NPC_Monster_Murjj( gentity_t *self );
374 void SP_NPC_Monster_Swamp( gentity_t *self );
375 void SP_NPC_Monster_Howler( gentity_t *self );
376 void SP_NPC_Monster_Claw( gentity_t *self );
377 void SP_NPC_Monster_Glider( gentity_t *self );
378 void SP_NPC_Monster_Flier2( gentity_t *self );
379 void SP_NPC_Monster_Lizard( gentity_t *self );
380 void SP_NPC_Monster_Fish( gentity_t *self );
381 void SP_NPC_Monster_Wampa( gentity_t *self );
382 void SP_NPC_Monster_Rancor( gentity_t *self );
383 void SP_NPC_MineMonster( gentity_t *self );
384 void SP_NPC_Droid_Interrogator( gentity_t *self );
385 void SP_NPC_Droid_Probe( gentity_t *self );
386 void SP_NPC_Droid_Mark1( gentity_t *self );
387 void SP_NPC_Droid_Mark2( gentity_t *self );
388 void SP_NPC_Droid_ATST( gentity_t *self );
389 void SP_NPC_Droid_Seeker( gentity_t *self );
390 void SP_NPC_Droid_Remote( gentity_t *self );
391 void SP_NPC_Droid_Sentry( gentity_t *self );
392 void SP_NPC_Droid_Gonk( gentity_t *self );
393 void SP_NPC_Droid_Mouse( gentity_t *self );
394 void SP_NPC_Droid_R2D2( gentity_t *self );
395 void SP_NPC_Droid_R5D2( gentity_t *self );
396 void SP_NPC_Droid_Protocol( gentity_t *self );
397 
398 void SP_NPC_Reborn_New( gentity_t *self);
399 void SP_NPC_Cultist( gentity_t *self );
400 void SP_NPC_Cultist_Saber( gentity_t *self );
401 void SP_NPC_Cultist_Saber_Powers( gentity_t *self );
402 void SP_NPC_Cultist_Destroyer( gentity_t *self );
403 void SP_NPC_Cultist_Commando( gentity_t *self );
404 
405 void SP_waypoint (gentity_t *ent);
406 void SP_waypoint_small (gentity_t *ent);
407 void SP_waypoint_navgoal (gentity_t *ent);
408 void SP_waypoint_navgoal_8 (gentity_t *ent);
409 void SP_waypoint_navgoal_4 (gentity_t *ent);
410 void SP_waypoint_navgoal_2 (gentity_t *ent);
411 void SP_waypoint_navgoal_1 (gentity_t *ent);
412 
413 void SP_CreateWind( gentity_t *ent );
414 void SP_CreateSpaceDust( gentity_t *ent );
415 void SP_CreateSnow( gentity_t *ent );
416 void SP_CreateRain( gentity_t *ent );
417 
418 void SP_point_combat( gentity_t *self );
419 
420 void SP_shooter_blaster( gentity_t *ent );
421 
422 void SP_team_CTF_redplayer( gentity_t *ent );
423 void SP_team_CTF_blueplayer( gentity_t *ent );
424 
425 void SP_team_CTF_redspawn( gentity_t *ent );
426 void SP_team_CTF_bluespawn( gentity_t *ent );
427 
428 void SP_misc_turret( gentity_t *ent );
429 void SP_misc_turretG2( gentity_t *base );
430 
SP_item_botroam(gentity_t * ent)431 void SP_item_botroam( gentity_t *ent ) { }
432 
SP_gametype_item(gentity_t * ent)433 void SP_gametype_item ( gentity_t* ent )
434 {
435 	gitem_t *item = NULL;
436 	char *value;
437 	int team = -1;
438 
439 	G_SpawnString("teamfilter", "", &value);
440 
441 	G_SetOrigin( ent, ent->s.origin );
442 
443 	// If a team filter is set then override any team settings for the spawns
444 	if ( level.mTeamFilter[0] )
445 	{
446 		if ( Q_stricmp ( level.mTeamFilter, "red") == 0 )
447 		{
448 			team = TEAM_RED;
449 		}
450 		else if ( Q_stricmp ( level.mTeamFilter, "blue") == 0 )
451 		{
452 			team = TEAM_BLUE;
453 		}
454 	}
455 
456 	if (ent->targetname && ent->targetname[0])
457 	{
458 		if (team != -1)
459 		{
460 			if (strstr(ent->targetname, "flag"))
461 			{
462 				if (team == TEAM_RED)
463 				{
464 					item = BG_FindItem("team_CTF_redflag");
465 				}
466 				else
467 				{ //blue
468 					item = BG_FindItem("team_CTF_blueflag");
469 				}
470 			}
471 		}
472 		else if (strstr(ent->targetname, "red_flag"))
473 		{
474 			item = BG_FindItem("team_CTF_redflag");
475 		}
476 		else if (strstr(ent->targetname, "blue_flag"))
477 		{
478 			item = BG_FindItem("team_CTF_blueflag");
479 		}
480 		else
481 		{
482 			item = NULL;
483 		}
484 
485 		if (item)
486 		{
487 			ent->targetname = NULL;
488 			ent->classname = item->classname;
489 			G_SpawnItem( ent, item );
490 		}
491 	}
492 }
493 
494 void SP_emplaced_gun( gentity_t *ent );
495 
496 spawn_t	spawns[] = {
497 	{ "emplaced_gun",						SP_emplaced_gun },
498 	{ "func_bobbing",						SP_func_bobbing },
499 	{ "func_breakable",						SP_func_breakable },
500 	{ "func_button",						SP_func_button },
501 	{ "func_door",							SP_func_door },
502 	{ "func_glass",							SP_func_glass },
503 	{ "func_group",							SP_info_null },
504 	{ "func_pendulum",						SP_func_pendulum },
505 	{ "func_plat",							SP_func_plat },
506 	{ "func_rotating",						SP_func_rotating },
507 	{ "func_static",						SP_func_static },
508 	{ "func_timer",							SP_func_timer }, // rename trigger_timer?
509 	{ "func_train",							SP_func_train },
510 	{ "func_usable",						SP_func_usable },
511 	{ "func_wall",							SP_func_wall },
512 	{ "fx_rain",							SP_CreateRain },
513 	{ "fx_runner",							SP_fx_runner },
514 	{ "fx_snow",							SP_CreateSnow },
515 	{ "fx_spacedust",						SP_CreateSpaceDust },
516 	{ "fx_wind",							SP_CreateWind },
517 	{ "gametype_item",						SP_gametype_item },
518 	{ "info_camp",							SP_info_camp },
519 	{ "info_jedimaster_start",				SP_info_jedimaster_start },
520 	{ "info_notnull",						SP_info_notnull }, // use target_position instead
521 	{ "info_null",							SP_info_null },
522 	{ "info_player_deathmatch",				SP_info_player_deathmatch },
523 	{ "info_player_duel",					SP_info_player_duel },
524 	{ "info_player_duel1",					SP_info_player_duel1 },
525 	{ "info_player_duel2",					SP_info_player_duel2 },
526 	{ "info_player_intermission",			SP_info_player_intermission },
527 	{ "info_player_intermission_blue",		SP_info_player_intermission_blue },
528 	{ "info_player_intermission_red",		SP_info_player_intermission_red },
529 	{ "info_player_siegeteam1",				SP_info_player_siegeteam1 },
530 	{ "info_player_siegeteam2",				SP_info_player_siegeteam2 },
531 	{ "info_player_start",					SP_info_player_start },
532 	{ "info_player_start_blue",				SP_info_player_start_blue },
533 	{ "info_player_start_red",				SP_info_player_start_red },
534 	{ "info_siege_decomplete",				SP_info_siege_decomplete },
535 	{ "info_siege_objective",				SP_info_siege_objective },
536 	{ "info_siege_radaricon",				SP_info_siege_radaricon },
537 	{ "item_botroam",						SP_item_botroam },
538 	{ "light",								SP_light },
539 	{ "misc_ammo_floor_unit",				SP_misc_ammo_floor_unit },
540 	{ "misc_bsp",							SP_misc_bsp },
541 	{ "misc_cubemap",						SP_misc_cubemap },
542 	{ "misc_faller",						SP_misc_faller },
543 	{ "misc_G2model",						SP_misc_G2model },
544 	{ "misc_holocron",						SP_misc_holocron },
545 	{ "misc_maglock",						SP_misc_maglock },
546 	{ "misc_model",							SP_misc_model },
547 	{ "misc_model_ammo_power_converter",	SP_misc_model_ammo_power_converter },
548 	{ "misc_model_breakable",				SP_misc_model_breakable },
549 	{ "misc_model_health_power_converter",	SP_misc_model_health_power_converter },
550 	{ "misc_model_shield_power_converter",	SP_misc_model_shield_power_converter },
551 	{ "misc_model_static",					SP_misc_model_static },
552 	{ "misc_portal_camera",					SP_misc_portal_camera },
553 	{ "misc_portal_surface",				SP_misc_portal_surface },
554 	{ "misc_shield_floor_unit",				SP_misc_shield_floor_unit },
555 	{ "misc_siege_item",					SP_misc_siege_item },
556 	{ "misc_skyportal",						SP_misc_skyportal },
557 	{ "misc_skyportal_orient",				SP_misc_skyportal_orient },
558 	{ "misc_teleporter_dest",				SP_misc_teleporter_dest },
559 	{ "misc_turret",						SP_misc_turret },
560 	{ "misc_turretG2",						SP_misc_turretG2 },
561 	{ "misc_weapon_shooter",				SP_misc_weapon_shooter },
562 	{ "misc_weather_zone",					SP_misc_weather_zone },
563 	{ "npc_alora",							SP_NPC_Alora },
564 	{ "npc_bartender",						SP_NPC_Bartender },
565 	{ "npc_bespincop",						SP_NPC_BespinCop },
566 	{ "npc_colombian_emplacedgunner",		SP_NPC_ShadowTrooper },
567 	{ "npc_colombian_rebel",				SP_NPC_Reborn },
568 	{ "npc_colombian_soldier",				SP_NPC_Reborn },
569 	{ "npc_cultist",						SP_NPC_Cultist },
570 	{ "npc_cultist_commando",				SP_NPC_Cultist_Commando },
571 	{ "npc_cultist_destroyer",				SP_NPC_Cultist_Destroyer },
572 	{ "npc_cultist_saber",					SP_NPC_Cultist_Saber },
573 	{ "npc_cultist_saber_powers",			SP_NPC_Cultist_Saber_Powers },
574 	{ "npc_desann",							SP_NPC_Desann },
575 	{ "npc_droid_atst",						SP_NPC_Droid_ATST },
576 	{ "npc_droid_gonk",						SP_NPC_Droid_Gonk },
577 	{ "npc_droid_interrogator",				SP_NPC_Droid_Interrogator },
578 	{ "npc_droid_mark1",					SP_NPC_Droid_Mark1 },
579 	{ "npc_droid_mark2",					SP_NPC_Droid_Mark2 },
580 	{ "npc_droid_mouse",					SP_NPC_Droid_Mouse },
581 	{ "npc_droid_probe",					SP_NPC_Droid_Probe },
582 	{ "npc_droid_protocol",					SP_NPC_Droid_Protocol },
583 	{ "npc_droid_r2d2",						SP_NPC_Droid_R2D2 },
584 	{ "npc_droid_r5d2",						SP_NPC_Droid_R5D2 },
585 	{ "npc_droid_remote",					SP_NPC_Droid_Remote },
586 	{ "npc_droid_seeker",					SP_NPC_Droid_Seeker },
587 	{ "npc_droid_sentry",					SP_NPC_Droid_Sentry },
588 	{ "npc_galak",							SP_NPC_Galak },
589 	{ "npc_gran",							SP_NPC_Gran },
590 	{ "npc_human_merc",						SP_NPC_Human_Merc },
591 	{ "npc_imperial",						SP_NPC_Imperial },
592 	{ "npc_impworker",						SP_NPC_ImpWorker },
593 	{ "npc_jan",							SP_NPC_Jan },
594 	{ "npc_jawa",							SP_NPC_Jawa },
595 	{ "npc_jedi",							SP_NPC_Jedi },
596 	{ "npc_kyle",							SP_NPC_Kyle },
597 	{ "npc_lando",							SP_NPC_Lando },
598 	{ "npc_luke",							SP_NPC_Luke },
599 	{ "npc_manuel_vergara_rmg",				SP_NPC_Desann },
600 	{ "npc_minemonster",					SP_NPC_MineMonster },
601 	{ "npc_monmothma",						SP_NPC_MonMothma },
602 	{ "npc_monster_claw",					SP_NPC_Monster_Claw },
603 	{ "npc_monster_fish",					SP_NPC_Monster_Fish },
604 	{ "npc_monster_flier2",					SP_NPC_Monster_Flier2 },
605 	{ "npc_monster_glider",					SP_NPC_Monster_Glider },
606 	{ "npc_monster_howler",					SP_NPC_Monster_Howler },
607 	{ "npc_monster_lizard",					SP_NPC_Monster_Lizard },
608 	{ "npc_monster_murjj",					SP_NPC_Monster_Murjj },
609 	{ "npc_monster_rancor",					SP_NPC_Monster_Rancor },
610 	{ "npc_monster_swamp",					SP_NPC_Monster_Swamp },
611 	{ "npc_monster_wampa",					SP_NPC_Monster_Wampa },
612 	{ "npc_morgankatarn",					SP_NPC_MorganKatarn },
613 	{ "npc_noghri",							SP_NPC_Noghri },
614 	{ "npc_prisoner",						SP_NPC_Prisoner },
615 	{ "npc_rebel",							SP_NPC_Rebel },
616 	{ "npc_reborn",							SP_NPC_Reborn },
617 	{ "npc_reborn_new",						SP_NPC_Reborn_New },
618 	{ "npc_reelo",							SP_NPC_Reelo },
619 	{ "npc_rodian",							SP_NPC_Rodian },
620 	{ "npc_shadowtrooper",					SP_NPC_ShadowTrooper },
621 	{ "npc_snowtrooper",					SP_NPC_Snowtrooper },
622 	{ "npc_spawner",						SP_NPC_spawner },
623 	{ "npc_stormtrooper",					SP_NPC_Stormtrooper },
624 	{ "npc_stormtrooperofficer",			SP_NPC_StormtrooperOfficer },
625 	{ "npc_swamptrooper",					SP_NPC_SwampTrooper },
626 	{ "npc_tavion",							SP_NPC_Tavion },
627 	{ "npc_tavion_new",						SP_NPC_Tavion_New },
628 	{ "npc_tie_pilot",						SP_NPC_Tie_Pilot },
629 	{ "npc_trandoshan",						SP_NPC_Trandoshan },
630 	{ "npc_tusken",							SP_NPC_Tusken },
631 	{ "npc_ugnaught",						SP_NPC_Ugnaught },
632 	{ "npc_vehicle",						SP_NPC_Vehicle },
633 	{ "npc_weequay",						SP_NPC_Weequay },
634 	{ "path_corner",						SP_path_corner },
635 	{ "point_combat",						SP_point_combat },
636 	{ "ref_tag",							SP_reference_tag },
637 	{ "ref_tag_huge",						SP_reference_tag },
638 	{ "shooter_blaster",					SP_shooter_blaster },
639 	{ "target_activate",					SP_target_activate },
640 	{ "target_counter",						SP_target_counter },
641 	{ "target_deactivate",					SP_target_deactivate },
642 	{ "target_delay",						SP_target_delay },
643 	{ "target_escapetrig",					SP_target_escapetrig },
644 	{ "target_give",						SP_target_give },
645 	{ "target_interest",					SP_target_interest },
646 	{ "target_kill",						SP_target_kill },
647 	{ "target_laser",						SP_target_laser },
648 	{ "target_level_change",				SP_target_level_change },
649 	{ "target_location",					SP_target_location },
650 	{ "target_play_music",					SP_target_play_music },
651 	{ "target_position",					SP_target_position },
652 	{ "target_print",						SP_target_print },
653 	{ "target_push",						SP_target_push },
654 	{ "target_random",						SP_target_random },
655 	{ "target_relay",						SP_target_relay },
656 	{ "target_remove_powerups",				SP_target_remove_powerups },
657 	{ "target_score",						SP_target_score },
658 	{ "target_screenshake",					SP_target_screenshake },
659 	{ "target_scriptrunner",				SP_target_scriptrunner },
660 	{ "target_siege_end",					SP_target_siege_end },
661 	{ "target_speaker",						SP_target_speaker },
662 	{ "target_teleporter",					SP_target_teleporter },
663 	{ "team_CTF_blueplayer",				SP_team_CTF_blueplayer },
664 	{ "team_CTF_bluespawn",					SP_team_CTF_bluespawn },
665 	{ "team_CTF_redplayer",					SP_team_CTF_redplayer },
666 	{ "team_CTF_redspawn",					SP_team_CTF_redspawn },
667 	{ "terrain",							SP_terrain },
668 	{ "trigger_always",						SP_trigger_always },
669 	{ "trigger_asteroid_field",				SP_trigger_asteroid_field },
670 	{ "trigger_hurt",						SP_trigger_hurt },
671 	{ "trigger_hyperspace",					SP_trigger_hyperspace },
672 	{ "trigger_lightningstrike",			SP_trigger_lightningstrike },
673 	{ "trigger_multiple",					SP_trigger_multiple },
674 	{ "trigger_once",						SP_trigger_once },
675 	{ "trigger_push",						SP_trigger_push },
676 	{ "trigger_shipboundary",				SP_trigger_shipboundary },
677 	{ "trigger_space",						SP_trigger_space },
678 	{ "trigger_teleport",					SP_trigger_teleport },
679 	{ "waypoint",							SP_waypoint },
680 	{ "waypoint_navgoal",					SP_waypoint_navgoal },
681 	{ "waypoint_navgoal_1",					SP_waypoint_navgoal_1 },
682 	{ "waypoint_navgoal_2",					SP_waypoint_navgoal_2 },
683 	{ "waypoint_navgoal_4",					SP_waypoint_navgoal_4 },
684 	{ "waypoint_navgoal_8",					SP_waypoint_navgoal_8 },
685 	{ "waypoint_small",						SP_waypoint_small },
686 };
687 
688 /*
689 ===============
690 G_CallSpawn
691 
692 Finds the spawn function for the entity and calls it,
693 returning qfalse if not found
694 ===============
695 */
spawncmp(const void * a,const void * b)696 static int spawncmp( const void *a, const void *b ) {
697 	return Q_stricmp( (const char *)a, ((spawn_t*)b)->name );
698 }
699 
G_CallSpawn(gentity_t * ent)700 qboolean G_CallSpawn( gentity_t *ent ) {
701 	spawn_t	*s;
702 	gitem_t	*item;
703 
704 	if ( !ent->classname ) {
705 		trap->Print( "G_CallSpawn: NULL classname\n" );
706 		return qfalse;
707 	}
708 
709 	// check item spawn functions
710 	//TODO: cant reorder items because compat so....?
711 	for ( item=bg_itemlist+1 ; item->classname ; item++ ) {
712 		if ( !strcmp(item->classname, ent->classname) ) {
713 			G_SpawnItem( ent, item );
714 			return qtrue;
715 		}
716 	}
717 
718 	// check normal spawn functions
719 	s = (spawn_t *)Q_LinearSearch( ent->classname, spawns, ARRAY_LEN( spawns ), sizeof( spawn_t ), spawncmp );
720 	if ( s )
721 	{// found it
722 		if ( VALIDSTRING( ent->healingsound ) )
723 			G_SoundIndex( ent->healingsound );
724 
725 		s->spawn( ent );
726 		return qtrue;
727 	}
728 
729 	trap->Print( "%s doesn't have a spawn function\n", ent->classname );
730 	return qfalse;
731 }
732 
733 /*
734 =============
735 G_NewString
736 
737 Builds a copy of the string, translating \n to real linefeeds
738 so message texts can be multi-line
739 =============
740 */
G_NewString(const char * string)741 char *G_NewString( const char *string )
742 {
743 	char *newb=NULL, *new_p=NULL;
744 	int i=0, len=0;
745 
746 	len = strlen( string )+1;
747 	new_p = newb = (char *)G_Alloc( len );
748 
749 	for ( i=0; i<len; i++ )
750 	{// turn \n into a real linefeed
751 		if ( string[i] == '\\' && i < len-1 )
752 		{
753 			if ( string[i+1] == 'n' )
754 			{
755 				*new_p++ = '\n';
756 				i++;
757 			}
758 			else
759 				*new_p++ = '\\';
760 		}
761 		else
762 			*new_p++ = string[i];
763 	}
764 
765 	return newb;
766 }
767 
G_NewString_Safe(const char * string)768 char *G_NewString_Safe( const char *string )
769 {
770 	char *newb=NULL, *new_p=NULL;
771 	int i=0, len=0;
772 
773 	len = strlen( string )+1;
774 	new_p = newb = (char *)malloc( len );
775 
776 	if ( !new_p )
777 		return NULL;
778 
779 	for ( i=0; i<len; i++ )
780 	{// turn \n into a real linefeed
781 		if ( string[i] == '\\' && i < len-1 )
782 		{
783 			if ( string[i+1] == 'n' )
784 			{
785 				*new_p++ = '\n';
786 				i++;
787 			}
788 			else
789 				*new_p++ = '\\';
790 		}
791 		else
792 			*new_p++ = string[i];
793 	}
794 
795 	return newb;
796 }
797 
798 /*
799 ===============
800 G_ParseField
801 
802 Takes a key/value pair and sets the binary values
803 in a gentity
804 ===============
805 */
806 
fieldcmp(const void * a,const void * b)807 static int fieldcmp( const void *a, const void *b ) {
808 	return Q_stricmp( (const char *)a, ((field_t*)b)->name );
809 }
810 
811 void Q3_SetParm ( int entID, int parmNum, const char *parmValue );
G_ParseField(const char * key,const char * value,gentity_t * ent)812 void G_ParseField( const char *key, const char *value, gentity_t *ent )
813 {
814 	field_t	*f;
815 	byte	*b;
816 	float	v;
817 	vec3_t	vec;
818 
819 	f = (field_t *)Q_LinearSearch( key, fields, ARRAY_LEN( fields ), sizeof( field_t ), fieldcmp );
820 	if ( f )
821 	{// found it
822 		b = (byte *)ent;
823 
824 		switch( f->type ) {
825 		case F_STRING:
826 			*(char **)(b+f->ofs) = G_NewString (value);
827 			break;
828 		case F_VECTOR:
829 			if ( sscanf( value, "%f %f %f", &vec[0], &vec[1], &vec[2] ) == 3 ) {
830 				((float *)(b+f->ofs))[0] = vec[0];
831 				((float *)(b+f->ofs))[1] = vec[1];
832 				((float *)(b+f->ofs))[2] = vec[2];
833 			}
834 			else {
835 				trap->Print( "G_ParseField: Failed sscanf on F_VECTOR (key/value: %s/%s)\n", key, value );
836 				((float *)(b+f->ofs))[0] = ((float *)(b+f->ofs))[1] = ((float *)(b+f->ofs))[2] = 0.0f;
837 			}
838 			break;
839 		case F_INT:
840 			*(int *)(b+f->ofs) = atoi(value);
841 			break;
842 		case F_FLOAT:
843 			*(float *)(b+f->ofs) = atof(value);
844 			break;
845 		case F_ANGLEHACK:
846 			v = atof(value);
847 			((float *)(b+f->ofs))[0] = 0;
848 			((float *)(b+f->ofs))[1] = v;
849 			((float *)(b+f->ofs))[2] = 0;
850 			break;
851 		case F_PARM1:
852 		case F_PARM2:
853 		case F_PARM3:
854 		case F_PARM4:
855 		case F_PARM5:
856 		case F_PARM6:
857 		case F_PARM7:
858 		case F_PARM8:
859 		case F_PARM9:
860 		case F_PARM10:
861 		case F_PARM11:
862 		case F_PARM12:
863 		case F_PARM13:
864 		case F_PARM14:
865 		case F_PARM15:
866 		case F_PARM16:
867 			Q3_SetParm( ent->s.number, (f->type - F_PARM1), (char *) value );
868 			break;
869 		}
870 		return;
871 	}
872 }
873 
874 #define ADJUST_AREAPORTAL() \
875 	if(ent->s.eType == ET_MOVER) \
876 	{ \
877 		trap->LinkEntity((sharedEntity_t *)ent); \
878 		trap->AdjustAreaPortalState((sharedEntity_t *)ent, qtrue); \
879 	}
880 
881 /*
882 ===================
883 G_SpawnGEntityFromSpawnVars
884 
885 Spawn an entity and fill in all of the level fields from
886 level.spawnVars[], then call the class specfic spawn function
887 ===================
888 */
G_SpawnGEntityFromSpawnVars(qboolean inSubBSP)889 void G_SpawnGEntityFromSpawnVars( qboolean inSubBSP ) {
890 	int			i;
891 	gentity_t	*ent;
892 	char		*s, *value, *gametypeName;
893 	static char *gametypeNames[GT_MAX_GAME_TYPE] = {"ffa", "holocron", "jedimaster", "duel", "powerduel", "single", "team", "siege", "ctf", "cty"};
894 
895 	// get the next free entity
896 	ent = G_Spawn();
897 
898 	for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
899 		G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );
900 	}
901 
902 	// check for "notsingle" flag
903 	if ( level.gametype == GT_SINGLE_PLAYER ) {
904 		G_SpawnInt( "notsingle", "0", &i );
905 		if ( i ) {
906 			ADJUST_AREAPORTAL();
907 			G_FreeEntity( ent );
908 			return;
909 		}
910 	}
911 	// check for "notteam" flag (GT_FFA, GT_DUEL, GT_SINGLE_PLAYER)
912 	if ( level.gametype >= GT_TEAM ) {
913 		G_SpawnInt( "notteam", "0", &i );
914 		if ( i ) {
915 			ADJUST_AREAPORTAL();
916 			G_FreeEntity( ent );
917 			return;
918 		}
919 	} else {
920 		G_SpawnInt( "notfree", "0", &i );
921 		if ( i ) {
922 			ADJUST_AREAPORTAL();
923 			G_FreeEntity( ent );
924 			return;
925 		}
926 	}
927 
928 	if( G_SpawnString( "gametype", NULL, &value ) ) {
929 		if( level.gametype >= GT_FFA && level.gametype < GT_MAX_GAME_TYPE ) {
930 			gametypeName = gametypeNames[level.gametype];
931 
932 			s = strstr( value, gametypeName );
933 			if( !s ) {
934 				ADJUST_AREAPORTAL();
935 				G_FreeEntity( ent );
936 				return;
937 			}
938 		}
939 	}
940 
941 	// move editor origin to pos
942 	VectorCopy( ent->s.origin, ent->s.pos.trBase );
943 	VectorCopy( ent->s.origin, ent->r.currentOrigin );
944 
945 	// if we didn't get a classname, don't bother spawning anything
946 	if ( !G_CallSpawn( ent ) ) {
947 		G_FreeEntity( ent );
948 	}
949 
950 	//Tag on the ICARUS scripting information only to valid recipients
951 	if ( trap->ICARUS_ValidEnt( (sharedEntity_t *)ent ) )
952 	{
953 		trap->ICARUS_InitEnt( (sharedEntity_t *)ent );
954 
955 		if ( ent->classname && ent->classname[0] )
956 		{
957 			if ( Q_strncmp( "NPC_", ent->classname, 4 ) != 0 )
958 			{//Not an NPC_spawner (rww - probably don't even care for MP, but whatever)
959 				G_ActivateBehavior( ent, BSET_SPAWN );
960 			}
961 		}
962 	}
963 }
964 
965 /*
966 ====================
967 G_AddSpawnVarToken
968 ====================
969 */
G_AddSpawnVarToken(const char * string)970 char *G_AddSpawnVarToken( const char *string ) {
971 	int		l;
972 	char	*dest;
973 
974 	l = strlen( string );
975 	if ( level.numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) {
976 		trap->Error( ERR_DROP, "G_AddSpawnVarToken: MAX_SPAWN_VARS_CHARS" );
977 	}
978 
979 	dest = level.spawnVarChars + level.numSpawnVarChars;
980 	memcpy( dest, string, l+1 );
981 
982 	level.numSpawnVarChars += l + 1;
983 
984 	return dest;
985 }
986 
AddSpawnField(char * field,char * value)987 void AddSpawnField(char *field, char *value)
988 {
989 	int	i;
990 
991 	for(i=0;i<level.numSpawnVars;i++)
992 	{
993 		if (Q_stricmp(level.spawnVars[i][0], field) == 0)
994 		{
995 			level.spawnVars[ i ][1] = G_AddSpawnVarToken( value );
996 			return;
997 		}
998 	}
999 
1000 	level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( field );
1001 	level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( value );
1002 	level.numSpawnVars++;
1003 }
1004 
1005 #define NOVALUE "novalue"
1006 
HandleEntityAdjustment(void)1007 static void HandleEntityAdjustment(void)
1008 {
1009 	char		*value;
1010 	vec3_t		origin, newOrigin, angles;
1011 	char		temp[MAX_QPATH];
1012 	float		rotation;
1013 
1014 	G_SpawnString("origin", NOVALUE, &value);
1015 	if (Q_stricmp(value, NOVALUE) != 0)
1016 	{
1017 		if ( sscanf( value, "%f %f %f", &origin[0], &origin[1], &origin[2] ) != 3 ) {
1018 			trap->Print( "HandleEntityAdjustment: failed sscanf on 'origin' (%s)\n", value );
1019 			VectorClear( origin );
1020 		}
1021 	}
1022 	else
1023 	{
1024 		origin[0] = origin[1] = origin[2] = 0.0;
1025 	}
1026 
1027 	rotation = DEG2RAD(level.mRotationAdjust);
1028 	newOrigin[0] = origin[0]*cos(rotation) - origin[1]*sin(rotation);
1029 	newOrigin[1] = origin[0]*sin(rotation) + origin[1]*cos(rotation);
1030 	newOrigin[2] = origin[2];
1031 	VectorAdd(newOrigin, level.mOriginAdjust, newOrigin);
1032 	// damn VMs don't handle outputing a float that is compatible with sscanf in all cases
1033 	Com_sprintf(temp, sizeof( temp ), "%0.0f %0.0f %0.0f", newOrigin[0], newOrigin[1], newOrigin[2]);
1034 	AddSpawnField("origin", temp);
1035 
1036 	G_SpawnString("angles", NOVALUE, &value);
1037 	if (Q_stricmp(value, NOVALUE) != 0)
1038 	{
1039 		if ( sscanf( value, "%f %f %f", &angles[0], &angles[1], &angles[2] ) != 3 ) {
1040 			trap->Print( "HandleEntityAdjustment: failed sscanf on 'angles' (%s)\n", value );
1041 			VectorClear( angles );
1042 		}
1043 
1044 		angles[YAW] = fmod(angles[YAW] + level.mRotationAdjust, 360.0f);
1045 		// damn VMs don't handle outputing a float that is compatible with sscanf in all cases
1046 		Com_sprintf(temp, sizeof( temp ), "%0.0f %0.0f %0.0f", angles[0], angles[1], angles[2]);
1047 		AddSpawnField("angles", temp);
1048 	}
1049 	else
1050 	{
1051 		G_SpawnString("angle", NOVALUE, &value);
1052 		if (Q_stricmp(value, NOVALUE) != 0)
1053 		{
1054 			angles[YAW] = atof( value );
1055 		}
1056 		else
1057 		{
1058 			angles[YAW] = 0.0;
1059 		}
1060 		angles[YAW] = fmod(angles[YAW] + level.mRotationAdjust, 360.0f);
1061 		Com_sprintf(temp, sizeof( temp ), "%0.0f", angles[YAW]);
1062 		AddSpawnField("angle", temp);
1063 	}
1064 
1065 	// RJR experimental code for handling "direction" field of breakable brushes
1066 	// though direction is rarely ever used.
1067 	G_SpawnString("direction", NOVALUE, &value);
1068 	if (Q_stricmp(value, NOVALUE) != 0)
1069 	{
1070 		if ( sscanf( value, "%f %f %f", &angles[0], &angles[1], &angles[2] ) != 3 ) {
1071 			trap->Print( "HandleEntityAdjustment: failed sscanf on 'direction' (%s)\n", value );
1072 			VectorClear( angles );
1073 		}
1074 	}
1075 	else
1076 	{
1077 		angles[0] = angles[1] = angles[2] = 0.0;
1078 	}
1079 	angles[YAW] = fmod(angles[YAW] + level.mRotationAdjust, 360.0f);
1080 	Com_sprintf(temp, sizeof( temp ), "%0.0f %0.0f %0.0f", angles[0], angles[1], angles[2]);
1081 	AddSpawnField("direction", temp);
1082 
1083 
1084 	AddSpawnField("BSPInstanceID", level.mTargetAdjust);
1085 
1086 	G_SpawnString("targetname", NOVALUE, &value);
1087 	if (Q_stricmp(value, NOVALUE) != 0)
1088 	{
1089 		Com_sprintf(temp, sizeof( temp ), "%s%s", level.mTargetAdjust, value);
1090 		AddSpawnField("targetname", temp);
1091 	}
1092 
1093 	G_SpawnString("target", NOVALUE, &value);
1094 	if (Q_stricmp(value, NOVALUE) != 0)
1095 	{
1096 		Com_sprintf(temp, sizeof( temp ), "%s%s", level.mTargetAdjust, value);
1097 		AddSpawnField("target", temp);
1098 	}
1099 
1100 	G_SpawnString("killtarget", NOVALUE, &value);
1101 	if (Q_stricmp(value, NOVALUE) != 0)
1102 	{
1103 		Com_sprintf(temp, sizeof( temp ), "%s%s", level.mTargetAdjust, value);
1104 		AddSpawnField("killtarget", temp);
1105 	}
1106 
1107 	G_SpawnString("brushparent", NOVALUE, &value);
1108 	if (Q_stricmp(value, NOVALUE) != 0)
1109 	{
1110 		Com_sprintf(temp, sizeof( temp ), "%s%s", level.mTargetAdjust, value);
1111 		AddSpawnField("brushparent", temp);
1112 	}
1113 
1114 	G_SpawnString("brushchild", NOVALUE, &value);
1115 	if (Q_stricmp(value, NOVALUE) != 0)
1116 	{
1117 		Com_sprintf(temp, sizeof( temp ), "%s%s", level.mTargetAdjust, value);
1118 		AddSpawnField("brushchild", temp);
1119 	}
1120 
1121 	G_SpawnString("enemy", NOVALUE, &value);
1122 	if (Q_stricmp(value, NOVALUE) != 0)
1123 	{
1124 		Com_sprintf(temp, sizeof( temp ), "%s%s", level.mTargetAdjust, value);
1125 		AddSpawnField("enemy", temp);
1126 	}
1127 
1128 	G_SpawnString("ICARUSname", NOVALUE, &value);
1129 	if (Q_stricmp(value, NOVALUE) != 0)
1130 	{
1131 		Com_sprintf(temp, sizeof( temp ), "%s%s", level.mTargetAdjust, value);
1132 		AddSpawnField("ICARUSname", temp);
1133 	}
1134 }
1135 
1136 /*
1137 ====================
1138 G_ParseSpawnVars
1139 
1140 Parses a brace bounded set of key / value pairs out of the
1141 level's entity strings into level.spawnVars[]
1142 
1143 This does not actually spawn an entity.
1144 ====================
1145 */
G_ParseSpawnVars(qboolean inSubBSP)1146 qboolean G_ParseSpawnVars( qboolean inSubBSP ) {
1147 	char		keyname[MAX_TOKEN_CHARS];
1148 	char		com_token[MAX_TOKEN_CHARS];
1149 
1150 	level.numSpawnVars = 0;
1151 	level.numSpawnVarChars = 0;
1152 
1153 	// parse the opening brace
1154 	if ( !trap->GetEntityToken( com_token, sizeof( com_token ) ) ) {
1155 		// end of spawn string
1156 		return qfalse;
1157 	}
1158 	if ( com_token[0] != '{' ) {
1159 		trap->Error( ERR_DROP, "G_ParseSpawnVars: found %s when expecting {",com_token );
1160 	}
1161 
1162 	// go through all the key / value pairs
1163 	while ( 1 ) {
1164 		// parse key
1165 		if ( !trap->GetEntityToken( keyname, sizeof( keyname ) ) ) {
1166 			trap->Error( ERR_DROP, "G_ParseSpawnVars: EOF without closing brace" );
1167 		}
1168 
1169 		if ( keyname[0] == '}' ) {
1170 			break;
1171 		}
1172 
1173 		// parse value
1174 		if ( !trap->GetEntityToken( com_token, sizeof( com_token ) ) ) {
1175 			trap->Error( ERR_DROP, "G_ParseSpawnVars: EOF without closing brace" );
1176 		}
1177 
1178 		if ( com_token[0] == '}' ) {
1179 			trap->Error( ERR_DROP, "G_ParseSpawnVars: closing brace without data" );
1180 		}
1181 		if ( level.numSpawnVars == MAX_SPAWN_VARS ) {
1182 			trap->Error( ERR_DROP, "G_ParseSpawnVars: MAX_SPAWN_VARS" );
1183 		}
1184 		level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( keyname );
1185 		level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( com_token );
1186 		level.numSpawnVars++;
1187 	}
1188 
1189 	if (inSubBSP)
1190 	{
1191 		HandleEntityAdjustment();
1192 	}
1193 
1194 	return qtrue;
1195 }
1196 
1197 
1198 static	char *defaultStyles[32][3] =
1199 {
1200 	{	// 0 normal
1201 		"z",
1202 		"z",
1203 		"z"
1204 	},
1205 	{	// 1 FLICKER (first variety)
1206 		"mmnmmommommnonmmonqnmmo",
1207 		"mmnmmommommnonmmonqnmmo",
1208 		"mmnmmommommnonmmonqnmmo"
1209 	},
1210 	{	// 2 SLOW STRONG PULSE
1211 		"abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcb",
1212 		"abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcb",
1213 		"abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcb"
1214 	},
1215 	{	// 3 CANDLE (first variety)
1216 		"mmmmmaaaaammmmmaaaaaabcdefgabcdefg",
1217 		"mmmmmaaaaammmmmaaaaaabcdefgabcdefg",
1218 		"mmmmmaaaaammmmmaaaaaabcdefgabcdefg"
1219 	},
1220 	{	// 4 FAST STROBE
1221 		"mamamamamama",
1222 		"mamamamamama",
1223 		"mamamamamama"
1224 	},
1225 	{	// 5 GENTLE PULSE 1
1226 		"jklmnopqrstuvwxyzyxwvutsrqponmlkj",
1227 		"jklmnopqrstuvwxyzyxwvutsrqponmlkj",
1228 		"jklmnopqrstuvwxyzyxwvutsrqponmlkj"
1229 	},
1230 	{	// 6 FLICKER (second variety)
1231 		"nmonqnmomnmomomno",
1232 		"nmonqnmomnmomomno",
1233 		"nmonqnmomnmomomno"
1234 	},
1235 	{	// 7 CANDLE (second variety)
1236 		"mmmaaaabcdefgmmmmaaaammmaamm",
1237 		"mmmaaaabcdefgmmmmaaaammmaamm",
1238 		"mmmaaaabcdefgmmmmaaaammmaamm"
1239 	},
1240 	{	// 8 CANDLE (third variety)
1241 		"mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa",
1242 		"mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa",
1243 		"mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"
1244 	},
1245 	{	// 9 SLOW STROBE (fourth variety)
1246 		"aaaaaaaazzzzzzzz",
1247 		"aaaaaaaazzzzzzzz",
1248 		"aaaaaaaazzzzzzzz"
1249 	},
1250 	{	// 10 FLUORESCENT FLICKER
1251 		"mmamammmmammamamaaamammma",
1252 		"mmamammmmammamamaaamammma",
1253 		"mmamammmmammamamaaamammma"
1254 	},
1255 	{	// 11 SLOW PULSE NOT FADE TO BLACK
1256 		"abcdefghijklmnopqrrqponmlkjihgfedcba",
1257 		"abcdefghijklmnopqrrqponmlkjihgfedcba",
1258 		"abcdefghijklmnopqrrqponmlkjihgfedcba"
1259 	},
1260 	{	// 12 FAST PULSE FOR JEREMY
1261 		"mkigegik",
1262 		"mkigegik",
1263 		"mkigegik"
1264 	},
1265 	{	// 13 Test Blending
1266 		"abcdefghijklmqrstuvwxyz",
1267 		"zyxwvutsrqmlkjihgfedcba",
1268 		"aammbbzzccllcckkffyyggp"
1269 	},
1270 	{	// 14
1271 		"",
1272 		"",
1273 		""
1274 	},
1275 	{	// 15
1276 		"",
1277 		"",
1278 		""
1279 	},
1280 	{	// 16
1281 		"",
1282 		"",
1283 		""
1284 	},
1285 	{	// 17
1286 		"",
1287 		"",
1288 		""
1289 	},
1290 	{	// 18
1291 		"",
1292 		"",
1293 		""
1294 	},
1295 	{	// 19
1296 		"",
1297 		"",
1298 		""
1299 	},
1300 	{	// 20
1301 		"",
1302 		"",
1303 		""
1304 	},
1305 	{	// 21
1306 		"",
1307 		"",
1308 		""
1309 	},
1310 	{	// 22
1311 		"",
1312 		"",
1313 		""
1314 	},
1315 	{	// 23
1316 		"",
1317 		"",
1318 		""
1319 	},
1320 	{	// 24
1321 		"",
1322 		"",
1323 		""
1324 	},
1325 	{	// 25
1326 		"",
1327 		"",
1328 		""
1329 	},
1330 	{	// 26
1331 		"",
1332 		"",
1333 		""
1334 	},
1335 	{	// 27
1336 		"",
1337 		"",
1338 		""
1339 	},
1340 	{	// 28
1341 		"",
1342 		"",
1343 		""
1344 	},
1345 	{	// 29
1346 		"",
1347 		"",
1348 		""
1349 	},
1350 	{	// 30
1351 		"",
1352 		"",
1353 		""
1354 	},
1355 	{	// 31
1356 		"",
1357 		"",
1358 		""
1359 	}
1360 };
1361 
1362 void *precachedKyle = 0;
1363 void scriptrunner_run (gentity_t *self);
1364 
1365 /*QUAKED worldspawn (0 0 0) ?
1366 
1367 Every map should have exactly one worldspawn.
1368 "music"		music wav file
1369 "gravity"	800 is default gravity
1370 "message"	Text to print during connection process
1371 
1372 BSP Options
1373 "gridsize"     size of lighting grid to "X Y Z". default="64 64 128"
1374 "ambient"      scale of global light (from _color)
1375 "fog"          shader name of the global fog texture - must include the full path, such as "textures/rj/fog1"
1376 "distancecull" value for vis for the maximum viewing distance
1377 "chopsize"     value for bsp on the maximum polygon / portal size
1378 "ls_Xr"	override lightstyle X with this pattern for Red.
1379 "ls_Xg"	green (valid patterns are "a-z")
1380 "ls_Xb"	blue (a is OFF, z is ON)
1381 
1382 "fogstart"		override fog start distance and force linear
1383 "radarrange" for Siege/Vehicle radar - default range is 2500
1384 */
1385 extern void EWebPrecache(void); //g_items.c
1386 float g_cullDistance;
SP_worldspawn(void)1387 void SP_worldspawn( void )
1388 {
1389 	char		*text, temp[32];
1390 	int			i;
1391 	int			lengthRed, lengthBlue, lengthGreen;
1392 
1393 	//I want to "cull" entities out of net sends to clients to reduce
1394 	//net traffic on our larger open maps -rww
1395 	G_SpawnFloat("distanceCull", "6000.0", &g_cullDistance);
1396 	trap->SetServerCull(g_cullDistance);
1397 
1398 	G_SpawnString( "classname", "", &text );
1399 	if ( Q_stricmp( text, "worldspawn" ) ) {
1400 		trap->Error( ERR_DROP, "SP_worldspawn: The first entity isn't 'worldspawn'" );
1401 	}
1402 
1403 	for ( i = 0 ; i < level.numSpawnVars ; i++ )
1404 	{
1405 		if ( Q_stricmp( "spawnscript", level.spawnVars[i][0] ) == 0 )
1406 		{//ONly let them set spawnscript, we don't want them setting an angle or something on the world.
1407 			G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], &g_entities[ENTITYNUM_WORLD] );
1408 		}
1409 	}
1410 	//The server will precache the standard model and animations, so that there is no hit
1411 	//when the first client connnects.
1412 	if (!BGPAFtextLoaded)
1413 	{
1414 		BG_ParseAnimationFile("models/players/_humanoid/animation.cfg", bgHumanoidAnimations, qtrue);
1415 	}
1416 
1417 	if (!precachedKyle)
1418 	{
1419 		int defSkin;
1420 
1421 		trap->G2API_InitGhoul2Model(&precachedKyle, "models/players/" DEFAULT_MODEL "/model.glm", 0, 0, -20, 0, 0);
1422 
1423 		if (precachedKyle)
1424 		{
1425 			defSkin = trap->R_RegisterSkin("models/players/" DEFAULT_MODEL "/model_default.skin");
1426 			trap->G2API_SetSkin(precachedKyle, 0, defSkin, defSkin);
1427 		}
1428 	}
1429 
1430 	if (!g2SaberInstance)
1431 	{
1432 		trap->G2API_InitGhoul2Model(&g2SaberInstance, DEFAULT_SABER_MODEL, 0, 0, -20, 0, 0);
1433 
1434 		if (g2SaberInstance)
1435 		{
1436 			// indicate we will be bolted to model 0 (ie the player) on bolt 0 (always the right hand) when we get copied
1437 			trap->G2API_SetBoltInfo(g2SaberInstance, 0, 0);
1438 			// now set up the gun bolt on it
1439 			trap->G2API_AddBolt(g2SaberInstance, 0, "*blade1");
1440 		}
1441 	}
1442 
1443 	if (level.gametype == GT_SIEGE)
1444 	{ //a tad bit of a hack, but..
1445 		EWebPrecache();
1446 	}
1447 
1448 	// make some data visible to connecting client
1449 	trap->SetConfigstring( CS_GAME_VERSION, GAME_VERSION );
1450 
1451 	trap->SetConfigstring( CS_LEVEL_START_TIME, va("%i", level.startTime ) );
1452 
1453 	G_SpawnString( "music", "", &text );
1454 	trap->SetConfigstring( CS_MUSIC, text );
1455 
1456 	G_SpawnString( "message", "", &text );
1457 	trap->SetConfigstring( CS_MESSAGE, text );				// map specific message
1458 
1459 	trap->SetConfigstring( CS_MOTD, g_motd.string );		// message of the day
1460 
1461 	G_SpawnString( "gravity", "800", &text );
1462 	trap->Cvar_Set( "g_gravity", text );
1463 	trap->Cvar_Update( &g_gravity );
1464 
1465 	G_SpawnString( "enableBreath", "0", &text );
1466 
1467 	G_SpawnString( "soundSet", "default", &text );
1468 	trap->SetConfigstring( CS_GLOBAL_AMBIENT_SET, text );
1469 
1470 	g_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD;
1471 	g_entities[ENTITYNUM_WORLD].r.ownerNum = ENTITYNUM_NONE;
1472 	g_entities[ENTITYNUM_WORLD].classname = "worldspawn";
1473 
1474 	g_entities[ENTITYNUM_NONE].s.number = ENTITYNUM_NONE;
1475 	g_entities[ENTITYNUM_NONE].r.ownerNum = ENTITYNUM_NONE;
1476 	g_entities[ENTITYNUM_NONE].classname = "nothing";
1477 
1478 	// see if we want a warmup time
1479 	trap->SetConfigstring( CS_WARMUP, "" );
1480 	if ( g_restarted.integer ) {
1481 		trap->Cvar_Set( "g_restarted", "0" );
1482 		trap->Cvar_Update( &g_restarted );
1483 		level.warmupTime = 0;
1484 	}
1485 	else if ( g_doWarmup.integer && level.gametype != GT_DUEL && level.gametype != GT_POWERDUEL && level.gametype != GT_SIEGE ) { // Turn it on
1486 		level.warmupTime = -1;
1487 		trap->SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
1488 		G_LogPrintf( "Warmup:\n" );
1489 	}
1490 
1491 	trap->SetConfigstring(CS_LIGHT_STYLES+(LS_STYLES_START*3)+0, defaultStyles[0][0]);
1492 	trap->SetConfigstring(CS_LIGHT_STYLES+(LS_STYLES_START*3)+1, defaultStyles[0][1]);
1493 	trap->SetConfigstring(CS_LIGHT_STYLES+(LS_STYLES_START*3)+2, defaultStyles[0][2]);
1494 
1495 	for(i=1;i<LS_NUM_STYLES;i++)
1496 	{
1497 		Com_sprintf(temp, sizeof(temp), "ls_%dr", i);
1498 		G_SpawnString(temp, defaultStyles[i][0], &text);
1499 		lengthRed = strlen(text);
1500 		trap->SetConfigstring(CS_LIGHT_STYLES+((i+LS_STYLES_START)*3)+0, text);
1501 
1502 		Com_sprintf(temp, sizeof(temp), "ls_%dg", i);
1503 		G_SpawnString(temp, defaultStyles[i][1], &text);
1504 		lengthGreen = strlen(text);
1505 		trap->SetConfigstring(CS_LIGHT_STYLES+((i+LS_STYLES_START)*3)+1, text);
1506 
1507 		Com_sprintf(temp, sizeof(temp), "ls_%db", i);
1508 		G_SpawnString(temp, defaultStyles[i][2], &text);
1509 		lengthBlue = strlen(text);
1510 		trap->SetConfigstring(CS_LIGHT_STYLES+((i+LS_STYLES_START)*3)+2, text);
1511 
1512 		if (lengthRed != lengthGreen || lengthGreen != lengthBlue)
1513 		{
1514 			Com_Error(ERR_DROP, "Style %d has inconsistent lengths: R %d, G %d, B %d",
1515 				i, lengthRed, lengthGreen, lengthBlue);
1516 		}
1517 	}
1518 }
1519 
1520 //rww - Planning on having something here?
SP_bsp_worldspawn(void)1521 qboolean SP_bsp_worldspawn ( void )
1522 {
1523 	return qtrue;
1524 }
1525 
G_PrecacheSoundsets(void)1526 void G_PrecacheSoundsets( void )
1527 {
1528 	gentity_t	*ent = NULL;
1529 	int i;
1530 	int countedSets = 0;
1531 
1532 	for ( i = 0; i < MAX_GENTITIES; i++ )
1533 	{
1534 		ent = &g_entities[i];
1535 
1536 		if (ent->inuse && ent->soundSet && ent->soundSet[0])
1537 		{
1538 			if (countedSets >= MAX_AMBIENT_SETS)
1539 			{
1540 				Com_Error(ERR_DROP, "MAX_AMBIENT_SETS was exceeded! (too many soundsets)\n");
1541 			}
1542 
1543 			ent->s.soundSetIndex = G_SoundSetIndex(ent->soundSet);
1544 			countedSets++;
1545 		}
1546 	}
1547 }
1548 
G_LinkLocations(void)1549 void G_LinkLocations( void ) {
1550 	int i, n;
1551 
1552 	if ( level.locations.linked )
1553 		return;
1554 
1555 	level.locations.linked = qtrue;
1556 
1557 	trap->SetConfigstring( CS_LOCATIONS, "unknown" );
1558 
1559 	for ( i=0, n=1; i<level.locations.num; i++ ) {
1560 		level.locations.data[i].cs_index = n;
1561 		trap->SetConfigstring( CS_LOCATIONS + n, level.locations.data[i].message );
1562 		n++;
1563 	}
1564 	// All linked together now
1565 }
1566 
1567 /*
1568 ==============
1569 G_SpawnEntitiesFromString
1570 
1571 Parses textual entity definitions out of an entstring and spawns gentities.
1572 ==============
1573 */
G_SpawnEntitiesFromString(qboolean inSubBSP)1574 void G_SpawnEntitiesFromString( qboolean inSubBSP ) {
1575 	// allow calls to G_Spawn*()
1576 	level.spawning = qtrue;
1577 	level.numSpawnVars = 0;
1578 
1579 	// the worldspawn is not an actual entity, but it still
1580 	// has a "spawn" function to perform any global setup
1581 	// needed by a level (setting configstrings or cvars, etc)
1582 	if ( !G_ParseSpawnVars(qfalse) ) {
1583 		trap->Error( ERR_DROP, "SpawnEntities: no entities" );
1584 	}
1585 
1586 	if (!inSubBSP)
1587 	{
1588 		SP_worldspawn();
1589 	}
1590 	else
1591 	{
1592 		// Skip this guy if its worldspawn fails
1593 		if ( !SP_bsp_worldspawn() )
1594 		{
1595 			return;
1596 		}
1597 	}
1598 
1599 	// parse ents
1600 	while( G_ParseSpawnVars(inSubBSP) ) {
1601 		G_SpawnGEntityFromSpawnVars(inSubBSP);
1602 	}
1603 
1604 	if( g_entities[ENTITYNUM_WORLD].behaviorSet[BSET_SPAWN] && g_entities[ENTITYNUM_WORLD].behaviorSet[BSET_SPAWN][0] )
1605 	{//World has a spawn script, but we don't want the world in ICARUS and running scripts,
1606 		//so make a scriptrunner and start it going.
1607 		gentity_t *script_runner = G_Spawn();
1608 		if ( script_runner )
1609 		{
1610 			script_runner->behaviorSet[BSET_USE] = g_entities[ENTITYNUM_WORLD].behaviorSet[BSET_SPAWN];
1611 			script_runner->count = 1;
1612 			script_runner->think = scriptrunner_run;
1613 			script_runner->nextthink = level.time + 100;
1614 
1615 			if ( script_runner->inuse )
1616 			{
1617 				trap->ICARUS_InitEnt( (sharedEntity_t *)script_runner );
1618 			}
1619 		}
1620 	}
1621 
1622 	if (!inSubBSP)
1623 	{
1624 		level.spawning = qfalse;			// any future calls to G_Spawn*() will be errors
1625 	}
1626 
1627 	G_LinkLocations();
1628 
1629 	G_PrecacheSoundsets();
1630 }
1631 
1632