doom3-bfg/neo/d3xp/script/Script_Interpreter.h

305 lines
7.8 KiB
C++

/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition 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 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition 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 Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef __SCRIPT_INTERPRETER_H__
#define __SCRIPT_INTERPRETER_H__
#define MAX_STACK_DEPTH 64
#define LOCALSTACK_SIZE 6144
typedef struct prstack_s
{
int s;
const function_t* f;
int stackbase;
} prstack_t;
class idInterpreter
{
private:
prstack_t callStack[ MAX_STACK_DEPTH ];
int callStackDepth;
int maxStackDepth;
byte localstack[ LOCALSTACK_SIZE ];
int localstackUsed;
int localstackBase;
int maxLocalstackUsed;
const function_t* currentFunction;
int instructionPointer;
int popParms;
const idEventDef* multiFrameEvent;
idEntity* eventEntity;
idThread* thread;
void PopParms( int numParms );
void PushString( const char* string );
void Push( int value );
const char* FloatToString( float value );
void AppendString( idVarDef* def, const char* from );
void SetString( idVarDef* def, const char* from );
const char* GetString( idVarDef* def );
varEval_t GetVariable( idVarDef* def );
idEntity* GetEntity( int entnum ) const;
idScriptObject* GetScriptObject( int entnum ) const;
void NextInstruction( int position );
void LeaveFunction( idVarDef* returnDef );
void CallEvent( const function_t* func, int argsize );
void CallSysEvent( const function_t* func, int argsize );
public:
bool doneProcessing;
bool threadDying;
bool terminateOnExit;
bool debug;
idInterpreter();
// save games
void Save( idSaveGame* savefile ) const; // archives object for save game file
void Restore( idRestoreGame* savefile ); // unarchives object from save game file
void SetThread( idThread* pThread );
void StackTrace() const;
int CurrentLine() const;
const char* CurrentFile() const;
void Error( VERIFY_FORMAT_STRING const char* fmt, ... ) const;
void Warning( VERIFY_FORMAT_STRING const char* fmt, ... ) const;
void DisplayInfo() const;
bool BeginMultiFrameEvent( idEntity* ent, const idEventDef* event );
void EndMultiFrameEvent( idEntity* ent, const idEventDef* event );
bool MultiFrameEventInProgress() const;
void ThreadCall( idInterpreter* source, const function_t* func, int args );
void EnterFunction( const function_t* func, bool clearStack );
void EnterObjectFunction( idEntity* self, const function_t* func, bool clearStack );
bool Execute();
void Reset();
bool GetRegisterValue( const char* name, idStr& out, int scopeDepth );
int GetCallstackDepth() const;
const prstack_t* GetCallstack() const;
const function_t* GetCurrentFunction() const;
idThread* GetThread() const;
};
/*
====================
idInterpreter::PopParms
====================
*/
ID_INLINE void idInterpreter::PopParms( int numParms )
{
// pop our parms off the stack
if( localstackUsed < numParms )
{
Error( "locals stack underflow\n" );
}
localstackUsed -= numParms;
}
/*
====================
idInterpreter::Push
====================
*/
ID_INLINE void idInterpreter::Push( int value )
{
if( localstackUsed + sizeof( int ) > LOCALSTACK_SIZE )
{
Error( "Push: locals stack overflow\n" );
}
*( int* )&localstack[ localstackUsed ] = value;
localstackUsed += sizeof( int );
}
/*
====================
idInterpreter::PushString
====================
*/
ID_INLINE void idInterpreter::PushString( const char* string )
{
if( localstackUsed + MAX_STRING_LEN > LOCALSTACK_SIZE )
{
Error( "PushString: locals stack overflow\n" );
}
idStr::Copynz( ( char* )&localstack[ localstackUsed ], string, MAX_STRING_LEN );
localstackUsed += MAX_STRING_LEN;
}
/*
====================
idInterpreter::FloatToString
====================
*/
ID_INLINE const char* idInterpreter::FloatToString( float value )
{
static char text[ 32 ];
if( value == ( float )( int )value )
{
sprintf( text, "%d", ( int )value );
}
else
{
sprintf( text, "%f", value );
}
return text;
}
/*
====================
idInterpreter::AppendString
====================
*/
ID_INLINE void idInterpreter::AppendString( idVarDef* def, const char* from )
{
if( def->initialized == idVarDef::stackVariable )
{
idStr::Append( ( char* )&localstack[ localstackBase + def->value.stackOffset ], MAX_STRING_LEN, from );
}
else
{
idStr::Append( def->value.stringPtr, MAX_STRING_LEN, from );
}
}
/*
====================
idInterpreter::SetString
====================
*/
ID_INLINE void idInterpreter::SetString( idVarDef* def, const char* from )
{
if( def->initialized == idVarDef::stackVariable )
{
idStr::Copynz( ( char* )&localstack[ localstackBase + def->value.stackOffset ], from, MAX_STRING_LEN );
}
else
{
idStr::Copynz( def->value.stringPtr, from, MAX_STRING_LEN );
}
}
/*
====================
idInterpreter::GetString
====================
*/
ID_INLINE const char* idInterpreter::GetString( idVarDef* def )
{
if( def->initialized == idVarDef::stackVariable )
{
return ( char* )&localstack[ localstackBase + def->value.stackOffset ];
}
else
{
return def->value.stringPtr;
}
}
/*
====================
idInterpreter::GetVariable
====================
*/
ID_INLINE varEval_t idInterpreter::GetVariable( idVarDef* def )
{
if( def->initialized == idVarDef::stackVariable )
{
varEval_t val;
val.intPtr = ( int* )&localstack[ localstackBase + def->value.stackOffset ];
return val;
}
else
{
return def->value;
}
}
/*
================
idInterpreter::GetEntity
================
*/
ID_INLINE idEntity* idInterpreter::GetEntity( int entnum ) const
{
assert( entnum <= MAX_GENTITIES );
if( ( entnum > 0 ) && ( entnum <= MAX_GENTITIES ) )
{
return gameLocal.entities[ entnum - 1 ];
}
return NULL;
}
/*
================
idInterpreter::GetScriptObject
================
*/
ID_INLINE idScriptObject* idInterpreter::GetScriptObject( int entnum ) const
{
idEntity* ent;
assert( entnum <= MAX_GENTITIES );
if( ( entnum > 0 ) && ( entnum <= MAX_GENTITIES ) )
{
ent = gameLocal.entities[ entnum - 1 ];
if( ent && ent->scriptObject.data )
{
return &ent->scriptObject;
}
}
return NULL;
}
/*
====================
idInterpreter::NextInstruction
====================
*/
ID_INLINE void idInterpreter::NextInstruction( int position )
{
// Before we execute an instruction, we increment instructionPointer,
// therefore we need to compensate for that here.
instructionPointer = position - 1;
}
#endif /* !__SCRIPT_INTERPRETER_H__ */