mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
1222 lines
23 KiB
C++
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 );
|
|
}
|