//----------------------------------------------------------------------------- // // $Logfile:: /Code/DLLs/game/gamescript.cpp $ // $Revision:: 5 $ // $Author:: Steven $ // $Date:: 10/08/02 1:37p $ // // Copyright (C) 1997 by Ritual Entertainment, Inc. // All rights reserved. // // This source is may not be distributed and/or modified without // expressly written permission by Ritual Entertainment, Inc. // // // DESCRIPTION: // Subclass of script that preprocesses labels // #include "_pch_cpp.h" #include "script.h" #include "gamescript.h" ScriptLibrarian ScriptLib; CLASS_DECLARATION( Class, GameScriptMarker, NULL ) { { NULL, NULL } }; CLASS_DECLARATION( Class, ScriptLibrarian, NULL ) { { NULL, NULL } }; ScriptLibrarian::~ScriptLibrarian() { int i; int num; num = scripts.NumObjects(); for( i = 1; i <= num; i++ ) { delete scripts.ObjectAt( i ); } } void ScriptLibrarian::CloseScripts( void ) { int i; int num; GameScript *scr; // Clear out the game and dialog scripts SetGameScript( "" ); SetDialogScript( "" ); num = scripts.NumObjects(); for( i = num; i > 0; i-- ) { scr = scripts.ObjectAt( i ); scripts.RemoveObjectAt( i ); delete scr; } } void ScriptLibrarian::SetDialogScript( const str &scriptname ) { dialog_script = scriptname; } void ScriptLibrarian::SetGameScript( const str &scriptname ) { game_script = scriptname; } const char *ScriptLibrarian::GetGameScript( void ) { return game_script.c_str(); } GameScript *ScriptLibrarian::FindScript( const char *name ) { int i; int num; GameScript *scr; str n; // Convert all forward slashes to back slashes n = G_FixSlashes( name ); num = scripts.NumObjects(); for( i = 1; i <= num; i++ ) { scr = scripts.ObjectAt( i ); if ( scr->Filename() == n ) { return scr; } } return NULL; } GameScript *ScriptLibrarian::GetScript( const char *name ) { GameScript *scr; str n; n = G_FixSlashes( name ); if ( !n.length() ) { return NULL; } // see if we have an absolute path specified, // if we don't use the same path as the map file if ( !strchr( n.c_str(), '/' ) ) { int i; str mapname; mapname = "maps/"; mapname += level.mapname; for( i = mapname.length() - 1; i >= 0; i-- ) { if ( mapname[ i ] == '/' ) { // skip back over the '/' i++; mapname[ i ] = 0; break; } } mapname += n; // copy it back into the write string n = mapname; } scr = FindScript( n.c_str() ); if ( !scr && ( gi.FS_ReadFile( n.c_str(), NULL, false ) != -1 ) ) { scr = new GameScript(); scr->LoadFile( n.c_str() ); scripts.AddObject( scr ); } return scr; } qboolean ScriptLibrarian::Goto( GameScript *scr, const char *name ) { const char *p; GameScript *s; str n; p = strstr( name, "::" ); if ( !p ) { return scr->Goto( name ); } else { n = str( name, 0, p - name ); if ( n == str( "dialog" ) ) { n = dialog_script; } s = GetScript( n.c_str() ); if ( !s ) { return false; } p += 2; if ( s->labelExists( p ) ) { scr->SetSourceScript( s ); return scr->Goto( p ); } } return false; } qboolean ScriptLibrarian::labelExists( GameScript *scr, const char *name ) { const char *p; GameScript *s; str n; // if we got passed a NULL than that means just run the script so of course it exists if ( !name ) { return true; } p = strstr( name, "::" ); if ( !p ) { return scr->labelExists( name ); } else { n = str( name, 0, p - name ); if ( n == str( "dialog" ) ) { n = dialog_script; } s = GetScript( n.c_str() ); if ( !s ) { return false; } p += 2; return s->labelExists( p ); } } CLASS_DECLARATION( Script, GameScript, NULL ) { { NULL, NULL } }; GameScript::GameScript() { sourcescript = this; labelList = NULL; crc = 0; } GameScript::GameScript( GameScript *scr ) { crc = 0; labelList = NULL; SetSourceScript( scr ); } GameScript::~GameScript() { Close(); } void GameScript::Close( void ) { FreeLabels(); Script::Close(); sourcescript = this; crc = 0; } void GameScript::SetSourceScript( GameScript *scr ) { if ( scr != this ) { Close(); sourcescript = scr->sourcescript; crc = sourcescript->crc; Parse( scr->buffer, scr->length, scr->Filename() ); } } void GameScript::FreeLabels( void ) { int i; int num; if ( labelList ) { num = labelList->NumObjects(); for( i = 1; i <= num; i++ ) { delete labelList->ObjectAt( i ); } delete labelList; } labelList = NULL; } void GameScript::LoadFile( const char *name ) { str n; // Convert all forward slashes to back slashes n = G_FixSlashes( name ); sourcescript = this; Script::LoadFile( n.c_str() ); FindLabels(); crc = gi.CalcCRC( (const unsigned char *)buffer, length ); } void GameScript::FindLabels( void ) { scriptmarker_t mark; const char *tok; script_label_t *label; int len; FreeLabels(); labelList = new Container; MarkPosition( &mark ); Reset(); while( TokenAvailable( true ) ) { tok = GetToken( true ); // see if it is a label if ( tok ) { len = strlen( tok ); if ( ( len > 1 ) && ( tok[ len - 1 ] == ':' ) ) { if ( !labelExists( tok ) ) { label = new script_label_t; MarkPosition( &label->pos ); label->labelname = tok; labelList->AddObject( label ); } else { warning( "FindLabels", "Duplicate labels %s\n", tok ); } } } } RestorePosition( &mark ); } qboolean GameScript::labelExists( const char *name ) { str labelname; script_label_t *label; int i; int num; // if we got passed a NULL than that means just run the script so of course it exists if ( !name ) { return true; } if ( !sourcescript->labelList ) { return false; } labelname = name; if ( !labelname.length() ) { return false; } if ( labelname[ labelname.length() - 1 ] != ':' ) { labelname += ":"; } num = sourcescript->labelList->NumObjects(); for( i = 1; i <= num; i++ ) { label = sourcescript->labelList->ObjectAt( i ); if ( labelname == label->labelname ) { return true; } } return false; } qboolean GameScript::Goto( const char *name ) { str labelname; script_label_t *label; int i; int num; if ( !sourcescript->labelList ) { return false; } labelname = name; if ( !labelname.length() ) { return false; } if ( labelname[ labelname.length() - 1 ] != ':' ) { labelname += ":"; } num = sourcescript->labelList->NumObjects(); for( i = 1; i <= num; i++ ) { label = sourcescript->labelList->ObjectAt( i ); if ( labelname == label->labelname ) { RestorePosition( &label->pos ); return true; } } return false; } void GameScript::Mark( GameScriptMarker *mark ) { assert( mark ); assert( sourcescript ); mark->filename = sourcescript->Filename(); MarkPosition( &mark->scriptmarker ); } void GameScript::Restore( GameScriptMarker *mark ) { // If we change this function, we must update the unarchive function as well GameScript *scr; assert( mark ); scr = ScriptLib.FindScript( mark->filename.c_str() ); if ( scr ) { SetSourceScript( scr ); } else { LoadFile( mark->filename.c_str() ); } RestorePosition( &mark->scriptmarker ); }