openmohaa/code/fgame/gamescript.cpp
2023-08-16 02:43:22 +02:00

1222 lines
23 KiB
C++

/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code 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 2 of the License,
or (at your option) any later version.
OpenMoHAA source code 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.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// gamescript.cpp : Subclass of script that preprocesses labels
#include "glb_local.h"
#include "gamescript.h"
#include "scriptcompiler.h"
#include "scriptmaster.h"
#include "scriptthread.h"
#include "scriptclass.h"
#include "scriptexception.h"
#include "level.h"
static unsigned char *current_progBuffer = NULL;
str& AbstractScript::Filename( void )
{
return Director.GetString( m_Filename );
}
const_str AbstractScript::ConstFilename( void )
{
return m_Filename;
}
bool AbstractScript::GetSourceAt( size_t sourcePos, str &sourceLine, int &column, int &line )
{
if( !m_SourceBuffer || sourcePos >= m_SourceLength ) {
return false;
}
line = 1;
column = 0;
int posLine = 0;
char *p = m_SourceBuffer;
char old_token;
for( int i = 0; i < sourcePos; i++, p++ )
{
column++;
if( *p == '\n' )
{
line++;
column = 0;
posLine = i + 1;
}
else if( *p == '\0' )
{
break;
}
}
while( *p != '\0' && *p != '\n' )
{
p++;
}
old_token = *p;
*p = '\0';
sourceLine = ( m_SourceBuffer + posLine );
*p = old_token;
return true;
}
void AbstractScript::PrintSourcePos( sourceinfo_t *sourcePos, bool dev )
{
int line;
int column;
str sourceLine;
if( GetSourceAt( sourcePos->sourcePos, sourceLine, column, line ) )
{
PrintSourcePos( sourceLine, column, line, dev );
}
else
{
glbs.DPrintf( "file '%s', source pos %d line %d column %d:\n", Filename().c_str(), sourcePos->sourcePos, sourcePos->line, sourcePos->column );
}
}
void AbstractScript::PrintSourcePos( size_t sourcePos, bool dev )
{
int line;
int column;
str sourceLine;
if( GetSourceAt( sourcePos, sourceLine, column, line ) )
{
PrintSourcePos( sourceLine, column, line, dev );
}
else
{
glbs.DPrintf( "file '%s', source pos %d:\n", Filename().c_str(), sourcePos );
}
}
void AbstractScript::PrintSourcePos( unsigned char *m_pCodePos, bool dev )
{
if( !m_ProgToSource )
{
return;
}
sourceinfo_t *codePos = m_ProgToSource->findKeyValue( m_pCodePos );
if( !codePos ) {
return;
}
PrintSourcePos( codePos, dev );
}
void AbstractScript::PrintSourcePos( str sourceLine, int column, int line, bool dev )
{
int i;
str markerLine = "";
for( i = 0; i < column; i++ )
{
markerLine.append( sourceLine[ i ] );
}
markerLine.append( "^" );
glbs.DPrintf( "(%s, %d):\n%s\n%s\n", Filename().c_str(), line, sourceLine.c_str(), markerLine.c_str() );
}
AbstractScript::AbstractScript()
{
m_ProgToSource = NULL;
m_SourceBuffer = NULL;
m_SourceLength = 0;
}
StateScript::StateScript()
{
m_Parent = NULL;
}
template<>
void Entry< const_str, script_label_t >::Archive( Archiver& arc )
{
unsigned int offset;
Director.ArchiveString( arc, key );
if( arc.Saving() )
{
offset = value.codepos - current_progBuffer;
arc.ArchiveUnsigned( &offset );
}
else
{
arc.ArchiveUnsigned( &offset );
value.codepos = current_progBuffer + offset;
value.key = key;
}
arc.ArchiveBool( &value.isprivate );
}
void StateScript::Archive( Archiver& arc )
{
label_list.Archive( arc );
}
bool StateScript::AddLabel( const_str label, unsigned char *pos, bool private_section )
{
if( label_list.findKeyValue( label ) )
{
return false;
}
script_label_t &s = label_list.addKeyValue( label );
s.codepos = pos;
s.key = label;
s.isprivate = private_section;
if( !label_list.findKeyValue(STRING_NULL) )
{
label_list.addKeyValue(STRING_NULL) = s;
}
reverse_label_list.AddObject( &s );
return true;
}
bool StateScript::AddLabel( str label, unsigned char *pos, bool private_section )
{
return AddLabel( Director.AddString( label ), pos, private_section );
}
unsigned char *StateScript::FindLabel( const_str label )
{
script_label_t *s;
ScriptClass *scriptClass;
GameScript *script;
s = label_list.findKeyValue( label );
if( s )
{
// check if the label is a private function
if( s->isprivate )
{
scriptClass = Director.CurrentScriptClass();
if( scriptClass )
{
script = scriptClass->GetScript();
// now check if the label's statescript matches this statescript
if( ( &script->m_State ) != this )
{
ScriptError( "Cannot call a private function." );
return NULL;
}
}
}
return s->codepos;
}
else
{
return NULL;
}
}
unsigned char *StateScript::FindLabel( str label )
{
return FindLabel( Director.AddString( label ) );
}
const_str StateScript::NearestLabel( unsigned char *pos )
{
unsigned int offset = pos - m_Parent->m_ProgBuffer;
unsigned int bestOfs = 0;
const_str label = STRING_NULL;
for( int i = 1; i <= reverse_label_list.NumObjects(); i++ )
{
script_label_t *l = reverse_label_list.ObjectAt( i );
if( ( l->codepos - m_Parent->m_ProgBuffer ) >= bestOfs )
{
bestOfs = l->codepos - m_Parent->m_ProgBuffer;
if( bestOfs > offset )
{
break;
}
label = l->key;
}
}
return label;
}
GameScript::GameScript()
{
m_Filename = STRING_NULL;
successCompile = false;
m_ProgBuffer = NULL;
m_ProgLength = 0;
m_bPrecompiled = false;
requiredStackSize = 0;
m_State.m_Parent = this;
}
GameScript::GameScript( const char *filename )
{
m_Filename = Director.AddString( filename );
successCompile = false;
m_ProgBuffer = NULL;
m_ProgLength = 0;
m_ProgToSource = NULL;
m_bPrecompiled = false;
m_SourceBuffer = NULL;
m_SourceLength = 0;
requiredStackSize = 0;
m_State.m_Parent = this;
}
GameScript::~GameScript()
{
Close();
}
struct pfixup_t {
bool isString;
unsigned int *ptr;
};
static Container< const_str > archivedEvents;
static Container< const_str > archivedStrings;
static Container< pfixup_t * > archivedPointerFixup;
void ArchiveOpcode( Archiver& arc, unsigned char *code )
{
unsigned int index;
arc.ArchiveByte( code );
switch( *code )
{
case OP_STORE_NIL:
case OP_STORE_NULL:
case OP_DONE:
break;
case OP_EXEC_CMD_COUNT1:
case OP_EXEC_CMD_METHOD_COUNT1:
case OP_EXEC_METHOD_COUNT1:
arc.ArchiveByte( code + 1 );
goto __exec;
case OP_EXEC_CMD0:
case OP_EXEC_CMD1:
case OP_EXEC_CMD2:
case OP_EXEC_CMD3:
case OP_EXEC_CMD4:
case OP_EXEC_CMD5:
case OP_EXEC_CMD_METHOD0:
case OP_EXEC_CMD_METHOD1:
case OP_EXEC_CMD_METHOD2:
case OP_EXEC_CMD_METHOD3:
case OP_EXEC_CMD_METHOD4:
case OP_EXEC_CMD_METHOD5:
case OP_EXEC_METHOD0:
case OP_EXEC_METHOD1:
case OP_EXEC_METHOD2:
case OP_EXEC_METHOD3:
case OP_EXEC_METHOD4:
case OP_EXEC_METHOD5:
code--;
__exec:
if( !arc.Loading() )
{
index = archivedEvents.AddUniqueObject( *reinterpret_cast< const_str * >( code + 2 ) );
}
arc.ArchiveUnsigned( &index );
if( arc.Loading() )
{
pfixup_t *p = new pfixup_t;
p->isString = false;
p->ptr = reinterpret_cast< unsigned int * >( code + 2 );
*reinterpret_cast< unsigned int * >( code + 2 ) = index;
archivedPointerFixup.AddObject( p );
}
break;
case OP_LOAD_FIELD_VAR:
case OP_LOAD_GAME_VAR:
case OP_LOAD_GROUP_VAR:
case OP_LOAD_LEVEL_VAR:
case OP_LOAD_LOCAL_VAR:
case OP_LOAD_OWNER_VAR:
case OP_LOAD_PARM_VAR:
case OP_LOAD_SELF_VAR:
case OP_LOAD_STORE_GAME_VAR:
case OP_LOAD_STORE_GROUP_VAR:
case OP_LOAD_STORE_LEVEL_VAR:
case OP_LOAD_STORE_LOCAL_VAR:
case OP_LOAD_STORE_OWNER_VAR:
case OP_LOAD_STORE_PARM_VAR:
case OP_LOAD_STORE_SELF_VAR:
case OP_STORE_FIELD:
case OP_STORE_FIELD_REF:
case OP_STORE_GAME_VAR:
case OP_STORE_GROUP_VAR:
case OP_STORE_LEVEL_VAR:
case OP_STORE_LOCAL_VAR:
case OP_STORE_OWNER_VAR:
case OP_STORE_PARM_VAR:
case OP_STORE_SELF_VAR:
case OP_STORE_STRING:
if( !arc.Loading() )
{
index = archivedStrings.AddUniqueObject( *reinterpret_cast< const_str * >( code + 1 ) );
}
arc.ArchiveUnsigned( &index );
if( arc.Loading() )
{
pfixup_t *p = new pfixup_t;
p->isString = true;
p->ptr = reinterpret_cast< unsigned int * >( code + 1 );
*reinterpret_cast< unsigned int * >( code + 1 ) = index;
archivedPointerFixup.AddObject( p );
}
break;
default:
if( OpcodeLength( *code ) > 1 )
arc.ArchiveRaw( code + 1, OpcodeLength( *code ) - 1 );
}
}
template<>
void Entry < unsigned char *, sourceinfo_t >::Archive( Archiver& arc )
{
unsigned int offset;
if( arc.Loading() )
{
arc.ArchiveUnsigned( &offset );
key = current_progBuffer + offset;
}
else
{
offset = key - current_progBuffer;
arc.ArchiveUnsigned( &offset );
}
arc.ArchiveUnsigned( &value.sourcePos );
arc.ArchiveInteger( &value.column );
arc.ArchiveInteger( &value.line );
}
void GameScript::Archive( Archiver& arc )
{
/*
int count = 0, i;
unsigned char *p, *code_pos, *code_end;
const_str s;
command_t *c, cmd;
arc.ArchiveSize( ( long * )&m_ProgLength );
if( arc.Saving() )
{
p = m_ProgBuffer;
current_progBuffer = m_ProgBuffer;
// archive opcodes
while( *p != OP_DONE )
{
ArchiveOpcode( arc, p );
p += OpcodeLength( *p );
}
ArchiveOpcode( arc, p );
// archive string dictionary list
i = archivedStrings.NumObjects();
arc.ArchiveInteger( &i );
for( ; i > 0; i-- )
{
Director.ArchiveString( arc, archivedStrings.ObjectAt( i ) );
}
// archive event list
i = archivedEvents.NumObjects();
arc.ArchiveInteger( &i );
for( ; i > 0; i-- )
{
c = Event::GetEventInfo( archivedEvents.ObjectAt( i ) );
arc.ArchiveString( &c->command );
arc.ArchiveInteger( &c->flags );
arc.ArchiveByte( &c->type );
}
}
else
{
m_ProgBuffer = ( unsigned char * )glbs.Malloc( m_ProgLength );
code_pos = m_ProgBuffer;
code_end = m_ProgBuffer + m_ProgLength;
current_progBuffer = m_ProgBuffer;
do
{
ArchiveOpcode( arc, code_pos );
code_pos += OpcodeLength( *code_pos );
} while( *code_pos != OP_DONE && arc.NoErrors() );
if( !arc.NoErrors() )
{
return;
}
// retrieve the string dictionary list
arc.ArchiveInteger( &i );
archivedStrings.Resize( i + 1 );
for( ; i > 0; i-- )
{
Director.ArchiveString( arc, s );
archivedStrings.AddObjectAt( i, s );
}
// retrieve the event list
arc.ArchiveInteger( &i );
archivedEvents.Resize( i + 1 );
for( ; i > 0; i-- )
{
arc.ArchiveString( &cmd.command );
arc.ArchiveInteger( &cmd.flags );
arc.ArchiveByte( &cmd.type );
archivedEvents.AddObjectAt( i, Event::GetEventWithFlags( cmd.command, cmd.flags, cmd.type ) );
}
// fix program string/event pointers
for( i = archivedPointerFixup.NumObjects(); i > 0; i-- )
{
pfixup_t *fixup = archivedPointerFixup.ObjectAt( i );
if( fixup->isString )
{
*fixup->ptr = archivedStrings.ObjectAt( *fixup->ptr );
}
else
{
*fixup->ptr = archivedEvents.ObjectAt( *fixup->ptr );
}
delete fixup;
}
successCompile = true;
}
// cleanup
archivedStrings.FreeObjectList();
archivedEvents.FreeObjectList();
archivedPointerFixup.FreeObjectList();
if( !arc.Loading() )
{
if( m_ProgToSource )
{
count = m_ProgToSource->size();
arc.ArchiveInteger( &count );
m_ProgToSource->Archive( arc );
}
else
{
arc.ArchiveInteger( &count );
}
}
else
{
arc.ArchiveInteger( &count );
if( count )
{
m_ProgToSource = new con_set < unsigned char *, sourceinfo_t >;
m_ProgToSource->Archive( arc );
}
}
arc.ArchiveUnsigned( &requiredStackSize );
arc.ArchiveBool( &m_bPrecompiled );
if( !m_bPrecompiled && arc.Loading() )
{
fileHandle_t filehandle = NULL;
m_SourceLength = glbs.FS_ReadFile( Filename().c_str(), ( void ** )&m_SourceBuffer, true );
if( m_SourceLength > 0 )
{
m_SourceBuffer = ( char * )glbs.Malloc( m_SourceLength );
glbs.FS_Read( m_SourceBuffer, m_SourceLength, filehandle );
glbs.FS_FCloseFile( filehandle );
}
}
m_State.Archive( arc );
current_progBuffer = NULL;*/
}
void GameScript::Archive( Archiver& arc, GameScript *& scr )
{
str filename;
if( arc.Saving() )
{
if (scr)
{
filename = scr->Filename();
}
else
{
filename = "";
}
arc.ArchiveString(&filename);
}
else
{
arc.ArchiveString(&filename);
if (filename != "")
{
scr = Director.GetScript(filename);
}
else
{
scr = NULL;
}
}
}
void GameScript::ArchiveCodePos( Archiver& arc, unsigned char **codePos )
{
int pos = 0;
str filename;
if( !arc.Saving() )
{
pos = *codePos - m_ProgBuffer;
if( pos >= 0 && pos < m_ProgLength )
{
filename = Filename();
}
}
arc.ArchiveInteger( &pos );
arc.ArchiveString( &filename );
if( arc.Loading() )
{
if( Filename() == filename )
{
*codePos = m_ProgBuffer + pos;
}
}
}
void GameScript::Close( void )
{
for( int i = m_CatchBlocks.NumObjects(); i > 0; i-- )
{
delete m_CatchBlocks.ObjectAt( i );
}
m_CatchBlocks.FreeObjectList();
if( m_ProgToSource )
{
delete m_ProgToSource;
m_ProgToSource = NULL;
}
if( m_ProgBuffer )
{
glbs.Free( m_ProgBuffer );
m_ProgBuffer = NULL;
}
if( m_SourceBuffer )
{
glbs.Free( m_SourceBuffer );
m_SourceBuffer = NULL;
}
m_ProgLength = 0;
m_SourceLength = 0;
m_bPrecompiled = false;
}
void GameScript::Load( const void *sourceBuffer, size_t sourceLength )
{
size_t nodeLength;
char *m_PreprocessedBuffer;
m_SourceBuffer = ( char * )glbs.Malloc( sourceLength + 2 );
m_SourceLength = sourceLength;
// Original mohaa doesn't reallocate the input string to append a newline
// This is a temporary workaround to handle the absolute disaster of newlines
// Both the lexer and grammar are extremely abhorrent at handling newlines followed by an EOF
m_SourceBuffer[ sourceLength ] = '\n';
m_SourceBuffer[ sourceLength + 1] = 0;
memcpy( m_SourceBuffer, sourceBuffer, sourceLength );
Compiler.Reset();
m_PreprocessedBuffer = Compiler.Preprocess( m_SourceBuffer );
nodeLength = Compiler.Parse( this, m_PreprocessedBuffer, "script" );
Compiler.Preclean( m_PreprocessedBuffer );
if( !nodeLength )
{
glbs.DPrintf2( "^~^~^ Script file compile error: Couldn't parse '%s'\n", Filename().c_str() );
return Close();
}
m_ProgBuffer = ( unsigned char * )glbs.Malloc( nodeLength );
m_ProgLength = Compiler.Compile( this, m_ProgBuffer );
if( !m_ProgLength )
{
glbs.DPrintf2( "^~^~^ Script file compile error: Couldn't compile '%s'\n", Filename().c_str() );
return Close();
}
requiredStackSize = Compiler.m_iInternalMaxVarStackOffset + 9 * Compiler.m_iMaxExternalVarStackOffset + 1;
successCompile = true;
}
bool GameScript::GetCodePos( unsigned char *codePos, str& filename, int& pos )
{
pos = codePos - m_ProgBuffer;
if( pos >= 0 && pos < m_ProgLength )
{
filename = Filename();
return true;
}
else
{
return false;
}
}
bool GameScript::SetCodePos( unsigned char *&codePos, str& filename, int pos )
{
if( Filename() == filename )
{
codePos = m_ProgBuffer + pos;
return true;
}
else
{
return false;
}
}
unsigned int GameScript::GetRequiredStackSize( void )
{
return requiredStackSize;
}
qboolean GameScript::labelExists( const char *name )
{
str labelname;
// if we got passed a NULL than that means just run the script so of course it exists
if ( !name )
{
return true;
}
if( m_State.FindLabel( name ) )
{
return true;
}
return false;
}
StateScript *GameScript::CreateCatchStateScript( unsigned char *try_begin_code_pos, unsigned char *try_end_code_pos )
{
CatchBlock *catchBlock = new CatchBlock;
catchBlock->m_TryStartCodePos = try_begin_code_pos;
catchBlock->m_TryEndCodePos = try_end_code_pos;
m_CatchBlocks.AddObject( catchBlock );
return &catchBlock->m_StateScript;
}
StateScript *GameScript::CreateSwitchStateScript( void )
{
return new StateScript;
}
StateScript *GameScript::GetCatchStateScript( unsigned char *in, unsigned char *&out )
{
CatchBlock *catchBlock;
CatchBlock *bestCatchBlock = NULL;
for( int i = m_CatchBlocks.NumObjects(); i > 0; i-- )
{
catchBlock = m_CatchBlocks.ObjectAt( i );
if( in >= catchBlock->m_TryStartCodePos && in < catchBlock->m_TryEndCodePos )
{
if( !bestCatchBlock || catchBlock->m_TryEndCodePos < bestCatchBlock->m_TryEndCodePos )
{
bestCatchBlock = catchBlock;
}
}
}
if( bestCatchBlock )
{
out = bestCatchBlock->m_TryEndCodePos;
return &bestCatchBlock->m_StateScript;
}
else
{
return NULL;
}
}
bool GameScript::ScriptCheck(void)
{
if (g_scriptcheck->integer == 1)
{
return true;
}
if (g_scriptcheck->integer == 2 || g_scriptcheck->integer == 3)
{
if (strstr(Filename().c_str(), "anim/") != Filename().c_str())
{
return true;
}
}
if (g_scriptcheck->integer == 3)
{
if (strstr(Filename().c_str(), "global/") != Filename().c_str())
{
return true;
}
}
return false;
}
ScriptThreadLabel::ScriptThreadLabel()
{
m_Script = NULL;
m_Label = STRING_EMPTY;
}
ScriptThread *ScriptThreadLabel::Create( Listener *listener )
{
if( !m_Script ) {
return NULL;
}
ScriptClass *scriptClass = new ScriptClass( m_Script, listener );
ScriptThread *thread = Director.CreateScriptThread( scriptClass, m_Label );
return thread;
}
void ScriptThreadLabel::Execute( Listener *listener )
{
if( !m_Script ) {
return;
}
ScriptThread *thread = Create( listener );
if( thread )
{
thread->Execute();
}
}
void ScriptThreadLabel::Execute( Listener *listener, Event &ev )
{
Execute( listener, &ev );
}
void ScriptThreadLabel::Execute( Listener *listener, Event *ev )
{
if( !m_Script ) {
return;
}
ScriptThread *thread = Create( listener );
if( thread )
{
thread->Execute( ev );
}
}
void ScriptThreadLabel::Execute(const SafePtr<Listener>& listener, const SafePtr<Listener>& param)
{
if (!m_Script) {
return;
}
ScriptVariable params[2];
params[0].setListenerValue(listener);
params[1].setListenerValue(param);
ScriptClass* scriptClass = new ScriptClass(m_Script, listener);
ScriptThread* thread = Director.CreateScriptThread(scriptClass, m_Label);
if (thread)
{
thread->Execute(params, 2);
}
}
void ScriptThreadLabel::Set(const char *label)
{
str script;
char buffer[ 1023 ];
char *p = buffer;
int i = 0;
bool foundLabel = false;
if( !label || !*label )
{
m_Script = NULL;
m_Label = STRING_EMPTY;
return;
}
strcpy( buffer, label );
while( true )
{
if( p[ 0 ] == ':' && p[ 1 ] == ':' )
{
*p = '\0';
script = buffer;
m_Label = Director.AddString( &p[ 2 ] );
foundLabel = true;
break;
}
p++;
i++;
if (*p == '\0')
{
break;
}
if (i >= 1023)
{
//we didn't find label but this is how it works.
//the whole string is the label
m_Label = Director.AddString(buffer);
script = buffer;
foundLabel = true;
break;
}
}
if( !foundLabel )
{
script = level.m_mapscript;
m_Label = Director.AddString(buffer);
}
m_Script = Director.GetGameScript( script );
if( !m_Script->m_State.FindLabel( m_Label ) )
{
str l = Director.GetString( m_Label );
m_Script = NULL;
m_Label = STRING_EMPTY;
ScriptError( "^~^~^ Could not find label '%s' in '%s'", l.c_str(), script.c_str() );
}
}
void ScriptThreadLabel::SetScript( const ScriptVariable& label )
{
if( label.GetType() == VARIABLE_STRING || label.GetType() == VARIABLE_CONSTSTRING )
{
m_Script = Director.GetGameScript( label.stringValue() );
m_Label = STRING_EMPTY;
}
else if( label.GetType() == VARIABLE_CONSTARRAY && label.arraysize() > 1 )
{
ScriptVariable *script = label[ 1 ];
ScriptVariable *labelname = label[ 2 ];
m_Script = Director.GetGameScript( script->stringValue() );
m_Label = labelname->constStringValue();
if( !m_Script->m_State.FindLabel( m_Label ) )
{
m_Script = NULL;
m_Label = STRING_EMPTY;
ScriptError( "^~^~^ Could not find label '%s' in '%s'", labelname->stringValue().c_str(), script->stringValue().c_str() );
}
}
else
{
ScriptError( "ScriptThreadLabel::SetScript: bad label type '%s'", label.GetTypeName() );
}
}
void ScriptThreadLabel::SetScript( const char *label )
{
str script;
char buffer[1023];
char *p = buffer;
int i = 0;
bool foundLabel = false;
if (!label || !*label)
{
m_Script = NULL;
m_Label = STRING_EMPTY;
return;
}
strcpy(buffer, label);
script = buffer;
while (true)
{
if (p[0] == ':' && p[1] == ':')
{
*p = '\0';
m_Label = Director.AddString(&p[2]);
foundLabel = true;
break;
}
p++;
i++;
if (*p == '\0')
{
m_Label = STRING_EMPTY;
foundLabel = true;
break;
}
if (i >= 1023)
{
//we didn't find label so empty label
m_Label = STRING_EMPTY;
foundLabel = false;
break;
}
}
m_Script = Director.GetGameScript(script);
if (!m_Script->m_State.FindLabel(m_Label))
{
str l = Director.GetString(m_Label);
m_Script = NULL;
m_Label = STRING_EMPTY;
ScriptError("^~^~^ Could not find label '%s' in '%s'", l.c_str(), script.c_str());
}
}
void ScriptThreadLabel::SetThread( const ScriptVariable& label )
{
ScriptThread *thread = NULL;
if( label.GetType() == VARIABLE_STRING || label.GetType() == VARIABLE_CONSTSTRING )
{
m_Script = Director.CurrentScriptClass()->GetScript();
m_Label = label.constStringValue();
}
else if( label.GetType() == VARIABLE_CONSTARRAY && label.arraysize() > 1 )
{
ScriptVariable *script = label[ 1 ];
ScriptVariable *labelname = label[ 2 ];
m_Script = Director.GetGameScript( script->stringValue() );
m_Label = labelname->constStringValue();
if( !m_Script->m_State.FindLabel( m_Label ) )
{
m_Script = NULL;
m_Label = STRING_EMPTY;
ScriptError( "^~^~^ Could not find label '%s' in '%s'", labelname->stringValue().c_str(), script->stringValue().c_str() );
}
}
else
{
ScriptError( "ScriptThreadLabel::SetThread bad label type '%s'", label.GetTypeName() );
}
}
bool ScriptThreadLabel::TrySet( const char *label )
{
try
{
Set( label );
}
catch( const char *string )
{
Com_Printf( "%s\n", string );
return false;
}
return true;
}
bool ScriptThreadLabel::TrySet( const_str label )
{
return TrySet( Director.GetString( label ) );
}
bool ScriptThreadLabel::TrySetScript( const char *label )
{
try
{
SetScript( label );
}
catch( const char *string )
{
Com_Printf( "%s\n", string );
return false;
}
return true;
}
bool ScriptThreadLabel::TrySetScript( const_str label )
{
return TrySetScript( Director.GetString( label ) );
}
void ScriptThreadLabel::GetScriptValue(ScriptVariable *var)
{
//FIXME: macro: 2 ?
ScriptVariable var_array[2];
if (m_Script)
{
var_array[0].setConstStringValue(m_Script->ConstFilename());
var_array[1].setConstStringValue(m_Label);
var->setConstArrayValue(var_array, 2);
for (int i = 0; i < 2; i++)
{
var_array[i].Clear();
}
}
else
{
var->Clear();
}
}
bool ScriptThreadLabel::IsSet( void )
{
return m_Script != NULL;
}
bool ScriptThreadLabel::IsFile(const_str filename)
{
return m_Script && m_Script->ConstFilename() == filename && m_Label == STRING_EMPTY;
}
void ScriptThreadLabel::Archive( Archiver& arc )
{
GameScript::Archive(arc, m_Script);
Director.ArchiveString( arc, m_Label );
}