diff --git a/code/fgame/scriptmaster.cpp b/code/fgame/scriptmaster.cpp index 07115d2a..9a75d96d 100644 --- a/code/fgame/scriptmaster.cpp +++ b/code/fgame/scriptmaster.cpp @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // scriptmaster.cpp : Spawns at the beginning of the maps, parse scripts. -#include "glb_local.h" +#include "g_local.h" #include "scriptmaster.h" #include "scriptthread.h" #include "scriptclass.h" @@ -35,1042 +35,1145 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "scriptexception.h" #ifdef WIN32 -#include +# include #else -#include -#include +# include +# include #endif -#if defined ( CGAME_DLL ) +#if defined(CGAME_DLL) -#include +# include -#define SCRIPT_Printf cgi.Printf -#define SCRIPT_DPrintf cgi.DPrintf +# define SCRIPT_Printf cgi.Printf +# define SCRIPT_DPrintf cgi.DPrintf -#elif defined ( GAME_DLL ) +#elif defined(GAME_DLL) -#include "hud.h" +# include "hud.h" -#include "dm_manager.h" -#include "player.h" -#include "entity.h" -#include "huddraw.h" -#include "weaputils.h" -#include "camera.h" -#include "consoleevent.h" +# include "dm_manager.h" +# include "player.h" +# include "entity.h" +# include "huddraw.h" +# include "weaputils.h" +# include "camera.h" +# include "consoleevent.h" -#define SCRIPT_Printf gi.Printf -#define SCRIPT_DPrintf gi.DPrintf +# define SCRIPT_Printf gi.Printf +# define SCRIPT_DPrintf gi.DPrintf #endif -con_set< str, ScriptThreadLabel > m_scriptCmds; +con_set m_scriptCmds; -str vision_current; +str vision_current; qboolean disable_team_change; qboolean disable_team_spectate; ScriptMaster Director; -ScriptEvent scriptedEvents[ SE_MAX ]; +ScriptEvent scriptedEvents[SE_MAX]; -CLASS_DECLARATION( Class, ScriptEvent, NULL ) -{ - { NULL, NULL } +CLASS_DECLARATION(Class, ScriptEvent, NULL) { + {NULL, NULL} }; // // world stuff // -Event EV_RegisterAlias -( - "alias", - EV_DEFAULT, - "ssSSSS", - "alias_name real_name arg1 arg2 arg3 arg4", - "Sets up an alias." +Event EV_SetTiki( + "settiki", + EV_DEFAULT, + NULL, + NULL, + "Not implemented - used to stop script error on dedicated server" ); Event EV_RegisterAliasAndCache ( - "aliascache", - EV_DEFAULT, - "ssSSSS", - "alias_name real_name arg1 arg2 arg3 arg4", - "Sets up an alias and caches the resourse." + "aliascache", + EV_DEFAULT, + "ssSSSS", + "alias_name real_name arg1 arg2 arg3 arg4", + "Sets up an alias and caches the resourse." +); +Event EV_RegisterAlias +( + "alias", + EV_DEFAULT, + "ssSSSS", + "alias_name real_name arg1 arg2 arg3 arg4", + "Sets up an alias." ); Event EV_Cache ( - "cache", - EV_CACHE, - "s", - "resourceName", - "pre-cache the given resource." + "cache", + EV_CACHE, + "s", + "resourceName", + "pre-cache the given resource." ); -CLASS_DECLARATION( Listener, ScriptMaster, NULL ) -{ - { &EV_RegisterAlias, &ScriptMaster::RegisterAlias }, - { &EV_RegisterAliasAndCache, &ScriptMaster::RegisterAliasAndCache }, - { &EV_Cache, &ScriptMaster::Cache }, - { NULL, NULL } +CLASS_DECLARATION(Listener, ScriptMaster, NULL) { + {&EV_RegisterAliasAndCache, &ScriptMaster::RegisterAliasAndCache}, + {&EV_RegisterAlias, &ScriptMaster::RegisterAlias }, + {&EV_Cache, &ScriptMaster::Cache }, + {NULL, NULL } }; -void ScriptMaster::Archive( Archiver& arc ) -{ - ScriptClass *scr; - ScriptVM *m_current; - ScriptThread *m_thread; - int num; - int i, j; - - if( arc.Saving() ) - { - num = (int)ScriptClass_allocator.Count(); - arc.ArchiveInteger( &num ); - - MEM_BlockAlloc_enum en = ScriptClass_allocator; - for( scr = en.NextElement(); scr != NULL; scr = en.NextElement() ) - { - scr->ArchiveInternal( arc ); - - num = 0; - for( m_current = scr->m_Threads; m_current != NULL; m_current = m_current->next ) - num++; - - arc.ArchiveInteger( &num ); - - for( m_current = scr->m_Threads; m_current != NULL; m_current = m_current->next ) - m_current->m_Thread->ArchiveInternal( arc ); - } - } - else - { - arc.ArchiveInteger( &num ); - - for( i = 0; i < num; i++ ) - { - scr = new ScriptClass(); - scr->ArchiveInternal( arc ); - - arc.ArchiveInteger( &num ); - - for( j = 0; j < num; j++ ) - { - m_thread = new ScriptThread( scr, NULL ); - m_thread->ArchiveInternal( arc ); - } - } - } - - timerList.Archive( arc ); - m_menus.Archive( arc ); -} - -void ScriptMaster::ArchiveString( Archiver& arc, const_str& s ) -{ - str s2; - byte b; - - if( arc.Loading() ) - { - arc.ArchiveByte( &b ); - if( b ) - { - arc.ArchiveString( &s2 ); - s = AddString( s2 ); - } - else - { - s = 0; - } - } - else - { - if( s ) - { - b = 1; - arc.ArchiveByte( &b ); - - s2 = Director.GetString( s ); - arc.ArchiveString( &s2 ); - } - else - { - b = 0; - arc.ArchiveByte( &b ); - } - } -} - -const char *ScriptMaster::ConstStrings[] = -{ - "", - "touch", "block", "trigger", "use", - "damage", "location", - "say", "fail", "bump", - "default", "all", - "move_action", "resume", "open", "close", "pickup", "reach", "start", "teleport", - "move", "move_end", "moveto", "walkto", "runto", "crouchto", "crawlto", "stop", - "reset", "prespawn", "spawn", "playerspawn", "skip", "roudstart", - "visible", "not_visible", - "done", "animdone", "upperanimdone", "saydone", "flaggedanimdone", - "idle", "walk", "shuffle", "anim/crouch.scr", - "forgot", - "jog_hunch", "jog_hunch_rifle", - "killed", "alarm", "scriptclass", "ai/utils/fact_script_factory.scr", "death", "death_fall_to_knees", - "enemy", "dead", "mood", "patrol", "runner", "follow", "action", - "move_begin", "action_begin", "action_end", "success", - "entry", "exit", "path", "node", "ask_count", "attacker", "usecover", "waitcover", - "void", "end", "attack", "near", - "papers", "check_papers", - "timeout", - "hostile", "leader", - "gamemap", - "bored", "nervous", "curious", "alert", "greet", "depend", - "anim", "anim_scripted", "anim_curious", "animloop", "undefined", "notset", - "increment", "decrement", "toggle", - "normal", "suspend", "mystery", "surprise", - "anim/crouch_run.scr", "anim/aim.scr", "anim/shoot.scr", "anim/mg42_shoot.scr", "anim/mg42_idle.scr", "anim_mg42_reload.scr", - "drive", - "global/weapon.scr", "global/moveto.scr", - "global/anim.scr", "global/anim_scripted.scr", "global/anim_noclip.scr", - "global/walkto.scr", "global/runto.scr", - "aimat", - "global/disabled_ai.scr", - "global/crouchto.scr", "global/crawlto.scr", "global/killed.scr", "global/pain.scr", - "pain", "track", "hasenemy", - "anim/cower.scr", "anim/stand.scr", "anim/idle.scr", "anim/surprise.scr", "anim/standshock.scr", "anim/standidentify", "anim/standflinch.scr", - "anim/dog_idle.scr", "anim/dog_attack.scr", "anim/dog_curious.scr", "anim/dog_chase.scr", - "cannon", "grenade", "heavy", - "item", "items", "item1", "item2", "item3", "item4", - "stand", "mg", "pistol", "rifle", "smg", - "turnto", "standing", "crouching", "prone", "offground", "walking", "running", "falling", - "anim_nothing", "anim_direct", "anim_path", "anim_waypoint", "anim_direct_nogravity", - "emotion_none", "emotion_neutral", - "emotion_worry", "emotion_panic", "emotion_fear", - "emotion_disgust", "emotion_anger", - "emotion_aiming", "emotion_determined", - "emotion_dead", - "emotion_curious", - "anim/emotion.scr", - "forceanim", "forceanim_scripted", - "turret", "cover", - "anim/pain.scr", "anim/killed.scr", "anim/attack.scr", "anim/sniper.scr", - "knees", "crawl", "floor", - "anim/patrol.scr", "anim/run.scr", - "crouch", "crouchwalk", "crouchrun", - "anim/crouch_walk.scr", "anim/walk.scr", "anim/prone.scr", - "anim/runawayfiring.scr", "anim/run_shoot.scr", - "anim/runto_alarm.scr", "anim/runto_casual.scr", "anim/runto_cover.scr", "anim/runto_danger.scr", "anim/runto_dive.scr", "anim/runto_flee.scr", "anim/runto_inopen.scr", - "anim/disguise_salute.scr", "anim/disguise_wait.scr", "anim/disguise_papers.scr", "anim/disguise_enemy.scr", "anim/disguise_halt.scr", "anim/disguise_accept.scr", "anim/disguise_deny.scr", - "anim/cornerleft.scr", "anim/cornerright.scr", "anim/overattack.scr", "anim/continue_last_anim.scr", - "flagged", - "anim/fullbody.scr", - "internal", - "salute", "sentry", "officier", "rover", - "none", "machinegunner", - "disguise", - "dog_idle", "dog_attack", "dog_curious", "dog_grenade", - "anim/grenadeturn.scr", "anim/grenadekick.scr", "anim/grenadethrow.scr", "anim/grenadetoss.scr", "anim/grenademartyr.scr", - "movedone", - "aim", "ontarget", - "unarmed", - "balcony_idle", "balcony_curious", "balcony_attack", "balcony_disguise", "balcony_grenade", "balcony_pain", "balcony_killed", - "weaponless", - "death_balcony_intro", "death_balcony_loop", "death_balcony_outtro", - "sounddone", - "noclip", - "german", "american", "spectator", "freeforall", "allies", "axis", - "draw", "kills", "allieswin", "axiswin", - "anim/say_curious_sight.scr", "anim/say_curious_sound.scr", "anim/say_grenade_sighted.scr", "anim/say_kill.scr", "anim/say_mandown.scr", "anim/say_sighted.scr", - "vehicleanimdone", - "postthink", - "turndone", - "anim/no_anim_killed.scr", - "mg42", "mp40", - "auto", - "both", - "runandshoot", - "respawn" -}; +const char *ScriptMaster::ConstStrings[] = { + "", + "touch", + "block", + "trigger", + "use", + "damage", + "location", + "say", + "fail", + "bump", + "default", + "all", + "move_action", + "resume", + "open", + "close", + "pickup", + "reach", + "start", + "teleport", + "move", + "move_end", + "moveto", + "walkto", + "runto", + "crouchto", + "crawlto", + "stop", + "reset", + "prespawn", + "spawn", + "playerspawn", + "skip", + "roudstart", + "visible", + "not_visible", + "done", + "animdone", + "upperanimdone", + "saydone", + "flaggedanimdone", + "idle", + "walk", + "shuffle", + "anim/crouch.scr", + "forgot", + "jog_hunch", + "jog_hunch_rifle", + "killed", + "alarm", + "scriptclass", + "ai/utils/fact_script_factory.scr", + "death", + "death_fall_to_knees", + "enemy", + "dead", + "mood", + "patrol", + "runner", + "follow", + "action", + "move_begin", + "action_begin", + "action_end", + "success", + "entry", + "exit", + "path", + "node", + "ask_count", + "attacker", + "usecover", + "waitcover", + "void", + "end", + "attack", + "near", + "papers", + "check_papers", + "timeout", + "hostile", + "leader", + "gamemap", + "bored", + "nervous", + "curious", + "alert", + "greet", + "depend", + "anim", + "anim_scripted", + "anim_curious", + "animloop", + "undefined", + "notset", + "increment", + "decrement", + "toggle", + "normal", + "suspend", + "mystery", + "surprise", + "anim/crouch_run.scr", + "anim/aim.scr", + "anim/shoot.scr", + "anim/mg42_shoot.scr", + "anim/mg42_idle.scr", + "anim_mg42_reload.scr", + "drive", + "global/weapon.scr", + "global/moveto.scr", + "global/anim.scr", + "global/anim_scripted.scr", + "global/anim_noclip.scr", + "global/walkto.scr", + "global/runto.scr", + "aimat", + "global/disabled_ai.scr", + "global/crouchto.scr", + "global/crawlto.scr", + "global/killed.scr", + "global/pain.scr", + "pain", + "track", + "hasenemy", + "anim/cower.scr", + "anim/stand.scr", + "anim/idle.scr", + "anim/surprise.scr", + "anim/standshock.scr", + "anim/standidentify", + "anim/standflinch.scr", + "anim/dog_idle.scr", + "anim/dog_attack.scr", + "anim/dog_curious.scr", + "anim/dog_chase.scr", + "cannon", + "grenade", + "heavy", + "item", + "items", + "item1", + "item2", + "item3", + "item4", + "stand", + "mg", + "pistol", + "rifle", + "smg", + "turnto", + "standing", + "crouching", + "prone", + "offground", + "walking", + "running", + "falling", + "anim_nothing", + "anim_direct", + "anim_path", + "anim_waypoint", + "anim_direct_nogravity", + "emotion_none", + "emotion_neutral", + "emotion_worry", + "emotion_panic", + "emotion_fear", + "emotion_disgust", + "emotion_anger", + "emotion_aiming", + "emotion_determined", + "emotion_dead", + "emotion_curious", + "anim/emotion.scr", + "forceanim", + "forceanim_scripted", + "turret", + "cover", + "anim/pain.scr", + "anim/killed.scr", + "anim/attack.scr", + "anim/sniper.scr", + "knees", + "crawl", + "floor", + "anim/patrol.scr", + "anim/run.scr", + "crouch", + "crouchwalk", + "crouchrun", + "anim/crouch_walk.scr", + "anim/walk.scr", + "anim/prone.scr", + "anim/runawayfiring.scr", + "anim/run_shoot.scr", + "anim/runto_alarm.scr", + "anim/runto_casual.scr", + "anim/runto_cover.scr", + "anim/runto_danger.scr", + "anim/runto_dive.scr", + "anim/runto_flee.scr", + "anim/runto_inopen.scr", + "anim/disguise_salute.scr", + "anim/disguise_wait.scr", + "anim/disguise_papers.scr", + "anim/disguise_enemy.scr", + "anim/disguise_halt.scr", + "anim/disguise_accept.scr", + "anim/disguise_deny.scr", + "anim/cornerleft.scr", + "anim/cornerright.scr", + "anim/overattack.scr", + "anim/continue_last_anim.scr", + "flagged", + "anim/fullbody.scr", + "internal", + "salute", + "sentry", + "officier", + "rover", + "none", + "machinegunner", + "disguise", + "dog_idle", + "dog_attack", + "dog_curious", + "dog_grenade", + "anim/grenadeturn.scr", + "anim/grenadekick.scr", + "anim/grenadethrow.scr", + "anim/grenadetoss.scr", + "anim/grenademartyr.scr", + "movedone", + "aim", + "ontarget", + "unarmed", + "balcony_idle", + "balcony_curious", + "balcony_attack", + "balcony_disguise", + "balcony_grenade", + "balcony_pain", + "balcony_killed", + "weaponless", + "death_balcony_intro", + "death_balcony_loop", + "death_balcony_outtro", + "sounddone", + "noclip", + "german", + "american", + "spectator", + "freeforall", + "allies", + "axis", + "draw", + "kills", + "allieswin", + "axiswin", + "anim/say_curious_sight.scr", + "anim/say_curious_sound.scr", + "anim/say_grenade_sighted.scr", + "anim/say_kill.scr", + "anim/say_mandown.scr", + "anim/say_sighted.scr", + "vehicleanimdone", + "postthink", + "turndone", + "anim/no_anim_killed.scr", + "mg42", + "mp40", + "auto", + "both", + "runandshoot", + "respawn"}; ScriptMaster::~ScriptMaster() { - Reset( false ); + Reset(false); } -void ScriptMaster::InitConstStrings( void ) +static int bLoadForMap(char *psMapsBuffer, const char *name) { - EventDef *eventDef; - const_str name; - unsigned int eventnum; - con_map_enum< Event *, EventDef > en; + cvar_t *mapname = gi.Cvar_Get("mapname", "", 0); + const char *token; - for( int i = 0; i < sizeof( ConstStrings ) / sizeof( ConstStrings[ 0 ] ); i++ ) - { - AddString( ConstStrings[ i ] ); - } + if (!strncmp("test", mapname->string, sizeof("test"))) { + return true; + } - Event::normalCommandList.clear(); - Event::returnCommandList.clear(); - Event::getterCommandList.clear(); - Event::setterCommandList.clear(); + token = COM_Parse(&psMapsBuffer); + if (!token || !*token) { + Com_Printf("ERROR bLoadForMap: %s alias with empty maps specification.\n", name); + return false; + } - en = Event::eventDefList; + while (token && *token) { + if (!Q_stricmpn(token, mapname->string, strlen(token))) { + return true; + } - for( en.NextValue(); en.CurrentValue() != NULL; en.NextValue() ) - { - eventDef = en.CurrentValue(); - eventnum = ( *en.CurrentKey() )->eventnum; - str command = eventDef->command.c_str(); - command.tolower(); + token = COM_Parse(&psMapsBuffer); + } - name = AddString( command ); - - if( eventDef->type == EV_NORMAL ) - { - Event::normalCommandList[ name ] = eventnum; - } - else if( eventDef->type == EV_RETURN ) - { - Event::returnCommandList[ name ] = eventnum; - } - else if( eventDef->type == EV_GETTER ) - { - Event::getterCommandList[ name ] = eventnum; - } - else if( eventDef->type == EV_SETTER ) - { - Event::setterCommandList[ name ] = eventnum; - } - } + return false; } -void ScriptMaster::CloseGameScript( void ) +void ScriptMaster::RegisterAliasInternal(Event *ev, bool bCache) { - con_map_enum< const_str, GameScript * > en( m_GameScripts ); - GameScript **g; - Container< GameScript * > gameScripts; + int i; + char parameters[MAX_STRING_CHARS]; + char *psMapsBuffer; + int subtitle; + bool bAlwaysLoaded = false; - for( g = en.NextValue(); g != NULL; g = en.NextValue() ) - { - gameScripts.AddObject( *g ); - } + // Get the parameters for this alias command - for( int i = gameScripts.NumObjects(); i > 0; i-- ) - { - delete gameScripts.ObjectAt( i ); - } + parameters[0] = 0; + subtitle = 0; + psMapsBuffer = NULL; - m_GameScripts.clear(); + for (i = 3; i <= ev->NumArgs(); i++) { + str s; + + // MOHAA doesn't check that + if (ev->IsListenerAt(i)) { + Listener *l = ev->GetListener(i); + + if (l && l == Director.CurrentThread()) { + s = "local"; + } else { + s = ev->GetString(i); + } + } else { + s = ev->GetString(i); + } + + if (subtitle) { + strcat(parameters, "\""); + strcat(parameters, s); + strcat(parameters, "\" "); + + subtitle = 0; + } else if (!s.icmp("maps")) { + i++; + psMapsBuffer = (char *)ev->GetToken(i).c_str(); + } else if (!s.icmp("always")) { + bAlwaysLoaded = true; + } else { + subtitle = s.icmp("subtitle") == 0; + + strcat(parameters, s); + strcat(parameters, " "); + } + } + + if (bAlwaysLoaded || bLoadForMap(psMapsBuffer, ev->GetString(1))) { + gi.GlobalAlias_Add(ev->GetString(1), ev->GetString(2), parameters); + + if (bCache) { + CacheResource(ev->GetString(2)); + } + } } -void ScriptMaster::Reset( qboolean samemap ) +void ScriptMaster::RegisterAliasAndCache(Event *ev) { - ScriptClass_allocator.FreeAll(); - - stackCount = 0; - cmdCount = 0; - cmdTime = 0; - maxTime = MAX_EXECUTION_TIME; - //pTop = &avar_Stack[ 0 ]; - iPaused = 0; - -#if defined ( GAME_DLL ) - for( int i = 1; i <= m_menus.NumObjects(); i++ ) - { - Hidemenu( m_menus.ObjectAt( i ), true ); - } - - m_menus.ClearObjectList(); -#endif - - if( !samemap ) - { - for( int i = 0; i < SE_MAX; i++ ) - { - scriptedEvents[ i ] = ScriptEvent(); - } - - CloseGameScript(); - StringDict.clear(); - InitConstStrings(); - } + RegisterAliasInternal(ev, true); } -const_str ScriptMaster::AddString( const char *s ) +void ScriptMaster::RegisterAlias(Event *ev) { - return StringDict.addKeyIndex( s ); + RegisterAliasInternal(ev); } -const_str ScriptMaster::AddString( str& s ) -{ - return StringDict.addKeyIndex( s ); -} - -const_str ScriptMaster::GetString( const char *s ) -{ - const_str cs = StringDict.findKeyIndex( s ); - - return cs ? cs : STRING_EMPTY; -} - -const_str ScriptMaster::GetString( str s ) -{ - return GetString( s.c_str() ); -} - -str& ScriptMaster::GetString( const_str s ) -{ - return StringDict[ s ]; -} - -void ScriptMaster::AddTiming( ScriptThread *thread, float time ) -{ - timerList.AddElement( thread, level.inttime + ( int )( time * 1000.0f + 0.5f ) ); -} - -void ScriptMaster::RemoveTiming( ScriptThread *thread ) -{ - timerList.RemoveElement( thread ); -} - -ScriptThread *ScriptMaster::CreateScriptThread( GameScript *scr, Listener *self, str label ) -{ - return CreateScriptThread( scr, self, Director.AddString( label ) ); -} - -ScriptThread *ScriptMaster::CreateScriptThread( GameScript *scr, Listener *self, const_str label ) -{ - ScriptClass *scriptClass = new ScriptClass( scr, self ); - - return CreateScriptThread( scriptClass, label ); -} - -ScriptThread *ScriptMaster::CreateScriptThread( ScriptClass *scriptClass, const_str label ) -{ - unsigned char *m_pCodePos = scriptClass->FindLabel( label ); - - if( !m_pCodePos ) - { - throw ScriptException( "ScriptMaster::CreateScriptThread: label '%s' does not exist in '%s'.", Director.GetString( label ).c_str(), scriptClass->Filename().c_str() ); - } - - return CreateScriptThread( scriptClass, m_pCodePos ); -} - -ScriptThread *ScriptMaster::CreateScriptThread( ScriptClass *scriptClass, str label ) -{ - if( label.length() && *label ) - { - return CreateScriptThread( scriptClass, Director.AddString( label ) ); - } - else - { - return CreateScriptThread( scriptClass, STRING_EMPTY ); - } -} - -ScriptThread *ScriptMaster::CreateScriptThread( ScriptClass *scriptClass, unsigned char *m_pCodePos ) -{ - return new ScriptThread( scriptClass, m_pCodePos ); -} - -ScriptThread *ScriptMaster::CreateThread( GameScript *scr, str label, Listener *self ) -{ - try - { - return CreateScriptThread( scr, self, label ); - } - catch( ScriptException& exc ) - { - gi.DPrintf( "ScriptMaster::CreateThread: %s\n", exc.string.c_str() ); - return NULL; - } -} - -ScriptThread *ScriptMaster::CreateThread( str filename, str label, Listener *self ) -{ - GameScript *scr = GetScript( filename ); - - if( !scr ) - { - return NULL; - } - - return CreateThread( scr, label, self ); -} - -ScriptClass *ScriptMaster::CurrentScriptClass( void ) -{ - return CurrentThread()->GetScriptClass(); -} - -ScriptThread *ScriptMaster::CurrentThread( void ) -{ - assert( m_CurrentThread ); - if( !m_CurrentThread ) - { - throw ScriptException( "current thread is NULL" ); - } - - return m_CurrentThread; -} - -ScriptThread *ScriptMaster::PreviousThread( void ) -{ - return m_PreviousThread; -} - -void ScriptMaster::ExecuteThread( GameScript *scr, str label ) -{ - ScriptThread *thread = CreateThread( scr, label ); - - try - { - if( thread ) { - thread->Execute(); - } - } - catch( ScriptException& exc ) - { - gi.DPrintf( "ScriptMaster::ExecuteThread: %s\n", exc.string.c_str() ); - } -} - -void ScriptMaster::ExecuteThread( str filename, str label ) -{ - GameScript *scr = GetScript( filename ); - - if( !scr ) - { - return; - } - - ExecuteThread( scr, label ); -} - -void ScriptMaster::ExecuteThread( GameScript *scr, str label, Event &parms ) -{ - ScriptThread *thread = CreateThread( scr, label ); - - try - { - thread->Execute( parms ); - } - catch( ScriptException& exc ) - { - gi.DPrintf( "ScriptMaster::ExecuteThread: %s\n", exc.string.c_str() ); - } -} - -void ScriptMaster::ExecuteThread( str filename, str label, Event &parms ) -{ - GameScript *scr = GetScript( filename ); - - if( !scr ) - { - return; - } - - ExecuteThread( scr, label, parms ); -} - -GameScript *ScriptMaster::GetTempScript( const char *data ) -{ - GameScript *scr = new GameScript; - - scr->Load( ( void * )data, strlen( data ) ); - - if( !scr->successCompile ) - { - return NULL; - } - - return scr; -} - -GameScript *ScriptMaster::GetGameScript( str filename, qboolean recompile ) -{ - const_str s = StringDict.findKeyIndex( filename ); - GameScript *scr = m_GameScripts[ s ]; - int i; - - if( scr != NULL && !recompile ) - { - if( !scr->successCompile ) - { - throw ScriptException( "Script '%s' was not properly loaded\n", filename.c_str() ); - } - - return scr; - } - else - { - if( scr && recompile ) - { - Container< ScriptClass * > list; - MEM_BlockAlloc_enum en = ScriptClass_allocator; - ScriptClass *scriptClass; - m_GameScripts[ s ] = NULL; - - for( scriptClass = en.NextElement(); scriptClass != NULL; scriptClass = en.NextElement() ) - { - if( scriptClass->GetScript() == scr ) - { - list.AddObject( scriptClass ); - } - } - - for( i = 1; i <= list.NumObjects(); i++ ) - { - delete list.ObjectAt( i ); - } - - delete scr; - } - - return GetGameScriptInternal( filename ); - } -} - -GameScript *ScriptMaster::GetGameScript( const_str filename, qboolean recompile ) -{ - return GetGameScript( Director.GetString( filename ), recompile ); -} - -GameScript *ScriptMaster::GetGameScriptInternal( str& filename ) -{ - void *sourceBuffer = NULL; - int sourceLength; - char filepath[ MAX_QPATH ]; - GameScript *scr; - - if( filename.length() >= MAX_QPATH ) - { - gi.Error( ERR_DROP, "Script filename '%s' exceeds maximum length of %d\n", filename.c_str(), MAX_QPATH ); - } - - scr = m_GameScripts[ StringDict.findKeyIndex( filename ) ]; - - if( scr != NULL ) - { - return scr; - } - - strcpy( filepath, filename.c_str() ); - gi.FS_CanonicalFilename( filepath ); - filename = filepath; - - scr = new GameScript( filename ); - - m_GameScripts[ StringDict.addKeyIndex( filename ) ] = scr; - - if( GetCompiledScript( scr ) ) - { - scr->m_Filename = Director.AddString( filename ); - return scr; - } - - sourceLength = gi.FS_ReadFile( filename.c_str(), &sourceBuffer, true ); - - if( sourceLength < 0 ) - { - throw ScriptException( "Can't find '%s'\n", filename.c_str() ); - } - - scr->Load( sourceBuffer, sourceLength ); - - gi.FS_FreeFile( sourceBuffer ); - - if( !scr->successCompile ) - { - throw ScriptException( "Script '%s' was not properly loaded", filename.c_str() ); - } - - return scr; -} - -GameScript *ScriptMaster::GetScript( str filename, qboolean recompile ) -{ - try - { - return GetGameScript( filename, recompile ); - } - catch( ScriptException& exc ) - { - gi.DPrintf( "ScriptMaster::GetScript: %s\n", exc.string.c_str() ); - } - - return NULL; -} - -GameScript *ScriptMaster::GetScript( const_str filename, qboolean recompile ) -{ - try - { - return GetGameScript( filename, recompile ); - } - catch( ScriptException& exc ) - { - gi.DPrintf( "ScriptMaster::GetScript: %s\n", exc.string.c_str() ); - } - - return NULL; -} - -void ScriptMaster::ExecuteRunning( void ) -{ - int i; - int startTime; - - if( stackCount ) - { - return; - } - - if( timerList.IsDirty() ) - { - cmdTime = 0; - cmdCount = 0; - startTime = level.svsTime; - - while( ( m_CurrentThread = ( ScriptThread * )timerList.GetNextElement( i ) ) ) - { - level.setTime( level.svsStartTime + i ); - - m_CurrentThread->m_ScriptVM->m_ThreadState = THREAD_RUNNING; - m_CurrentThread->m_ScriptVM->Execute(); - } - - level.setTime( startTime ); - level.m_LoopProtection = true; - } - - startTime = gi.Milliseconds(); -} - -void ScriptMaster::SetTime( int time ) -{ - timerList.SetTime( time ); - timerList.SetDirty(); -} - -void ScriptMaster::PrintStatus( void ) -{ - str status; - int iThreadNum = 0; - int iThreadRunning = 0; - int iThreadWaiting = 0; - int iThreadSuspended = 0; - MEM_BlockAlloc_enum en = ScriptClass_allocator; - ScriptClass *scriptClass; - char szBuffer[ MAX_STRING_TOKENS ]; - - status = "num state label script \n"; - status += "------- ---------- --------------- ---------------\n"; - - for( scriptClass = en.NextElement(); scriptClass != NULL; scriptClass = en.NextElement() ) - { - ScriptVM *vm; - - for( vm = scriptClass->m_Threads; vm != NULL; vm = vm->next ) - { - sprintf( szBuffer, "%.7d", iThreadNum ); - status += szBuffer + str( " " ); - - switch( vm->ThreadState() ) - { - case THREAD_CONTEXT_SWITCH: - case THREAD_RUNNING: - sprintf( szBuffer, "%8s", "running" ); - iThreadRunning++; - break; - case THREAD_WAITING: - sprintf( szBuffer, "%8s", "waiting" ); - iThreadWaiting++; - break; - case THREAD_SUSPENDED: - sprintf( szBuffer, "%8s", "suspended" ); - iThreadSuspended++; - break; - } - - status += szBuffer; - - sprintf( szBuffer, "%15s", vm->Label().c_str() ); - status += szBuffer + str( " " ); - - sprintf( szBuffer, "%15s", vm->Filename().c_str() ); - status += szBuffer; - - status += "\n"; - iThreadNum++; - } - } - - status += "------- ---------- --------------- ---------------\n"; - status += str( m_GameScripts.size() ) + " total scripts compiled\n"; - status += str( iThreadNum ) + " total threads ( " + str( iThreadRunning ) + " running thread(s), " + str( iThreadWaiting ) + " waiting thread(s), " + str( iThreadSuspended ) + " suspended thread(s) )\n"; - - gi.Printf( status.c_str() ); -} - -void ScriptMaster::PrintThread( int iThreadNum ) -{ - int iThread = 0; - ScriptVM *vm; - bool bFoundThread = false; - str status; - MEM_BlockAlloc_enum en = ScriptClass_allocator; - ScriptClass *scriptClass; - - for( scriptClass = en.NextElement(); scriptClass != NULL; scriptClass = en.NextElement() ) - { - for( vm = scriptClass->m_Threads; vm != NULL; vm = vm->next ) - { - if( iThread == iThreadNum ) - { - bFoundThread = true; - break; - } - - iThread++; - } - - if( bFoundThread ) - { - break; - } - } - - if( !bFoundThread ) - { - gi.Printf( "Can't find thread id %i.\n", iThreadNum ); - } - - status = "-------------------------\n"; - status += "num: " + str( iThreadNum ) + "\n"; - - switch( vm->ThreadState() ) - { - case THREAD_CONTEXT_SWITCH: - status += "state: running (context switch)\n"; - break; - case THREAD_RUNNING: - status += "state: running\n"; - break; - case THREAD_WAITING: - status += "state: waiting\n"; - break; - case THREAD_SUSPENDED: - status += "state: suspended\n"; - break; - } - - status += "script: '" + vm->Filename() + "'\n"; - status += "label: '" + vm->Label() + "'\n"; - status += "waittill: "; - - if( !vm->m_Thread->m_WaitForList ) - { - status += "(none)\n"; - } - else - { - con_set_enum< const_str, ConList > en = *vm->m_Thread->m_WaitForList; - Entry< const_str, ConList > *entry; - int i = 0; - - for( entry = en.NextElement(); entry != NULL; entry = en.NextElement() ) - { - str& name = Director.GetString( entry->key ); - - if( i > 0 ) - { - status += ", "; - } - - status += "'" + name + "'"; - - for( int j = 1; j <= entry->value.NumObjects(); j++ ) - { - Listener *l = entry->value.ObjectAt( j ); - - if( j > 1 ) - { - status += ", "; - } - - if( l ) - { - status += " on " + str( l->getClassname() ); - } - else - { - status += " on (null)"; - } - } - - i++; - } - - status += "\n"; - } - - gi.Printf( status.c_str() ); -} - -static int bLoadForMap( char *psMapsBuffer, const char *name ) -{ - cvar_t *mapname = gi.Cvar_Get( "mapname", "", 0 ); - const char *token; - - if( !strncmp( "test", mapname->string, sizeof( "test" ) ) ) { - return true; - } - - token = COM_Parse( &psMapsBuffer ); - if( !token || !*token ) - { - Com_Printf( "ERROR bLoadForMap: %s alias with empty maps specification.\n", name ); - return false; - } - - while( token && *token ) - { - if( !Q_stricmpn( token, mapname->string, strlen( token ) ) ) { - return true; - } - - token = COM_Parse( &psMapsBuffer ); - } - - return false; -} - -void ScriptMaster::RegisterAliasInternal - ( - Event *ev, - bool bCache - ) +void ScriptMaster::Cache(Event *ev) { #ifdef GAME_DLL - int i; - char parameters[ MAX_STRING_CHARS ]; - char *psMapsBuffer; - int subtitle; - bool bAlwaysLoaded = false; + if (!precache->integer) { + return; + } - // Get the parameters for this alias command - - parameters[ 0 ] = 0; - subtitle = 0; - psMapsBuffer = NULL; - - for( i = 3; i <= ev->NumArgs(); i++ ) - { - str s; - - // MOHAA doesn't check that - if( ev->IsListenerAt( i ) ) - { - Listener *l = ev->GetListener( i ); - - if( l && l == Director.CurrentThread() ) - { - s = "local"; - } - else - { - s = ev->GetString( i ); - } - } - else - { - s = ev->GetString( i ); - } - - if( subtitle ) - { - strcat( parameters, "\"" ); - strcat( parameters, s ); - strcat( parameters, "\" " ); - - subtitle = 0; - } - else if( !s.icmp( "maps" ) ) - { - i++; - psMapsBuffer = ( char * )ev->GetToken( i ).c_str(); - } else if (!s.icmp("always")) { - bAlwaysLoaded = true; - } else { - subtitle = s.icmp( "subtitle" ) == 0; - - strcat( parameters, s ); - strcat( parameters, " " ); - } - } - - if(bAlwaysLoaded || bLoadForMap( psMapsBuffer, ev->GetString( 1 ) ) ) - { - gi.GlobalAlias_Add( ev->GetString( 1 ), ev->GetString( 2 ), parameters ); - - if (bCache) { - CacheResource(ev->GetString(2)); - } - } + CacheResource(ev->GetString(1)); #endif } -void ScriptMaster::RegisterAlias - ( - Event *ev - ) +void ScriptMaster::InitConstStrings(void) { - RegisterAliasInternal( ev ); + EventDef *eventDef; + const_str name; + unsigned int eventnum; + con_map_enum en; + + for (int i = 0; i < sizeof(ConstStrings) / sizeof(ConstStrings[0]); i++) { + AddString(ConstStrings[i]); + } + + Event::normalCommandList.clear(); + Event::returnCommandList.clear(); + Event::getterCommandList.clear(); + Event::setterCommandList.clear(); + + en = Event::eventDefList; + + for (en.NextValue(); en.CurrentValue() != NULL; en.NextValue()) { + eventDef = en.CurrentValue(); + eventnum = (*en.CurrentKey())->eventnum; + str command = eventDef->command.c_str(); + command.tolower(); + + name = AddString(command); + + if (eventDef->type == EV_NORMAL) { + Event::normalCommandList[name] = eventnum; + } else if (eventDef->type == EV_RETURN) { + Event::returnCommandList[name] = eventnum; + } else if (eventDef->type == EV_GETTER) { + Event::getterCommandList[name] = eventnum; + } else if (eventDef->type == EV_SETTER) { + Event::setterCommandList[name] = eventnum; + } + } } -void ScriptMaster::RegisterAliasAndCache - ( - Event *ev - ) +ScriptThread *ScriptMaster::CreateThread(str filename, str label, Listener *self) { - RegisterAliasInternal( ev, true ); + GameScript *scr = GetScript(filename); + + if (!scr) { + return NULL; + } + + return CreateThread(scr, label, self); } -void ScriptMaster::Cache - ( - Event *ev - ) +ScriptThread *ScriptMaster::CreateThread(GameScript *scr, str label, Listener *self) { -#ifdef GAME_DLL - if( !precache->integer ) - return; + try { + return CreateScriptThread(scr, self, label); + } catch (ScriptException& exc) { + gi.DPrintf("ScriptMaster::CreateThread: %s\n", exc.string.c_str()); + return NULL; + } +} - CacheResource( ev->GetString( 1 ) ); +void ScriptMaster::ExecuteThread(str filename, str label) +{ + GameScript *scr = GetScript(filename); + + if (!scr) { + return; + } + + ExecuteThread(scr, label); +} + +void ScriptMaster::ExecuteThread(GameScript *scr, str label) +{ + ScriptThread *thread = CreateThread(scr, label); + + try { + if (thread) { + thread->Execute(); + } + } catch (ScriptException& exc) { + gi.DPrintf("ScriptMaster::ExecuteThread: %s\n", exc.string.c_str()); + } +} + +void ScriptMaster::ExecuteThread(str filename, str label, Event& parms) +{ + GameScript *scr = GetScript(filename); + + if (!scr) { + return; + } + + ExecuteThread(scr, label, parms); +} + +void ScriptMaster::ExecuteThread(GameScript *scr, str label, Event& parms) +{ + ScriptThread *thread = CreateThread(scr, label); + + try { + thread->Execute(parms); + } catch (ScriptException& exc) { + gi.DPrintf("ScriptMaster::ExecuteThread: %s\n", exc.string.c_str()); + } +} + +ScriptThread *ScriptMaster::CreateScriptThread(GameScript *scr, Listener *self, const_str label) +{ + ScriptClass *scriptClass = new ScriptClass(scr, self); + + return CreateScriptThread(scriptClass, label); +} + +ScriptThread *ScriptMaster::CreateScriptThread(ScriptClass *scriptClass, unsigned char *m_pCodePos) +{ + return new ScriptThread(scriptClass, m_pCodePos); +} + +ScriptThread *ScriptMaster::CreateScriptThread(ScriptClass *scriptClass, const_str label) +{ + unsigned char *m_pCodePos = scriptClass->FindLabel(label); + + if (!m_pCodePos) { + throw ScriptException( + "ScriptMaster::CreateScriptThread: label '%s' does not exist in '%s'.", + Director.GetString(label).c_str(), + scriptClass->Filename().c_str() + ); + } + + return CreateScriptThread(scriptClass, m_pCodePos); +} + +ScriptThread *ScriptMaster::CreateScriptThread(GameScript *scr, Listener *self, str label) +{ + return CreateScriptThread(scr, self, Director.AddString(label)); +} + +ScriptThread *ScriptMaster::CreateScriptThread(ScriptClass *scriptClass, str label) +{ + if (label.length() && *label) { + return CreateScriptThread(scriptClass, Director.AddString(label)); + } else { + return CreateScriptThread(scriptClass, STRING_EMPTY); + } +} + +void ScriptMaster::Reset(qboolean samemap) +{ + ScriptClass_allocator.FreeAll(); + + stackCount = 0; + cmdCount = 0; + cmdTime = 0; + maxTime = MAX_EXECUTION_TIME; + //pTop = &avar_Stack[ 0 ]; + iPaused = 0; + +#if defined(GAME_DLL) + for (int i = 1; i <= m_menus.NumObjects(); i++) { + Hidemenu(m_menus.ObjectAt(i), true); + } + + m_menus.ClearObjectList(); #endif + + if (!samemap) { + for (int i = 0; i < SE_MAX; i++) { + scriptedEvents[i] = ScriptEvent(); + } + + CloseGameScript(); + StringDict.clear(); + InitConstStrings(); + } } -void ScriptMaster::AddMenu( str name ) +void ScriptMaster::ExecuteRunning(void) { - m_menus.AddUniqueObject( name ); + int i; + int startTime; + + if (stackCount) { + return; + } + + if (timerList.IsDirty()) { + cmdTime = 0; + cmdCount = 0; + startTime = level.svsTime; + + while ((m_CurrentThread = (ScriptThread *)timerList.GetNextElement(i))) { + level.setTime(level.svsStartTime + i); + + m_CurrentThread->m_ScriptVM->m_ThreadState = THREAD_RUNNING; + m_CurrentThread->m_ScriptVM->Execute(); + } + + level.setTime(startTime); + level.m_LoopProtection = true; + } + + startTime = gi.Milliseconds(); } -void ScriptMaster::RemoveMenu( str name ) +void ScriptMaster::SetTime(int time) { - if( m_menus.IndexOfObject( name ) ) - { - m_menus.RemoveObject( name ); - } + timerList.SetTime(time); + timerList.SetDirty(); } -void ScriptMaster::LoadMenus( void ) +void ScriptMaster::AddTiming(ScriptThread *thread, float time) { - for( int i = 1; i <= m_menus.NumObjects(); i++ ) - { - Showmenu( m_menus.ObjectAt( i ), true ); - } + timerList.AddElement(thread, level.inttime + (int)(time * 1000.0f + 0.5f)); +} + +void ScriptMaster::RemoveTiming(ScriptThread *thread) +{ + timerList.RemoveElement(thread); +} + +ScriptClass *ScriptMaster::CurrentScriptClass(void) +{ + return CurrentThread()->GetScriptClass(); +} + +void ScriptMaster::CloseGameScript(void) +{ + con_map_enum en(m_GameScripts); + GameScript **g; + Container gameScripts; + + for (g = en.NextValue(); g != NULL; g = en.NextValue()) { + gameScripts.AddObject(*g); + } + + for (int i = gameScripts.NumObjects(); i > 0; i--) { + delete gameScripts.ObjectAt(i); + } + + m_GameScripts.clear(); +} + +GameScript *ScriptMaster::GetGameScriptInternal(str& filename) +{ + void *sourceBuffer = NULL; + int sourceLength; + char filepath[MAX_QPATH]; + GameScript *scr; + + if (filename.length() >= MAX_QPATH) { + gi.Error(ERR_DROP, "Script filename '%s' exceeds maximum length of %d\n", filename.c_str(), MAX_QPATH); + } + + scr = m_GameScripts[StringDict.findKeyIndex(filename)]; + + if (scr != NULL) { + return scr; + } + + strcpy(filepath, filename.c_str()); + gi.FS_CanonicalFilename(filepath); + filename = filepath; + + scr = new GameScript(filename); + + m_GameScripts[StringDict.addKeyIndex(filename)] = scr; + + if (GetCompiledScript(scr)) { + scr->m_Filename = Director.AddString(filename); + return scr; + } + + sourceLength = gi.FS_ReadFile(filename.c_str(), &sourceBuffer, true); + + if (sourceLength < 0) { + throw ScriptException("Can't find '%s'\n", filename.c_str()); + } + + scr->Load(sourceBuffer, sourceLength); + + gi.FS_FreeFile(sourceBuffer); + + if (!scr->successCompile) { + throw ScriptException("Script '%s' was not properly loaded", filename.c_str()); + } + + return scr; +} + +GameScript *ScriptMaster::GetGameScript(const_str filename, qboolean recompile) +{ + return GetGameScript(Director.GetString(filename), recompile); +} + +GameScript *ScriptMaster::GetGameScript(str filename, qboolean recompile) +{ + const_str s = StringDict.findKeyIndex(filename); + GameScript *scr = m_GameScripts[s]; + int i; + + if (scr != NULL && !recompile) { + if (!scr->successCompile) { + throw ScriptException("Script '%s' was not properly loaded\n", filename.c_str()); + } + + return scr; + } else { + if (scr && recompile) { + Container list; + MEM_BlockAlloc_enum en = ScriptClass_allocator; + ScriptClass *scriptClass; + m_GameScripts[s] = NULL; + + for (scriptClass = en.NextElement(); scriptClass != NULL; scriptClass = en.NextElement()) { + if (scriptClass->GetScript() == scr) { + list.AddObject(scriptClass); + } + } + + for (i = 1; i <= list.NumObjects(); i++) { + delete list.ObjectAt(i); + } + + delete scr; + } + + return GetGameScriptInternal(filename); + } +} + +GameScript *ScriptMaster::GetScript(const_str filename, qboolean recompile) +{ + try { + return GetGameScript(filename, recompile); + } catch (ScriptException& exc) { + gi.DPrintf("ScriptMaster::GetScript: %s\n", exc.string.c_str()); + } + + return NULL; +} + +GameScript *ScriptMaster::GetScript(str filename, qboolean recompile) +{ + try { + return GetGameScript(filename, recompile); + } catch (ScriptException& exc) { + gi.DPrintf("ScriptMaster::GetScript: %s\n", exc.string.c_str()); + } + + return NULL; +} + +void ScriptMaster::ArchiveString(Archiver& arc, const_str& s) +{ + str s2; + byte b; + + if (arc.Loading()) { + arc.ArchiveByte(&b); + if (b) { + arc.ArchiveString(&s2); + s = AddString(s2); + } else { + s = 0; + } + } else { + if (s) { + b = 1; + arc.ArchiveByte(&b); + + s2 = Director.GetString(s); + arc.ArchiveString(&s2); + } else { + b = 0; + arc.ArchiveByte(&b); + } + } +} + +void ScriptMaster::Archive(Archiver& arc) +{ + ScriptClass *scr; + ScriptVM *m_current; + ScriptThread *m_thread; + int num; + int i, j; + + if (arc.Saving()) { + num = (int)ScriptClass_allocator.Count(); + arc.ArchiveInteger(&num); + + MEM_BlockAlloc_enum en = ScriptClass_allocator; + for (scr = en.NextElement(); scr != NULL; scr = en.NextElement()) { + scr->ArchiveInternal(arc); + + num = 0; + for (m_current = scr->m_Threads; m_current != NULL; m_current = m_current->next) { + num++; + } + + arc.ArchiveInteger(&num); + + for (m_current = scr->m_Threads; m_current != NULL; m_current = m_current->next) { + m_current->m_Thread->ArchiveInternal(arc); + } + } + } else { + arc.ArchiveInteger(&num); + + for (i = 0; i < num; i++) { + scr = new ScriptClass(); + scr->ArchiveInternal(arc); + + arc.ArchiveInteger(&num); + + for (j = 0; j < num; j++) { + m_thread = new ScriptThread(scr, NULL); + m_thread->ArchiveInternal(arc); + } + } + } + + timerList.Archive(arc); + m_menus.Archive(arc); +} + +GameScript *ScriptMaster::GetTempScript(const char *data) +{ + GameScript *scr = new GameScript; + + scr->Load((void *)data, strlen(data)); + + if (!scr->successCompile) { + return NULL; + } + + return scr; +} + +void ScriptMaster::AddMenu(str name) +{ + m_menus.AddUniqueObject(name); +} + +void ScriptMaster::RemoveMenu(str name) +{ + if (m_menus.IndexOfObject(name)) { + m_menus.RemoveObject(name); + } +} + +void ScriptMaster::LoadMenus(void) +{ + for (int i = 1; i <= m_menus.NumObjects(); i++) { + Showmenu(m_menus.ObjectAt(i), true); + } +} + +ScriptThread *ScriptMaster::PreviousThread(void) +{ + return m_PreviousThread; +} + +ScriptThread *ScriptMaster::CurrentThread(void) +{ + return m_CurrentThread; +} + +ScriptThread *ScriptMaster::CurrentScriptThread(void) +{ + assert(m_CurrentThread); + if (!m_CurrentThread) { + ScriptError("current thread is NULL"); + } + + return m_CurrentThread; +} + +const_str ScriptMaster::AddString(const char *s) +{ + return StringDict.addKeyIndex(s); +} + +const_str ScriptMaster::AddString(str& s) +{ + return StringDict.addKeyIndex(s); +} + +const_str ScriptMaster::GetString(const char *s) +{ + const_str cs = StringDict.findKeyIndex(s); + + return cs ? cs : STRING_EMPTY; +} + +const_str ScriptMaster::GetString(str s) +{ + return GetString(s.c_str()); +} + +str& ScriptMaster::GetString(const_str s) +{ + return StringDict[s]; +} + +void ScriptMaster::Pause() +{ + iPaused++; +} + +void ScriptMaster::Unpause() +{ + if (iPaused-- == 1) { + ExecuteRunning(); + } +} + +void ScriptMaster::AllowPause(bool allow) +{ + if (allow) { + iPaused = 0; + } else { + iPaused = -1; + } +} + +void ScriptMaster::PrintStatus(void) +{ + str status; + int iThreadNum = 0; + int iThreadRunning = 0; + int iThreadWaiting = 0; + int iThreadSuspended = 0; + MEM_BlockAlloc_enum en = ScriptClass_allocator; + ScriptClass *scriptClass; + char szBuffer[MAX_STRING_TOKENS]; + + status = "num state label script \n"; + status += "------- ---------- --------------- ---------------\n"; + + for (scriptClass = en.NextElement(); scriptClass != NULL; scriptClass = en.NextElement()) { + ScriptVM *vm; + + for (vm = scriptClass->m_Threads; vm != NULL; vm = vm->next) { + sprintf(szBuffer, "%.7d", iThreadNum); + status += szBuffer + str(" "); + + switch (vm->ThreadState()) { + case THREAD_RUNNING: + sprintf(szBuffer, "%8s", "running"); + iThreadRunning++; + break; + case THREAD_WAITING: + sprintf(szBuffer, "%8s", "waiting"); + iThreadWaiting++; + break; + case THREAD_SUSPENDED: + sprintf(szBuffer, "%8s", "suspended"); + iThreadSuspended++; + break; + } + + status += szBuffer; + + sprintf(szBuffer, "%15s", vm->Label().c_str()); + status += szBuffer + str(" "); + + sprintf(szBuffer, "%15s", vm->Filename().c_str()); + status += szBuffer; + + status += "\n"; + iThreadNum++; + } + } + + status += "------- ---------- --------------- ---------------\n"; + status += str(m_GameScripts.size()) + " total scripts compiled\n"; + status += str(iThreadNum) + " total threads ( " + str(iThreadRunning) + " running thread(s), " + str(iThreadWaiting) + + " waiting thread(s), " + str(iThreadSuspended) + " suspended thread(s) )\n"; + + gi.Printf(status.c_str()); +} + +void ScriptMaster::PrintThread(int iThreadNum) +{ + int iThread = 0; + ScriptVM *vm; + bool bFoundThread = false; + str status; + MEM_BlockAlloc_enum en = ScriptClass_allocator; + ScriptClass *scriptClass; + + for (scriptClass = en.NextElement(); scriptClass != NULL; scriptClass = en.NextElement()) { + for (vm = scriptClass->m_Threads; vm != NULL; vm = vm->next) { + if (iThread == iThreadNum) { + bFoundThread = true; + break; + } + + iThread++; + } + + if (bFoundThread) { + break; + } + } + + if (!bFoundThread) { + gi.Printf("Can't find thread id %i.\n", iThreadNum); + } + + status = "-------------------------\n"; + status += "num: " + str(iThreadNum) + "\n"; + + switch (vm->ThreadState()) { + case THREAD_RUNNING: + status += "state: running\n"; + break; + case THREAD_WAITING: + status += "state: waiting\n"; + break; + case THREAD_SUSPENDED: + status += "state: suspended\n"; + break; + } + + status += "script: '" + vm->Filename() + "'\n"; + status += "label: '" + vm->Label() + "'\n"; + status += "waittill: "; + + if (!vm->m_Thread->m_WaitForList) { + status += "(none)\n"; + } else { + con_set_enum en = *vm->m_Thread->m_WaitForList; + Entry *entry; + int i = 0; + + for (entry = en.NextElement(); entry != NULL; entry = en.NextElement()) { + str& name = Director.GetString(entry->key); + + if (i > 0) { + status += ", "; + } + + status += "'" + name + "'"; + + for (int j = 1; j <= entry->value.NumObjects(); j++) { + Listener *l = entry->value.ObjectAt(j); + + if (j > 1) { + status += ", "; + } + + if (l) { + status += " on " + str(l->getClassname()); + } else { + status += " on (null)"; + } + } + + i++; + } + + status += "\n"; + } + + gi.Printf(status.c_str()); } diff --git a/code/fgame/scriptmaster.h b/code/fgame/scriptmaster.h index 2fba6384..dbc3d42c 100644 --- a/code/fgame/scriptmaster.h +++ b/code/fgame/scriptmaster.h @@ -22,30 +22,31 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // scriptmaster.h: Handle events, parse scripts, spawn at the beginning of the map -#ifndef __SCRIPTMASTER_H__ -#define __SCRIPTMASTER_H__ +#pragma once #include "class.h" #include "listener.h" #include "scriptvm.h" #include -#define MAX_COMMANDS 20 -#define MAX_EXECUTION_TIME 3000 +#define MAX_COMMANDS 20 +#define MAX_EXECUTION_TIME 3000 -void Showmenu( const str& name, qboolean bForce ); -void Hidemenu( const str& name, qboolean bForce ); +void Showmenu(const str& name, qboolean bForce); +void Hidemenu(const str& name, qboolean bForce); -#define MAX_VAR_STACK 1024 -#define MAX_FASTEVENT 10 +#define MAX_VAR_STACK 1024 +#define MAX_FASTEVENT 10 class ScriptMaster : public Listener { -public: - // VM recursions - int stackCount; + friend class ScriptThread; - // Global stack (not needed anymore) +public: + // VM recursions + int stackCount; + + // Global stack (not needed anymore) #if 0 ScriptVariable avar_Stack[ MAX_VAR_STACK+1 ]; // Global variables stack Event fastEvent[ MAX_FASTEVENT+1 ]; // Event that will be executed @@ -53,91 +54,90 @@ public: ScriptVariable *pTop; // Top variable on the stack #endif - // Command variables - unsigned int cmdCount; // cmd count - int cmdTime; // Elapsed VM execution time - int maxTime; // Maximum VM execution time + // Command variables + unsigned int cmdCount; // cmd count + int cmdTime; // Elapsed VM execution time + int maxTime; // Maximum VM execution time - // Thread variables - SafePtr m_PreviousThread; // parm.previousthread - SafePtr m_CurrentThread; // current running thread + // Thread variables + SafePtr m_PreviousThread; // parm.previousthread + SafePtr m_CurrentThread; // current running thread - con_map< const_str, GameScript * > m_GameScripts; // compiled gamescripts + con_map m_GameScripts; // compiled gamescripts - // Miscellaneous - Container< str > m_menus; // Script menus - con_timer timerList; // waiting threads list - con_arrayset< str, str > StringDict; // const strings (improve performance) - int iPaused; // num times paused + // Miscellaneous + Container m_menus; // Script menus + con_timer timerList; // waiting threads list + con_arrayset StringDict; // const strings (improve performance) + int iPaused; // num times paused protected: - static const char *ConstStrings[]; + static const char *ConstStrings[]; -private: - GameScript *GetGameScriptInternal( str& filename ); - void InitConstStrings( void ); +protected: + void InitConstStrings(void); + void CloseGameScript(); + GameScript *GetGameScriptInternal(str& filename); + void ExecuteRunning(); + void Cache(Event *ev); + void RegisterAliasAndCache(Event *ev); + void RegisterAlias(Event *ev); + void RegisterAliasInternal(Event *ev, bool bCache = false); public: - CLASS_PROTOTYPE( ScriptMaster ); + CLASS_PROTOTYPE(ScriptMaster); - virtual ~ScriptMaster(); + virtual ~ScriptMaster(); - void Archive( Archiver &arc ) override; - void ArchiveString( Archiver& arc, const_str& s ); + // + // Thread executions + // + ScriptThread *CreateThread(GameScript *scr, str label, Listener *self = NULL); + ScriptThread *CreateThread(str filename, str label, Listener *self = NULL); + void ExecuteThread(GameScript *scr, str label = ""); + void ExecuteThread(str filename, str label = ""); + void ExecuteThread(GameScript *scr, str label, Event &parms); + void ExecuteThread(str filename, str label, Event &parms); + ScriptThread *CreateScriptThread(ScriptClass *scriptClass, unsigned char *m_pCodePos); + ScriptThread *CreateScriptThread(GameScript *scr, Listener *self, const_str label); + ScriptThread *CreateScriptThread(GameScript *scr, Listener *self, str label); + ScriptThread *CreateScriptThread(ScriptClass *scriptClass, const_str label); + ScriptThread *CreateScriptThread(ScriptClass *scriptClass, str label); + void Reset(qboolean samemap = false); + ScriptThread *PreviousThread(void); + ScriptThread *CurrentThread(void); + ScriptThread *CurrentScriptThread(void); + ScriptClass *CurrentScriptClass(void); - const_str AddString( const char *s ); - const_str AddString( str& s ); - const_str GetString( const char *s ); - const_str GetString( str s ); + GameScript *GetGameScript(const_str filename, qboolean recompile = false); + GameScript *GetGameScript(str filename, qboolean recompile = false); + GameScript *GetScript(const_str filename, qboolean recompile = false); + GameScript *GetScript(str filename, qboolean recompile = false); - str& GetString( const_str s ); + void SetTime(int time); - void AddTiming( ScriptThread *thread, float time ); - void RemoveTiming( ScriptThread *thread ); + void AddTiming(ScriptThread *thread, float time); + void RemoveTiming(ScriptThread *thread); + const_str AddString(const char *s); + const_str AddString(str& s); + const_str GetString(const char *s); + const_str GetString(str s); + str & GetString(const_str s); - void AddMenu( str name ); - void RemoveMenu( str name ); - void LoadMenus( void ); + void ArchiveString(Archiver& arc, const_str& s); - ScriptThread *CreateScriptThread( GameScript *scr, Listener *self, const_str label ); - ScriptThread *CreateScriptThread( GameScript *scr, Listener *self, str label ); - ScriptThread *CreateScriptThread( ScriptClass *scriptClass, const_str label ); - ScriptThread *CreateScriptThread( ScriptClass *scriptClass, str label ); - ScriptThread *CreateScriptThread( ScriptClass *scriptClass, unsigned char *m_pCodePos ); - ScriptThread *CreateThread( GameScript *scr, str label, Listener *self = NULL ); - ScriptThread *CreateThread( str filename, str label, Listener *self = NULL ); - ScriptClass *CurrentScriptClass( void ); + void Pause(); + void Unpause(); + void AllowPause(bool allow); + void AddMenu(str name); + void RemoveMenu(str name); + void LoadMenus(void); + void Archive(Archiver& arc) override; - ScriptThread *CurrentThread( void ); - ScriptThread *PreviousThread( void ); + GameScript *GetTempScript(const char *data); - void ExecuteThread( GameScript *scr, str label = "" ); - void ExecuteThread( str filename, str label = "" ); - - void ExecuteThread( GameScript *scr, str label, Event &parms ); - void ExecuteThread( str filename, str label, Event &parms ); - - GameScript *GetTempScript( const char *data ); - GameScript *GetGameScript( str filename, qboolean recompile = false ); - GameScript *GetGameScript( const_str filename, qboolean recompile = false ); - GameScript *GetScript( str filename, qboolean recompile = false ); - GameScript *GetScript( const_str filename, qboolean recompile = false ); - - void CloseGameScript(); - void Reset( qboolean samemap = false ); - - void ExecuteRunning(); - void SetTime( int time ); - - void PrintStatus( void ); - void PrintThread( int iThreadNum ); - // - // Events - // - void RegisterAliasInternal( Event *ev, bool bCache = false ); - void RegisterAlias( Event *ev ); - void RegisterAliasAndCache( Event *ev ); - void Cache( Event *ev ); + void PrintStatus(void); + void PrintThread(int iThreadNum); }; extern Event EV_RegisterAlias; @@ -146,75 +146,62 @@ extern Event EV_Cache; extern qboolean disable_team_change; extern qboolean disable_team_spectate; -extern str vision_current; +extern str vision_current; extern Event EV_ScriptThread_Trace; extern Event EV_ScriptThread_SightTrace; extern Event EV_ScriptThread_VisionSetNaked; extern Event EV_ScriptThread_CancelWaiting; -extern con_set< str, ScriptThreadLabel > m_scriptCmds; -extern ScriptMaster Director; +extern con_set m_scriptCmds; +extern ScriptMaster Director; -typedef enum scriptedEvType_e -{ - SE_DEFAULT, - SE_CONNECTED, - SE_DISCONNECTED, - SE_SPAWN, - SE_DAMAGE, - SE_KILL, - SE_KEYPRESS, - SE_INTERMISSION, - SE_SERVERCOMMAND, - SE_CHANGETEAM, - SE_MAX +typedef enum scriptedEvType_e { + SE_DEFAULT, + SE_CONNECTED, + SE_DISCONNECTED, + SE_SPAWN, + SE_DAMAGE, + SE_KILL, + SE_KEYPRESS, + SE_INTERMISSION, + SE_SERVERCOMMAND, + SE_CHANGETEAM, + SE_MAX } scriptedEvType_t; class ScriptEvent : public Class { public: - ScriptThreadLabel label; + ScriptThreadLabel label; public: - CLASS_PROTOTYPE( ScriptEvent ); + CLASS_PROTOTYPE(ScriptEvent); - void Archive( Archiver& arc ) override; + void Archive(Archiver& arc) override; - bool IsRegistered( void ); - void Trigger( Event *ev ); + bool IsRegistered(void); + void Trigger(Event *ev); }; -inline void ScriptEvent::Archive - ( - Archiver& arc - ) +inline void ScriptEvent::Archive(Archiver& arc) { - label.Archive( arc ); + label.Archive(arc); } -inline bool ScriptEvent::IsRegistered - ( - void - ) +inline bool ScriptEvent::IsRegistered(void) { - return label.IsSet(); + return label.IsSet(); } -inline void ScriptEvent::Trigger - ( - Event *ev - ) +inline void ScriptEvent::Trigger(Event *ev) { - if( label.IsSet() ) - { - label.Execute( NULL, ev ); - } + if (label.IsSet()) { + label.Execute(NULL, ev); + } - delete ev; + delete ev; } extern ScriptEvent scriptedEvents[]; - -#endif /* scriptmaster.h */