codemp/game/g_spawn.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 
00004 #include "g_local.h"
00005 
00006 qboolean        G_SpawnString( const char *key, const char *defaultString, char **out ) {
00007         int             i;
00008 
00009         if ( !level.spawning ) {
00010                 *out = (char *)defaultString;
00011 //              G_Error( "G_SpawnString() called while not spawning" );
00012         }
00013 
00014         for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
00015                 if ( !Q_stricmp( key, level.spawnVars[i][0] ) ) {
00016                         *out = level.spawnVars[i][1];
00017                         return qtrue;
00018                 }
00019         }
00020 
00021         *out = (char *)defaultString;
00022         return qfalse;
00023 }
00024 
00025 qboolean        G_SpawnFloat( const char *key, const char *defaultString, float *out ) {
00026         char            *s;
00027         qboolean        present;
00028 
00029         present = G_SpawnString( key, defaultString, &s );
00030         *out = atof( s );
00031         return present;
00032 }
00033 
00034 qboolean        G_SpawnInt( const char *key, const char *defaultString, int *out ) {
00035         char            *s;
00036         qboolean        present;
00037 
00038         present = G_SpawnString( key, defaultString, &s );
00039         *out = atoi( s );
00040         return present;
00041 }
00042 
00043 qboolean        G_SpawnVector( const char *key, const char *defaultString, float *out ) {
00044         char            *s;
00045         qboolean        present;
00046 
00047         present = G_SpawnString( key, defaultString, &s );
00048         sscanf( s, "%f %f %f", &out[0], &out[1], &out[2] );
00049         return present;
00050 }
00051 
00052 
00053 
00054 BG_field_t fields[] = {
00055         {"classname", FOFS(classname), F_LSTRING},
00056         {"teamnodmg", FOFS(teamnodmg), F_INT},
00057         {"teamowner", FOFS(s.teamowner), F_INT},
00058         {"teamuser", FOFS(alliedTeam), F_INT},
00059         {"alliedTeam", FOFS(alliedTeam), F_INT},//for misc_turrets
00060         {"roffname", FOFS(roffname), F_LSTRING},
00061         {"rofftarget", FOFS(rofftarget), F_LSTRING},
00062         {"healingclass", FOFS(healingclass), F_LSTRING},
00063         {"healingsound", FOFS(healingsound), F_LSTRING},
00064         {"healingrate", FOFS(healingrate), F_INT},
00065         {"ownername", FOFS(ownername), F_LSTRING},
00066         {"origin", FOFS(s.origin), F_VECTOR},
00067         {"model", FOFS(model), F_LSTRING},
00068         {"model2", FOFS(model2), F_LSTRING},
00069         {"spawnflags", FOFS(spawnflags), F_INT},
00070         {"speed", FOFS(speed), F_FLOAT},
00071         {"target", FOFS(target), F_LSTRING},
00072         {"target2", FOFS(target2), F_LSTRING},
00073         {"target3", FOFS(target3), F_LSTRING},
00074         {"target4", FOFS(target4), F_LSTRING},
00075         {"target5", FOFS(target5), F_LSTRING},
00076         {"target6", FOFS(target6), F_LSTRING},
00077         {"NPC_targetname", FOFS(NPC_targetname), F_LSTRING},
00078         {"NPC_target", FOFS(NPC_target), F_LSTRING},
00079         {"NPC_target2", FOFS(target2), F_LSTRING},//NPC_spawner only
00080         {"NPC_target4", FOFS(target4), F_LSTRING},//NPC_spawner only
00081         {"NPC_type", FOFS(NPC_type), F_LSTRING},
00082         {"targetname", FOFS(targetname), F_LSTRING},
00083         {"message", FOFS(message), F_LSTRING},
00084         {"team", FOFS(team), F_LSTRING},
00085         {"wait", FOFS(wait), F_FLOAT},
00086         {"delay", FOFS(delay), F_INT},
00087         {"random", FOFS(random), F_FLOAT},
00088         {"count", FOFS(count), F_INT},
00089         {"health", FOFS(health), F_INT},
00090         {"light", 0, F_IGNORE},
00091         {"dmg", FOFS(damage), F_INT},
00092         {"angles", FOFS(s.angles), F_VECTOR},
00093         {"angle", FOFS(s.angles), F_ANGLEHACK},
00094         {"targetShaderName", FOFS(targetShaderName), F_LSTRING},
00095         {"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING},
00096         {"linear", FOFS(alt_fire), F_INT},//for movers to use linear movement
00097 
00098         {"closetarget", FOFS(closetarget), F_LSTRING},//for doors
00099         {"opentarget", FOFS(opentarget), F_LSTRING},//for doors
00100         {"paintarget", FOFS(paintarget), F_LSTRING},//for doors
00101 
00102         {"goaltarget", FOFS(goaltarget), F_LSTRING},//for siege
00103         {"idealclass", FOFS(idealclass), F_LSTRING},//for siege spawnpoints
00104 
00105         //rww - icarus stuff:
00106         {"spawnscript", FOFS(behaviorSet[BSET_SPAWN]), F_LSTRING},//name of script to run
00107         {"usescript", FOFS(behaviorSet[BSET_USE]), F_LSTRING},//name of script to run
00108         {"awakescript", FOFS(behaviorSet[BSET_AWAKE]), F_LSTRING},//name of script to run
00109         {"angerscript", FOFS(behaviorSet[BSET_ANGER]), F_LSTRING},//name of script to run
00110         {"attackscript", FOFS(behaviorSet[BSET_ATTACK]), F_LSTRING},//name of script to run
00111         {"victoryscript", FOFS(behaviorSet[BSET_VICTORY]), F_LSTRING},//name of script to run
00112         {"lostenemyscript", FOFS(behaviorSet[BSET_LOSTENEMY]), F_LSTRING},//name of script to run
00113         {"painscript", FOFS(behaviorSet[BSET_PAIN]), F_LSTRING},//name of script to run
00114         {"fleescript", FOFS(behaviorSet[BSET_FLEE]), F_LSTRING},//name of script to run
00115         {"deathscript", FOFS(behaviorSet[BSET_DEATH]), F_LSTRING},//name of script to run
00116         {"delayscript", FOFS(behaviorSet[BSET_DELAYED]), F_LSTRING},//name of script to run
00117         {"delayscripttime", FOFS(delayScriptTime), F_INT},//name of script to run
00118         {"blockedscript", FOFS(behaviorSet[BSET_BLOCKED]), F_LSTRING},//name of script to run
00119         {"ffirescript", FOFS(behaviorSet[BSET_FFIRE]), F_LSTRING},//name of script to run
00120         {"ffdeathscript", FOFS(behaviorSet[BSET_FFDEATH]), F_LSTRING},//name of script to run
00121         {"mindtrickscript", FOFS(behaviorSet[BSET_MINDTRICK]), F_LSTRING},//name of script to run
00122         {"script_targetname", FOFS(script_targetname), F_LSTRING},//scripts look for this when "affecting"
00123 
00124         {"fullName", FOFS(fullName), F_LSTRING},
00125 
00126         {"soundSet", FOFS(soundSet), F_LSTRING},
00127         {"radius", FOFS(radius), F_FLOAT},
00128         {"numchunks", FOFS(radius), F_FLOAT},//for func_breakables
00129         {"chunksize", FOFS(mass), F_FLOAT},//for func_breakables
00130 
00131 //Script parms - will this handle clamping to 16 or whatever length of parm[0] is?
00132         {"parm1", 0, F_PARM1},
00133         {"parm2", 0, F_PARM2},
00134         {"parm3", 0, F_PARM3},
00135         {"parm4", 0, F_PARM4},
00136         {"parm5", 0, F_PARM5},
00137         {"parm6", 0, F_PARM6},
00138         {"parm7", 0, F_PARM7},
00139         {"parm8", 0, F_PARM8},
00140         {"parm9", 0, F_PARM9},
00141         {"parm10", 0, F_PARM10},
00142         {"parm11", 0, F_PARM11},
00143         {"parm12", 0, F_PARM12},
00144         {"parm13", 0, F_PARM13},
00145         {"parm14", 0, F_PARM14},
00146         {"parm15", 0, F_PARM15},
00147         {"parm16", 0, F_PARM16},
00148 
00149         {NULL}
00150 };
00151 
00152 
00153 typedef struct {
00154         char    *name;
00155         void    (*spawn)(gentity_t *ent);
00156 } spawn_t;
00157 
00158 void SP_info_player_start (gentity_t *ent);
00159 void SP_info_player_duel( gentity_t *ent );
00160 void SP_info_player_duel1( gentity_t *ent );
00161 void SP_info_player_duel2( gentity_t *ent );
00162 void SP_info_player_deathmatch (gentity_t *ent);
00163 void SP_info_player_siegeteam1 (gentity_t *ent);
00164 void SP_info_player_siegeteam2 (gentity_t *ent);
00165 void SP_info_player_intermission (gentity_t *ent);
00166 void SP_info_player_intermission_red (gentity_t *ent);
00167 void SP_info_player_intermission_blue (gentity_t *ent);
00168 void SP_info_jedimaster_start (gentity_t *ent);
00169 void SP_info_player_start_red (gentity_t *ent);
00170 void SP_info_player_start_blue (gentity_t *ent);
00171 void SP_info_firstplace(gentity_t *ent);
00172 void SP_info_secondplace(gentity_t *ent);
00173 void SP_info_thirdplace(gentity_t *ent);
00174 void SP_info_podium(gentity_t *ent);
00175 
00176 void SP_info_siege_objective (gentity_t *ent);
00177 void SP_info_siege_radaricon (gentity_t *ent);
00178 void SP_info_siege_decomplete (gentity_t *ent);
00179 void SP_target_siege_end (gentity_t *ent);
00180 void SP_misc_siege_item (gentity_t *ent);
00181 
00182 void SP_func_plat (gentity_t *ent);
00183 void SP_func_static (gentity_t *ent);
00184 void SP_func_rotating (gentity_t *ent);
00185 void SP_func_bobbing (gentity_t *ent);
00186 void SP_func_pendulum( gentity_t *ent );
00187 void SP_func_button (gentity_t *ent);
00188 void SP_func_door (gentity_t *ent);
00189 void SP_func_train (gentity_t *ent);
00190 void SP_func_timer (gentity_t *self);
00191 void SP_func_breakable (gentity_t *ent);
00192 void SP_func_glass (gentity_t *ent);
00193 void SP_func_usable( gentity_t *ent);
00194 void SP_func_wall( gentity_t *ent );
00195 
00196 void SP_trigger_lightningstrike( gentity_t *ent );
00197 
00198 void SP_trigger_always (gentity_t *ent);
00199 void SP_trigger_multiple (gentity_t *ent);
00200 void SP_trigger_once( gentity_t *ent );
00201 void SP_trigger_push (gentity_t *ent);
00202 void SP_trigger_teleport (gentity_t *ent);
00203 void SP_trigger_hurt (gentity_t *ent);
00204 void SP_trigger_space(gentity_t *self);
00205 void SP_trigger_shipboundary(gentity_t *self);
00206 void SP_trigger_hyperspace(gentity_t *self);
00207 void SP_trigger_asteroid_field(gentity_t *self);
00208 
00209 void SP_target_remove_powerups( gentity_t *ent );
00210 void SP_target_give (gentity_t *ent);
00211 void SP_target_delay (gentity_t *ent);
00212 void SP_target_speaker (gentity_t *ent);
00213 void SP_target_print (gentity_t *ent);
00214 void SP_target_laser (gentity_t *self);
00215 void SP_target_character (gentity_t *ent);
00216 void SP_target_score( gentity_t *ent );
00217 void SP_target_teleporter( gentity_t *ent );
00218 void SP_target_relay (gentity_t *ent);
00219 void SP_target_kill (gentity_t *ent);
00220 void SP_target_position (gentity_t *ent);
00221 void SP_target_location (gentity_t *ent);
00222 void SP_target_counter (gentity_t *self);
00223 void SP_target_random (gentity_t *self);
00224 void SP_target_scriptrunner( gentity_t *self );
00225 void SP_target_interest (gentity_t *self);
00226 void SP_target_activate (gentity_t *self);
00227 void SP_target_deactivate (gentity_t *self);
00228 void SP_target_level_change( gentity_t *self );
00229 void SP_target_play_music( gentity_t *self );
00230 void SP_target_push (gentity_t *ent);
00231 
00232 void SP_light (gentity_t *self);
00233 void SP_info_null (gentity_t *self);
00234 void SP_info_notnull (gentity_t *self);
00235 void SP_info_camp (gentity_t *self);
00236 void SP_path_corner (gentity_t *self);
00237 
00238 void SP_misc_teleporter_dest (gentity_t *self);
00239 void SP_misc_model(gentity_t *ent);
00240 void SP_misc_model_static(gentity_t *ent);
00241 void SP_misc_G2model(gentity_t *ent);
00242 void SP_misc_portal_camera(gentity_t *ent);
00243 void SP_misc_portal_surface(gentity_t *ent);
00244 void SP_misc_weather_zone( gentity_t *ent );
00245 
00246 void SP_misc_bsp (gentity_t *ent);
00247 void SP_terrain (gentity_t *ent);
00248 void SP_misc_skyportal_orient (gentity_t *ent);
00249 void SP_misc_skyportal (gentity_t *ent);
00250 
00251 void SP_misc_ammo_floor_unit(gentity_t *ent);
00252 void SP_misc_shield_floor_unit( gentity_t *ent );
00253 void SP_misc_model_shield_power_converter( gentity_t *ent );
00254 void SP_misc_model_ammo_power_converter( gentity_t *ent );
00255 void SP_misc_model_health_power_converter( gentity_t *ent );
00256 
00257 void SP_fx_runner( gentity_t *ent );
00258 
00259 void SP_target_screenshake(gentity_t *ent);
00260 void SP_target_escapetrig(gentity_t *ent);
00261 
00262 void SP_misc_maglock ( gentity_t *self );
00263 
00264 void SP_misc_faller(gentity_t *ent);
00265 
00266 void SP_misc_holocron(gentity_t *ent);
00267 
00268 void SP_reference_tag ( gentity_t *ent );
00269 
00270 void SP_misc_weapon_shooter( gentity_t *self );
00271 
00272 void SP_NPC_spawner( gentity_t *self );
00273 
00274 void SP_NPC_Vehicle( gentity_t *self);
00275 
00276 void SP_NPC_Kyle( gentity_t *self );
00277 void SP_NPC_Lando( gentity_t *self );
00278 void SP_NPC_Jan( gentity_t *self );
00279 void SP_NPC_Luke( gentity_t *self );
00280 void SP_NPC_MonMothma( gentity_t *self );
00281 void SP_NPC_Tavion( gentity_t *self );
00282 void SP_NPC_Tavion_New( gentity_t *self );
00283 void SP_NPC_Alora( gentity_t *self );
00284 void SP_NPC_Reelo( gentity_t *self );
00285 void SP_NPC_Galak( gentity_t *self );
00286 void SP_NPC_Desann( gentity_t *self );
00287 void SP_NPC_Bartender( gentity_t *self );
00288 void SP_NPC_MorganKatarn( gentity_t *self );
00289 void SP_NPC_Jedi( gentity_t *self );
00290 void SP_NPC_Prisoner( gentity_t *self );
00291 void SP_NPC_Rebel( gentity_t *self );
00292 void SP_NPC_Stormtrooper( gentity_t *self );
00293 void SP_NPC_StormtrooperOfficer( gentity_t *self );
00294 void SP_NPC_Snowtrooper( gentity_t *self);
00295 void SP_NPC_Tie_Pilot( gentity_t *self );
00296 void SP_NPC_Ugnaught( gentity_t *self );
00297 void SP_NPC_Jawa( gentity_t *self );
00298 void SP_NPC_Gran( gentity_t *self );
00299 void SP_NPC_Rodian( gentity_t *self );
00300 void SP_NPC_Weequay( gentity_t *self );
00301 void SP_NPC_Trandoshan( gentity_t *self );
00302 void SP_NPC_Tusken( gentity_t *self );
00303 void SP_NPC_Noghri( gentity_t *self );
00304 void SP_NPC_SwampTrooper( gentity_t *self );
00305 void SP_NPC_Imperial( gentity_t *self );
00306 void SP_NPC_ImpWorker( gentity_t *self );
00307 void SP_NPC_BespinCop( gentity_t *self );
00308 void SP_NPC_Reborn( gentity_t *self );
00309 void SP_NPC_ShadowTrooper( gentity_t *self );
00310 void SP_NPC_Monster_Murjj( gentity_t *self );
00311 void SP_NPC_Monster_Swamp( gentity_t *self );
00312 void SP_NPC_Monster_Howler( gentity_t *self );
00313 void SP_NPC_Monster_Claw( gentity_t *self );
00314 void SP_NPC_Monster_Glider( gentity_t *self );
00315 void SP_NPC_Monster_Flier2( gentity_t *self );
00316 void SP_NPC_Monster_Lizard( gentity_t *self );
00317 void SP_NPC_Monster_Fish( gentity_t *self );
00318 void SP_NPC_Monster_Wampa( gentity_t *self );
00319 void SP_NPC_Monster_Rancor( gentity_t *self );
00320 void SP_NPC_MineMonster( gentity_t *self );
00321 void SP_NPC_Droid_Interrogator( gentity_t *self );
00322 void SP_NPC_Droid_Probe( gentity_t *self );
00323 void SP_NPC_Droid_Mark1( gentity_t *self );
00324 void SP_NPC_Droid_Mark2( gentity_t *self );
00325 void SP_NPC_Droid_ATST( gentity_t *self );
00326 void SP_NPC_Droid_Seeker( gentity_t *self );
00327 void SP_NPC_Droid_Remote( gentity_t *self );
00328 void SP_NPC_Droid_Sentry( gentity_t *self );
00329 void SP_NPC_Droid_Gonk( gentity_t *self );
00330 void SP_NPC_Droid_Mouse( gentity_t *self );
00331 void SP_NPC_Droid_R2D2( gentity_t *self );
00332 void SP_NPC_Droid_R5D2( gentity_t *self );
00333 void SP_NPC_Droid_Protocol( gentity_t *self );
00334 
00335 void SP_NPC_Reborn_New( gentity_t *self);
00336 void SP_NPC_Cultist( gentity_t *self );
00337 void SP_NPC_Cultist_Saber( gentity_t *self );
00338 void SP_NPC_Cultist_Saber_Powers( gentity_t *self );
00339 void SP_NPC_Cultist_Destroyer( gentity_t *self );
00340 void SP_NPC_Cultist_Commando( gentity_t *self );
00341 
00342 void SP_waypoint (gentity_t *ent);
00343 void SP_waypoint_small (gentity_t *ent);
00344 void SP_waypoint_navgoal (gentity_t *ent);
00345 void SP_waypoint_navgoal_8 (gentity_t *ent);
00346 void SP_waypoint_navgoal_4 (gentity_t *ent);
00347 void SP_waypoint_navgoal_2 (gentity_t *ent);
00348 void SP_waypoint_navgoal_1 (gentity_t *ent);
00349 
00350 void SP_CreateSpaceDust( gentity_t *ent );
00351 void SP_CreateSnow( gentity_t *ent );
00352 void SP_CreateRain( gentity_t *ent );
00353 
00354 void SP_point_combat( gentity_t *self );
00355 
00356 void SP_shooter_blaster( gentity_t *ent );
00357 
00358 void SP_team_CTF_redplayer( gentity_t *ent );
00359 void SP_team_CTF_blueplayer( gentity_t *ent );
00360 
00361 void SP_team_CTF_redspawn( gentity_t *ent );
00362 void SP_team_CTF_bluespawn( gentity_t *ent );
00363 
00364 void SP_misc_turret( gentity_t *ent );
00365 void SP_misc_turretG2( gentity_t *base );
00366 
00367 
00368 void SP_item_botroam( gentity_t *ent )
00369 {
00370 }
00371 
00372 void SP_gametype_item ( gentity_t* ent )
00373 {
00374         gitem_t *item = NULL;
00375         char *value;
00376         int team = -1;
00377 
00378         G_SpawnString("teamfilter", "", &value);
00379 
00380         G_SetOrigin( ent, ent->s.origin );
00381 
00382         // If a team filter is set then override any team settings for the spawns
00383         if ( level.mTeamFilter[0] )
00384         {
00385                 if ( Q_stricmp ( level.mTeamFilter, "red") == 0 )
00386                 {
00387                         team = TEAM_RED;
00388                 }
00389                 else if ( Q_stricmp ( level.mTeamFilter, "blue") == 0 )
00390                 {
00391                         team = TEAM_BLUE;
00392                 }
00393         }
00394 
00395         if (ent->targetname && ent->targetname[0])
00396         {
00397                 if (team != -1)
00398                 {
00399                         if (strstr(ent->targetname, "flag"))
00400                         {
00401                                 if (team == TEAM_RED)
00402                                 {
00403                                         item = BG_FindItem("team_CTF_redflag");
00404                                 }
00405                                 else
00406                                 { //blue
00407                                         item = BG_FindItem("team_CTF_blueflag");
00408                                 }
00409                         }
00410                 }
00411                 else if (strstr(ent->targetname, "red_flag"))
00412                 {
00413                         item = BG_FindItem("team_CTF_redflag");
00414                 }
00415                 else if (strstr(ent->targetname, "blue_flag"))
00416                 {
00417                         item = BG_FindItem("team_CTF_blueflag");
00418                 }
00419                 else
00420                 {
00421                         item = NULL;
00422                 }
00423 
00424                 if (item)
00425                 {
00426                         ent->targetname = NULL;
00427                         ent->classname = item->classname;
00428                         G_SpawnItem( ent, item );
00429                 }
00430         }
00431 }
00432 
00433 void SP_emplaced_gun( gentity_t *ent );
00434 
00435 spawn_t spawns[] = {
00436         // info entities don't do anything at all, but provide positional
00437         // information for things controlled by other processes
00438         {"info_player_start", SP_info_player_start},
00439         {"info_player_duel", SP_info_player_duel},
00440         {"info_player_duel1", SP_info_player_duel1},
00441         {"info_player_duel2", SP_info_player_duel2},
00442         {"info_player_deathmatch", SP_info_player_deathmatch},
00443         {"info_player_siegeteam1", SP_info_player_siegeteam1},
00444         {"info_player_siegeteam2", SP_info_player_siegeteam2},
00445         {"info_player_intermission", SP_info_player_intermission},
00446         {"info_player_intermission_red", SP_info_player_intermission_red},
00447         {"info_player_intermission_blue", SP_info_player_intermission_blue},
00448         {"info_jedimaster_start", SP_info_jedimaster_start},
00449         {"info_player_start_red", SP_info_player_start_red},
00450         {"info_player_start_blue", SP_info_player_start_blue},
00451         {"info_null", SP_info_null},
00452         {"info_notnull", SP_info_notnull},              // use target_position instead
00453         {"info_camp", SP_info_camp},
00454 
00455         {"info_siege_objective", SP_info_siege_objective},
00456         {"info_siege_radaricon", SP_info_siege_radaricon},
00457         {"info_siege_decomplete", SP_info_siege_decomplete},
00458         {"target_siege_end", SP_target_siege_end},
00459         {"misc_siege_item", SP_misc_siege_item},
00460 
00461         {"func_plat", SP_func_plat},
00462         {"func_button", SP_func_button},
00463         {"func_door", SP_func_door},
00464         {"func_static", SP_func_static},
00465         {"func_rotating", SP_func_rotating},
00466         {"func_bobbing", SP_func_bobbing},
00467         {"func_pendulum", SP_func_pendulum},
00468         {"func_train", SP_func_train},
00469         {"func_group", SP_info_null},
00470         {"func_timer", SP_func_timer},                  // rename trigger_timer?
00471         {"func_breakable", SP_func_breakable},
00472         {"func_glass", SP_func_glass},
00473         {"func_usable", SP_func_usable},
00474         {"func_wall", SP_func_wall},
00475 
00476         // Triggers are brush objects that cause an effect when contacted
00477         // by a living player, usually involving firing targets.
00478         // While almost everything could be done with
00479         // a single trigger class and different targets, triggered effects
00480         // could not be client side predicted (push and teleport).
00481         {"trigger_lightningstrike", SP_trigger_lightningstrike},
00482 
00483         {"trigger_always", SP_trigger_always},
00484         {"trigger_multiple", SP_trigger_multiple},
00485         {"trigger_once", SP_trigger_once},
00486         {"trigger_push", SP_trigger_push},
00487         {"trigger_teleport", SP_trigger_teleport},
00488         {"trigger_hurt", SP_trigger_hurt},
00489         {"trigger_space", SP_trigger_space},
00490         {"trigger_shipboundary", SP_trigger_shipboundary},
00491         {"trigger_hyperspace", SP_trigger_hyperspace},
00492         {"trigger_asteroid_field", SP_trigger_asteroid_field},
00493 
00494         // targets perform no action by themselves, but must be triggered
00495         // by another entity
00496         {"target_give", SP_target_give},
00497         {"target_remove_powerups", SP_target_remove_powerups},
00498         {"target_delay", SP_target_delay},
00499         {"target_speaker", SP_target_speaker},
00500         {"target_print", SP_target_print},
00501         {"target_laser", SP_target_laser},
00502         {"target_score", SP_target_score},
00503         {"target_teleporter", SP_target_teleporter},
00504         {"target_relay", SP_target_relay},
00505         {"target_kill", SP_target_kill},
00506         {"target_position", SP_target_position},
00507         {"target_location", SP_target_location},
00508         {"target_counter", SP_target_counter},
00509         {"target_random", SP_target_random},
00510         {"target_scriptrunner", SP_target_scriptrunner},
00511         {"target_interest", SP_target_interest},
00512         {"target_activate", SP_target_activate},
00513         {"target_deactivate", SP_target_deactivate},
00514         {"target_level_change", SP_target_level_change},
00515         {"target_play_music", SP_target_play_music},
00516         {"target_push", SP_target_push},
00517 
00518         {"light", SP_light},
00519         {"path_corner", SP_path_corner},
00520 
00521         {"misc_teleporter_dest", SP_misc_teleporter_dest},
00522         {"misc_model", SP_misc_model},
00523         {"misc_model_static", SP_misc_model_static},
00524         {"misc_G2model", SP_misc_G2model},
00525         {"misc_portal_surface", SP_misc_portal_surface},
00526         {"misc_portal_camera", SP_misc_portal_camera},
00527         {"misc_weather_zone", SP_misc_weather_zone},
00528 
00529         {"misc_bsp", SP_misc_bsp},
00530         {"terrain", SP_terrain},
00531         {"misc_skyportal_orient", SP_misc_skyportal_orient},
00532         {"misc_skyportal", SP_misc_skyportal},
00533 
00534         //rwwFIXMEFIXME: only for testing rmg team stuff
00535         {"gametype_item", SP_gametype_item },
00536 
00537         {"misc_ammo_floor_unit", SP_misc_ammo_floor_unit},
00538         {"misc_shield_floor_unit", SP_misc_shield_floor_unit},
00539         {"misc_model_shield_power_converter", SP_misc_model_shield_power_converter},
00540         {"misc_model_ammo_power_converter", SP_misc_model_ammo_power_converter},
00541         {"misc_model_health_power_converter", SP_misc_model_health_power_converter},
00542 
00543         {"fx_runner", SP_fx_runner},
00544 
00545         {"target_screenshake", SP_target_screenshake},
00546         {"target_escapetrig", SP_target_escapetrig},
00547 
00548         {"misc_maglock", SP_misc_maglock},
00549 
00550         {"misc_faller", SP_misc_faller},
00551 
00552         {"ref_tag",     SP_reference_tag},
00553         {"ref_tag_huge",        SP_reference_tag},
00554 
00555         {"misc_weapon_shooter", SP_misc_weapon_shooter},
00556 
00557         //new NPC ents
00558         {"NPC_spawner", SP_NPC_spawner},
00559 
00560         {"NPC_Vehicle", SP_NPC_Vehicle },
00561         {"NPC_Kyle", SP_NPC_Kyle },
00562         {"NPC_Lando", SP_NPC_Lando },
00563         {"NPC_Jan", SP_NPC_Jan },
00564         {"NPC_Luke", SP_NPC_Luke },
00565         {"NPC_MonMothma", SP_NPC_MonMothma },
00566         {"NPC_Tavion", SP_NPC_Tavion },
00567         
00568         //new tavion
00569         {"NPC_Tavion_New", SP_NPC_Tavion_New },
00570 
00571         //new alora
00572         {"NPC_Alora", SP_NPC_Alora },
00573 
00574         {"NPC_Reelo", SP_NPC_Reelo },
00575         {"NPC_Galak", SP_NPC_Galak },
00576         {"NPC_Desann", SP_NPC_Desann },
00577         {"NPC_Bartender", SP_NPC_Bartender },
00578         {"NPC_MorganKatarn", SP_NPC_MorganKatarn },
00579         {"NPC_Jedi", SP_NPC_Jedi },
00580         {"NPC_Prisoner", SP_NPC_Prisoner },
00581         {"NPC_Rebel", SP_NPC_Rebel },
00582         {"NPC_Stormtrooper", SP_NPC_Stormtrooper },
00583         {"NPC_StormtrooperOfficer", SP_NPC_StormtrooperOfficer },
00584         {"NPC_Snowtrooper", SP_NPC_Snowtrooper },
00585         {"NPC_Tie_Pilot", SP_NPC_Tie_Pilot },
00586         {"NPC_Ugnaught", SP_NPC_Ugnaught },
00587         {"NPC_Jawa", SP_NPC_Jawa },
00588         {"NPC_Gran", SP_NPC_Gran },
00589         {"NPC_Rodian", SP_NPC_Rodian },
00590         {"NPC_Weequay", SP_NPC_Weequay },
00591         {"NPC_Trandoshan", SP_NPC_Trandoshan },
00592         {"NPC_Tusken", SP_NPC_Tusken },
00593         {"NPC_Noghri", SP_NPC_Noghri },
00594         {"NPC_SwampTrooper", SP_NPC_SwampTrooper },
00595         {"NPC_Imperial", SP_NPC_Imperial },
00596         {"NPC_ImpWorker", SP_NPC_ImpWorker },
00597         {"NPC_BespinCop", SP_NPC_BespinCop },
00598         {"NPC_Reborn", SP_NPC_Reborn },
00599         {"NPC_ShadowTrooper", SP_NPC_ShadowTrooper },
00600         {"NPC_Monster_Murjj", SP_NPC_Monster_Murjj },
00601         {"NPC_Monster_Swamp", SP_NPC_Monster_Swamp },
00602         {"NPC_Monster_Howler", SP_NPC_Monster_Howler },
00603         {"NPC_MineMonster",     SP_NPC_MineMonster },
00604         {"NPC_Monster_Claw", SP_NPC_Monster_Claw },
00605         {"NPC_Monster_Glider", SP_NPC_Monster_Glider },
00606         {"NPC_Monster_Flier2", SP_NPC_Monster_Flier2 },
00607         {"NPC_Monster_Lizard", SP_NPC_Monster_Lizard },
00608         {"NPC_Monster_Fish", SP_NPC_Monster_Fish },
00609         {"NPC_Monster_Wampa", SP_NPC_Monster_Wampa },
00610         {"NPC_Monster_Rancor", SP_NPC_Monster_Rancor },
00611         {"NPC_Droid_Interrogator", SP_NPC_Droid_Interrogator },
00612         {"NPC_Droid_Probe", SP_NPC_Droid_Probe },
00613         {"NPC_Droid_Mark1", SP_NPC_Droid_Mark1 },
00614         {"NPC_Droid_Mark2", SP_NPC_Droid_Mark2 },
00615         {"NPC_Droid_ATST", SP_NPC_Droid_ATST },
00616         {"NPC_Droid_Seeker", SP_NPC_Droid_Seeker },
00617         {"NPC_Droid_Remote", SP_NPC_Droid_Remote },
00618         {"NPC_Droid_Sentry", SP_NPC_Droid_Sentry },
00619         {"NPC_Droid_Gonk", SP_NPC_Droid_Gonk },
00620         {"NPC_Droid_Mouse", SP_NPC_Droid_Mouse },
00621         {"NPC_Droid_R2D2", SP_NPC_Droid_R2D2 },
00622         {"NPC_Droid_R5D2", SP_NPC_Droid_R5D2 },
00623         {"NPC_Droid_Protocol", SP_NPC_Droid_Protocol },
00624 
00625         //maybe put these guys in some day, for now just spawn reborns in their place.
00626         {"NPC_Reborn_New", SP_NPC_Reborn_New },
00627         {"NPC_Cultist", SP_NPC_Cultist },
00628         {"NPC_Cultist_Saber", SP_NPC_Cultist_Saber },
00629         {"NPC_Cultist_Saber_Powers", SP_NPC_Cultist_Saber_Powers },
00630         {"NPC_Cultist_Destroyer", SP_NPC_Cultist_Destroyer },
00631         {"NPC_Cultist_Commando", SP_NPC_Cultist_Commando },
00632 
00633         //rwwFIXMEFIXME: Faked for testing NPCs (another other things) in RMG with sof2 assets
00634         {"NPC_Colombian_Soldier", SP_NPC_Reborn },
00635         {"NPC_Colombian_Rebel", SP_NPC_Reborn },
00636         {"NPC_Colombian_EmplacedGunner", SP_NPC_ShadowTrooper },
00637         {"NPC_Manuel_Vergara_RMG", SP_NPC_Desann },
00638 //      {"info_NPCnav", SP_waypoint},
00639 
00640         {"waypoint", SP_waypoint},
00641         {"waypoint_small", SP_waypoint_small},
00642         {"waypoint_navgoal", SP_waypoint_navgoal},
00643         {"waypoint_navgoal_8", SP_waypoint_navgoal_8},
00644         {"waypoint_navgoal_4", SP_waypoint_navgoal_4},
00645         {"waypoint_navgoal_2", SP_waypoint_navgoal_2},
00646         {"waypoint_navgoal_1", SP_waypoint_navgoal_1},
00647 
00648         {"fx_spacedust", SP_CreateSpaceDust},
00649         {"fx_rain", SP_CreateRain},
00650         {"fx_snow", SP_CreateSnow},
00651 
00652         {"point_combat", SP_point_combat},
00653 
00654         {"misc_holocron", SP_misc_holocron},
00655 
00656         {"shooter_blaster", SP_shooter_blaster},
00657 
00658         {"team_CTF_redplayer", SP_team_CTF_redplayer},
00659         {"team_CTF_blueplayer", SP_team_CTF_blueplayer},
00660 
00661         {"team_CTF_redspawn", SP_team_CTF_redspawn},
00662         {"team_CTF_bluespawn", SP_team_CTF_bluespawn},
00663 
00664         {"item_botroam", SP_item_botroam},
00665 
00666         {"emplaced_gun", SP_emplaced_gun},
00667 
00668         {"misc_turret", SP_misc_turret},
00669         {"misc_turretG2", SP_misc_turretG2},
00670 
00671 
00672         {0, 0}
00673 };
00674 
00675 /*
00676 ===============
00677 G_CallSpawn
00678 
00679 Finds the spawn function for the entity and calls it,
00680 returning qfalse if not found
00681 ===============
00682 */
00683 qboolean G_CallSpawn( gentity_t *ent ) {
00684         spawn_t *s;
00685         gitem_t *item;
00686 
00687         if ( !ent->classname ) {
00688                 G_Printf ("G_CallSpawn: NULL classname\n");
00689                 return qfalse;
00690         }
00691 
00692         // check item spawn functions
00693         for ( item=bg_itemlist+1 ; item->classname ; item++ ) {
00694                 if ( !strcmp(item->classname, ent->classname) ) {
00695                         G_SpawnItem( ent, item );
00696                         return qtrue;
00697                 }
00698         }
00699 
00700         // check normal spawn functions
00701         for ( s=spawns ; s->name ; s++ ) {
00702                 if ( !strcmp(s->name, ent->classname) ) {
00703                         // found it
00704                         if (ent->healingsound && ent->healingsound[0])
00705                         { //yeah...this can be used for anything, so.. precache it if it's there
00706                                 G_SoundIndex(ent->healingsound);
00707                         }
00708                         s->spawn(ent);
00709                         return qtrue;
00710                 }
00711         }
00712         G_Printf ("%s doesn't have a spawn function\n", ent->classname);
00713         return qfalse;
00714 }
00715 
00716 /*
00717 =============
00718 G_NewString
00719 
00720 Builds a copy of the string, translating \n to real linefeeds
00721 so message texts can be multi-line
00722 =============
00723 */
00724 char *G_NewString( const char *string ) {
00725         char    *newb, *new_p;
00726         int             i,l;
00727         
00728         l = strlen(string) + 1;
00729 
00730         newb = (char *) G_Alloc( l );
00731 
00732         new_p = newb;
00733 
00734         // turn \n into a real linefeed
00735         for ( i=0 ; i< l ; i++ ) {
00736                 if (string[i] == '\\' && i < l-1) {
00737                         i++;
00738                         if (string[i] == 'n') {
00739                                 *new_p++ = '\n';
00740                         } else {
00741                                 *new_p++ = '\\';
00742                         }
00743                 } else {
00744                         *new_p++ = string[i];
00745                 }
00746         }
00747         
00748         return newb;
00749 }
00750 
00751 
00752 
00753 
00754 
00755 /*
00756 ===================
00757 G_SpawnGEntityFromSpawnVars
00758 
00759 Spawn an entity and fill in all of the level fields from
00760 level.spawnVars[], then call the class specfic spawn function
00761 ===================
00762 */
00763 #include "../namespace_begin.h"
00764 void BG_ParseField( BG_field_t *l_fields, const char *key, const char *value, byte *ent );
00765 #include "../namespace_end.h"
00766 void G_SpawnGEntityFromSpawnVars( qboolean inSubBSP ) {
00767         int                     i;
00768         gentity_t       *ent;
00769         char            *s, *value, *gametypeName;
00770         static char *gametypeNames[] = {"ffa", "holocron", "jedimaster", "duel", "powerduel", "single", "team", "siege", "ctf", "cty"};
00771 
00772         // get the next free entity
00773         ent = G_Spawn();
00774 
00775         for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
00776                 BG_ParseField( fields, level.spawnVars[i][0], level.spawnVars[i][1], (byte *)ent );
00777         }
00778 
00779         // check for "notsingle" flag
00780         if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
00781                 G_SpawnInt( "notsingle", "0", &i );
00782                 if ( i ) {
00783                         G_FreeEntity( ent );
00784                         return;
00785                 }
00786         }
00787         // check for "notteam" flag (GT_FFA, GT_DUEL, GT_SINGLE_PLAYER)
00788         if ( g_gametype.integer >= GT_TEAM ) {
00789                 G_SpawnInt( "notteam", "0", &i );
00790                 if ( i ) {
00791                         G_FreeEntity( ent );
00792                         return;
00793                 }
00794         } else {
00795                 G_SpawnInt( "notfree", "0", &i );
00796                 if ( i ) {
00797                         G_FreeEntity( ent );
00798                         return;
00799                 }
00800         }
00801 
00802         G_SpawnInt( "notta", "0", &i );
00803         if ( i ) {
00804                 G_FreeEntity( ent );
00805                 return;
00806         }
00807 
00808         if( G_SpawnString( "gametype", NULL, &value ) ) {
00809                 if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {
00810                         gametypeName = gametypeNames[g_gametype.integer];
00811 
00812                         s = strstr( value, gametypeName );
00813                         if( !s ) {
00814                                 G_FreeEntity( ent );
00815                                 return;
00816                         }
00817                 }
00818         }
00819 
00820         // move editor origin to pos
00821         VectorCopy( ent->s.origin, ent->s.pos.trBase );
00822         VectorCopy( ent->s.origin, ent->r.currentOrigin );
00823 
00824         // if we didn't get a classname, don't bother spawning anything
00825         if ( !G_CallSpawn( ent ) ) {
00826                 G_FreeEntity( ent );
00827         }
00828 
00829         //Tag on the ICARUS scripting information only to valid recipients
00830         if ( trap_ICARUS_ValidEnt( ent ) )
00831         {
00832                 trap_ICARUS_InitEnt( ent );
00833 
00834                 if ( ent->classname && ent->classname[0] )
00835                 {
00836                         if ( Q_strncmp( "NPC_", ent->classname, 4 ) != 0 )
00837                         {//Not an NPC_spawner (rww - probably don't even care for MP, but whatever)
00838                                 G_ActivateBehavior( ent, BSET_SPAWN );
00839                         }
00840                 }
00841         }
00842 }
00843 
00844 
00845 
00846 /*
00847 ====================
00848 G_AddSpawnVarToken
00849 ====================
00850 */
00851 char *G_AddSpawnVarToken( const char *string ) {
00852         int             l;
00853         char    *dest;
00854 
00855         l = strlen( string );
00856         if ( level.numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) {
00857                 G_Error( "G_AddSpawnVarToken: MAX_SPAWN_CHARS" );
00858         }
00859 
00860         dest = level.spawnVarChars + level.numSpawnVarChars;
00861         memcpy( dest, string, l+1 );
00862 
00863         level.numSpawnVarChars += l + 1;
00864 
00865         return dest;
00866 }
00867 
00868 void AddSpawnField(char *field, char *value)
00869 {
00870         int     i;
00871 
00872         for(i=0;i<level.numSpawnVars;i++)
00873         {
00874                 if (Q_stricmp(level.spawnVars[i][0], field) == 0)
00875                 {
00876                         level.spawnVars[ i ][1] = G_AddSpawnVarToken( value );
00877                         return;
00878                 }
00879         }
00880 
00881         level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( field );
00882         level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( value );
00883         level.numSpawnVars++;
00884 }
00885 
00886 #define NOVALUE "novalue"
00887 
00888 static void HandleEntityAdjustment(void)
00889 {
00890         char            *value;
00891         vec3_t          origin, newOrigin, angles;
00892         char            temp[MAX_QPATH];
00893         float           rotation;
00894 
00895         G_SpawnString("origin", NOVALUE, &value);
00896         if (Q_stricmp(value, NOVALUE) != 0)
00897         {
00898                 sscanf( value, "%f %f %f", &origin[0], &origin[1], &origin[2] );
00899         }
00900         else
00901         {
00902                 origin[0] = origin[1] = origin[2] = 0.0;
00903         }
00904 
00905         rotation = DEG2RAD(level.mRotationAdjust);
00906         newOrigin[0] = origin[0]*cos(rotation) - origin[1]*sin(rotation);
00907         newOrigin[1] = origin[0]*sin(rotation) + origin[1]*cos(rotation);
00908         newOrigin[2] = origin[2];
00909         VectorAdd(newOrigin, level.mOriginAdjust, newOrigin);
00910         // damn VMs don't handle outputing a float that is compatible with sscanf in all cases
00911         Com_sprintf(temp, MAX_QPATH, "%0.0f %0.0f %0.0f", newOrigin[0], newOrigin[1], newOrigin[2]);
00912         AddSpawnField("origin", temp);
00913 
00914         G_SpawnString("angles", NOVALUE, &value);
00915         if (Q_stricmp(value, NOVALUE) != 0)
00916         {
00917                 sscanf( value, "%f %f %f", &angles[0], &angles[1], &angles[2] );
00918 
00919                 angles[1] = fmod(angles[1] + level.mRotationAdjust, 360.0f);
00920                 // damn VMs don't handle outputing a float that is compatible with sscanf in all cases
00921                 Com_sprintf(temp, MAX_QPATH, "%0.0f %0.0f %0.0f", angles[0], angles[1], angles[2]);
00922                 AddSpawnField("angles", temp);
00923         }
00924         else
00925         {
00926                 G_SpawnString("angle", NOVALUE, &value);
00927                 if (Q_stricmp(value, NOVALUE) != 0)
00928                 {
00929                         sscanf( value, "%f", &angles[1] );
00930                 }
00931                 else
00932                 {
00933                         angles[1] = 0.0;
00934                 }
00935                 angles[1] = fmod(angles[1] + level.mRotationAdjust, 360.0f);
00936                 Com_sprintf(temp, MAX_QPATH, "%0.0f", angles[1]);
00937                 AddSpawnField("angle", temp);
00938         }
00939 
00940         // RJR experimental code for handling "direction" field of breakable brushes
00941         // though direction is rarely ever used.
00942         G_SpawnString("direction", NOVALUE, &value);
00943         if (Q_stricmp(value, NOVALUE) != 0)
00944         {
00945                 sscanf( value, "%f %f %f", &angles[0], &angles[1], &angles[2] );
00946         }
00947         else
00948         {
00949                 angles[0] = angles[1] = angles[2] = 0.0;
00950         }
00951         angles[1] = fmod(angles[1] + level.mRotationAdjust, 360.0f);
00952         Com_sprintf(temp, MAX_QPATH, "%0.0f %0.0f %0.0f", angles[0], angles[1], angles[2]);
00953         AddSpawnField("direction", temp);
00954 
00955 
00956         AddSpawnField("BSPInstanceID", level.mTargetAdjust);
00957 
00958         G_SpawnString("targetname", NOVALUE, &value);
00959         if (Q_stricmp(value, NOVALUE) != 0)
00960         {
00961                 Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
00962                 AddSpawnField("targetname", temp);
00963         }
00964 
00965         G_SpawnString("target", NOVALUE, &value);
00966         if (Q_stricmp(value, NOVALUE) != 0)
00967         {
00968                 Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
00969                 AddSpawnField("target", temp);
00970         }
00971 
00972         G_SpawnString("killtarget", NOVALUE, &value);
00973         if (Q_stricmp(value, NOVALUE) != 0)
00974         {
00975                 Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
00976                 AddSpawnField("killtarget", temp);
00977         }
00978 
00979         G_SpawnString("brushparent", NOVALUE, &value);
00980         if (Q_stricmp(value, NOVALUE) != 0)
00981         {
00982                 Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
00983                 AddSpawnField("brushparent", temp);
00984         }
00985 
00986         G_SpawnString("brushchild", NOVALUE, &value);
00987         if (Q_stricmp(value, NOVALUE) != 0)
00988         {
00989                 Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
00990                 AddSpawnField("brushchild", temp);
00991         }
00992 
00993         G_SpawnString("enemy", NOVALUE, &value);
00994         if (Q_stricmp(value, NOVALUE) != 0)
00995         {
00996                 Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
00997                 AddSpawnField("enemy", temp);
00998         }
00999 
01000         G_SpawnString("ICARUSname", NOVALUE, &value);
01001         if (Q_stricmp(value, NOVALUE) != 0)
01002         {
01003                 Com_sprintf(temp, MAX_QPATH, "%s%s", level.mTargetAdjust, value);
01004                 AddSpawnField("ICARUSname", temp);
01005         }
01006 }
01007 
01008 /*
01009 ====================
01010 G_ParseSpawnVars
01011 
01012 Parses a brace bounded set of key / value pairs out of the
01013 level's entity strings into level.spawnVars[]
01014 
01015 This does not actually spawn an entity.
01016 ====================
01017 */
01018 qboolean G_ParseSpawnVars( qboolean inSubBSP ) {
01019         char            keyname[MAX_TOKEN_CHARS];
01020         char            com_token[MAX_TOKEN_CHARS];
01021 
01022         level.numSpawnVars = 0;
01023         level.numSpawnVarChars = 0;
01024 
01025         // parse the opening brace
01026         if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
01027                 // end of spawn string
01028                 return qfalse;
01029         }
01030         if ( com_token[0] != '{' ) {
01031                 G_Error( "G_ParseSpawnVars: found %s when expecting {",com_token );
01032         }
01033 
01034         // go through all the key / value pairs
01035         while ( 1 ) {   
01036                 // parse key
01037                 if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) {
01038                         G_Error( "G_ParseSpawnVars: EOF without closing brace" );
01039                 }
01040 
01041                 if ( keyname[0] == '}' ) {
01042                         break;
01043                 }
01044                 
01045                 // parse value  
01046                 if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
01047                         G_Error( "G_ParseSpawnVars: EOF without closing brace" );
01048                 }
01049 
01050                 if ( com_token[0] == '}' ) {
01051                         G_Error( "G_ParseSpawnVars: closing brace without data" );
01052                 }
01053                 if ( level.numSpawnVars == MAX_SPAWN_VARS ) {
01054                         G_Error( "G_ParseSpawnVars: MAX_SPAWN_VARS" );
01055                 }
01056                 level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( keyname );
01057                 level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( com_token );
01058                 level.numSpawnVars++;
01059         }
01060 
01061         if (inSubBSP)
01062         {
01063                 HandleEntityAdjustment();
01064         }
01065 
01066         return qtrue;
01067 }
01068 
01069 
01070 static  char *defaultStyles[32][3] = 
01071 {
01072         {       // 0 normal
01073                 "z",
01074                 "z",
01075                 "z"
01076         },
01077         {       // 1 FLICKER (first variety)
01078                 "mmnmmommommnonmmonqnmmo",
01079                 "mmnmmommommnonmmonqnmmo",
01080                 "mmnmmommommnonmmonqnmmo"
01081         },
01082         {       // 2 SLOW STRONG PULSE
01083                 "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcb",
01084                 "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcb",
01085                 "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcb"
01086         },
01087         {       // 3 CANDLE (first variety)
01088                 "mmmmmaaaaammmmmaaaaaabcdefgabcdefg",
01089                 "mmmmmaaaaammmmmaaaaaabcdefgabcdefg",
01090                 "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"
01091         },
01092         {       // 4 FAST STROBE
01093                 "mamamamamama",
01094                 "mamamamamama",
01095                 "mamamamamama"
01096         },
01097         {       // 5 GENTLE PULSE 1
01098                 "jklmnopqrstuvwxyzyxwvutsrqponmlkj",
01099                 "jklmnopqrstuvwxyzyxwvutsrqponmlkj",
01100                 "jklmnopqrstuvwxyzyxwvutsrqponmlkj"
01101         },
01102         {       // 6 FLICKER (second variety)
01103                 "nmonqnmomnmomomno",
01104                 "nmonqnmomnmomomno",
01105                 "nmonqnmomnmomomno"
01106         },
01107         {       // 7 CANDLE (second variety)
01108                 "mmmaaaabcdefgmmmmaaaammmaamm",
01109                 "mmmaaaabcdefgmmmmaaaammmaamm",
01110                 "mmmaaaabcdefgmmmmaaaammmaamm"
01111         },
01112         {       // 8 CANDLE (third variety)
01113                 "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa",
01114                 "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa",
01115                 "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"
01116         },
01117         {       // 9 SLOW STROBE (fourth variety)
01118                 "aaaaaaaazzzzzzzz",
01119                 "aaaaaaaazzzzzzzz",
01120                 "aaaaaaaazzzzzzzz"
01121         },
01122         {       // 10 FLUORESCENT FLICKER
01123                 "mmamammmmammamamaaamammma",
01124                 "mmamammmmammamamaaamammma",
01125                 "mmamammmmammamamaaamammma"
01126         },
01127         {       // 11 SLOW PULSE NOT FADE TO BLACK
01128                 "abcdefghijklmnopqrrqponmlkjihgfedcba",
01129                 "abcdefghijklmnopqrrqponmlkjihgfedcba",
01130                 "abcdefghijklmnopqrrqponmlkjihgfedcba"
01131         },
01132         {       // 12 FAST PULSE FOR JEREMY
01133                 "mkigegik",
01134                 "mkigegik",
01135                 "mkigegik"
01136         },
01137         {       // 13 Test Blending
01138                 "abcdefghijklmqrstuvwxyz",
01139                 "zyxwvutsrqmlkjihgfedcba",
01140                 "aammbbzzccllcckkffyyggp"
01141         },
01142         {       // 14
01143                 "",
01144                 "",
01145                 ""
01146         },
01147         {       // 15
01148                 "",
01149                 "",
01150                 ""
01151         },
01152         {       // 16
01153                 "",
01154                 "",
01155                 ""
01156         },
01157         {       // 17
01158                 "",
01159                 "",
01160                 ""
01161         },
01162         {       // 18
01163                 "",
01164                 "",
01165                 ""
01166         },
01167         {       // 19
01168                 "",
01169                 "",
01170                 ""
01171         },
01172         {       // 20
01173                 "",
01174                 "",
01175                 ""
01176         },
01177         {       // 21
01178                 "",
01179                 "",
01180                 ""
01181         },
01182         {       // 22
01183                 "",
01184                 "",
01185                 ""
01186         },
01187         {       // 23
01188                 "",
01189                 "",
01190                 ""
01191         },
01192         {       // 24
01193                 "",
01194                 "",
01195                 ""
01196         },
01197         {       // 25
01198                 "",
01199                 "",
01200                 ""
01201         },
01202         {       // 26
01203                 "",
01204                 "",
01205                 ""
01206         },
01207         {       // 27
01208                 "",
01209                 "",
01210                 ""
01211         },
01212         {       // 28
01213                 "",
01214                 "",
01215                 ""
01216         },
01217         {       // 29
01218                 "",
01219                 "",
01220                 ""
01221         },
01222         {       // 30
01223                 "",
01224                 "",
01225                 ""
01226         },
01227         {       // 31
01228                 "",
01229                 "",
01230                 ""
01231         }
01232 };
01233 
01234 void *precachedKyle = 0;
01235 void scriptrunner_run (gentity_t *self);
01236 
01237 /*QUAKED worldspawn (0 0 0) ?
01238 
01239 Every map should have exactly one worldspawn.
01240 "music"         music wav file
01241 "gravity"       800 is default gravity
01242 "message"       Text to print during connection process
01243 
01244 BSP Options
01245 "gridsize"     size of lighting grid to "X Y Z". default="64 64 128"
01246 "ambient"      scale of global light (from _color)
01247 "fog"          shader name of the global fog texture - must include the full path, such as "textures/rj/fog1"
01248 "distancecull" value for vis for the maximum viewing distance
01249 "chopsize"     value for bsp on the maximum polygon / portal size
01250 "ls_Xr" override lightstyle X with this pattern for Red.
01251 "ls_Xg" green (valid patterns are "a-z")
01252 "ls_Xb" blue (a is OFF, z is ON)
01253 
01254 "fogstart"              override fog start distance and force linear
01255 "radarrange" for Siege/Vehicle radar - default range is 2500
01256 */
01257 extern void EWebPrecache(void); //g_items.c
01258 float g_cullDistance;
01259 void SP_worldspawn( void ) 
01260 {
01261         char            *text, temp[32];
01262         int                     i;
01263         int                     lengthRed, lengthBlue, lengthGreen;
01264 
01265         //I want to "cull" entities out of net sends to clients to reduce
01266         //net traffic on our larger open maps -rww
01267         G_SpawnFloat("distanceCull", "6000.0", &g_cullDistance);
01268         trap_SetServerCull(g_cullDistance);
01269 
01270         G_SpawnString( "classname", "", &text );
01271         if ( Q_stricmp( text, "worldspawn" ) ) {
01272                 G_Error( "SP_worldspawn: The first entity isn't 'worldspawn'" );
01273         }
01274 
01275         for ( i = 0 ; i < level.numSpawnVars ; i++ ) 
01276         {
01277                 if ( Q_stricmp( "spawnscript", level.spawnVars[i][0] ) == 0 )
01278                 {//ONly let them set spawnscript, we don't want them setting an angle or something on the world.
01279                         BG_ParseField( fields, level.spawnVars[i][0], level.spawnVars[i][1], (byte *)&g_entities[ENTITYNUM_WORLD] );
01280                 }
01281         }
01282         //The server will precache the standard model and animations, so that there is no hit
01283         //when the first client connnects.
01284         if (!BGPAFtextLoaded)
01285         {
01286                 BG_ParseAnimationFile("models/players/_humanoid/animation.cfg", bgHumanoidAnimations, qtrue);
01287         }
01288 
01289         if (!precachedKyle)
01290         {
01291                 int defSkin;
01292 
01293                 trap_G2API_InitGhoul2Model(&precachedKyle, "models/players/kyle/model.glm", 0, 0, -20, 0, 0);
01294 
01295                 if (precachedKyle)
01296                 {
01297                         defSkin = trap_R_RegisterSkin("models/players/kyle/model_default.skin");
01298                         trap_G2API_SetSkin(precachedKyle, 0, defSkin, defSkin);
01299                 }
01300         }
01301 
01302         if (!g2SaberInstance)
01303         {
01304                 trap_G2API_InitGhoul2Model(&g2SaberInstance, "models/weapons2/saber/saber_w.glm", 0, 0, -20, 0, 0);
01305 
01306                 if (g2SaberInstance)
01307                 {
01308                         // indicate we will be bolted to model 0 (ie the player) on bolt 0 (always the right hand) when we get copied
01309                         trap_G2API_SetBoltInfo(g2SaberInstance, 0, 0);
01310                         // now set up the gun bolt on it
01311                         trap_G2API_AddBolt(g2SaberInstance, 0, "*blade1");
01312                 }
01313         }
01314 
01315         if (g_gametype.integer == GT_SIEGE)
01316         { //a tad bit of a hack, but..
01317                 EWebPrecache();
01318         }
01319 
01320         // make some data visible to connecting client
01321         trap_SetConfigstring( CS_GAME_VERSION, GAME_VERSION );
01322 
01323         trap_SetConfigstring( CS_LEVEL_START_TIME, va("%i", level.startTime ) );
01324 
01325         G_SpawnString( "music", "", &text );
01326         trap_SetConfigstring( CS_MUSIC, text );
01327 
01328         G_SpawnString( "message", "", &text );
01329         trap_SetConfigstring( CS_MESSAGE, text );                               // map specific message
01330 
01331         trap_SetConfigstring( CS_MOTD, g_motd.string );         // message of the day
01332 
01333         G_SpawnString( "gravity", "800", &text );
01334         trap_Cvar_Set( "g_gravity", text );
01335 
01336         G_SpawnString( "enableBreath", "0", &text );
01337         trap_Cvar_Set( "g_enableBreath", text );
01338 
01339         G_SpawnString( "soundSet", "default", &text );
01340         trap_SetConfigstring( CS_GLOBAL_AMBIENT_SET, text );
01341 
01342         g_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD;
01343         g_entities[ENTITYNUM_WORLD].classname = "worldspawn";
01344 
01345         // see if we want a warmup time
01346         trap_SetConfigstring( CS_WARMUP, "" );
01347         if ( g_restarted.integer ) {
01348                 trap_Cvar_Set( "g_restarted", "0" );
01349                 level.warmupTime = 0;
01350         } 
01351         /*
01352         else if ( g_doWarmup.integer && g_gametype.integer != GT_DUEL && g_gametype.integer != GT_POWERDUEL ) { // Turn it on
01353                 level.warmupTime = -1;
01354                 trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
01355                 G_LogPrintf( "Warmup:\n" );
01356         }
01357         */
01358 
01359         trap_SetConfigstring(CS_LIGHT_STYLES+(LS_STYLES_START*3)+0, defaultStyles[0][0]);
01360         trap_SetConfigstring(CS_LIGHT_STYLES+(LS_STYLES_START*3)+1, defaultStyles[0][1]);
01361         trap_SetConfigstring(CS_LIGHT_STYLES+(LS_STYLES_START*3)+2, defaultStyles[0][2]);
01362         
01363         for(i=1;i<LS_NUM_STYLES;i++)
01364         {
01365                 Com_sprintf(temp, sizeof(temp), "ls_%dr", i);
01366                 G_SpawnString(temp, defaultStyles[i][0], &text);
01367                 lengthRed = strlen(text);
01368                 trap_SetConfigstring(CS_LIGHT_STYLES+((i+LS_STYLES_START)*3)+0, text);
01369 
01370                 Com_sprintf(temp, sizeof(temp), "ls_%dg", i);
01371                 G_SpawnString(temp, defaultStyles[i][1], &text);
01372                 lengthGreen = strlen(text);
01373                 trap_SetConfigstring(CS_LIGHT_STYLES+((i+LS_STYLES_START)*3)+1, text);
01374 
01375                 Com_sprintf(temp, sizeof(temp), "ls_%db", i);
01376                 G_SpawnString(temp, defaultStyles[i][2], &text);
01377                 lengthBlue = strlen(text);
01378                 trap_SetConfigstring(CS_LIGHT_STYLES+((i+LS_STYLES_START)*3)+2, text);
01379 
01380                 if (lengthRed != lengthGreen || lengthGreen != lengthBlue)
01381                 {
01382                         Com_Error(ERR_DROP, "Style %d has inconsistent lengths: R %d, G %d, B %d", 
01383                                 i, lengthRed, lengthGreen, lengthBlue);
01384                 }
01385         }               
01386 }
01387 
01388 //rww - Planning on having something here?
01389 qboolean SP_bsp_worldspawn ( void )
01390 {
01391         return qtrue;
01392 }
01393 
01394 void G_PrecacheSoundsets( void )
01395 {
01396         gentity_t       *ent = NULL;
01397         int i;
01398         int countedSets = 0;
01399 
01400         for ( i = 0; i < MAX_GENTITIES; i++ )
01401         {
01402                 ent = &g_entities[i];
01403 
01404                 if (ent->inuse && ent->soundSet && ent->soundSet[0])
01405                 {
01406                         if (countedSets >= MAX_AMBIENT_SETS)
01407                         {
01408                                 Com_Error(ERR_DROP, "MAX_AMBIENT_SETS was exceeded! (too many soundsets)\n");
01409                         }
01410 
01411                         ent->s.soundSetIndex = G_SoundSetIndex(ent->soundSet);
01412                         countedSets++;
01413                 }
01414         }
01415 }
01416 
01417 /*
01418 ==============
01419 G_SpawnEntitiesFromString
01420 
01421 Parses textual entity definitions out of an entstring and spawns gentities.
01422 ==============
01423 */
01424 void G_SpawnEntitiesFromString( qboolean inSubBSP ) {
01425         // allow calls to G_Spawn*()
01426         level.spawning = qtrue;
01427         level.numSpawnVars = 0;
01428 
01429         // the worldspawn is not an actual entity, but it still
01430         // has a "spawn" function to perform any global setup
01431         // needed by a level (setting configstrings or cvars, etc)
01432         if ( !G_ParseSpawnVars(qfalse) ) {
01433                 G_Error( "SpawnEntities: no entities" );
01434         }
01435 
01436         if (!inSubBSP)
01437         {
01438                 SP_worldspawn();
01439         }
01440         else
01441         {
01442                 // Skip this guy if its worldspawn fails
01443                 if ( !SP_bsp_worldspawn() )
01444                 {
01445                         return;
01446                 }
01447         }
01448 
01449         // parse ents
01450         while( G_ParseSpawnVars(inSubBSP) ) {
01451                 G_SpawnGEntityFromSpawnVars(inSubBSP);
01452         }       
01453 
01454         if( g_entities[ENTITYNUM_WORLD].behaviorSet[BSET_SPAWN] && g_entities[ENTITYNUM_WORLD].behaviorSet[BSET_SPAWN][0] )
01455         {//World has a spawn script, but we don't want the world in ICARUS and running scripts,
01456                 //so make a scriptrunner and start it going.
01457                 gentity_t *script_runner = G_Spawn();
01458                 if ( script_runner )
01459                 {
01460                         script_runner->behaviorSet[BSET_USE] = g_entities[ENTITYNUM_WORLD].behaviorSet[BSET_SPAWN];
01461                         script_runner->count = 1;
01462                         script_runner->think = scriptrunner_run;
01463                         script_runner->nextthink = level.time + 100;
01464 
01465                         if ( script_runner->inuse )
01466                         {
01467                                 trap_ICARUS_InitEnt( script_runner );
01468                         }
01469                 }
01470         }
01471 
01472         if (!inSubBSP)
01473         {
01474                 level.spawning = qfalse;                        // any future calls to G_Spawn*() will be errors
01475         }
01476 
01477         G_PrecacheSoundsets();
01478 }
01479