/* * G_Teams_InitLevel */ void G_Teams_Init( void ) { edict_t *ent; // set the team names with default ones trap_ConfigString( CS_TEAM_SPECTATOR_NAME, GS_DefaultTeamName( TEAM_SPECTATOR ) ); trap_ConfigString( CS_TEAM_PLAYERS_NAME, GS_DefaultTeamName( TEAM_PLAYERS ) ); trap_ConfigString( CS_TEAM_ALPHA_NAME, GS_DefaultTeamName( TEAM_ALPHA ) ); trap_ConfigString( CS_TEAM_BETA_NAME, GS_DefaultTeamName( TEAM_BETA ) ); g_teams_maxplayers = trap_Cvar_Get( "g_teams_maxplayers", "0", CVAR_ARCHIVE ); g_teams_allow_uneven = trap_Cvar_Get( "g_teams_allow_uneven", "1", CVAR_ARCHIVE ); //unlock all teams and clear up team lists memset( teamlist, 0, sizeof( teamlist ) ); for( ent = game.edicts + 1; PLAYERNUM( ent ) < gs.maxclients; ent++ ) { if( ent->r.inuse ) { memset( &ent->r.client->teamstate, 0, sizeof( ent->r.client->teamstate ) ); memset( &ent->r.client->resp, 0, sizeof( ent->r.client->resp ) ); ent->s.team = ent->r.client->team = TEAM_SPECTATOR; G_GhostClient( ent ); ent->movetype = MOVETYPE_NOCLIP; // allow freefly ent->r.client->teamstate.timeStamp = level.time; ent->r.client->resp.timeStamp = level.time; } } }
static void light_use( edict_t *self, edict_t *other, edict_t *activator ) { if( self->spawnflags & START_OFF ) { trap_ConfigString( CS_LIGHTS+self->style, "m" ); self->spawnflags &= ~START_OFF; } else { trap_ConfigString( CS_LIGHTS+self->style, "a" ); self->spawnflags |= START_OFF; } }
/* * TVM_AddGameCommand */ static void TVM_AddGameCommand( tvm_relay_t *relay, const char *name, void *callback ) { int i; #ifndef NDEBUG // check for double add for( i = 0; i < MAX_GAMECOMMANDS; i++ ) { if( g_Commands[i].name[0] == '\0' ) { continue; } if( !Q_stricmp( g_Commands[i].name, name ) ) { assert( false ); } } #endif // find a free one and add it for( i = 0; i < MAX_GAMECOMMANDS; i++ ) { if( g_Commands[i].name[0] == '\0' ) { g_Commands[i].func = callback; Q_strncpyz( g_Commands[i].name, name, sizeof( g_Commands[i].name ) ); trap_ConfigString( relay, CS_GAMECOMMANDS + i, name ); return; } } TVM_RelayError( relay, "G_AddCommand: Couldn't find a free g_Commands spot for the new command\n" ); }
/* * TVM_SpawnEntities * * Creates a server's entity / program execution context by * parsing textual entity definitions out of an ent file. */ void TVM_SpawnEntities( tvm_relay_t *relay, const char *mapname, const char *entities, int entstrlen ) { edict_t *ent; int i; assert( mapname ); Q_strncpyz( relay->mapname, mapname, sizeof( relay->mapname ) ); GClip_ClearWorld( relay ); // clear areas links memset( relay->edicts, 0, relay->maxentities * sizeof( relay->edicts[0] ) ); for( i = 0, ent = &relay->edicts[0]; i < relay->maxentities; i++, ent++ ) { ent->relay = relay; ent->s.number = i; } relay->numentities = 0; // overwrite gamecommands from the relay for( i = 0; i < MAX_GAMECOMMANDS; i++ ) { assert( CS_GAMECOMMANDS + i < MAX_CONFIGSTRINGS ); relay->configStringsOverwritten[CS_GAMECOMMANDS + i] = true; trap_ConfigString( relay, CS_GAMECOMMANDS + i, "" ); } TVM_RemoveGameCommands( relay ); TVM_AddGameCommands( relay ); }
/* * G_PrecacheGameCommands */ void G_PrecacheGameCommands( void ) { int i; for( i = 0; i < MAX_GAMECOMMANDS; i++ ) trap_ConfigString( CS_GAMECOMMANDS + i, g_Commands[i].name ); }
static void G_Gametype_GENERIC_Init( void ) { trap_ConfigString( CS_GAMETYPETITLE, "Generic Deathmatch" ); trap_ConfigString( CS_GAMETYPEVERSION, "1.0" ); trap_ConfigString( CS_GAMETYPEAUTHOR, "Warsow Development Team" ); trap_Cvar_ForceSet( "g_gametype", "generic" ); level.gametype.spawnableItemsMask = ( IT_WEAPON|IT_AMMO|IT_ARMOR|IT_POWERUP|IT_HEALTH ); level.gametype.respawnableItemsMask = ( IT_WEAPON|IT_AMMO|IT_ARMOR|IT_POWERUP|IT_HEALTH ); level.gametype.dropableItemsMask = ( IT_WEAPON|IT_AMMO|IT_ARMOR|IT_POWERUP|IT_HEALTH ); level.gametype.pickableItemsMask = ( level.gametype.spawnableItemsMask|level.gametype.dropableItemsMask ); if( GS_Instagib() ) level.gametype.pickableItemsMask &= ~G_INSTAGIB_NEGATE_ITEMMASK; level.gametype.isTeamBased = false; level.gametype.isRace = false; level.gametype.isTutorial = false; level.gametype.inverseScore = false; level.gametype.hasChallengersQueue = false; level.gametype.maxPlayersPerTeam = 0; level.gametype.ammo_respawn = 20; level.gametype.armor_respawn = 25; level.gametype.weapon_respawn = 5; level.gametype.health_respawn = 25; level.gametype.powerup_respawn = 90; level.gametype.megahealth_respawn = 20; level.gametype.ultrahealth_respawn = 60; level.gametype.countdownEnabled = false; level.gametype.mathAbortDisabled = false; level.gametype.canForceModels = true; level.gametype.canShowMinimap = false; level.gametype.teamOnlyMinimap = true; level.gametype.spawnpointRadius = 256; level.gametype.canShowMinimap = false; level.gametype.teamOnlyMinimap = true; level.gametype.mmCompatible = false; if( GS_Instagib() ) level.gametype.spawnpointRadius *= 2; trap_ConfigString( CS_SCB_PLAYERTAB_LAYOUT, "%n 164 %i 64 %l 48 %p 18 %p 18" ); trap_ConfigString( CS_SCB_PLAYERTAB_TITLES, "Name Score Ping C R" ); }
//QUAKED worldspawn (0 0 0) ? // //Only used for the world. //"sky" environment map name //"skyaxis" vector axis for rotating sky //"skyrotate" speed of rotation in degrees/second //"sounds" music cd track number //"gravity" 800 is default gravity //"message" text to print at user logon //======================== static void SP_worldspawn( edict_t *ent ) { ent->movetype = MOVETYPE_PUSH; ent->r.solid = SOLID_YES; ent->r.inuse = true; // since the world doesn't use G_Spawn() VectorClear( ent->s.origin ); VectorClear( ent->s.angles ); GClip_SetBrushModel( ent, "*0" ); // sets mins / maxs and modelindex 1 G_PureModel( "*0" ); if( st.nextmap ) Q_strncpyz( level.nextmap, st.nextmap, sizeof( level.nextmap ) ); // make some data visible to the server /* message = trap_GetFullnameFromMapList( level.mapname ); if( message && message[0] ) ent->message = G_LevelCopyString( message ); */ if( ent->message && ent->message[0] ) { trap_ConfigString( CS_MESSAGE, ent->message ); Q_strncpyz( level.level_name, ent->message, sizeof( level.level_name ) ); } else { trap_ConfigString( CS_MESSAGE, level.mapname ); Q_strncpyz( level.level_name, level.mapname, sizeof( level.level_name ) ); } // send music if( st.music ) { trap_ConfigString( CS_AUDIOTRACK, st.music ); trap_PureSound( st.music ); } if( st.gravity ) level.gravity = atof( st.gravity ); if( st.colorCorrection ) { level.colorCorrection = trap_ImageIndex( st.colorCorrection ); gs.gameState.stats[GAMESTAT_COLORCORRECTION] = level.colorCorrection; } }
void SP_light( edict_t *self ) { if( !self->targetname ) { G_FreeEdict( self ); return; } if( self->style >= 32 ) { self->use = light_use; if( self->spawnflags & START_OFF ) trap_ConfigString( CS_LIGHTS+self->style, "a" ); else trap_ConfigString( CS_LIGHTS+self->style, "m" ); } }
/*QUAKED props_skyportal (.6 .7 .7) (-8 -8 0) (8 8 16) "fov" for the skybox default is whatever client's fov is set to "scale" is world/skyarea ratio if you want to keep a certain perspective when player moves around the world "noents" makes the skyportal ignore entities within the sky area, making them invisible for the player */ void SP_skyportal( edict_t *ent ) { // default to client's FOV // if (!st.fov) // st.fov = 90; ent->r.svflags = SVF_NOCLIENT; trap_ConfigString( CS_SKYBOX, va( "%.3f %.3f %.3f %.1f %.1f %d %.1f %.1f %.1f", ent->s.origin[0], ent->s.origin[1], ent->s.origin[2], st.fov, st.scale, st.noents, ent->s.angles[0], ent->s.angles[1], ent->s.angles[2] ) ); }
/* * TVM_RemoveGameCommands */ void TVM_RemoveGameCommands( tvm_relay_t *relay ) { int i; for( i = 0; i < MAX_GAMECOMMANDS; i++ ) { if( g_Commands[i].name[0] != '\0' ) { g_Commands[i].func = NULL; g_Commands[i].name[0] = 0; trap_ConfigString( relay, CS_GAMECOMMANDS + i, "" ); } } }
/* * ClientDisconnect * Called when a player drops from the server. * Will not be called between levels. */ void ClientDisconnect( edict_t *ent, const char *reason ) { int team; if( !ent->r.client || !ent->r.inuse ) return; // always report in RACE mode if( GS_RaceGametype() || ( ent->r.client->team != TEAM_SPECTATOR && ( GS_MatchState() == MATCH_STATE_PLAYTIME || GS_MatchState() == MATCH_STATE_POSTMATCH ) ) ) G_AddPlayerReport( ent, GS_MatchState() == MATCH_STATE_POSTMATCH ); for( team = TEAM_PLAYERS; team < GS_MAX_TEAMS; team++ ) G_Teams_UnInvitePlayer( team, ent ); if( !level.gametype.disableObituaries || !(ent->r.svflags & SVF_FAKECLIENT ) ) { if( !reason ) G_PrintMsg( NULL, "%s" S_COLOR_WHITE " disconnected\n", ent->r.client->netname ); else G_PrintMsg( NULL, "%s" S_COLOR_WHITE " disconnected (%s" S_COLOR_WHITE ")\n", ent->r.client->netname, reason ); } // send effect if( ent->s.team > TEAM_SPECTATOR ) G_TeleportEffect( ent, false ); ent->r.client->team = TEAM_SPECTATOR; G_ClientRespawn( ent, true ); // respawn as ghost ent->movetype = MOVETYPE_NOCLIP; // allow freefly // let the gametype scripts know this client just disconnected G_Gametype_ScoreEvent( ent->r.client, "disconnect", NULL ); G_FreeAI( ent ); AI_EnemyRemoved( ent ); ent->r.inuse = false; ent->r.svflags = SVF_NOCLIENT; memset( ent->r.client, 0, sizeof( *ent->r.client ) ); ent->r.client->ps.playerNum = PLAYERNUM( ent ); trap_ConfigString( CS_PLAYERINFOS+PLAYERNUM( ent ), "" ); GClip_UnlinkEntity( ent ); G_Match_CheckReadys(); }
/* * G_AddCommand */ void G_AddCommand( const char *name, gamecommandfunc_t callback ) { int i; char temp[MAX_QPATH]; static const char *blacklist[] = { "callvotevalidate", "callvotepassed", NULL }; Q_strncpyz( temp, name, sizeof( temp ) ); for( i = 0; blacklist[i] != NULL; i++ ) { if( !Q_stricmp( blacklist[i], temp ) ) { G_Printf( "WARNING: G_AddCommand: command name '%s' is write protected\n", temp ); return; } } // see if we already had it in game side for( i = 0; i < MAX_GAMECOMMANDS; i++ ) { if( !g_Commands[i].name[0] ) break; if( !Q_stricmp( g_Commands[i].name, temp ) ) { // update func if different if( g_Commands[i].func != callback ) g_Commands[i].func = ( gamecommandfunc_t )callback; return; } } if( i == MAX_GAMECOMMANDS ) { G_Error( "G_AddCommand: Couldn't find a free g_Commands spot for the new command. (increase MAX_GAMECOMMANDS)\n" ); return; } // we don't have it, add it g_Commands[i].func = ( gamecommandfunc_t )callback; Q_strncpyz( g_Commands[i].name, temp, sizeof( g_Commands[i].name ) ); // add the configstring if the precache process was already done if( level.canSpawnEntities ) trap_ConfigString( CS_GAMECOMMANDS + i, g_Commands[i].name ); }
/* * G_UpdatePlayerInfoString */ static void G_UpdatePlayerInfoString( int playerNum ) { char playerString[MAX_INFO_STRING]; gclient_t *client; assert( playerNum >= 0 && playerNum < gs.maxclients ); client = &game.clients[playerNum]; // update client information in cgame playerString[0] = 0; Info_SetValueForKey( playerString, "name", client->netname ); Info_SetValueForKey( playerString, "hand", va( "%i", client->hand ) ); Info_SetValueForKey( playerString, "color", va( "%i %i %i", client->color[0], client->color[1], client->color[2] ) ); playerString[MAX_CONFIGSTRING_CHARS-1] = 0; trap_ConfigString( CS_PLAYERINFOS + playerNum, playerString ); }
static void target_lightramp_think( edict_t *self ) { char style[2]; style[0] = 'a' + self->moveinfo.movedir[0] + ( level.time - self->timeStamp ) / game.snapFrameTime * self->moveinfo.movedir[2]; style[1] = 0; trap_ConfigString( CS_LIGHTS+self->enemy->style, style ); if( level.time - self->timeStamp < self->speed * 1000 ) { self->nextThink = level.time + 1; } else if( self->spawnflags & 1 ) { char temp; temp = self->moveinfo.movedir[0]; self->moveinfo.movedir[0] = self->moveinfo.movedir[1]; self->moveinfo.movedir[1] = temp; self->moveinfo.movedir[2] *= -1; } }
/* * G_UpdateMMPlayerInfoString */ static void G_UpdateMMPlayerInfoString( int playerNum ) { char playerString[MAX_INFO_STRING]; gclient_t *client; assert( playerNum >= 0 && playerNum < gs.maxclients ); client = &game.clients[playerNum]; if( playerNum >= MAX_MMPLAYERINFOS ) { return; // oops } // update client information in cgame playerString[0] = 0; if( client->mmflags != 0 ) { Info_SetValueForKey( playerString, "f", va( "%x", client->mmflags ) ); // use hex for shorter representation } playerString[MAX_CONFIGSTRING_CHARS-1] = 0; trap_ConfigString( CS_MMPLAYERINFOS + playerNum, playerString ); }
/* * SetItemNames * * Called by worldspawn */ void G_PrecacheItems( void ) { int i; gsitem_t *item; // precache item names and weapondefs for( i = 1; ( item = GS_FindItemByTag( i ) ) != NULL; i++ ) { trap_ConfigString( CS_ITEMS + i, item->name ); if( item->type & IT_WEAPON && GS_GetWeaponDef( item->tag ) ) { G_PrecacheWeapondef( i, &GS_GetWeaponDef( item->tag )->firedef ); G_PrecacheWeapondef( i, &GS_GetWeaponDef( item->tag )->firedef_weak ); } } // precache items if( GS_Instagib() ) { item = GS_FindItemByTag( WEAP_INSTAGUN ); PrecacheItem( item ); } else { for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ ) { item = GS_FindItemByTag( i ); PrecacheItem( item ); } } // Vic: precache ammo pack if it's droppable item = GS_FindItemByClassname( "item_ammopack" ); if( item && G_Gametype_CanDropItem( item, qtrue ) ) { PrecacheItem( item ); } }
/* * G_Gametype_Init */ void G_Gametype_Init( void ) { bool changed = false; const char *mapGametype; g_gametypes_list = trap_Cvar_Get( "g_gametypes_list", "", CVAR_NOSET|CVAR_ARCHIVE ); G_Gametype_GenerateGametypesList(); // fill the g_gametypes_list cvar // empty string to allow all g_votable_gametypes = trap_Cvar_Get( "g_votable_gametypes", "", CVAR_ARCHIVE ); if( !g_gametype ) // first time initialized changed = true; g_gametype = trap_Cvar_Get( "g_gametype", "dm", CVAR_SERVERINFO|CVAR_ARCHIVE|CVAR_LATCH ); //get the match cvars too g_warmup_timelimit = trap_Cvar_Get( "g_warmup_timelimit", "5", CVAR_ARCHIVE ); g_postmatch_timelimit = trap_Cvar_Get( "g_postmatch_timelimit", "4", CVAR_ARCHIVE ); g_countdown_time = trap_Cvar_Get( "g_countdown_time", "5", CVAR_ARCHIVE ); g_match_extendedtime = trap_Cvar_Get( "g_match_extendedtime", "2", CVAR_ARCHIVE ); // game settings g_timelimit = trap_Cvar_Get( "g_timelimit", "10", CVAR_ARCHIVE ); g_scorelimit = trap_Cvar_Get( "g_scorelimit", "0", CVAR_ARCHIVE ); g_allow_falldamage = trap_Cvar_Get( "g_allow_falldamage", "1", CVAR_ARCHIVE ); g_allow_selfdamage = trap_Cvar_Get( "g_allow_selfdamage", "1", CVAR_ARCHIVE ); g_allow_teamdamage = trap_Cvar_Get( "g_allow_teamdamage", "1", CVAR_ARCHIVE ); g_allow_bunny = trap_Cvar_Get( "g_allow_bunny", "1", CVAR_ARCHIVE|CVAR_READONLY ); // map-specific gametype mapGametype = G_asCallMapGametype(); if( mapGametype[0] && G_Gametype_Exists( mapGametype ) ) trap_Cvar_Set( g_gametype->name, mapGametype ); // update latched gametype change if( g_gametype->latched_string ) { if( G_Gametype_Exists( g_gametype->latched_string ) ) { trap_Cvar_ForceSet( "g_gametype", va( "%s", g_gametype->latched_string ) ); changed = true; } else { G_Printf( "G_Gametype: Invalid new gametype, change ignored\n" ); trap_Cvar_ForceSet( "g_gametype", va( "%s", g_gametype->string ) ); } } if( !G_Gametype_Exists( g_gametype->string ) ) { G_Printf( "G_Gametype: Wrong value: '%s'. Setting up with default (dm)\n", g_gametype->string ); trap_Cvar_ForceSet( "g_gametype", "dm" ); changed = true; } G_Printf( "-------------------------------------\n" ); G_Printf( "Initalizing '%s' gametype\n", g_gametype->string ); if( changed ) { const char *configs_path = "configs/server/gametypes/"; G_InitChallengersQueue(); // print a hint for admins so they know there's a chance to execute a // config here, but don't show it as an error, because it isn't G_Printf( "loading %s%s.cfg\n", configs_path, g_gametype->string ); trap_Cmd_ExecuteText( EXEC_NOW, va( "exec %s%s.cfg silent\n", configs_path, g_gametype->string ) ); trap_Cbuf_Execute(); // on a listen server, override gametype-specific settings in config trap_Cmd_ExecuteText( EXEC_NOW, "vstr ui_startservercmd\n" ); trap_Cbuf_Execute(); } // fixme: we are doing this twice because the gametype may check for GS_Instagib G_CheckCvars(); // update GS_Instagib, GS_FallDamage, etc G_Gametype_SetDefaults(); // Init the current gametype if( !GT_asLoadScript( g_gametype->string ) ) G_Gametype_GENERIC_Init(); GS_SetGametypeName( g_gametype->string ); trap_ConfigString( CS_GAMETYPENAME, g_gametype->string ); G_CheckCvars(); // update GS_Instagib, GS_FallDamage, etc // ch : if new gametype has been initialized, transfer the // client-specific ratings to gametype-specific list if( changed ) G_TransferRatings(); }
/* * SpawnEntities * * Creates a server's entity / program execution context by * parsing textual entity definitions out of an ent file. */ void G_InitLevel( char *mapname, char *entities, int entstrlen, unsigned int levelTime, unsigned int serverTime, unsigned int realTime ) { char *mapString = NULL; char name[MAX_CONFIGSTRING_CHARS]; int i; edict_t *ent; char *token; const gsitem_t *item; G_asGarbageCollect( true ); GT_asCallShutdown(); G_asCallMapExit(); G_asShutdownMapScript(); GT_asShutdownScript(); G_FreeCallvotes(); game.serverTime = serverTime; game.realtime = realTime; game.levelSpawnCount++; GClip_ClearWorld(); // clear areas links if( !entities ) G_Error( "G_SpawnLevel: NULL entities string\n" ); // make a copy of the raw entities string so it's not freed with the pool mapString = ( char * )G_Malloc( entstrlen + 1 ); memcpy( mapString, entities, entstrlen ); Q_strncpyz( name, mapname, sizeof( name ) ); // clear old data G_LevelInitPool( strlen( mapname ) + 1 + ( entstrlen + 1 ) * 2 + G_LEVELPOOL_BASE_SIZE ); G_StringPoolInit(); memset( &level, 0, sizeof( level_locals_t ) ); memset( &gs.gameState, 0, sizeof( gs.gameState ) ); level.spawnedTimeStamp = game.realtime; level.time = levelTime; level.gravity = g_gravity->value; // get the strings back Q_strncpyz( level.mapname, name, sizeof( level.mapname ) ); level.mapString = ( char * )G_LevelMalloc( entstrlen + 1 ); level.mapStrlen = entstrlen; memcpy( level.mapString, mapString, entstrlen ); G_Free( mapString ); mapString = NULL; // make a copy of the raw entities string for parsing level.map_parsed_ents = ( char * )G_LevelMalloc( entstrlen + 1 ); level.map_parsed_ents[0] = 0; if( !level.time ) memset( game.edicts, 0, game.maxentities * sizeof( game.edicts[0] ) ); else { G_FreeEdict( world ); for( i = gs.maxclients + 1; i < game.maxentities; i++ ) { if( game.edicts[i].r.inuse ) G_FreeEdict( game.edicts + i ); } } game.numentities = gs.maxclients + 1; // link client fields on player ents for( i = 0; i < gs.maxclients; i++ ) { game.edicts[i+1].s.number = i+1; game.edicts[i+1].r.client = &game.clients[i]; game.edicts[i+1].r.inuse = ( trap_GetClientState( i ) >= CS_CONNECTED ) ? true : false; memset( &game.clients[i].level, 0, sizeof( game.clients[0].level ) ); game.clients[i].level.timeStamp = level.time; } // initialize game subsystems trap_ConfigString( CS_MAPNAME, level.mapname ); trap_ConfigString( CS_SKYBOX, "" ); trap_ConfigString( CS_AUDIOTRACK, "" ); trap_ConfigString( CS_STATNUMS, va( "%i %i %i", STAT_SCORE, STAT_HEALTH, STAT_LAST_KILLER ) ); trap_ConfigString( CS_POWERUPEFFECTS, va( "%i %i %i %i", EF_QUAD, EF_SHELL, EF_CARRIER, EF_REGEN ) ); trap_ConfigString( CS_SCB_PLAYERTAB_LAYOUT, "" ); trap_ConfigString( CS_SCB_PLAYERTAB_TITLES, "" ); trap_ConfigString( CS_MATCHNAME, "" ); trap_ConfigString( CS_MATCHSCORE, "" ); // reset map messages for( i = 0; i < MAX_HELPMESSAGES; i++ ) { trap_ConfigString( CS_HELPMESSAGES + i, "" ); } G_InitGameCommands(); G_MapLocations_Init(); G_CallVotes_Init(); G_SpawnQueue_Init(); G_Teams_Init(); // load map script G_asLoadMapScript( level.mapname ); G_Gametype_Init(); // ch : this would be the location to "transfer ratings" G_PrecacheItems(); // set configstrings for items (gametype must be initialized) G_PrecacheMedia(); G_PrecacheGameCommands(); // adding commands after this point won't update them to the client AI_InitLevel(); // load navigation file of the current map // start spawning entities level.canSpawnEntities = true; G_InitBodyQueue(); // reserve some spots for dead player bodies entities = level.mapString; i = 0; ent = NULL; while( 1 ) { level.spawning_entity = NULL; // parse the opening brace token = COM_Parse( &entities ); if( !entities ) break; if( token[0] != '{' ) G_Error( "G_SpawnMapEntities: found %s when expecting {", token ); if( !ent ) { ent = world; G_InitEdict( world ); } else ent = G_Spawn(); ent->spawnString = entities; // keep track of string definition of this entity entities = ED_ParseEdict( entities, ent ); if( !ent->classname ) { i++; // racesow - introducing the freestyle map bug again in // order to make some freestyle maps work if( !level.gametype.freestyleMapFix ) G_FreeEdict( ent ); // !racesow G_FreeEdict( ent ); continue; } if( !G_CanSpawnEntity( ent ) ) { i++; G_FreeEdict( ent ); continue; } if( !G_CallSpawn( ent ) ) { i++; G_FreeEdict( ent ); continue; } // check whether an item is allowed to spawn if( ( item = ent->item ) ) { // not pickable items aren't spawnable if( item->flags & ITFLAG_PICKABLE ) { if( G_Gametype_CanSpawnItem( item ) ) { // override entity's classname with whatever item specifies ent->classname = item->classname; PrecacheItem( item ); continue; } } i++; G_FreeEdict( ent ); continue; } } G_FindTeams(); // is the parsing string sane? assert( (int)level.map_parsed_len < entstrlen ); level.map_parsed_ents[level.map_parsed_len] = 0; // make sure server got the edicts data trap_LocateEntities( game.edicts, sizeof( game.edicts[0] ), game.numentities, game.maxentities ); // items need brush model entities spawned before they are linked G_Items_FinishSpawningItems(); // // initialize game subsystems which require entities initialized // // call gametype specific GT_asCallSpawn(); // call map specific G_asCallMapInit(); AI_InitEntitiesData(); // always start in warmup match state and let the thinking code // revert it to wait state if empty ( so gametype based item masks are setup ) G_Match_LaunchState( MATCH_STATE_WARMUP ); G_asGarbageCollect( true ); // racesow RS_Init(); }
/* * G_Match_SetAutorecordState */ static void G_Match_SetAutorecordState( const char *state ) { trap_ConfigString( CS_AUTORECORDSTATE, state ); }
/* * G_Match_LaunchState */ void G_Match_LaunchState( int matchState ) { static bool advance_queue = false; if( game.asEngine != NULL ) { // give the gametype a chance to refuse the state change, or to set up things for it if( !GT_asCallMatchStateFinished( matchState ) ) return; } else { // There isn't any script, run generic fuction if( !G_Gametype_GENERIC_MatchStateFinished( matchState ) ) return; } GS_GamestatSetFlag( GAMESTAT_FLAG_MATCHEXTENDED, false ); GS_GamestatSetFlag( GAMESTAT_FLAG_WAITING, false ); if( matchState == MATCH_STATE_POSTMATCH ) { level.finalMatchDuration = game.serverTime - GS_MatchStartTime(); } if( ( matchState == MATCH_STATE_POSTMATCH && GS_RaceGametype() ) || ( matchState != MATCH_STATE_POSTMATCH && gs.gameState.stats[GAMESTAT_MATCHSTATE] == MATCH_STATE_POSTMATCH ) ) { // entering postmatch in race or leaving postmatch in normal gt G_Match_SendReport(); trap_MM_GameState( false ); } switch( matchState ) { default: case MATCH_STATE_WARMUP: { advance_queue = false; level.forceStart = false; gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_WARMUP; gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)( fabs( g_warmup_timelimit->value * 60 ) * 1000 ); gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime; // race has playtime in warmup too, so flag the matchmaker about this if( GS_RaceGametype() ) trap_MM_GameState( true ); break; } case MATCH_STATE_COUNTDOWN: { advance_queue = true; gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_COUNTDOWN; gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)( fabs( g_countdown_time->value ) * 1000 ); gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime; break; } case MATCH_STATE_PLAYTIME: { // ch : should clear some statcollection memory from warmup? advance_queue = true; // shouldn't be needed here level.forceStart = false; gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_PLAYTIME; gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)( fabs( 60 * g_timelimit->value )*1000 ); gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime; // request a new match UUID trap_ConfigString( CS_MATCHUUID, "" ); // tell matchmaker that the game is on, so if // client disconnects before SendReport, it is flagged // as 'purgable' on MM side trap_MM_GameState( true ); } break; case MATCH_STATE_POSTMATCH: { gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_POSTMATCH; gs.gameState.longstats[GAMELONG_MATCHDURATION] = (unsigned int)fabs( g_postmatch_timelimit->value * 1000 ); // postmatch time in seconds gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime; G_Timeout_Reset(); level.teamlock = false; level.forceExit = false; G_Match_Autorecord_Stats(); } break; case MATCH_STATE_WAITEXIT: { if( advance_queue ) { G_Teams_AdvanceChallengersQueue(); advance_queue = true; } gs.gameState.stats[GAMESTAT_MATCHSTATE] = MATCH_STATE_WAITEXIT; gs.gameState.longstats[GAMELONG_MATCHDURATION] = 25000; gs.gameState.longstats[GAMELONG_MATCHSTART] = game.serverTime; level.exitNow = false; } break; } // give the gametype the chance to setup for the new state if( game.asEngine != NULL ) GT_asCallMatchStateStarted(); else G_Gametype_GENERIC_MatchStateStarted(); G_UpdatePlayersMatchMsgs(); }
void G_PrecacheMedia( void ) { // // MODELS // // THIS ORDER MUST MATCH THE DEFINES IN gs_public.h // you can add more, max 255 trap_ModelIndex( "#gunblade/gunblade.md3" ); // WEAP_GUNBLADE trap_ModelIndex( "#machinegun/machinegun.md3" ); // WEAP_MACHINEGUN trap_ModelIndex( "#riotgun/riotgun.md3" ); // WEAP_RIOTGUN trap_ModelIndex( "#glauncher/glauncher.md3" ); // WEAP_GRENADELAUNCHER trap_ModelIndex( "#rlauncher/rlauncher.md3" ); // WEAP_ROCKETLAUNCHER trap_ModelIndex( "#plasmagun/plasmagun.md3" ); // WEAP_PLASMAGUN trap_ModelIndex( "#lasergun/lasergun.md3" ); // WEAP_LASERGUN trap_ModelIndex( "#electrobolt/electrobolt.md3" ); // WEAP_ELECTROBOLT trap_ModelIndex( "#instagun/instagun.md3" ); // WEAP_INSTAGUN //------------------- // precache our basic player models, they are just a very few trap_ModelIndex( "$models/players/bigvic" ); trap_SkinIndex( "models/players/bigvic/default" ); // FIXME: Temporarily use normal gib until the head is fixed trap_ModelIndex( "models/objects/gibs/illuminati1/illuminati1.md3" ); // // SOUNDS // // jalfixme : most of these sounds can be played from the clients trap_SoundIndex( S_WORLD_WATER_IN ); // feet hitting water trap_SoundIndex( S_WORLD_WATER_OUT ); // feet leaving water trap_SoundIndex( S_WORLD_UNDERWATER ); trap_SoundIndex( S_WORLD_SLIME_IN ); trap_SoundIndex( S_WORLD_SLIME_OUT ); trap_SoundIndex( S_WORLD_UNDERSLIME ); trap_SoundIndex( S_WORLD_LAVA_IN ); trap_SoundIndex( S_WORLD_LAVA_OUT ); trap_SoundIndex( S_WORLD_UNDERLAVA ); trap_SoundIndex( va( S_PLAYER_BURN_1_to_2, 1 ) ); trap_SoundIndex( va( S_PLAYER_BURN_1_to_2, 2 ) ); //wsw: pb disable unreferenced sounds //trap_SoundIndex (S_LAND); // landing thud trap_SoundIndex( S_HIT_WATER ); trap_SoundIndex( S_WEAPON_NOAMMO ); // announcer // readyup trap_SoundIndex( S_ANNOUNCER_READY_UP_POLITE ); trap_SoundIndex( S_ANNOUNCER_READY_UP_PISSEDOFF ); // countdown trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_GET_READY_TO_FIGHT_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_GET_READY_TO_FIGHT_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_READY_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_READY_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_COUNT_1_to_3_SET_1_to_2, 1, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_COUNT_1_to_3_SET_1_to_2, 2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_COUNT_1_to_3_SET_1_to_2, 3, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_COUNT_1_to_3_SET_1_to_2, 1, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_COUNT_1_to_3_SET_1_to_2, 2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_COUNT_1_to_3_SET_1_to_2, 3, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_FIGHT_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_COUNTDOWN_FIGHT_1_to_2, 2 ) ); // postmatch trap_SoundIndex( va( S_ANNOUNCER_POSTMATCH_GAMEOVER_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_POSTMATCH_GAMEOVER_1_to_2, 2 ) ); // timeout trap_SoundIndex( va( S_ANNOUNCER_TIMEOUT_MATCH_RESUMED_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_TIMEOUT_MATCH_RESUMED_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_TIMEOUT_TIMEOUT_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_TIMEOUT_TIMEOUT_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_TIMEOUT_TIMEIN_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_TIMEOUT_TIMEIN_1_to_2, 2 ) ); // callvote trap_SoundIndex( va( S_ANNOUNCER_CALLVOTE_CALLED_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_CALLVOTE_CALLED_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_CALLVOTE_FAILED_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_CALLVOTE_FAILED_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_CALLVOTE_PASSED_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_CALLVOTE_PASSED_1_to_2, 2 ) ); trap_SoundIndex( S_ANNOUNCER_CALLVOTE_VOTE_NOW ); // overtime trap_SoundIndex( S_ANNOUNCER_OVERTIME_GOING_TO_OVERTIME ); trap_SoundIndex( S_ANNOUNCER_OVERTIME_OVERTIME ); trap_SoundIndex( va( S_ANNOUNCER_OVERTIME_SUDDENDEATH_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_OVERTIME_SUDDENDEATH_1_to_2, 2 ) ); // score trap_SoundIndex( va( S_ANNOUNCER_SCORE_TAKEN_LEAD_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_TAKEN_LEAD_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_LOST_LEAD_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_LOST_LEAD_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_TIED_LEAD_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_TIED_LEAD_1_to_2, 2 ) ); if( GS_TeamBasedGametype() ) { trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TAKEN_LEAD_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TAKEN_LEAD_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_LOST_LEAD_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_LOST_LEAD_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TIED_LEAD_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TIED_LEAD_1_to_2, 2 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TIED_LEAD_1_to_2, 1 ) ); trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TIED_LEAD_1_to_2, 2 ) ); //trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_1_to_4_TAKEN_LEAD_1_to_2, 3, 1 ) ); //trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_1_to_4_TAKEN_LEAD_1_to_2, 3, 2 ) ); //trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_1_to_4_TAKEN_LEAD_1_to_2, 4, 1 ) ); //trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_1_to_4_TAKEN_LEAD_1_to_2, 4, 2 ) ); } // // LIGHTSTYLES // // light animation tables. 'a' is total darkness, 'z' is doublebright. // 0 normal trap_ConfigString( CS_LIGHTS+0, "m" ); // 1 FLICKER (first variety) trap_ConfigString( CS_LIGHTS+1, "mmnmmommommnonmmonqnmmo" ); // 2 SLOW STRONG PULSE trap_ConfigString( CS_LIGHTS+2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba" ); // 3 CANDLE (first variety) trap_ConfigString( CS_LIGHTS+3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg" ); // 4 FAST STROBE trap_ConfigString( CS_LIGHTS+4, "mamamamamama" ); // 5 GENTLE PULSE 1 trap_ConfigString( CS_LIGHTS+5, "jklmnopqrstuvwxyzyxwvutsrqponmlkj" ); // 6 FLICKER (second variety) trap_ConfigString( CS_LIGHTS+6, "nmonqnmomnmomomno" ); // 7 CANDLE (second variety) trap_ConfigString( CS_LIGHTS+7, "mmmaaaabcdefgmmmmaaaammmaamm" ); // 8 CANDLE (third variety) trap_ConfigString( CS_LIGHTS+8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa" ); // 9 SLOW STROBE (fourth variety) trap_ConfigString( CS_LIGHTS+9, "aaaaaaaazzzzzzzz" ); // 10 FLUORESCENT FLICKER trap_ConfigString( CS_LIGHTS+10, "mmamammmmammamamaaamammma" ); // 11 SLOW PULSE NOT FADE TO BLACK trap_ConfigString( CS_LIGHTS+11, "abcdefghijklmnopqrrqponmlkjihgfedcba" ); // styles 32-62 are assigned by the light program for switchable lights // 63 testing trap_ConfigString( CS_LIGHTS+63, "a" ); }