mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-12-02 17:02:17 +00:00
2579 lines
51 KiB
C++
2579 lines
51 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
|
Copyright (C) 2012 Robert Beckebans
|
|
|
|
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.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#pragma hdrstop
|
|
#include "precompiled.h"
|
|
|
|
|
|
#include "../Game_local.h"
|
|
|
|
// simple types. function types are dynamically allocated
|
|
idTypeDef type_void( ev_void, &def_void, "void", 0, NULL );
|
|
|
|
// RB: 64 bit fixes, changed all pointer types to intptr_t
|
|
idTypeDef type_scriptevent( ev_scriptevent, &def_scriptevent, "scriptevent", sizeof( intptr_t ), NULL );
|
|
idTypeDef type_namespace( ev_namespace, &def_namespace, "namespace", sizeof( intptr_t ), NULL );
|
|
idTypeDef type_string( ev_string, &def_string, "string", MAX_STRING_LEN, NULL );
|
|
idTypeDef type_float( ev_float, &def_float, "float", sizeof( intptr_t ), NULL );
|
|
idTypeDef type_vector( ev_vector, &def_vector, "vector", E_EVENT_SIZEOF_VEC, NULL );
|
|
idTypeDef type_entity( ev_entity, &def_entity, "entity", sizeof( intptr_t ), NULL ); // stored as entity number pointer
|
|
idTypeDef type_field( ev_field, &def_field, "field", sizeof( intptr_t ), NULL );
|
|
idTypeDef type_function( ev_function, &def_function, "function", sizeof( intptr_t ), &type_void );
|
|
idTypeDef type_virtualfunction( ev_virtualfunction, &def_virtualfunction, "virtual function", sizeof( intptr_t ), NULL );
|
|
idTypeDef type_pointer( ev_pointer, &def_pointer, "pointer", sizeof( intptr_t ), NULL );
|
|
idTypeDef type_object( ev_object, &def_object, "object", sizeof( intptr_t ), NULL ); // stored as entity number pointer
|
|
idTypeDef type_jumpoffset( ev_jumpoffset, &def_jumpoffset, "<jump>", sizeof( intptr_t ), NULL ); // only used for jump opcodes
|
|
idTypeDef type_argsize( ev_argsize, &def_argsize, "<argsize>", sizeof( intptr_t ), NULL ); // only used for function call and thread opcodes
|
|
idTypeDef type_boolean( ev_boolean, &def_boolean, "boolean", sizeof( intptr_t ), NULL );
|
|
// RB end
|
|
|
|
idVarDef def_void( &type_void );
|
|
idVarDef def_scriptevent( &type_scriptevent );
|
|
idVarDef def_namespace( &type_namespace );
|
|
idVarDef def_string( &type_string );
|
|
idVarDef def_float( &type_float );
|
|
idVarDef def_vector( &type_vector );
|
|
idVarDef def_entity( &type_entity );
|
|
idVarDef def_field( &type_field );
|
|
idVarDef def_function( &type_function );
|
|
idVarDef def_virtualfunction( &type_virtualfunction );
|
|
idVarDef def_pointer( &type_pointer );
|
|
idVarDef def_object( &type_object );
|
|
idVarDef def_jumpoffset( &type_jumpoffset ); // only used for jump opcodes
|
|
idVarDef def_argsize( &type_argsize );
|
|
idVarDef def_boolean( &type_boolean );
|
|
|
|
/***********************************************************************
|
|
|
|
function_t
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
================
|
|
function_t::function_t
|
|
================
|
|
*/
|
|
function_t::function_t()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
/*
|
|
================
|
|
function_t::Allocated
|
|
================
|
|
*/
|
|
size_t function_t::Allocated() const
|
|
{
|
|
return name.Allocated() + parmSize.Allocated();
|
|
}
|
|
|
|
/*
|
|
================
|
|
function_t::SetName
|
|
================
|
|
*/
|
|
void function_t::SetName( const char* name )
|
|
{
|
|
this->name = name;
|
|
}
|
|
|
|
/*
|
|
================
|
|
function_t::Name
|
|
================
|
|
*/
|
|
const char* function_t::Name() const
|
|
{
|
|
return name;
|
|
}
|
|
|
|
/*
|
|
================
|
|
function_t::Clear
|
|
================
|
|
*/
|
|
void function_t::Clear()
|
|
{
|
|
eventdef = NULL;
|
|
def = NULL;
|
|
type = NULL;
|
|
firstStatement = 0;
|
|
numStatements = 0;
|
|
parmTotal = 0;
|
|
locals = 0;
|
|
filenum = 0;
|
|
name.Clear();
|
|
parmSize.Clear();
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
idTypeDef
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
================
|
|
idTypeDef::idTypeDef
|
|
================
|
|
*/
|
|
idTypeDef::idTypeDef( etype_t etype, idVarDef* edef, const char* ename, int esize, idTypeDef* aux )
|
|
{
|
|
name = ename;
|
|
type = etype;
|
|
def = edef;
|
|
size = esize;
|
|
auxType = aux;
|
|
|
|
parmTypes.SetGranularity( 1 );
|
|
parmNames.SetGranularity( 1 );
|
|
functions.SetGranularity( 1 );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::idTypeDef
|
|
================
|
|
*/
|
|
idTypeDef::idTypeDef( const idTypeDef& other )
|
|
{
|
|
*this = other;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::operator=
|
|
================
|
|
*/
|
|
void idTypeDef::operator=( const idTypeDef& other )
|
|
{
|
|
type = other.type;
|
|
def = other.def;
|
|
name = other.name;
|
|
size = other.size;
|
|
auxType = other.auxType;
|
|
parmTypes = other.parmTypes;
|
|
parmNames = other.parmNames;
|
|
functions = other.functions;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::Allocated
|
|
================
|
|
*/
|
|
size_t idTypeDef::Allocated() const
|
|
{
|
|
size_t memsize;
|
|
int i;
|
|
|
|
memsize = name.Allocated() + parmTypes.Allocated() + parmNames.Allocated() + functions.Allocated();
|
|
for( i = 0; i < parmTypes.Num(); i++ )
|
|
{
|
|
memsize += parmNames[ i ].Allocated();
|
|
}
|
|
|
|
return memsize;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::Inherits
|
|
|
|
Returns true if basetype is an ancestor of this type.
|
|
================
|
|
*/
|
|
bool idTypeDef::Inherits( const idTypeDef* basetype ) const
|
|
{
|
|
idTypeDef* superType;
|
|
|
|
if( type != ev_object )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( this == basetype )
|
|
{
|
|
return true;
|
|
}
|
|
for( superType = auxType; superType != NULL; superType = superType->auxType )
|
|
{
|
|
if( superType == basetype )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::MatchesType
|
|
|
|
Returns true if both types' base types and parameters match
|
|
================
|
|
*/
|
|
bool idTypeDef::MatchesType( const idTypeDef& matchtype ) const
|
|
{
|
|
int i;
|
|
|
|
if( this == &matchtype )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if( ( type != matchtype.type ) || ( auxType != matchtype.auxType ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( parmTypes.Num() != matchtype.parmTypes.Num() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for( i = 0; i < matchtype.parmTypes.Num(); i++ )
|
|
{
|
|
if( parmTypes[ i ] != matchtype.parmTypes[ i ] )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::MatchesVirtualFunction
|
|
|
|
Returns true if both functions' base types and parameters match
|
|
================
|
|
*/
|
|
bool idTypeDef::MatchesVirtualFunction( const idTypeDef& matchfunc ) const
|
|
{
|
|
int i;
|
|
|
|
if( this == &matchfunc )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if( ( type != matchfunc.type ) || ( auxType != matchfunc.auxType ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( parmTypes.Num() != matchfunc.parmTypes.Num() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( parmTypes.Num() > 0 )
|
|
{
|
|
if( !parmTypes[ 0 ]->Inherits( matchfunc.parmTypes[ 0 ] ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for( i = 1; i < matchfunc.parmTypes.Num(); i++ )
|
|
{
|
|
if( parmTypes[ i ] != matchfunc.parmTypes[ i ] )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::AddFunctionParm
|
|
|
|
Adds a new parameter for a function type.
|
|
================
|
|
*/
|
|
void idTypeDef::AddFunctionParm( idTypeDef* parmtype, const char* name )
|
|
{
|
|
if( type != ev_function )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( "idTypeDef::AddFunctionParm : tried to add parameter on non-function type" );
|
|
#else
|
|
gameLocal.Error( "idTypeDef::AddFunctionParm : tried to add parameter on non-function type" );
|
|
#endif
|
|
}
|
|
|
|
parmTypes.Append( parmtype );
|
|
idStr& parmName = parmNames.Alloc();
|
|
parmName = name;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::AddField
|
|
|
|
Adds a new field to an object type.
|
|
================
|
|
*/
|
|
void idTypeDef::AddField( idTypeDef* fieldtype, const char* name )
|
|
{
|
|
if( type != ev_object )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( "idTypeDef::AddField : tried to add field to non-object type" );
|
|
#else
|
|
gameLocal.Error( "idTypeDef::AddField : tried to add field to non-object type" );
|
|
#endif
|
|
}
|
|
|
|
parmTypes.Append( fieldtype );
|
|
idStr& parmName = parmNames.Alloc();
|
|
parmName = name;
|
|
|
|
if( fieldtype->FieldType()->Inherits( &type_object ) )
|
|
{
|
|
size += type_object.Size();
|
|
}
|
|
else
|
|
{
|
|
size += fieldtype->FieldType()->Size();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::SetName
|
|
================
|
|
*/
|
|
void idTypeDef::SetName( const char* newname )
|
|
{
|
|
name = newname;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::Name
|
|
================
|
|
*/
|
|
const char* idTypeDef::Name() const
|
|
{
|
|
return name;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::Type
|
|
================
|
|
*/
|
|
etype_t idTypeDef::Type() const
|
|
{
|
|
return type;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::Size
|
|
================
|
|
*/
|
|
int idTypeDef::Size() const
|
|
{
|
|
return size;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::SuperClass
|
|
|
|
If type is an object, then returns the object's superclass
|
|
================
|
|
*/
|
|
idTypeDef* idTypeDef::SuperClass() const
|
|
{
|
|
if( type != ev_object )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( "idTypeDef::SuperClass : tried to get superclass of a non-object type" );
|
|
#else
|
|
gameLocal.Error( "idTypeDef::SuperClass : tried to get superclass of a non-object type" );
|
|
#endif
|
|
}
|
|
|
|
return auxType;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::ReturnType
|
|
|
|
If type is a function, then returns the function's return type
|
|
================
|
|
*/
|
|
idTypeDef* idTypeDef::ReturnType() const
|
|
{
|
|
if( type != ev_function )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( "idTypeDef::ReturnType: tried to get return type on non-function type" );
|
|
#else
|
|
gameLocal.Error( "idTypeDef::ReturnType: tried to get return type on non-function type" );
|
|
#endif
|
|
}
|
|
|
|
return auxType;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::SetReturnType
|
|
|
|
If type is a function, then sets the function's return type
|
|
================
|
|
*/
|
|
void idTypeDef::SetReturnType( idTypeDef* returntype )
|
|
{
|
|
if( type != ev_function )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( "idTypeDef::SetReturnType: tried to set return type on non-function type" );
|
|
#else
|
|
gameLocal.Error( "idTypeDef::SetReturnType: tried to set return type on non-function type" );
|
|
#endif
|
|
}
|
|
|
|
auxType = returntype;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::FieldType
|
|
|
|
If type is a field, then returns it's type
|
|
================
|
|
*/
|
|
idTypeDef* idTypeDef::FieldType() const
|
|
{
|
|
if( type != ev_field )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( "idTypeDef::FieldType: tried to get field type on non-field type" );
|
|
#else
|
|
gameLocal.Error( "idTypeDef::FieldType: tried to get field type on non-field type" );
|
|
#endif
|
|
}
|
|
|
|
return auxType;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::SetFieldType
|
|
|
|
If type is a field, then sets the function's return type
|
|
================
|
|
*/
|
|
void idTypeDef::SetFieldType( idTypeDef* fieldtype )
|
|
{
|
|
if( type != ev_field )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( "idTypeDef::SetFieldType: tried to set return type on non-function type" );
|
|
#else
|
|
gameLocal.Error( "idTypeDef::SetFieldType: tried to set return type on non-function type" );
|
|
#endif
|
|
}
|
|
|
|
auxType = fieldtype;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::PointerType
|
|
|
|
If type is a pointer, then returns the type it points to
|
|
================
|
|
*/
|
|
idTypeDef* idTypeDef::PointerType() const
|
|
{
|
|
if( type != ev_pointer )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( "idTypeDef::PointerType: tried to get pointer type on non-pointer" );
|
|
#else
|
|
gameLocal.Error( "idTypeDef::PointerType: tried to get pointer type on non-pointer" );
|
|
#endif
|
|
}
|
|
|
|
return auxType;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::SetPointerType
|
|
|
|
If type is a pointer, then sets the pointer's type
|
|
================
|
|
*/
|
|
void idTypeDef::SetPointerType( idTypeDef* pointertype )
|
|
{
|
|
if( type != ev_pointer )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( "idTypeDef::SetPointerType: tried to set type on non-pointer" );
|
|
#else
|
|
gameLocal.Error( "idTypeDef::SetPointerType: tried to set type on non-pointer" );
|
|
#endif
|
|
}
|
|
|
|
auxType = pointertype;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::NumParameters
|
|
================
|
|
*/
|
|
int idTypeDef::NumParameters() const
|
|
{
|
|
return parmTypes.Num();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::GetParmType
|
|
================
|
|
*/
|
|
idTypeDef* idTypeDef::GetParmType( int parmNumber ) const
|
|
{
|
|
assert( parmNumber >= 0 );
|
|
assert( parmNumber < parmTypes.Num() );
|
|
return parmTypes[ parmNumber ];
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::GetParmName
|
|
================
|
|
*/
|
|
const char* idTypeDef::GetParmName( int parmNumber ) const
|
|
{
|
|
assert( parmNumber >= 0 );
|
|
assert( parmNumber < parmTypes.Num() );
|
|
return parmNames[ parmNumber ];
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::NumFunctions
|
|
================
|
|
*/
|
|
int idTypeDef::NumFunctions() const
|
|
{
|
|
return functions.Num();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::GetFunctionNumber
|
|
================
|
|
*/
|
|
int idTypeDef::GetFunctionNumber( const function_t* func ) const
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < functions.Num(); i++ )
|
|
{
|
|
if( functions[ i ] == func )
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::GetFunction
|
|
================
|
|
*/
|
|
const function_t* idTypeDef::GetFunction( int funcNumber ) const
|
|
{
|
|
assert( funcNumber >= 0 );
|
|
assert( funcNumber < functions.Num() );
|
|
return functions[ funcNumber ];
|
|
}
|
|
|
|
/*
|
|
================
|
|
idTypeDef::AddFunction
|
|
================
|
|
*/
|
|
void idTypeDef::AddFunction( const function_t* func )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < functions.Num(); i++ )
|
|
{
|
|
if( !strcmp( functions[ i ]->def->Name(), func->def->Name() ) )
|
|
{
|
|
if( func->def->TypeDef()->MatchesVirtualFunction( *functions[ i ]->def->TypeDef() ) )
|
|
{
|
|
functions[ i ] = func;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
functions.Append( func );
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
idVarDef
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
================
|
|
idVarDef::idVarDef()
|
|
================
|
|
*/
|
|
idVarDef::idVarDef( idTypeDef* typeptr )
|
|
{
|
|
typeDef = typeptr;
|
|
num = 0;
|
|
scope = NULL;
|
|
numUsers = 0;
|
|
initialized = idVarDef::uninitialized;
|
|
memset( &value, 0, sizeof( value ) );
|
|
name = NULL;
|
|
next = NULL;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idVarDef::~idVarDef
|
|
============
|
|
*/
|
|
idVarDef::~idVarDef()
|
|
{
|
|
if( name )
|
|
{
|
|
name->RemoveDef( this );
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
idVarDef::Name
|
|
============
|
|
*/
|
|
const char* idVarDef::Name() const
|
|
{
|
|
return name->Name();
|
|
}
|
|
|
|
/*
|
|
============
|
|
idVarDef::GlobalName
|
|
============
|
|
*/
|
|
const char* idVarDef::GlobalName() const
|
|
{
|
|
if( scope != &def_namespace )
|
|
{
|
|
return va( "%s::%s", scope->GlobalName(), name->Name() );
|
|
}
|
|
else
|
|
{
|
|
return name->Name();
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
idVarDef::DepthOfScope
|
|
============
|
|
*/
|
|
int idVarDef::DepthOfScope( const idVarDef* otherScope ) const
|
|
{
|
|
const idVarDef* def;
|
|
int depth;
|
|
|
|
depth = 1;
|
|
for( def = otherScope; def != NULL; def = def->scope )
|
|
{
|
|
if( def == scope )
|
|
{
|
|
return depth;
|
|
}
|
|
depth++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idVarDef::SetFunction
|
|
============
|
|
*/
|
|
void idVarDef::SetFunction( function_t* func )
|
|
{
|
|
assert( typeDef );
|
|
initialized = initializedConstant;
|
|
assert( typeDef->Type() == ev_function );
|
|
value.functionPtr = func;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idVarDef::SetObject
|
|
============
|
|
*/
|
|
void idVarDef::SetObject( idScriptObject* object )
|
|
{
|
|
assert( typeDef );
|
|
initialized = initialized;
|
|
assert( typeDef->Inherits( &type_object ) );
|
|
*value.objectPtrPtr = object;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idVarDef::SetValue
|
|
============
|
|
*/
|
|
void idVarDef::SetValue( const eval_t& _value, bool constant )
|
|
{
|
|
assert( typeDef );
|
|
if( constant )
|
|
{
|
|
initialized = initializedConstant;
|
|
}
|
|
else
|
|
{
|
|
initialized = initializedVariable;
|
|
}
|
|
|
|
switch( typeDef->Type() )
|
|
{
|
|
case ev_pointer :
|
|
case ev_boolean :
|
|
case ev_field :
|
|
*value.intPtr = _value._int;
|
|
break;
|
|
|
|
case ev_jumpoffset :
|
|
value.jumpOffset = _value._int;
|
|
break;
|
|
|
|
case ev_argsize :
|
|
value.argSize = _value._int;
|
|
break;
|
|
|
|
case ev_entity :
|
|
*value.entityNumberPtr = _value.entity;
|
|
break;
|
|
|
|
case ev_string :
|
|
idStr::Copynz( value.stringPtr, _value.stringPtr, MAX_STRING_LEN );
|
|
break;
|
|
|
|
case ev_float :
|
|
*value.floatPtr = _value._float;
|
|
break;
|
|
|
|
case ev_vector :
|
|
value.vectorPtr->x = _value.vector[ 0 ];
|
|
value.vectorPtr->y = _value.vector[ 1 ];
|
|
value.vectorPtr->z = _value.vector[ 2 ];
|
|
break;
|
|
|
|
case ev_function :
|
|
value.functionPtr = _value.function;
|
|
break;
|
|
|
|
case ev_virtualfunction :
|
|
value.virtualFunction = _value._int;
|
|
break;
|
|
|
|
case ev_object :
|
|
*value.entityNumberPtr = _value.entity;
|
|
break;
|
|
|
|
default :
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( va( "weird type on '%s'", Name() ) );
|
|
#else
|
|
gameLocal.Error( "weird type on '%s'", Name() );
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
idVarDef::SetString
|
|
============
|
|
*/
|
|
void idVarDef::SetString( const char* string, bool constant )
|
|
{
|
|
if( constant )
|
|
{
|
|
initialized = initializedConstant;
|
|
}
|
|
else
|
|
{
|
|
initialized = initializedVariable;
|
|
}
|
|
|
|
assert( typeDef && ( typeDef->Type() == ev_string ) );
|
|
idStr::Copynz( value.stringPtr, string, MAX_STRING_LEN );
|
|
}
|
|
|
|
/*
|
|
============
|
|
idVarDef::PrintInfo
|
|
============
|
|
*/
|
|
void idVarDef::PrintInfo( idFile* file, int instructionPointer ) const
|
|
{
|
|
statement_t* jumpst;
|
|
int jumpto;
|
|
etype_t etype;
|
|
int i;
|
|
int len;
|
|
const char* ch;
|
|
|
|
if( initialized == initializedConstant )
|
|
{
|
|
file->Printf( "const " );
|
|
}
|
|
|
|
etype = typeDef->Type();
|
|
switch( etype )
|
|
{
|
|
case ev_jumpoffset :
|
|
jumpto = instructionPointer + value.jumpOffset;
|
|
jumpst = &gameLocal.program.GetStatement( jumpto );
|
|
file->Printf( "address %d [%s(%d)]", jumpto, gameLocal.program.GetFilename( jumpst->file ), jumpst->linenumber );
|
|
break;
|
|
|
|
case ev_function :
|
|
if( value.functionPtr->eventdef )
|
|
{
|
|
file->Printf( "event %s", GlobalName() );
|
|
}
|
|
else
|
|
{
|
|
file->Printf( "function %s", GlobalName() );
|
|
}
|
|
break;
|
|
|
|
case ev_field :
|
|
file->Printf( "field %d", value.ptrOffset );
|
|
break;
|
|
|
|
case ev_argsize:
|
|
file->Printf( "args %d", value.argSize );
|
|
break;
|
|
|
|
default:
|
|
file->Printf( "%s ", typeDef->Name() );
|
|
if( initialized == initializedConstant )
|
|
{
|
|
switch( etype )
|
|
{
|
|
case ev_string :
|
|
file->Printf( "\"" );
|
|
len = strlen( value.stringPtr );
|
|
ch = value.stringPtr;
|
|
for( i = 0; i < len; i++, ch++ )
|
|
{
|
|
if( idStr::CharIsPrintable( *ch ) )
|
|
{
|
|
file->Printf( "%c", *ch );
|
|
}
|
|
else if( *ch == '\n' )
|
|
{
|
|
file->Printf( "\\n" );
|
|
}
|
|
else
|
|
{
|
|
file->Printf( "\\x%.2x", static_cast<int>( *ch ) );
|
|
}
|
|
}
|
|
file->Printf( "\"" );
|
|
break;
|
|
|
|
case ev_vector :
|
|
file->Printf( "'%s'", value.vectorPtr->ToString() );
|
|
break;
|
|
|
|
case ev_float :
|
|
file->Printf( "%f", *value.floatPtr );
|
|
break;
|
|
|
|
case ev_virtualfunction :
|
|
file->Printf( "vtable[ %d ]", value.virtualFunction );
|
|
break;
|
|
|
|
default :
|
|
file->Printf( "%d", *value.intPtr );
|
|
break;
|
|
}
|
|
}
|
|
else if( initialized == stackVariable )
|
|
{
|
|
file->Printf( "stack[%d]", value.stackOffset );
|
|
}
|
|
else
|
|
{
|
|
file->Printf( "global[%d]", num );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
idVarDef
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
============
|
|
idVarDefName::AddDef
|
|
============
|
|
*/
|
|
void idVarDefName::AddDef( idVarDef* def )
|
|
{
|
|
assert( def->next == NULL );
|
|
def->name = this;
|
|
def->next = defs;
|
|
defs = def;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idVarDefName::RemoveDef
|
|
============
|
|
*/
|
|
void idVarDefName::RemoveDef( idVarDef* def )
|
|
{
|
|
if( defs == def )
|
|
{
|
|
defs = def->next;
|
|
}
|
|
else
|
|
{
|
|
for( idVarDef* d = defs; d->next != NULL; d = d->next )
|
|
{
|
|
if( d->next == def )
|
|
{
|
|
d->next = def->next;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
def->next = NULL;
|
|
def->name = NULL;
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
idScriptObject
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
============
|
|
idScriptObject::idScriptObject
|
|
============
|
|
*/
|
|
idScriptObject::idScriptObject()
|
|
{
|
|
data = NULL;
|
|
type = &type_object;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::~idScriptObject
|
|
============
|
|
*/
|
|
idScriptObject::~idScriptObject()
|
|
{
|
|
Free();
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::Free
|
|
============
|
|
*/
|
|
void idScriptObject::Free()
|
|
{
|
|
if( data )
|
|
{
|
|
Mem_Free( data );
|
|
}
|
|
|
|
data = NULL;
|
|
type = &type_object;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idScriptObject::Save
|
|
================
|
|
*/
|
|
void idScriptObject::Save( idSaveGame* savefile ) const
|
|
{
|
|
// RB: 64 bit fix, changed size_t to int
|
|
int size;
|
|
// RB end
|
|
|
|
if( type == &type_object && data == NULL )
|
|
{
|
|
// Write empty string for uninitialized object
|
|
savefile->WriteString( "" );
|
|
}
|
|
else
|
|
{
|
|
savefile->WriteString( type->Name() );
|
|
size = type->Size();
|
|
savefile->WriteInt( size );
|
|
savefile->Write( data, size );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idScriptObject::Restore
|
|
================
|
|
*/
|
|
void idScriptObject::Restore( idRestoreGame* savefile )
|
|
{
|
|
idStr typeName;
|
|
// RB: 64 bit fix, changed size_t to int
|
|
int size;
|
|
// RB end
|
|
|
|
savefile->ReadString( typeName );
|
|
|
|
// Empty string signals uninitialized object
|
|
if( typeName.Length() == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( !SetType( typeName ) )
|
|
{
|
|
savefile->Error( "idScriptObject::Restore: failed to restore object of type '%s'.", typeName.c_str() );
|
|
}
|
|
|
|
// RB: 64 bit fix, changed size_t to int
|
|
savefile->ReadInt( size );
|
|
// RB end
|
|
if( size != type->Size() )
|
|
{
|
|
savefile->Error( "idScriptObject::Restore: size of object '%s' doesn't match size in save game.", typeName.c_str() );
|
|
}
|
|
|
|
savefile->Read( data, size );
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::SetType
|
|
|
|
Allocates an object and initializes memory.
|
|
============
|
|
*/
|
|
bool idScriptObject::SetType( const char* typeName )
|
|
{
|
|
size_t size;
|
|
idTypeDef* newtype;
|
|
|
|
// lookup the type
|
|
newtype = gameLocal.program.FindType( typeName );
|
|
|
|
// only allocate memory if the object type changes
|
|
if( newtype != type )
|
|
{
|
|
Free();
|
|
if( !newtype )
|
|
{
|
|
gameLocal.Warning( "idScriptObject::SetType: Unknown type '%s'", typeName );
|
|
return false;
|
|
}
|
|
|
|
if( !newtype->Inherits( &type_object ) )
|
|
{
|
|
gameLocal.Warning( "idScriptObject::SetType: Can't create object of type '%s'. Must be an object type.", newtype->Name() );
|
|
return false;
|
|
}
|
|
|
|
// set the type
|
|
type = newtype;
|
|
|
|
// allocate the memory
|
|
size = type->Size();
|
|
data = ( byte* )Mem_Alloc( size, TAG_SCRIPT );
|
|
}
|
|
|
|
// init object memory
|
|
ClearObject();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::ClearObject
|
|
|
|
Resets the memory for the script object without changing its type.
|
|
============
|
|
*/
|
|
void idScriptObject::ClearObject()
|
|
{
|
|
size_t size;
|
|
|
|
if( type != &type_object )
|
|
{
|
|
// init object memory
|
|
size = type->Size();
|
|
memset( data, 0, size );
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::HasObject
|
|
============
|
|
*/
|
|
bool idScriptObject::HasObject() const
|
|
{
|
|
return ( type != &type_object );
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::GetTypeDef
|
|
============
|
|
*/
|
|
idTypeDef* idScriptObject::GetTypeDef() const
|
|
{
|
|
return type;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::GetTypeName
|
|
============
|
|
*/
|
|
const char* idScriptObject::GetTypeName() const
|
|
{
|
|
return type->Name();
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::GetConstructor
|
|
============
|
|
*/
|
|
const function_t* idScriptObject::GetConstructor() const
|
|
{
|
|
const function_t* func;
|
|
|
|
func = GetFunction( "init" );
|
|
return func;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::GetDestructor
|
|
============
|
|
*/
|
|
const function_t* idScriptObject::GetDestructor() const
|
|
{
|
|
const function_t* func;
|
|
|
|
func = GetFunction( "destroy" );
|
|
return func;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::GetFunction
|
|
============
|
|
*/
|
|
const function_t* idScriptObject::GetFunction( const char* name ) const
|
|
{
|
|
const function_t* func;
|
|
|
|
if( type == &type_object )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
func = gameLocal.program.FindFunction( name, type );
|
|
return func;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idScriptObject::GetVariable
|
|
============
|
|
*/
|
|
byte* idScriptObject::GetVariable( const char* name, etype_t etype ) const
|
|
{
|
|
int i;
|
|
int pos;
|
|
const idTypeDef* t = type;
|
|
const idTypeDef* parm;
|
|
|
|
if( t == &type_object || t == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
do
|
|
{
|
|
if( t->SuperClass() != &type_object )
|
|
{
|
|
pos = t->SuperClass()->Size();
|
|
}
|
|
else
|
|
{
|
|
pos = 0;
|
|
}
|
|
for( i = 0; i < t->NumParameters(); i++ )
|
|
{
|
|
parm = t->GetParmType( i );
|
|
if( !strcmp( t->GetParmName( i ), name ) )
|
|
{
|
|
if( etype != parm->FieldType()->Type() )
|
|
{
|
|
return NULL;
|
|
}
|
|
return &data[ pos ];
|
|
}
|
|
|
|
if( parm->FieldType()->Inherits( &type_object ) )
|
|
{
|
|
pos += type_object.Size();
|
|
}
|
|
else
|
|
{
|
|
pos += parm->FieldType()->Size();
|
|
}
|
|
}
|
|
t = t->SuperClass();
|
|
}
|
|
while( t != NULL && ( t != &type_object ) );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
idProgram
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
============
|
|
idProgram::AllocType
|
|
============
|
|
*/
|
|
idTypeDef* idProgram::AllocType( idTypeDef& type )
|
|
{
|
|
idTypeDef* newtype = new( TAG_SCRIPT ) idTypeDef( type );
|
|
typesHash.Add( idStr::Hash( type.Name() ), types.Append( newtype ) );
|
|
return newtype;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idProgram::AllocType
|
|
============
|
|
*/
|
|
idTypeDef* idProgram::AllocType( etype_t etype, idVarDef* edef, const char* ename, int esize, idTypeDef* aux )
|
|
{
|
|
idTypeDef* newtype = new( TAG_SCRIPT ) idTypeDef( etype, edef, ename, esize, aux );
|
|
typesHash.Add( idStr::Hash( ename ), types.Append( newtype ) );
|
|
return newtype;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idProgram::GetType
|
|
|
|
Returns a preexisting complex type that matches the parm, or allocates
|
|
a new one and copies it out.
|
|
============
|
|
*/
|
|
idTypeDef* idProgram::GetType( idTypeDef& type, bool allocate )
|
|
{
|
|
|
|
for( int i = typesHash.First( idStr::Hash( type.Name() ) ); i != -1; i = typesHash.Next( i ) )
|
|
{
|
|
if( types[ i ]->MatchesType( type ) && !strcmp( types[ i ]->Name(), type.Name() ) )
|
|
{
|
|
return types[ i ];
|
|
}
|
|
}
|
|
|
|
if( !allocate )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// allocate a new one
|
|
return AllocType( type );
|
|
}
|
|
|
|
/*
|
|
============
|
|
idProgram::FindType
|
|
|
|
Returns a preexisting complex type that matches the name, or returns NULL if not found
|
|
============
|
|
*/
|
|
idTypeDef* idProgram::FindType( const char* name )
|
|
{
|
|
|
|
for( int i = typesHash.First( idStr::Hash( name ) ); i != -1; i = typesHash.Next( i ) )
|
|
{
|
|
idTypeDef* check = types[ i ];
|
|
if( !strcmp( check->Name(), name ) )
|
|
{
|
|
return check;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idProgram::GetDefList
|
|
============
|
|
*/
|
|
idVarDef* idProgram::GetDefList( const char* name ) const
|
|
{
|
|
int i, hash;
|
|
|
|
hash = varDefNameHash.GenerateKey( name, true );
|
|
for( i = varDefNameHash.First( hash ); i != -1; i = varDefNameHash.Next( i ) )
|
|
{
|
|
if( idStr::Cmp( varDefNames[i]->Name(), name ) == 0 )
|
|
{
|
|
return varDefNames[i]->GetDefs();
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idProgram::AddDefToNameList
|
|
============
|
|
*/
|
|
void idProgram::AddDefToNameList( idVarDef* def, const char* name )
|
|
{
|
|
int i, hash;
|
|
|
|
hash = varDefNameHash.GenerateKey( name, true );
|
|
for( i = varDefNameHash.First( hash ); i != -1; i = varDefNameHash.Next( i ) )
|
|
{
|
|
if( idStr::Cmp( varDefNames[i]->Name(), name ) == 0 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if( i == -1 )
|
|
{
|
|
i = varDefNames.Append( new( TAG_SCRIPT ) idVarDefName( name ) );
|
|
varDefNameHash.Add( hash, i );
|
|
}
|
|
varDefNames[i]->AddDef( def );
|
|
}
|
|
|
|
// RB: moved from AllocDef
|
|
byte* idProgram::ReserveDefMemory( int size )
|
|
{
|
|
byte* mem = &variables[ numVariables ];
|
|
numVariables += size;
|
|
if( numVariables > sizeof( variables ) )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( va( "Exceeded global memory size (%zd bytes)", sizeof( variables ) ) );
|
|
#else
|
|
gameLocal.Error( "Exceeded global memory size (%zd bytes)", sizeof( variables ) );
|
|
#endif
|
|
}
|
|
|
|
memset( mem, 0, size );
|
|
|
|
return mem;
|
|
}
|
|
// RB end
|
|
|
|
// RB: moved from AllocDef
|
|
idVarDef* idProgram::AllocVarDef( idTypeDef* type, const char* name, idVarDef* scope )
|
|
{
|
|
// allocate a new def
|
|
idVarDef* def = new( TAG_SCRIPT ) idVarDef( type );
|
|
def->scope = scope;
|
|
def->numUsers = 1;
|
|
def->num = varDefs.Append( def );
|
|
|
|
// add the def to the list with defs with this name and set the name pointer
|
|
AddDefToNameList( def, name );
|
|
|
|
return def;
|
|
}
|
|
// RB end
|
|
|
|
|
|
/*
|
|
============
|
|
idProgram::AllocDef
|
|
============
|
|
*/
|
|
idVarDef* idProgram::AllocDef( idTypeDef* type, const char* name, idVarDef* scope, bool constant )
|
|
{
|
|
idVarDef* def;
|
|
idStr element;
|
|
idVarDef* def_x;
|
|
idVarDef* def_y;
|
|
idVarDef* def_z;
|
|
|
|
// allocate a new def
|
|
def = AllocVarDef( type, name, scope );
|
|
|
|
if( ( type->Type() == ev_vector ) || ( ( type->Type() == ev_field ) && ( type->FieldType()->Type() == ev_vector ) ) )
|
|
{
|
|
//
|
|
// vector
|
|
//
|
|
if( !strcmp( name, RESULT_STRING ) )
|
|
{
|
|
// <RESULT> vector defs don't need the _x, _y and _z components
|
|
assert( scope->Type() == ev_function );
|
|
def->value.stackOffset = scope->value.functionPtr->locals;
|
|
def->initialized = idVarDef::stackVariable;
|
|
scope->value.functionPtr->locals += type->Size();
|
|
}
|
|
else if( scope->TypeDef()->Inherits( &type_object ) )
|
|
{
|
|
idTypeDef newtype( ev_field, NULL, "float field", 0, &type_float );
|
|
|
|
// RB: changed local type to ftype
|
|
idTypeDef* ftype = GetType( newtype, true );
|
|
|
|
// set the value to the variable's position in the object
|
|
def->value.ptrOffset = scope->TypeDef()->Size();
|
|
|
|
// make automatic defs for the vectors elements
|
|
// origin can be accessed as origin_x, origin_y, and origin_z
|
|
sprintf( element, "%s_x", def->Name() );
|
|
def_x = AllocDef( ftype, element, scope, constant );
|
|
|
|
sprintf( element, "%s_y", def->Name() );
|
|
def_y = AllocDef( ftype, element, scope, constant );
|
|
def_y->value.ptrOffset = def_x->value.ptrOffset + sizeof( float );
|
|
|
|
sprintf( element, "%s_z", def->Name() );
|
|
def_z = AllocDef( ftype, element, scope, constant );
|
|
def_z->value.ptrOffset = def_y->value.ptrOffset + sizeof( float );
|
|
// RB end
|
|
}
|
|
else
|
|
{
|
|
// RB: from dhewm3
|
|
idTypeDef newtype( ev_float, &def_float, "vector float", 0, NULL );
|
|
idTypeDef* ftype = GetType( newtype, true );
|
|
|
|
// make automatic defs for the vectors elements
|
|
// origin can be accessed as origin_x, origin_y, and origin_z
|
|
sprintf( element, "%s_x", def->Name() );
|
|
def_x = AllocVarDef( ftype, element, scope );
|
|
|
|
sprintf( element, "%s_y", def->Name() );
|
|
def_y = AllocVarDef( ftype, element, scope );
|
|
|
|
sprintf( element, "%s_z", def->Name() );
|
|
def_z = AllocVarDef( ftype, element, scope );
|
|
|
|
// get the memory for the full vector and point the _x, _y and _z
|
|
// defs at the vector member offsets
|
|
if( scope->Type() == ev_function )
|
|
{
|
|
// vector on stack
|
|
def->value.stackOffset = scope->value.functionPtr->locals;
|
|
def->initialized = idVarDef::stackVariable;
|
|
scope->value.functionPtr->locals += type->Size();
|
|
|
|
def_x->value.stackOffset = def->value.stackOffset;
|
|
def_y->value.stackOffset = def_x->value.stackOffset + sizeof( float );
|
|
def_z->value.stackOffset = def_y->value.stackOffset + sizeof( float );
|
|
}
|
|
else
|
|
{
|
|
// global vector
|
|
def->value.bytePtr = ReserveDefMemory( type->Size() );
|
|
def_x->value.bytePtr = def->value.bytePtr;
|
|
def_y->value.bytePtr = def_x->value.bytePtr + sizeof( float );
|
|
def_z->value.bytePtr = def_y->value.bytePtr + sizeof( float );
|
|
}
|
|
|
|
def_x->initialized = def->initialized;
|
|
def_y->initialized = def->initialized;
|
|
def_z->initialized = def->initialized;
|
|
// RB end
|
|
}
|
|
}
|
|
else if( scope->TypeDef()->Inherits( &type_object ) )
|
|
{
|
|
//
|
|
// object variable
|
|
//
|
|
// set the value to the variable's position in the object
|
|
def->value.ptrOffset = scope->TypeDef()->Size();
|
|
}
|
|
else if( scope->Type() == ev_function )
|
|
{
|
|
//
|
|
// stack variable
|
|
//
|
|
// since we don't know how many local variables there are,
|
|
// we have to have them go backwards on the stack
|
|
def->value.stackOffset = scope->value.functionPtr->locals;
|
|
def->initialized = idVarDef::stackVariable;
|
|
|
|
if( type->Inherits( &type_object ) )
|
|
{
|
|
// objects only have their entity number on the stack, not the entire object
|
|
scope->value.functionPtr->locals += type_object.Size();
|
|
}
|
|
else
|
|
{
|
|
scope->value.functionPtr->locals += type->Size();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// global variable
|
|
//
|
|
// RB begin
|
|
def->value.bytePtr = ReserveDefMemory( def->TypeDef()->Size() );
|
|
// RB end
|
|
|
|
//memset( def->value.bytePtr, 0, def->TypeDef()->Size() );
|
|
}
|
|
|
|
return def;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idProgram::GetDef
|
|
|
|
If type is NULL, it will match any type
|
|
============
|
|
*/
|
|
idVarDef* idProgram::GetDef( const idTypeDef* type, const char* name, const idVarDef* scope ) const
|
|
{
|
|
idVarDef* def;
|
|
idVarDef* bestDef;
|
|
int bestDepth;
|
|
int depth;
|
|
|
|
bestDepth = 0;
|
|
bestDef = NULL;
|
|
for( def = GetDefList( name ); def != NULL; def = def->Next() )
|
|
{
|
|
if( def->scope->Type() == ev_namespace )
|
|
{
|
|
depth = def->DepthOfScope( scope );
|
|
if( !depth )
|
|
{
|
|
// not in the same namespace
|
|
continue;
|
|
}
|
|
}
|
|
else if( def->scope != scope )
|
|
{
|
|
// in a different function
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
depth = 1;
|
|
}
|
|
|
|
if( !bestDef || ( depth < bestDepth ) )
|
|
{
|
|
bestDepth = depth;
|
|
bestDef = def;
|
|
}
|
|
}
|
|
|
|
// see if the name is already in use for another type
|
|
if( bestDef && type && ( bestDef->TypeDef() != type ) )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( va( "Type mismatch on redeclaration of %s", name ) );
|
|
#else
|
|
gameLocal.Error( "Type mismatch on redeclaration of %s", name );
|
|
#endif
|
|
}
|
|
|
|
return bestDef;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idProgram::FreeDef
|
|
============
|
|
*/
|
|
void idProgram::FreeDef( idVarDef* def, const idVarDef* scope )
|
|
{
|
|
idVarDef* e;
|
|
int i;
|
|
|
|
if( def->Type() == ev_vector )
|
|
{
|
|
idStr name;
|
|
|
|
sprintf( name, "%s_x", def->Name() );
|
|
e = GetDef( NULL, name, scope );
|
|
if( e )
|
|
{
|
|
FreeDef( e, scope );
|
|
}
|
|
|
|
sprintf( name, "%s_y", def->Name() );
|
|
e = GetDef( NULL, name, scope );
|
|
if( e )
|
|
{
|
|
FreeDef( e, scope );
|
|
}
|
|
|
|
sprintf( name, "%s_z", def->Name() );
|
|
e = GetDef( NULL, name, scope );
|
|
if( e )
|
|
{
|
|
FreeDef( e, scope );
|
|
}
|
|
}
|
|
|
|
varDefs.RemoveIndex( def->num );
|
|
for( i = def->num; i < varDefs.Num(); i++ )
|
|
{
|
|
varDefs[ i ]->num = i;
|
|
}
|
|
|
|
delete def;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idProgram::FindFreeResultDef
|
|
============
|
|
*/
|
|
idVarDef* idProgram::FindFreeResultDef( idTypeDef* type, const char* name, idVarDef* scope, const idVarDef* a, const idVarDef* b )
|
|
{
|
|
idVarDef* def;
|
|
|
|
for( def = GetDefList( name ); def != NULL; def = def->Next() )
|
|
{
|
|
if( def == a || def == b )
|
|
{
|
|
continue;
|
|
}
|
|
if( def->TypeDef() != type )
|
|
{
|
|
continue;
|
|
}
|
|
if( def->scope != scope )
|
|
{
|
|
continue;
|
|
}
|
|
if( def->numUsers <= 1 )
|
|
{
|
|
continue;
|
|
}
|
|
return def;
|
|
}
|
|
|
|
return AllocDef( type, name, scope, false );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::FindFunction
|
|
|
|
Searches for the specified function in the currently loaded script. A full namespace should be
|
|
specified if not in the global namespace.
|
|
|
|
Returns 0 if function not found.
|
|
Returns >0 if function found.
|
|
================
|
|
*/
|
|
function_t* idProgram::FindFunction( const char* name ) const
|
|
{
|
|
int start;
|
|
int pos;
|
|
idVarDef* namespaceDef;
|
|
idVarDef* def;
|
|
|
|
assert( name );
|
|
|
|
idStr fullname = name;
|
|
start = 0;
|
|
namespaceDef = &def_namespace;
|
|
do
|
|
{
|
|
pos = fullname.Find( "::", true, start );
|
|
if( pos < 0 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
idStr namespaceName = fullname.Mid( start, pos - start );
|
|
def = GetDef( NULL, namespaceName, namespaceDef );
|
|
if( !def )
|
|
{
|
|
// couldn't find namespace
|
|
return NULL;
|
|
}
|
|
namespaceDef = def;
|
|
|
|
// skip past the ::
|
|
start = pos + 2;
|
|
}
|
|
while( def->Type() == ev_namespace );
|
|
|
|
idStr funcName = fullname.Right( fullname.Length() - start );
|
|
def = GetDef( NULL, funcName, namespaceDef );
|
|
if( !def )
|
|
{
|
|
// couldn't find function
|
|
return NULL;
|
|
}
|
|
|
|
if( ( def->Type() == ev_function ) && ( def->value.functionPtr->eventdef == NULL ) )
|
|
{
|
|
return def->value.functionPtr;
|
|
}
|
|
|
|
// is not a function, or is an eventdef
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::FindFunction
|
|
|
|
Searches for the specified object function in the currently loaded script.
|
|
|
|
Returns 0 if function not found.
|
|
Returns >0 if function found.
|
|
================
|
|
*/
|
|
function_t* idProgram::FindFunction( const char* name, const idTypeDef* type ) const
|
|
{
|
|
const idVarDef* tdef;
|
|
const idVarDef* def;
|
|
|
|
// look for the function
|
|
def = NULL;
|
|
for( tdef = type->def; tdef != &def_object; tdef = tdef->TypeDef()->SuperClass()->def )
|
|
{
|
|
def = GetDef( NULL, name, tdef );
|
|
if( def )
|
|
{
|
|
return def->value.functionPtr;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::AllocFunction
|
|
================
|
|
*/
|
|
function_t& idProgram::AllocFunction( idVarDef* def )
|
|
{
|
|
if( functions.Num() >= functions.Max() )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( va( "Exceeded maximum allowed number of functions (%d)", functions.Max() ) );
|
|
#else
|
|
gameLocal.Error( "Exceeded maximum allowed number of functions (%d)", functions.Max() );
|
|
#endif
|
|
}
|
|
|
|
// fill in the dfunction
|
|
function_t& func = *functions.Alloc();
|
|
func.eventdef = NULL;
|
|
func.def = def;
|
|
func.type = def->TypeDef();
|
|
func.firstStatement = 0;
|
|
func.numStatements = 0;
|
|
func.parmTotal = 0;
|
|
func.locals = 0;
|
|
func.filenum = filenum;
|
|
func.parmSize.SetGranularity( 1 );
|
|
func.SetName( def->GlobalName() );
|
|
|
|
def->SetFunction( &func );
|
|
|
|
return func;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::SetEntity
|
|
================
|
|
*/
|
|
void idProgram::SetEntity( const char* name, idEntity* ent )
|
|
{
|
|
idVarDef* def;
|
|
idStr defName( "$" );
|
|
|
|
defName += name;
|
|
|
|
def = GetDef( &type_entity, defName, &def_namespace );
|
|
if( def != NULL && ( def->initialized != idVarDef::stackVariable ) )
|
|
{
|
|
// 0 is reserved for NULL entity
|
|
if( !ent )
|
|
{
|
|
*def->value.entityNumberPtr = 0;
|
|
}
|
|
else
|
|
{
|
|
*def->value.entityNumberPtr = ent->entityNumber + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::AllocStatement
|
|
================
|
|
*/
|
|
statement_t* idProgram::AllocStatement()
|
|
{
|
|
if( statements.Num() >= statements.Max() )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( va( "Exceeded maximum allowed number of statements (%d)", statements.Max() ) );
|
|
#else
|
|
gameLocal.Error( "Exceeded maximum allowed number of statements (%d)", statements.Max() );
|
|
#endif
|
|
}
|
|
return statements.Alloc();
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idProgram::BeginCompilation
|
|
|
|
called before compiling a batch of files, clears the pr struct
|
|
==============
|
|
*/
|
|
void idProgram::BeginCompilation()
|
|
{
|
|
statement_t* statement;
|
|
|
|
FreeData();
|
|
|
|
#if defined(USE_EXCEPTIONS)
|
|
try
|
|
#endif
|
|
{
|
|
// make the first statement a return for a "NULL" function
|
|
statement = AllocStatement();
|
|
statement->linenumber = 0;
|
|
statement->file = 0;
|
|
statement->op = OP_RETURN;
|
|
statement->a = NULL;
|
|
statement->b = NULL;
|
|
statement->c = NULL;
|
|
|
|
// define NULL
|
|
//AllocDef( &type_void, "<NULL>", &def_namespace, true );
|
|
|
|
// define the return def
|
|
returnDef = AllocDef( &type_vector, "<RETURN>", &def_namespace, false );
|
|
|
|
// define the return def for strings
|
|
returnStringDef = AllocDef( &type_string, "<RETURN>", &def_namespace, false );
|
|
|
|
// define the sys object
|
|
sysDef = AllocDef( &type_void, "sys", &def_namespace, true );
|
|
}
|
|
#if defined(USE_EXCEPTIONS)
|
|
catch( idCompileError& err )
|
|
{
|
|
gameLocal.Error( "%s", err.GetError() );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idProgram::DisassembleStatement
|
|
==============
|
|
*/
|
|
void idProgram::DisassembleStatement( idFile* file, int instructionPointer ) const
|
|
{
|
|
// RB: added const
|
|
const opcode_t* op;
|
|
// RB end
|
|
const statement_t* statement;
|
|
|
|
statement = &statements[ instructionPointer ];
|
|
op = &idCompiler::opcodes[ statement->op ];
|
|
file->Printf( "%20s(%d):\t%6d: %15s\t", fileList[ statement->file ].c_str(), statement->linenumber, instructionPointer, op->opname );
|
|
|
|
if( statement->a )
|
|
{
|
|
file->Printf( "\ta: " );
|
|
statement->a->PrintInfo( file, instructionPointer );
|
|
}
|
|
|
|
if( statement->b )
|
|
{
|
|
file->Printf( "\tb: " );
|
|
statement->b->PrintInfo( file, instructionPointer );
|
|
}
|
|
|
|
if( statement->c )
|
|
{
|
|
file->Printf( "\tc: " );
|
|
statement->c->PrintInfo( file, instructionPointer );
|
|
}
|
|
|
|
file->Printf( "\n" );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idProgram::Disassemble
|
|
==============
|
|
*/
|
|
void idProgram::Disassemble() const
|
|
{
|
|
int i;
|
|
int instructionPointer;
|
|
const function_t* func;
|
|
idFile* file;
|
|
|
|
file = fileSystem->OpenFileByMode( "script/disasm.txt", FS_WRITE );
|
|
|
|
for( i = 0; i < functions.Num(); i++ )
|
|
{
|
|
func = &functions[ i ];
|
|
if( func->eventdef )
|
|
{
|
|
// skip eventdefs
|
|
continue;
|
|
}
|
|
|
|
file->Printf( "\nfunction %s() %d stack used, %d parms, %d locals {\n", func->Name(), func->locals, func->parmTotal, func->locals - func->parmTotal );
|
|
|
|
for( instructionPointer = 0; instructionPointer < func->numStatements; instructionPointer++ )
|
|
{
|
|
DisassembleStatement( file, func->firstStatement + instructionPointer );
|
|
}
|
|
|
|
file->Printf( "}\n" );
|
|
}
|
|
|
|
fileSystem->CloseFile( file );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idProgram::FinishCompilation
|
|
|
|
Called after all files are compiled to check for errors
|
|
==============
|
|
*/
|
|
void idProgram::FinishCompilation()
|
|
{
|
|
int i;
|
|
|
|
top_functions = functions.Num();
|
|
top_statements = statements.Num();
|
|
top_types = types.Num();
|
|
top_defs = varDefs.Num();
|
|
top_files = fileList.Num();
|
|
|
|
variableDefaults.Clear();
|
|
variableDefaults.SetNum( numVariables );
|
|
|
|
for( i = 0; i < numVariables; i++ )
|
|
{
|
|
variableDefaults[ i ] = variables[ i ];
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idProgram::CompileStats
|
|
|
|
called after all files are compiled to report memory usage.
|
|
==============
|
|
*/
|
|
void idProgram::CompileStats()
|
|
{
|
|
int memused;
|
|
int memallocated;
|
|
int numdefs;
|
|
int stringspace;
|
|
int funcMem;
|
|
int i;
|
|
|
|
gameLocal.Printf( "---------- Compile stats ----------\n" );
|
|
gameLocal.DPrintf( "Files loaded:\n" );
|
|
|
|
stringspace = 0;
|
|
for( i = 0; i < fileList.Num(); i++ )
|
|
{
|
|
gameLocal.DPrintf( " %s\n", fileList[ i ].c_str() );
|
|
stringspace += fileList[ i ].Allocated();
|
|
}
|
|
stringspace += fileList.Size();
|
|
|
|
numdefs = varDefs.Num();
|
|
memused = varDefs.Num() * sizeof( idVarDef );
|
|
memused += types.Num() * sizeof( idTypeDef );
|
|
memused += stringspace;
|
|
|
|
for( i = 0; i < types.Num(); i++ )
|
|
{
|
|
memused += types[ i ]->Allocated();
|
|
}
|
|
|
|
funcMem = functions.MemoryUsed();
|
|
for( i = 0; i < functions.Num(); i++ )
|
|
{
|
|
funcMem += functions[ i ].Allocated();
|
|
}
|
|
|
|
memallocated = funcMem + memused + sizeof( idProgram );
|
|
|
|
memused += statements.MemoryUsed();
|
|
memused += functions.MemoryUsed(); // name and filename of functions are shared, so no need to include them
|
|
memused += sizeof( variables );
|
|
|
|
gameLocal.Printf( "\nMemory usage:\n" );
|
|
gameLocal.Printf( " Strings: %d, %d bytes\n", fileList.Num(), stringspace );
|
|
gameLocal.Printf( " Statements: %d, %d bytes\n", statements.Num(), statements.MemoryUsed() );
|
|
gameLocal.Printf( " Functions: %d, %d bytes\n", functions.Num(), funcMem );
|
|
gameLocal.Printf( " Variables: %d bytes\n", numVariables );
|
|
gameLocal.Printf( " Mem used: %d bytes\n", memused );
|
|
gameLocal.Printf( " Static data: %d bytes\n", sizeof( idProgram ) );
|
|
gameLocal.Printf( " Allocated: %d bytes\n", memallocated );
|
|
gameLocal.Printf( " Thread size: %d bytes\n\n", sizeof( idThread ) );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::CompileText
|
|
================
|
|
*/
|
|
bool idProgram::CompileText( const char* source, const char* text, bool console )
|
|
{
|
|
idCompiler compiler;
|
|
int i;
|
|
idVarDef* def;
|
|
idStr ospath;
|
|
|
|
// use a full os path for GetFilenum since it calls OSPathToRelativePath to convert filenames from the parser
|
|
ospath = fileSystem->RelativePathToOSPath( source );
|
|
filenum = GetFilenum( ospath );
|
|
|
|
#if defined(USE_EXCEPTIONS)
|
|
try
|
|
#endif
|
|
{
|
|
compiler.CompileFile( text, filename, console );
|
|
|
|
// check to make sure all functions prototyped have code
|
|
for( i = 0; i < varDefs.Num(); i++ )
|
|
{
|
|
def = varDefs[ i ];
|
|
if( ( def->Type() == ev_function ) && ( ( def->scope->Type() == ev_namespace ) || def->scope->TypeDef()->Inherits( &type_object ) ) )
|
|
{
|
|
if( !def->value.functionPtr->eventdef && !def->value.functionPtr->firstStatement )
|
|
{
|
|
#if defined(USE_EXCEPTIONS)
|
|
throw idCompileError( va( "function %s was not defined\n", def->GlobalName() ) );
|
|
#else
|
|
gameLocal.Error( "function %s was not defined\n", def->GlobalName() );
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#if defined(USE_EXCEPTIONS)
|
|
catch( idCompileError& err )
|
|
{
|
|
if( console )
|
|
{
|
|
gameLocal.Printf( "%s\n", err.GetError() );
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
gameLocal.Error( "%s\n", err.GetError() );
|
|
}
|
|
};
|
|
#endif
|
|
|
|
if( !console )
|
|
{
|
|
CompileStats();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::CompileFunction
|
|
================
|
|
*/
|
|
const function_t* idProgram::CompileFunction( const char* functionName, const char* text )
|
|
{
|
|
bool result;
|
|
|
|
result = CompileText( functionName, text, false );
|
|
|
|
if( g_disasm.GetBool() )
|
|
{
|
|
Disassemble();
|
|
}
|
|
|
|
if( !result )
|
|
{
|
|
gameLocal.Error( "Compile failed." );
|
|
}
|
|
|
|
return FindFunction( functionName );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::CompileFile
|
|
================
|
|
*/
|
|
void idProgram::CompileFile( const char* filename )
|
|
{
|
|
char* src;
|
|
bool result;
|
|
|
|
if( fileSystem->ReadFile( filename, ( void** )&src, NULL ) < 0 )
|
|
{
|
|
gameLocal.Error( "Couldn't load %s\n", filename );
|
|
}
|
|
|
|
result = CompileText( filename, src, false );
|
|
|
|
fileSystem->FreeFile( src );
|
|
|
|
if( g_disasm.GetBool() )
|
|
{
|
|
Disassemble();
|
|
}
|
|
|
|
if( !result )
|
|
{
|
|
gameLocal.Error( "Compile failed in file %s.", filename );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::FreeData
|
|
================
|
|
*/
|
|
void idProgram::FreeData()
|
|
{
|
|
int i;
|
|
|
|
// free the defs
|
|
varDefs.DeleteContents( true );
|
|
varDefNames.DeleteContents( true );
|
|
varDefNameHash.Free();
|
|
|
|
returnDef = NULL;
|
|
returnStringDef = NULL;
|
|
sysDef = NULL;
|
|
|
|
// free any special types we've created
|
|
types.DeleteContents( true );
|
|
typesHash.Free();
|
|
|
|
filenum = 0;
|
|
|
|
numVariables = 0;
|
|
memset( variables, 0, sizeof( variables ) );
|
|
|
|
// clear all the strings in the functions so that it doesn't look like we're leaking memory.
|
|
for( i = 0; i < functions.Num(); i++ )
|
|
{
|
|
functions[ i ].Clear();
|
|
}
|
|
|
|
filename.Clear();
|
|
fileList.Clear();
|
|
statements.Clear();
|
|
functions.Clear();
|
|
|
|
top_functions = 0;
|
|
top_statements = 0;
|
|
top_types = 0;
|
|
top_defs = 0;
|
|
top_files = 0;
|
|
|
|
filename = "";
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::Startup
|
|
================
|
|
*/
|
|
void idProgram::Startup( const char* defaultScript )
|
|
{
|
|
gameLocal.Printf( "Initializing scripts\n" );
|
|
|
|
// make sure all data is freed up
|
|
idThread::Restart();
|
|
|
|
// get ready for loading scripts
|
|
BeginCompilation();
|
|
|
|
// load the default script
|
|
if( defaultScript && *defaultScript )
|
|
{
|
|
CompileFile( defaultScript );
|
|
}
|
|
|
|
FinishCompilation();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::Save
|
|
================
|
|
*/
|
|
void idProgram::Save( idSaveGame* savefile ) const
|
|
{
|
|
int i;
|
|
int currentFileNum = top_files;
|
|
|
|
savefile->WriteInt( ( fileList.Num() - currentFileNum ) );
|
|
while( currentFileNum < fileList.Num() )
|
|
{
|
|
savefile->WriteString( fileList[ currentFileNum ] );
|
|
currentFileNum++;
|
|
}
|
|
|
|
for( i = 0; i < variableDefaults.Num(); i++ )
|
|
{
|
|
if( variables[i] != variableDefaults[i] )
|
|
{
|
|
savefile->WriteInt( i );
|
|
savefile->WriteByte( variables[i] );
|
|
}
|
|
}
|
|
// Mark the end of the diff with default variables with -1
|
|
savefile->WriteInt( -1 );
|
|
|
|
savefile->WriteInt( numVariables );
|
|
for( i = variableDefaults.Num(); i < numVariables; i++ )
|
|
{
|
|
savefile->WriteByte( variables[i] );
|
|
}
|
|
|
|
int checksum = CalculateChecksum();
|
|
savefile->WriteInt( checksum );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::Restore
|
|
================
|
|
*/
|
|
bool idProgram::Restore( idRestoreGame* savefile )
|
|
{
|
|
int i, num, index;
|
|
bool result = true;
|
|
idStr scriptname;
|
|
|
|
savefile->ReadInt( num );
|
|
for( i = 0; i < num; i++ )
|
|
{
|
|
savefile->ReadString( scriptname );
|
|
CompileFile( scriptname );
|
|
}
|
|
|
|
savefile->ReadInt( index );
|
|
while( index >= 0 )
|
|
{
|
|
savefile->ReadByte( variables[index] );
|
|
savefile->ReadInt( index );
|
|
}
|
|
|
|
savefile->ReadInt( num );
|
|
for( i = variableDefaults.Num(); i < num; i++ )
|
|
{
|
|
savefile->ReadByte( variables[i] );
|
|
}
|
|
|
|
int saved_checksum, checksum;
|
|
|
|
savefile->ReadInt( saved_checksum );
|
|
checksum = CalculateChecksum();
|
|
|
|
if( saved_checksum != checksum )
|
|
{
|
|
result = false;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::CalculateChecksum
|
|
================
|
|
*/
|
|
int idProgram::CalculateChecksum() const
|
|
{
|
|
int i, result;
|
|
|
|
typedef struct
|
|
{
|
|
unsigned short op;
|
|
int a;
|
|
int b;
|
|
int c;
|
|
unsigned short linenumber;
|
|
unsigned short file;
|
|
} statementBlock_t;
|
|
|
|
statementBlock_t* statementList = new( TAG_SCRIPT ) statementBlock_t[ statements.Num() ];
|
|
|
|
memset( statementList, 0, ( sizeof( statementBlock_t ) * statements.Num() ) );
|
|
|
|
// Copy info into new list, using the variable numbers instead of a pointer to the variable
|
|
for( i = 0; i < statements.Num(); i++ )
|
|
{
|
|
statementList[i].op = statements[i].op;
|
|
|
|
if( statements[i].a )
|
|
{
|
|
statementList[i].a = statements[i].a->num;
|
|
}
|
|
else
|
|
{
|
|
statementList[i].a = -1;
|
|
}
|
|
if( statements[i].b )
|
|
{
|
|
statementList[i].b = statements[i].b->num;
|
|
}
|
|
else
|
|
{
|
|
statementList[i].b = -1;
|
|
}
|
|
if( statements[i].c )
|
|
{
|
|
statementList[i].c = statements[i].c->num;
|
|
}
|
|
else
|
|
{
|
|
statementList[i].c = -1;
|
|
}
|
|
|
|
statementList[i].linenumber = statements[i].linenumber;
|
|
statementList[i].file = statements[i].file;
|
|
}
|
|
|
|
result = MD4_BlockChecksum( statementList, ( sizeof( statementBlock_t ) * statements.Num() ) );
|
|
|
|
delete [] statementList;
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idProgram::Restart
|
|
|
|
Restores all variables to their initial value
|
|
==============
|
|
*/
|
|
void idProgram::Restart()
|
|
{
|
|
int i;
|
|
|
|
idThread::Restart();
|
|
|
|
//
|
|
// since there may have been a script loaded by the map or the user may
|
|
// have typed "script" from the console, free up any types and vardefs that
|
|
// have been allocated after the initial startup
|
|
//
|
|
for( i = top_types; i < types.Num(); i++ )
|
|
{
|
|
delete types[ i ];
|
|
}
|
|
types.SetNum( top_types );
|
|
|
|
typesHash.Free();
|
|
for( i = 0; i < types.Num(); i++ )
|
|
{
|
|
typesHash.Add( idStr::Hash( types[i]->Name() ), i );
|
|
}
|
|
|
|
for( i = top_defs; i < varDefs.Num(); i++ )
|
|
{
|
|
delete varDefs[ i ];
|
|
}
|
|
varDefs.SetNum( top_defs );
|
|
|
|
for( i = top_functions; i < functions.Num(); i++ )
|
|
{
|
|
functions[ i ].Clear();
|
|
}
|
|
functions.SetNum( top_functions );
|
|
|
|
statements.SetNum( top_statements );
|
|
fileList.SetNum( top_files );
|
|
filename.Clear();
|
|
|
|
// reset the variables to their default values
|
|
numVariables = variableDefaults.Num();
|
|
for( i = 0; i < numVariables; i++ )
|
|
{
|
|
variables[ i ] = variableDefaults[ i ];
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::GetFilenum
|
|
================
|
|
*/
|
|
int idProgram::GetFilenum( const char* name )
|
|
{
|
|
if( filename == name )
|
|
{
|
|
return filenum;
|
|
}
|
|
|
|
idStr strippedName;
|
|
strippedName = fileSystem->OSPathToRelativePath( name );
|
|
if( !strippedName.Length() )
|
|
{
|
|
// not off the base path so just use the full path
|
|
filenum = fileList.AddUnique( name );
|
|
}
|
|
else
|
|
{
|
|
filenum = fileList.AddUnique( strippedName );
|
|
}
|
|
|
|
// save the unstripped name so that we don't have to strip the incoming name every time we call GetFilenum
|
|
filename = name;
|
|
|
|
return filenum;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::idProgram
|
|
================
|
|
*/
|
|
idProgram::idProgram()
|
|
{
|
|
varDefs.SetGranularity( 256 );
|
|
varDefNames.SetGranularity( 256 );
|
|
|
|
FreeData();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::~idProgram
|
|
================
|
|
*/
|
|
idProgram::~idProgram()
|
|
{
|
|
FreeData();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idProgram::ReturnEntity
|
|
================
|
|
*/
|
|
void idProgram::ReturnEntity( idEntity* ent )
|
|
{
|
|
if( ent )
|
|
{
|
|
*returnDef->value.entityNumberPtr = ent->entityNumber + 1;
|
|
}
|
|
else
|
|
{
|
|
*returnDef->value.entityNumberPtr = 0;
|
|
}
|
|
}
|