xash3d-fwgs/engine/common/host_state.c

212 lines
4.8 KiB
C

/*
host_cmd.c - dedicated and normal host
Copyright (C) 2017 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "common.h"
#include "platform/platform.h"
void COM_InitHostState( void )
{
memset( GameState, 0, sizeof( game_status_t ));
}
static void Host_SetState( host_state_t newState, qboolean clearNext )
{
if( clearNext )
GameState->nextstate = newState;
GameState->curstate = newState;
if( clearNext && newState == STATE_RUNFRAME )
{
// states finished here
GameState->backgroundMap = false;
GameState->loadGame = false;
GameState->newGame = false;
}
}
static void Host_SetNextState( host_state_t nextState )
{
ASSERT( GameState->curstate == STATE_RUNFRAME );
GameState->nextstate = nextState;
}
void COM_NewGame( char const *pMapName )
{
if( GameState->nextstate != STATE_RUNFRAME )
return;
if( UI_CreditsActive( ))
return;
Q_strncpy( GameState->levelName, pMapName, sizeof( GameState->levelName ));
Host_SetNextState( STATE_LOAD_LEVEL );
GameState->backgroundMap = false;
GameState->landmarkName[0] = 0;
GameState->loadGame = false;
GameState->newGame = true;
SV_ShutdownGame(); // exit from current game
}
void COM_LoadLevel( char const *pMapName, qboolean background )
{
if( GameState->nextstate != STATE_RUNFRAME )
return;
if( UI_CreditsActive( ))
return;
Q_strncpy( GameState->levelName, pMapName, sizeof( GameState->levelName ));
Host_SetNextState( STATE_LOAD_LEVEL );
GameState->backgroundMap = background;
GameState->landmarkName[0] = 0;
GameState->loadGame = false;
GameState->newGame = false;
SV_ShutdownGame(); // exit from current game
}
void COM_LoadGame( char const *pMapName )
{
if( GameState->nextstate != STATE_RUNFRAME )
return;
if( UI_CreditsActive( ))
return;
Q_strncpy( GameState->levelName, pMapName, sizeof( GameState->levelName ));
Host_SetNextState( STATE_LOAD_GAME );
GameState->backgroundMap = false;
GameState->newGame = false;
GameState->loadGame = true;
}
void COM_ChangeLevel( char const *pNewLevel, char const *pLandmarkName, qboolean background )
{
if( GameState->nextstate != STATE_RUNFRAME )
return;
if( UI_CreditsActive( ))
return;
Q_strncpy( GameState->levelName, pNewLevel, sizeof( GameState->levelName ));
GameState->backgroundMap = background;
if( COM_CheckString( pLandmarkName ))
{
Q_strncpy( GameState->landmarkName, pLandmarkName, sizeof( GameState->landmarkName ));
GameState->loadGame = true;
}
else
{
GameState->landmarkName[0] = 0;
GameState->loadGame = false;
}
Host_SetNextState( STATE_CHANGELEVEL );
GameState->newGame = false;
}
static void Host_ShutdownGame( void )
{
SV_ShutdownGame();
switch( GameState->nextstate )
{
case STATE_LOAD_GAME:
case STATE_LOAD_LEVEL:
Host_SetState( GameState->nextstate, true );
break;
default:
Host_SetState( STATE_RUNFRAME, true );
break;
}
}
static void Host_RunFrame( float time )
{
// at this time, we don't need to get events from OS on dedicated
#if !XASH_DEDICATED
Platform_RunEvents();
#endif // XASH_DEDICATED
// engine main frame
Host_Frame( time );
switch( GameState->nextstate )
{
case STATE_RUNFRAME:
break;
case STATE_LOAD_GAME:
case STATE_LOAD_LEVEL:
SCR_BeginLoadingPlaque( GameState->backgroundMap );
// intentionally fallthrough
case STATE_GAME_SHUTDOWN:
Host_SetState( STATE_GAME_SHUTDOWN, false );
break;
case STATE_CHANGELEVEL:
SCR_BeginLoadingPlaque( GameState->backgroundMap );
Host_SetState( GameState->nextstate, true );
break;
default:
Host_SetState( STATE_RUNFRAME, true );
break;
}
}
void COM_Frame( float time )
{
int loopCount = 0;
if( setjmp( host.abortframe ))
return;
while( 1 )
{
int oldState = GameState->curstate;
// execute the current state (and transition to the next state if not in STATE_RUNFRAME)
switch( GameState->curstate )
{
case STATE_LOAD_LEVEL:
SV_ExecLoadLevel();
Host_SetState( STATE_RUNFRAME, true );
break;
case STATE_LOAD_GAME:
SV_ExecLoadGame();
Host_SetState( STATE_RUNFRAME, true );
break;
case STATE_CHANGELEVEL:
SV_ExecChangeLevel();
Host_SetState( STATE_RUNFRAME, true );
break;
case STATE_RUNFRAME:
Host_RunFrame( time );
break;
case STATE_GAME_SHUTDOWN:
Host_ShutdownGame();
break;
}
if( oldState == STATE_RUNFRAME )
break;
if(( GameState->curstate == oldState ) || ( ++loopCount > 8 ))
Sys_Error( "state infinity loop!\n" );
}
}