stvoy-sp-sdk/game/g_spawn.cpp

1235 lines
38 KiB
C++

#include "g_local.h"
#include "g_functions.h"
#include "boltOns.h"
#include "g_infostrings.h"
extern cvar_t *g_spskill;
extern void NAV_GenerateSquadRoutes (int squadPathNum);
// these vars I moved here out of the level_locals_t struct simply because it's pointless to try saving them,
// and the level_locals_t struct is included in the save process... -slc
//
qboolean spawning = qfalse; // the G_Spawn*() functions are valid (only turned on during one function)
int numSpawnVars;
char *spawnVars[MAX_SPAWN_VARS][2]; // key / value pairs
int numSpawnVarChars;
char spawnVarChars[MAX_SPAWN_VARS_CHARS];
//NOTENOTE: Be sure to change the mirrored code in cgmain.cpp
typedef map< string, unsigned char, less<string>, allocator< unsigned char > > namePrecache_m;
namePrecache_m as_preCacheMap;
qboolean G_SpawnString( const char *key, const char *defaultString, char **out ) {
int i;
if ( !spawning ) {
*out = (char *)defaultString;
// G_Error( "G_SpawnString() called while not spawning" );
}
for ( i = 0 ; i < numSpawnVars ; i++ ) {
if ( !strcmp( key, spawnVars[i][0] ) ) {
*out = spawnVars[i][1];
return qtrue;
}
}
*out = (char *)defaultString;
return qfalse;
}
qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out ) {
char *s;
qboolean present;
present = G_SpawnString( key, defaultString, &s );
*out = atof( s );
return present;
}
qboolean G_SpawnInt( const char *key, const char *defaultString, int *out ) {
char *s;
qboolean present;
present = G_SpawnString( key, defaultString, &s );
*out = atoi( s );
return present;
}
qboolean G_SpawnVector( const char *key, const char *defaultString, float *out ) {
char *s;
qboolean present;
present = G_SpawnString( key, defaultString, &s );
sscanf( s, "%f %f %f", &out[0], &out[1], &out[2] );
return present;
}
qboolean G_SpawnVector4( const char *key, const char *defaultString, float *out ) {
char *s;
qboolean present;
present = G_SpawnString( key, defaultString, &s );
sscanf( s, "%f %f %f %f", &out[0], &out[1], &out[2], &out[3] );
return present;
}
qboolean G_SpawnFlag( const char *key, int flag, int *out )
{
//find that key
for ( int i = 0 ; i < numSpawnVars ; i++ )
{
if ( !strcmp( key, spawnVars[i][0] ) )
{
//found the key
if ( atoi( spawnVars[i][1] ) != 0 )
{//if it's non-zero, and in the flag
*out |= flag;
}
else
{//if it's zero, or out the flag
*out &= ~flag;
}
return qtrue;
}
}
return qfalse;
}
stringID_table_t flagTable [] =
{
"noTED", EF_NO_TED,
//stringID_table_t Must end with a null entry
"", NULL
};
//
// fields are needed for spawning from the entity string
//
typedef enum {
F_INT,
F_FLOAT,
F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
F_GSTRING, // string on disk, pointer in memory, TAG_GAME
F_VECTOR,
F_VECTOR4,
F_ANGLEHACK,
F_ENTITY, // index on disk, pointer in memory
F_ITEM, // index on disk, pointer in memory
F_CLIENT, // index on disk, pointer in memory
F_PARM1, // Special case for parms
F_PARM2, // Special case for parms
F_PARM3, // Special case for parms
F_PARM4, // Special case for parms
F_PARM5, // Special case for parms
F_PARM6, // Special case for parms
F_PARM7, // Special case for parms
F_PARM8, // Special case for parms
F_PARM9, // Special case for parms
F_PARM10, // Special case for parms
F_PARM11, // Special case for parms
F_PARM12, // Special case for parms
F_PARM13, // Special case for parms
F_PARM14, // Special case for parms
F_PARM15, // Special case for parms
F_PARM16, // Special case for parms
F_FLAG, // special case for flags
F_IGNORE
} fieldtype_t;
typedef struct
{
char *name;
int ofs;
fieldtype_t type;
int flags;
} field_t;
field_t fields[] = {
//Fields for benefit of Radiant only
{"autobound", FOFS(classname), F_IGNORE},
{"groupname", FOFS(classname), F_IGNORE},
{"noBasicSounds", FOFS(classname), F_IGNORE},//will be looked at separately
{"noCombatSounds", FOFS(classname), F_IGNORE},//will be looked at separately
{"noExtraSounds", FOFS(classname), F_IGNORE},//will be looked at separately
{"classname", FOFS(classname), F_LSTRING},
{"origin", FOFS(s.origin), F_VECTOR},
{"mins", FOFS(mins), F_VECTOR},
{"maxs", FOFS(maxs), F_VECTOR},
{"model", FOFS(model), F_LSTRING},
{"model2", FOFS(model2), F_LSTRING},
{"model3", FOFS(target), F_LSTRING},//for misc_replicator_item only!!!
{"model4", FOFS(target2), F_LSTRING},//for misc_replicator_item only!!!
{"model5", FOFS(target3), F_LSTRING},//for misc_replicator_item only!!!
{"model6", FOFS(target4), F_LSTRING},//for misc_replicator_item only!!!
{"spawnflags", FOFS(spawnflags), F_INT},
{"speed", FOFS(speed), F_FLOAT},
{"duration", FOFS(speed), F_FLOAT},//for psycho jism
{"gravity", FOFS(speed), F_FLOAT},//For target_gravity_change
{"leadDist", FOFS(speed), F_FLOAT},//For waypoint_squadpath
{"interest", FOFS(health), F_INT},//For target_interest
{"target", FOFS(target), F_LSTRING},
{"target2", FOFS(target2), F_LSTRING},
{"target3", FOFS(target3), F_LSTRING},
{"target4", FOFS(target4), F_LSTRING},
{"targetname", FOFS(targetname), F_LSTRING},
{"material", FOFS(material), F_INT},
{"message", FOFS(message), F_LSTRING},
{"infoString", FOFS(infoString), F_LSTRING},
{"team", FOFS(team), F_LSTRING},
{"mapname", FOFS(message), F_LSTRING},
{"wait", FOFS(wait), F_FLOAT},
{"finaltime", FOFS(wait), F_FLOAT},//For dlight
{"random", FOFS(random), F_FLOAT},
{"FOV", FOFS(random), F_FLOAT},//for ref_tags and trigger_visibles
{"count", FOFS(count), F_INT},
{"health", FOFS(health), F_INT},
{"friction", FOFS(health), F_INT},//For target_friction_change
{"light", 0, F_IGNORE},
{"dmg", FOFS(damage), F_INT},
{"angles", FOFS(s.angles), F_VECTOR},
{"angle", FOFS(s.angles), F_ANGLEHACK},
{"cameraGroup", FOFS(cameraGroup), F_LSTRING},
{"radius", FOFS(radius), F_FLOAT},
{"hiderange", FOFS(radius), F_FLOAT},//for triggers only
{"starttime", FOFS(radius), F_FLOAT},//for dlight
{"type", FOFS(count), F_FLOAT},//for fx_crew_beam_in
{"fullName", FOFS(fullName), F_LSTRING},
//Script parms - will this handle clamping to 16 or whatever length of parm[0] is?
{"parm1", 0, F_PARM1},
{"parm2", 0, F_PARM2},
{"parm3", 0, F_PARM3},
{"parm4", 0, F_PARM4},
{"parm5", 0, F_PARM5},
{"parm6", 0, F_PARM6},
{"parm7", 0, F_PARM7},
{"parm8", 0, F_PARM8},
{"parm9", 0, F_PARM9},
{"parm10", 0, F_PARM10},
{"parm11", 0, F_PARM11},
{"parm12", 0, F_PARM12},
{"parm13", 0, F_PARM13},
{"parm14", 0, F_PARM14},
{"parm15", 0, F_PARM15},
{"parm16", 0, F_PARM16},
{"noTED", FOFS(s.eFlags), F_FLAG},
//MCG - Begin
//extra fields for ents
{"delay", FOFS(delay), F_INT},
{"sounds", FOFS(sounds), F_INT},
{"closetarget", FOFS(closetarget), F_LSTRING},//for doors
{"opentarget", FOFS(opentarget), F_LSTRING},//for doors
{"paintarget", FOFS(paintarget), F_LSTRING},//for doors
{"soundGroup", FOFS(paintarget), F_LSTRING},//for target_speakers
{"backwardstarget", FOFS(paintarget), F_LSTRING},//for trigger_bidirectional
{"splashDamage", FOFS(splashDamage), F_INT},
{"splashRadius", FOFS(splashRadius), F_INT},
//Script stuff
{"spawnscript", FOFS(behaviorSet[BSET_SPAWN]), F_LSTRING},//name of script to run
{"idlescript", FOFS(behaviorSet[BSET_IDLE]), F_LSTRING},//name of script to run
{"touchscript", FOFS(behaviorSet[BSET_TOUCH]), F_LSTRING},//name of script to run
{"usescript", FOFS(behaviorSet[BSET_USE]), F_LSTRING},//name of script to run
{"awakescript", FOFS(behaviorSet[BSET_AWAKE]), F_LSTRING},//name of script to run
{"angerscript", FOFS(behaviorSet[BSET_ANGER]), F_LSTRING},//name of script to run
{"attackscript", FOFS(behaviorSet[BSET_ATTACK]), F_LSTRING},//name of script to run
{"victoryscript", FOFS(behaviorSet[BSET_VICTORY]), F_LSTRING},//name of script to run
{"lostenemyscript", FOFS(behaviorSet[BSET_LOSTENEMY]), F_LSTRING},//name of script to run
{"painscript", FOFS(behaviorSet[BSET_PAIN]), F_LSTRING},//name of script to run
{"fleescript", FOFS(behaviorSet[BSET_FLEE]), F_LSTRING},//name of script to run
{"deathscript", FOFS(behaviorSet[BSET_DEATH]), F_LSTRING},//name of script to run
{"delayscript", FOFS(behaviorSet[BSET_DELAYED]), F_LSTRING},//name of script to run
{"delayscripttime", FOFS(delayScriptTime), F_INT},//name of script to run
{"blockedscript", FOFS(behaviorSet[BSET_BLOCKED]), F_LSTRING},//name of script to run
{"ffirescript", FOFS(behaviorSet[BSET_FFIRE]), F_LSTRING},//name of script to run
{"ffdeathscript", FOFS(behaviorSet[BSET_FFDEATH]), F_LSTRING},//name of script to run
{"script_targetname", FOFS(script_targetname), F_LSTRING},//scripts look for this when "affecting"
//For NPCs
//{"playerTeam", FOFS(playerTeam), F_INT},
//{"enemyTeam", FOFS(enemyTeam), F_INT},
{"NPC_targetname", FOFS(NPC_targetname), F_LSTRING},
{"NPC_target", FOFS(NPC_target), F_LSTRING},
{"NPC_target2", FOFS(target2), F_LSTRING},//NPC_spawner only
{"NPC_type", FOFS(NPC_type), F_LSTRING},
//formation
//{"squadname", FOFS(squadname), F_LSTRING},
{"ownername", FOFS(ownername), F_LSTRING},
{"squadtarget", FOFS(paintarget), F_LSTRING},//For squadpoints
//freaky camera shit
{"startRGBA", FOFS(startRGBA), F_VECTOR4},
{"finalRGBA", FOFS(finalRGBA), F_VECTOR4},
//MCG - End
{"soundSet", FOFS(soundSet), F_LSTRING},
{NULL}
};
typedef struct {
char *name;
void (*spawn)(gentity_t *ent);
} spawn_t;
void SP_info_player_start (gentity_t *ent);
void SP_info_player_deathmatch (gentity_t *ent);
void SP_info_player_intermission (gentity_t *ent);
void SP_info_firstplace(gentity_t *ent);
void SP_info_secondplace(gentity_t *ent);
void SP_info_thirdplace(gentity_t *ent);
void SP_func_plat (gentity_t *ent);
void SP_func_static (gentity_t *ent);
void SP_func_rotating (gentity_t *ent);
void SP_func_bobbing (gentity_t *ent);
void SP_func_breakable (gentity_t *self);
void SP_func_pendulum( gentity_t *ent );
void SP_func_button (gentity_t *ent);
void SP_func_door (gentity_t *ent);
void SP_func_train (gentity_t *ent);
void SP_func_timer (gentity_t *self);
void SP_func_wall (gentity_t *ent);
void SP_func_usable( gentity_t *self );
void SP_func_stasis_door( gentity_t *self );
void SP_trigger_always (gentity_t *ent);
void SP_trigger_multiple (gentity_t *ent);
void SP_trigger_once (gentity_t *ent);
void SP_trigger_push (gentity_t *ent);
void SP_trigger_teleport (gentity_t *ent);
void SP_trigger_hurt (gentity_t *ent);
void SP_trigger_formation (gentity_t *ent);
void SP_trigger_bidirectional (gentity_t *ent);
void SP_trigger_entdist (gentity_t *self);
void SP_trigger_location( gentity_t *ent );
void SP_trigger_visible( gentity_t *self );
void SP_target_give (gentity_t *ent);
void SP_target_delay (gentity_t *ent);
void SP_target_speaker (gentity_t *ent);
void SP_target_print (gentity_t *ent);
void SP_target_laser (gentity_t *self);
void SP_target_character (gentity_t *ent);
void SP_target_score( gentity_t *ent );
void SP_target_teleporter( gentity_t *ent );
void SP_target_relay (gentity_t *ent);
void SP_target_kill (gentity_t *ent);
void SP_target_position (gentity_t *ent);
void SP_target_location (gentity_t *ent);
void SP_target_push (gentity_t *ent);
void SP_target_random (gentity_t *self);
void SP_target_counter (gentity_t *self);
void SP_target_create_formation (gentity_t *self);
void SP_target_scriptrunner (gentity_t *self);
void SP_target_interest (gentity_t *self);
void SP_target_activate (gentity_t *self);
void SP_target_deactivate (gentity_t *self);
void SP_target_gravity_change( gentity_t *self );
void SP_target_friction_change( gentity_t *self );
void SP_target_level_change( gentity_t *self );
void SP_target_change_parm( gentity_t *self );
void SP_target_play_music( gentity_t *self );
void SP_target_autosave( gentity_t *self );
void SP_target_interface( gentity_t *self );
void SP_light (gentity_t *self);
void SP_info_null (gentity_t *self);
void SP_info_notnull (gentity_t *self);
void SP_path_corner (gentity_t *self);
void SP_misc_teleporter (gentity_t *self);
void SP_misc_teleporter_dest (gentity_t *self);
void SP_misc_model(gentity_t *ent);
void SP_misc_turret (gentity_t *base);
void SP_laser_arm (gentity_t *base);
void SP_misc_model_borg_ammo( gentity_t *ent );
void SP_misc_model_borg_health( gentity_t *ent );
void SP_misc_model_borg_disnode( gentity_t *ent );
void SP_misc_model_stasis_ammo( gentity_t *ent );
void SP_misc_model_stasis_ammo_floor( gentity_t *ent );
void SP_misc_model_stasis_health( gentity_t *ent );
void SP_misc_model_stasis_health_floor( gentity_t *ent );
void SP_misc_model_scavenger_ammo( gentity_t *ent );
void SP_misc_model_scavenger_health( gentity_t *ent );
void SP_misc_model_forge_ammo( gentity_t *ent );
void SP_misc_model_forge_health( gentity_t *ent );
void SP_misc_model_forge_panel( gentity_t *ent );
void SP_misc_model_forge_defence_grid( gentity_t *ent );
void SP_misc_model_forge_reaver_container( gentity_t *ent );
void SP_misc_model_forge_mega_ammo( gentity_t *ent );
void SP_misc_model_dreadnought_ammo( gentity_t *ent );
void SP_misc_model_dreadnought_health( gentity_t *ent );
void SP_misc_model_stasis_control_switch( gentity_t *ent );
void SP_misc_model_proton_ammo( gentity_t *ent );
void SP_misc_model_proton_health( gentity_t *ent );
void SP_misc_model_plasma_filter( gentity_t *ent );
void SP_misc_model_stasis_crystal_station( gentity_t *ent );
void SP_misc_model_borg_crystal_station( gentity_t *ent );
void SP_misc_model_scav_crystal_station( gentity_t *ent );
void SP_misc_model_dn_crystal_station( gentity_t *ent );
void SP_misc_model_breakable(gentity_t *ent);//stays as an ent
void SP_misc_portal_camera(gentity_t *ent);
void SP_misc_portal_surface(gentity_t *ent);
void SP_misc_camera_focus (gentity_t *self);
void SP_misc_camera_track (gentity_t *self);
void SP_misc_dlight (gentity_t *ent);
void SP_misc_stasis_shooter( gentity_t *self );
void SP_shooter_rocket( gentity_t *ent );
void SP_shooter_plasma( gentity_t *ent );
void SP_shooter_grenade( gentity_t *ent );
void SP_misc_replicator_item( gentity_t *ent );
//New spawn functions
void SP_reference_tag ( gentity_t *ent );
void SP_NPC_spawner( gentity_t *self );
void SP_NPC_starfleet( gentity_t *self );
void SP_NPC_starfleet_random( gentity_t *self );
void SP_NPC_Tuvok( gentity_t *self );
void SP_NPC_Kim( gentity_t *self );
void SP_NPC_Doctor( gentity_t *self);
void SP_NPC_Paris( gentity_t *self);
void SP_NPC_Torres( gentity_t *self);
void SP_NPC_Janeway( gentity_t *self);
void SP_NPC_Seven( gentity_t *self);
void SP_NPC_Chakotay( gentity_t *self);
void SP_NPC_Neelix( gentity_t *self);
void SP_NPC_Vorik( gentity_t *self);
void SP_NPC_Foster( gentity_t *self);
void SP_NPC_Munro( gentity_t *self);
void SP_NPC_MunroScav( gentity_t *self);
void SP_NPC_Telsia( gentity_t *self);
void SP_NPC_Biessman( gentity_t *self);
void SP_NPC_Chang( gentity_t *self);
void SP_NPC_Chell( gentity_t *self);
void SP_NPC_Jurot( gentity_t *self);
void SP_NPC_Parasite( gentity_t *self );
void SP_NPC_borg( gentity_t *self );
void SP_NPC_Stasis( gentity_t *self );
void SP_NPC_klingon( gentity_t *self );
void SP_NPC_Malon( gentity_t *self );
void SP_NPC_Hirogen( gentity_t *self );
void SP_NPC_Hirogen_Alpha( gentity_t *self);
void SP_NPC_Imperial( gentity_t *self );
void SP_NPC_Species8472( gentity_t *self );
void SP_NPC_Headbot( gentity_t *self );
void SP_NPC_scoutbot( gentity_t *self );
void SP_NPC_HunterSeeker( gentity_t *self );
void SP_NPC_HKbot( gentity_t *self ); //FIXME: Obsolete
void SP_NPC_warriorbot( gentity_t *self );
void SP_NPC_Harvester( gentity_t *self );
void SP_NPC_Reaver( gentity_t *self );
void SP_NPC_ReaverGuard( gentity_t *self );
void SP_NPC_Avatar( gentity_t *self );
void SP_NPC_Vohrsoth( gentity_t *self );
void SP_NPC_Desperado( gentity_t *self );
void SP_NPC_Paladin( gentity_t *self );
void SP_NPC_BioHulk( gentity_t *self );
void SP_NPC_ChaoticaGuard( gentity_t *self );
void SP_NPC_Chaotica( gentity_t *self );
void SP_NPC_SatansRobot( gentity_t *self );
void SP_NPC_CaptainProton( gentity_t *self );
void SP_NPC_Buster( gentity_t *self );
void SP_NPC_Goodheart( gentity_t *self );
void SP_ambient_etherian_mine( gentity_t *self );
void SP_ambient_etherian_fixits( gentity_t *self );
void SP_ambient_etherian_fliers (gentity_t *self);
void SP_waypoint (gentity_t *ent);
void SP_waypoint_small (gentity_t *ent);
void SP_waypoint_squadpath (gentity_t *ent);
void SP_waypoint_navgoal (gentity_t *ent);
void SP_waypoint_navgoal_8 (gentity_t *ent);
void SP_waypoint_navgoal_4 (gentity_t *ent);
void SP_waypoint_navgoal_2 (gentity_t *ent);
void SP_waypoint_navgoal_1 (gentity_t *ent);
void SP_fx_spark ( gentity_t *ent );
void SP_fx_steam ( gentity_t *ent );
void SP_fx_bolt ( gentity_t *ent );
void SP_fx_drip ( gentity_t *ent );
void SP_fx_plasma ( gentity_t *ent );
void SP_fx_electricfire ( gentity_t *ent );
void SP_fx_surface_explosion( gentity_t *ent );
void SP_fx_electrical_explosion( gentity_t *ent );
void SP_fx_smoke ( gentity_t *ent );
void SP_fx_teleporter ( gentity_t *ent );
void SP_fx_stream ( gentity_t *ent );
void SP_fx_psycho_jism( gentity_t *ent );
void SP_fx_cooking_steam( gentity_t *ent );
void SP_fx_laser( gentity_t *ent );
void SP_fx_transporter_stream( gentity_t *ent );
void SP_fx_explosion_trail( gentity_t *ent );
void SP_fx_blow_chunks( gentity_t *ent );
void SP_fx_borg_energy_beam( gentity_t *ent );
void SP_fx_shimmery_thing( gentity_t *ent );
void SP_fx_borg_bolt ( gentity_t *ent );
void SP_fx_crew_beam_in( gentity_t *ent );
void SP_fx_forge_bolt( gentity_t *ent );
void SP_fx_stasis_teleporter( gentity_t *ent );
void SP_fx_stasis_mushrooms( gentity_t *ent );
void SP_fx_dn_beam_glow( gentity_t *ent );
void SP_fx_garden_fountain( gentity_t *ent );
void SP_object_cargo_barrel1( gentity_t *ent );
void SP_point_combat (gentity_t *self);
spawn_t spawns[] = {
{"info_player_start", SP_info_player_start},
{"info_player_deathmatch", SP_info_player_deathmatch},
{"func_plat", SP_func_plat},
{"func_button", SP_func_button},
{"func_door", SP_func_door},
{"func_static", SP_func_static},
{"func_rotating", SP_func_rotating},
{"func_bobbing", SP_func_bobbing},
{"func_breakable", SP_func_breakable},
{"func_pendulum", SP_func_pendulum},
{"func_train", SP_func_train},
{"func_timer", SP_func_timer}, // rename trigger_timer?
{"func_wall", SP_func_wall},
{"func_usable", SP_func_usable},
{"func_stasis_door", SP_func_stasis_door},
{"trigger_always", SP_trigger_always},
{"trigger_multiple", SP_trigger_multiple},
{"trigger_once", SP_trigger_once},
{"trigger_push", SP_trigger_push},
{"trigger_teleport", SP_trigger_teleport},
{"trigger_hurt", SP_trigger_hurt},
{"trigger_formation", SP_trigger_formation},
{"trigger_bidirectional", SP_trigger_bidirectional},
{"trigger_entdist", SP_trigger_entdist},
{"trigger_location", SP_trigger_location},
{"trigger_visible", SP_trigger_visible},
{"target_give", SP_target_give},
{"target_delay", SP_target_delay},
{"target_speaker", SP_target_speaker},
{"target_print", SP_target_print},
{"target_laser", SP_target_laser},
{"target_score", SP_target_score},
{"target_teleporter", SP_target_teleporter},
{"target_relay", SP_target_relay},
{"target_kill", SP_target_kill},
{"target_position", SP_target_position},
{"target_location", SP_target_location},
{"target_push", SP_target_push},
{"target_random", SP_target_random},
{"target_counter", SP_target_counter},
{"target_create_formation", SP_target_create_formation},
{"target_scriptrunner", SP_target_scriptrunner},
{"target_interest", SP_target_interest},
{"target_activate", SP_target_activate},
{"target_deactivate", SP_target_deactivate},
{"target_gravity_change", SP_target_gravity_change},
{"target_friction_change", SP_target_friction_change},
{"target_level_change", SP_target_level_change},
{"target_change_parm", SP_target_change_parm},
{"target_play_music", SP_target_play_music},
{"target_autosave", SP_target_autosave},
{"target_interface", SP_target_interface},
{"light", SP_light},
{"info_null", SP_info_null},
{"func_group", SP_info_null},
{"info_notnull", SP_info_notnull}, // use target_position instead
{"path_corner", SP_path_corner},
{"misc_teleporter", SP_misc_teleporter},
{"misc_teleporter_dest", SP_misc_teleporter_dest},
{"misc_model", SP_misc_model},
{"misc_turret", SP_misc_turret},
{"misc_laser_arm", SP_laser_arm},
// Borg misc models
{"misc_model_borg_ammo", SP_misc_model_borg_ammo},
{"misc_model_borg_health", SP_misc_model_borg_health},
{"misc_model_borg_disnode", SP_misc_model_borg_disnode},
// Stasis misc models
{"misc_model_stasis_ammo", SP_misc_model_stasis_ammo},
{"misc_model_stasis_health", SP_misc_model_stasis_health},
{"misc_model_stasis_ammo_floor", SP_misc_model_stasis_ammo_floor},
{"misc_model_stasis_health_floor", SP_misc_model_stasis_health_floor},
{"misc_model_forge_ammo", SP_misc_model_forge_ammo},
{"misc_model_forge_health", SP_misc_model_forge_health},
{"misc_model_forge_panel", SP_misc_model_forge_panel},
{"misc_model_forge_defence_grid", SP_misc_model_forge_defence_grid},
{"misc_model_forge_reaver_container", SP_misc_model_forge_reaver_container},
{"misc_model_forge_mega_ammo", SP_misc_model_forge_mega_ammo},
{"misc_model_dreadnought_ammo", SP_misc_model_dreadnought_ammo},
{"misc_model_dreadnought_health", SP_misc_model_dreadnought_health},
{"misc_model_proton_ammo", SP_misc_model_proton_ammo},
{"misc_model_proton_health", SP_misc_model_proton_health},
{"misc_model_stasis_control_switch", SP_misc_model_stasis_control_switch},
{"misc_model_plasma_filter", SP_misc_model_plasma_filter},
{"misc_model_stasis_crystal_station", SP_misc_model_stasis_crystal_station},
{"misc_model_borg_crystal_station", SP_misc_model_borg_crystal_station},
{"misc_model_dn_crystal_station", SP_misc_model_dn_crystal_station},
{"misc_model_scav_crystal_station", SP_misc_model_scav_crystal_station},
{"misc_model_scavenger_ammo", SP_misc_model_scavenger_ammo},
{"misc_model_scavenger_health", SP_misc_model_scavenger_health},
{"misc_model_breakable", SP_misc_model_breakable},
{"misc_portal_surface", SP_misc_portal_surface},
{"misc_portal_camera", SP_misc_portal_camera},
{"misc_camera_focus", SP_misc_camera_focus},
{"misc_camera_track", SP_misc_camera_track},
{"misc_dlight", SP_misc_dlight},
{"misc_stasis_shooter", SP_misc_stasis_shooter},
{"misc_replicator_item", SP_misc_replicator_item},
{"shooter_rocket", SP_shooter_rocket},
{"shooter_grenade", SP_shooter_grenade},
{"shooter_plasma", SP_shooter_plasma},
{"ref_tag", SP_reference_tag},
//new NPC ents
{"NPC_spawner", SP_NPC_spawner},
{"NPC_starfleet", SP_NPC_starfleet},
{"NPC_starfleet_random", SP_NPC_starfleet_random},
{"NPC_Tuvok", SP_NPC_Tuvok },
{"NPC_Kim", SP_NPC_Kim },
{"NPC_Doctor", SP_NPC_Doctor},
{"NPC_Paris", SP_NPC_Paris},
{"NPC_Torres", SP_NPC_Torres},
{"NPC_Janeway", SP_NPC_Janeway},
{"NPC_Seven", SP_NPC_Seven},
{"NPC_Chakotay", SP_NPC_Chakotay},
{"NPC_Neelix", SP_NPC_Neelix},
{"NPC_Vorik", SP_NPC_Vorik},
{"NPC_Foster", SP_NPC_Foster},
{"NPC_Munro", SP_NPC_Munro},
{"NPC_MunroScav", SP_NPC_MunroScav},
{"NPC_Telsia", SP_NPC_Telsia},
{"NPC_Biessman", SP_NPC_Biessman},
{"NPC_Chang", SP_NPC_Chang},
{"NPC_Chell", SP_NPC_Chell},
{"NPC_Jurot", SP_NPC_Jurot},
{"NPC_Parasite", SP_NPC_Parasite},
{"NPC_borg", SP_NPC_borg},
{"NPC_Stasis", SP_NPC_Stasis},
{"NPC_klingon", SP_NPC_klingon},
{"NPC_Malon", SP_NPC_Malon},
{"NPC_Hirogen", SP_NPC_Hirogen},
{"NPC_Hirogen_Alpha", SP_NPC_Hirogen_Alpha},
{"NPC_Imperial", SP_NPC_Imperial},
{"NPC_Imperial_Blue", SP_NPC_Imperial},
{"NPC_Imperial_Gold", SP_NPC_Imperial},
{"NPC_Imperial_Raider", SP_NPC_Imperial},
{"NPC_Headbot", SP_NPC_Headbot},
{"NPC_scoutbot", SP_NPC_scoutbot},
{"NPC_HKbot", SP_NPC_HKbot}, //FIXME: Obsolete
{"NPC_HunterSeeker", SP_NPC_HunterSeeker},
{"NPC_warriorbot", SP_NPC_warriorbot},
{"NPC_Harvester", SP_NPC_Harvester},
{"NPC_Reaver", SP_NPC_Reaver},
{"NPC_ReaverGuard", SP_NPC_ReaverGuard},
{"NPC_Avatar", SP_NPC_Avatar},
{"NPC_Species8472", SP_NPC_Species8472},
{"NPC_Vohrsoth", SP_NPC_Vohrsoth},
{"NPC_Desperado", SP_NPC_Desperado},
{"NPC_Paladin", SP_NPC_Paladin},
{"NPC_BioHulk", SP_NPC_BioHulk},
{"NPC_ChaoticaGuard", SP_NPC_ChaoticaGuard},
{"NPC_Chaotica", SP_NPC_Chaotica},
{"NPC_SatansRobot", SP_NPC_SatansRobot},
{"NPC_CaptainProton", SP_NPC_CaptainProton},
{"NPC_Buster", SP_NPC_Buster},
{"NPC_Goodheart", SP_NPC_Goodheart},
{"ambient_etherian_mine", SP_ambient_etherian_mine},
{"ambient_etherian_fixits", SP_ambient_etherian_fixits},
{"ambient_etherian_fliers", SP_ambient_etherian_fliers},
{"waypoint", SP_waypoint},
{"waypoint_small", SP_waypoint_small},
{"waypoint_squadpath", SP_waypoint_squadpath},
{"waypoint_navgoal", SP_waypoint_navgoal},
{"waypoint_navgoal_8", SP_waypoint_navgoal_8},
{"waypoint_navgoal_4", SP_waypoint_navgoal_4},
{"waypoint_navgoal_2", SP_waypoint_navgoal_2},
{"waypoint_navgoal_1", SP_waypoint_navgoal_1},
{"fx_spark", SP_fx_spark},
{"fx_steam", SP_fx_steam},
{"fx_bolt", SP_fx_bolt},
{"fx_drip", SP_fx_drip},
{"fx_plasma", SP_fx_plasma},
{"fx_elecfire", SP_fx_electricfire},
{"fx_surface_explosion", SP_fx_surface_explosion},
{"fx_electrical_explosion", SP_fx_electrical_explosion},
{"fx_smoke", SP_fx_smoke},
{"fx_stasis_teleporter", SP_fx_teleporter }, // Really evil name hacking
{"fx_energy_stream", SP_fx_stream },
{"fx_psycho_jism", SP_fx_psycho_jism},
{"fx_cooking_steam", SP_fx_cooking_steam},
{"fx_laser", SP_fx_laser},
{"fx_transporter_stream", SP_fx_transporter_stream},
{"fx_explosion_trail", SP_fx_explosion_trail},
{"fx_blow_chunks", SP_fx_blow_chunks},
{"fx_borg_energy_beam", SP_fx_borg_energy_beam},
{"fx_shimmery_thing", SP_fx_shimmery_thing},
{"fx_borg_bolt", SP_fx_borg_bolt},
{"fx_crew_beam_in", SP_fx_crew_beam_in},
{"fx_forge_bolt", SP_fx_forge_bolt},
{"fx_teleporter", SP_fx_stasis_teleporter}, // Really evil name hacking
{"fx_stasis_mushrooms", SP_fx_stasis_mushrooms},
{"fx_dn_beam_glow", SP_fx_dn_beam_glow},
{"fx_garden_fountain", SP_fx_garden_fountain},
{"object_cargo_barrel1", SP_object_cargo_barrel1},
{"point_combat", SP_point_combat},
{NULL, NULL}
};
/*
===============
G_CallSpawn
Finds the spawn function for the entity and calls it,
returning qfalse if not found
===============
*/
qboolean G_CallSpawn( gentity_t *ent ) {
spawn_t *s;
gitem_t *item;
if ( !ent->classname ) {
gi.Printf (S_COLOR_RED"G_CallSpawn: NULL classname\n");
return qfalse;
}
// check item spawn functions
for ( item=bg_itemlist+1 ; item->classname ; item++ ) {
if ( !strcmp(item->classname, ent->classname) ) {
// found it
G_SpawnItem( ent, item );
return qtrue;
}
}
// check normal spawn functions
for ( s=spawns ; s->name ; s++ ) {
if ( !strcmp(s->name, ent->classname) ) {
// found it
s->spawn(ent);
return qtrue;
}
}
gi.Printf (S_COLOR_RED"%s doesn't have a spawn function\n", ent->classname);
return qfalse;
}
/*
=============
G_NewString
Builds a copy of the string, translating \n to real linefeeds
so message texts can be multi-line
=============
*/
char *G_NewString( const char *string ) {
char *newb, *new_p;
int i,l;
if(!string || !string[0])
{
//gi.Printf(S_COLOR_RED"Error: G_NewString called with NULL string!\n");
return (char *)string;
}
l = strlen(string) + 1;
newb = (char *) G_Alloc( l );
new_p = newb;
// turn \n into a real linefeed
for ( i=0 ; i< l ; i++ ) {
if (string[i] == '\\' && i < l-1) {
i++;
if (string[i] == 'n') {
*new_p++ = '\n';
} else {
*new_p++ = '\\';
}
} else {
*new_p++ = string[i];
}
}
return newb;
}
/*
===============
G_ParseField
Takes a key/value pair and sets the binary values
in a gentity
===============
*/
void Q3_SetParm (int entID, int parmNum, const char *parmValue);
void G_ParseField( const char *key, const char *value, gentity_t *ent ) {
field_t *f;
byte *b;
float v;
vec3_t vec;
vec4_t vec4;
for ( f=fields ; f->name ; f++ ) {
if ( !Q_stricmp(f->name, key) ) {
// found it
b = (byte *)ent;
switch( f->type ) {
case F_LSTRING:
*(char **)(b+f->ofs) = G_NewString (value);
break;
case F_VECTOR:
{
int _iFieldsRead = sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
assert(_iFieldsRead==3);
if (_iFieldsRead!=3)
{
gi.Printf (S_COLOR_YELLOW"G_ParseField: VEC3 sscanf() failed to read 3 floats ('angle' key bug?)\n");
}
((float *)(b+f->ofs))[0] = vec[0];
((float *)(b+f->ofs))[1] = vec[1];
((float *)(b+f->ofs))[2] = vec[2];
break;
}
case F_VECTOR4:
{
int _iFieldsRead = sscanf (value, "%f %f %f %f", &vec4[0], &vec4[1], &vec4[2], &vec4[3]);
assert(_iFieldsRead==4);
if (_iFieldsRead!=4)
{
gi.Printf (S_COLOR_YELLOW"G_ParseField: VEC4 sscanf() failed to read 4 floats\n");
}
((float *)(b+f->ofs))[0] = vec4[0];
((float *)(b+f->ofs))[1] = vec4[1];
((float *)(b+f->ofs))[2] = vec4[2];
((float *)(b+f->ofs))[3] = vec4[3];
break;
}
case F_INT:
*(int *)(b+f->ofs) = atoi(value);
break;
case F_FLOAT:
*(float *)(b+f->ofs) = atof(value);
break;
case F_ANGLEHACK:
v = atof(value);
((float *)(b+f->ofs))[0] = 0;
((float *)(b+f->ofs))[1] = v;
((float *)(b+f->ofs))[2] = 0;
break;
case F_PARM1:
case F_PARM2:
case F_PARM3:
case F_PARM4:
case F_PARM5:
case F_PARM6:
case F_PARM7:
case F_PARM8:
case F_PARM9:
case F_PARM10:
case F_PARM11:
case F_PARM12:
case F_PARM13:
case F_PARM14:
case F_PARM15:
case F_PARM16:
Q3_SetParm( ent->s.number, (f->type - F_PARM1), (char *) value );
break;
case F_FLAG:
{//try to find the proper flag for that key:
int flag = GetIDForString ( flagTable, key );
if ( flag > 0 )
{
G_SpawnFlag( key, flag, (int *)(b+f->ofs) );
}
else
{
gi.Printf (S_COLOR_YELLOW"WARNING: G_ParseField: can't find flag for key %s\n", key);
}
}
break;
default:
case F_IGNORE:
break;
}
return;
}
}
}
static qboolean SpawnForCurrentDifficultySetting( gentity_t *ent )
{
extern cvar_t *com_buildScript;
if (com_buildScript->integer) { //always spawn when building a pak file
return qtrue;
}
if ( ent->spawnflags & ( 1 << (8 + g_spskill->integer )) ) {// easy -256 medium -512 hard -1024
return qfalse;
} else {
return qtrue;
}
}
/*
===================
G_SpawnGEntityFromSpawnVars
Spawn an entity and fill in all of the level fields from
level.spawnVars[], then call the class specfic spawn function
===================
*/
void G_SpawnGEntityFromSpawnVars( void ) {
int i;
gentity_t *ent;
// get the next free entity
ent = G_Spawn();
for ( i = 0 ; i < numSpawnVars ; i++ ) {
G_ParseField( spawnVars[i][0], spawnVars[i][1], ent );
}
G_SpawnInt( "notsingle", "0", &i );
if ( i || !SpawnForCurrentDifficultySetting( ent ) ) {
G_FreeEntity( ent );
return;
}
// move editor origin to pos
VectorCopy( ent->s.origin, ent->s.pos.trBase );
VectorCopy( ent->s.origin, ent->currentOrigin );
if ( VALIDSTRING( ent->infoString ) )
{
int inf;
// The infoString, if there is one, should just be the enum, so get the index
inf = IS_GetInfostring( ent->infoString );
if ( inf )
{
// Now we'll get the real infostring
ent->infoString = bg_infoItemList[inf].infoString;
VectorCopy( bg_infoItemList[inf].color, ent->startRGBA );
}
else
{
// Hmmm, bogus infostring
ent->infoString = NULL;
}
}
// if we didn't get a classname, don't bother spawning anything
if ( !G_CallSpawn( ent ) ) {
G_FreeEntity( ent );
return;
}
//Tag on the ICARUS scripting information only to valid recipients
if ( ICARUS_ValidEnt( ent ) )
{
ICARUS_InitEnt( ent );
if ( ent->classname && ent->classname[0] )
{
if ( strncmp( "NPC_", ent->classname, 4 ) != 0 )
{//Not an NPC_spawner
if ( ent->behaviorSet[BSET_SPAWN] )
{
G_ActivateBehavior( ent, BSET_SPAWN );
}
}
}
}
G_InitBoltOnData( ent );
}
/*
====================
G_AddSpawnVarToken
====================
*/
char *G_AddSpawnVarToken( const char *string ) {
int l;
char *dest;
l = strlen( string );
if ( numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) {
G_Error( "G_AddSpawnVarToken: MAX_SPAWN_VARS" );
}
dest = spawnVarChars + numSpawnVarChars;
memcpy( dest, string, l+1 );
numSpawnVarChars += l + 1;
return dest;
}
/*
====================
G_ParseSpawnVars
Parses a brace bounded set of key / value pairs out of the
level's entity strings into level.spawnVars[]
This does not actually spawn an entity.
====================
*/
qboolean G_ParseSpawnVars( char **data ) {
char keyname[MAX_STRING_CHARS];
char *com_token;
numSpawnVars = 0;
numSpawnVarChars = 0;
// parse the opening brace
com_token = COM_Parse( data );
if ( !*data ) {
// end of spawn string
return qfalse;
}
if ( com_token[0] != '{' ) {
G_Error( "G_ParseSpawnVars: found %s when expecting {",com_token );
}
// go through all the key / value pairs
while ( 1 ) {
// parse key
com_token = COM_Parse( data );
if ( com_token[0] == '}' ) {
break;
}
if ( !data ) {
G_Error( "G_ParseSpawnVars: EOF without closing brace" );
}
Q_strncpyz( keyname, com_token, sizeof(keyname) );
// parse value
com_token = COM_Parse( data );
if ( com_token[0] == '}' ) {
G_Error( "G_ParseSpawnVars: closing brace without data" );
}
if ( !data ) {
G_Error( "G_ParseSpawnVars: EOF without closing brace" );
}
if ( numSpawnVars == MAX_SPAWN_VARS ) {
G_Error( "G_ParseSpawnVars: MAX_SPAWN_VARS" );
}
spawnVars[ numSpawnVars ][0] = G_AddSpawnVarToken( keyname );
spawnVars[ numSpawnVars ][1] = G_AddSpawnVarToken( com_token );
numSpawnVars++;
}
return qtrue;
}
/*QUAKED worldspawn (0 0 0) ?
Every map should have exactly one worldspawn.
"music" path to WAV or MP3 files (e.g. "music\intro.mp3 music\loopfile.mp3")
"gravity" 800 is default gravity
"message" Text to print during connection process
"soundSet" Ambient sound set to play when map is started
"spawnscript" runs this script
*/
void SP_worldspawn( void ) {
char *s;
int i;
for ( i = 0 ; i < numSpawnVars ; i++ )
{
if ( Q_stricmp( "spawnscript", spawnVars[i][0] ) == 0 )
{//ONly let them set spawnscript, we don't want them setting an angle or something on the world.
G_ParseField( spawnVars[i][0], spawnVars[i][1], &g_entities[ENTITYNUM_WORLD] );
}
}
G_SpawnString( "classname", "", &s );
if ( Q_stricmp( s, "worldspawn" ) ) {
G_Error( "SP_worldspawn: The first entity isn't 'worldspawn'" );
}
// make some data visible to connecting client
G_SpawnString( "music", "", &s );
gi.SetConfigstring( CS_MUSIC, s );
G_SpawnString( "infostring", "", &s );
if (*s)
{
int inf;
// The infoString, if there is one, should just be the enum, so get the index
inf = IS_GetInfostring( s );
if ( inf )
{
// map specific message
// Now we'll get the real infostring
s = va("%i",inf);
gi.SetConfigstring( CS_MESSAGE, s );
}
}
else
{
G_SpawnString( "message", "", &s );
gi.SetConfigstring( CS_MESSAGE, s ); // map specific message
}
G_SpawnString( "gravity", "800", &s );
extern SavedGameJustLoaded_e g_eSavedGameJustLoaded;
if (g_eSavedGameJustLoaded != eFULL)
{
gi.cvar_set( "g_gravity", s );
}
G_SpawnString( "soundSet", "default", &s );
gi.SetConfigstring( CS_AMBIENT_SET, s );
g_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD;
g_entities[ENTITYNUM_WORLD].classname = "worldspawn";
}
/*
-------------------------
G_ParsePrecaches
-------------------------
*/
void G_ParsePrecaches( void )
{
gentity_t *ent = NULL;
//Clear any old lists
as_preCacheMap.clear();
for ( int i = 0; i < globals.num_entities; i++ )
{
ent = &g_entities[i];
if VALIDSTRING( ent->soundSet )
{
as_preCacheMap[ (char *) ent->soundSet ] = 1;
}
}
}
/*
==============
G_SpawnEntitiesFromString
Parses textual entity definitions out of an entstring and spawns gentities.
==============
*/
extern int num_waypoints;
extern void RG_RouteGen(void);
extern void NAV_GenerateSquadPaths (void);
extern qboolean NPCsPrecached;
void G_SpawnEntitiesFromString( const char *entityString ) {
char *entities;
entities = (char *)entityString; // I had problems getting the compiler to live with const
// allow calls to G_Spawn*()
spawning = qtrue;
NPCsPrecached = qfalse;
numSpawnVars = 0;
// the worldspawn is not an actual entity, but it still
// has a "spawn" function to perform any global setup
// needed by a level (setting configstrings or cvars, etc)
if ( !G_ParseSpawnVars( &entities ) ) {
G_Error( "SpawnEntities: no entities" );
}
SP_worldspawn();
// parse ents
while( G_ParseSpawnVars( &entities ) )
{
G_SpawnGEntityFromSpawnVars();
}
//Search the entities for precache information
G_ParsePrecaches();
if( g_entities[ENTITYNUM_WORLD].behaviorSet[BSET_SPAWN] && g_entities[ENTITYNUM_WORLD].behaviorSet[BSET_SPAWN][0] )
{//World has a spawn script, but we don't want the world in ICARUS and running scripts,
//so make a scriptrunner and start it going.
gentity_t *script_runner = G_Spawn();
if ( script_runner )
{
script_runner->behaviorSet[BSET_USE] = g_entities[ENTITYNUM_WORLD].behaviorSet[BSET_SPAWN];
script_runner->count = 1;
script_runner->e_ThinkFunc = thinkF_scriptrunner_run;
script_runner->nextthink = level.time + 100;
if ( ICARUS_ValidEnt( script_runner ) )
{
ICARUS_InitEnt( script_runner );
}
}
}
//gi.Printf(S_COLOR_YELLOW"Total waypoints: %d\n", num_waypoints);
//Automatically run routegen
//RG_RouteGen();
NAV_GenerateSquadPaths();
spawning = qfalse; // any future calls to G_Spawn*() will be errors
}