// Copyright (C) 2004 Id Software, Inc. // #ifndef __SCRIPT_PROGRAM_H__ #define __SCRIPT_PROGRAM_H__ class idScriptObject; class idEventDef; class idVarDef; class idTypeDef; class idEntity; class idThread; class idSaveGame; class idRestoreGame; #define MAX_STRING_LEN 128 // HUMANHEAD PCF BG 5/30/06: Added 20% to script max values. // HUMANHEAD pdm: Ran out of space on some maps. TODO figure out why this is happening. #define MAX_GLOBALS 530840 // in bytes //#define MAX_GLOBALS 196608 // in bytes // HUMANHEAD END #define MAX_STRINGS 1024 #define MAX_FUNCS 3686 #define MAX_STATEMENTS 113050 // statement_t - 18 bytes last I checked // HUMANHEAD END PCF typedef enum { ev_error = -1, ev_void, ev_scriptevent, ev_namespace, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_virtualfunction, ev_pointer, ev_object, ev_jumpoffset, ev_argsize, ev_boolean } etype_t; class function_t { public: function_t(); size_t Allocated( void ) const; void SetName( const char *name ); const char *Name( void ) const; void Clear( void ); private: idStr name; public: const idEventDef *eventdef; idVarDef *def; const idTypeDef *type; int firstStatement; int numStatements; int parmTotal; int locals; // total ints of parms + locals int filenum; // source file defined in idList parmSize; }; typedef union eval_s { const char *stringPtr; float _float; float vector[ 3 ]; function_t *function; int _int; int entity; } eval_t; /*********************************************************************** idTypeDef Contains type information for variables and functions. ***********************************************************************/ class idTypeDef { private: etype_t type; idStr name; int size; // function types are more complex idTypeDef *auxType; // return type idList parmTypes; idStrList parmNames; idList functions; public: idVarDef *def; // a def that points to this type idTypeDef( const idTypeDef &other ); idTypeDef( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ); void operator=( const idTypeDef& other ); size_t Allocated( void ) const; bool Inherits( const idTypeDef *basetype ) const; bool MatchesType( const idTypeDef &matchtype ) const; bool MatchesVirtualFunction( const idTypeDef &matchfunc ) const; void AddFunctionParm( idTypeDef *parmtype, const char *name ); void AddField( idTypeDef *fieldtype, const char *name ); void SetName( const char *newname ); const char *Name( void ) const; etype_t Type( void ) const; int Size( void ) const; idTypeDef *SuperClass( void ) const; idTypeDef *ReturnType( void ) const; void SetReturnType( idTypeDef *type ); idTypeDef *FieldType( void ) const; void SetFieldType( idTypeDef *type ); idTypeDef *PointerType( void ) const; void SetPointerType( idTypeDef *type ); int NumParameters( void ) const; idTypeDef *GetParmType( int parmNumber ) const; const char *GetParmName( int parmNumber ) const; int NumFunctions( void ) const; int GetFunctionNumber( const function_t *func ) const; const function_t *GetFunction( int funcNumber ) const; void AddFunction( const function_t *func ); //HUMANHEAD: aob virtual void PushOntoStack( const char* parm, class hhThread* thread ) const {} virtual const char* GetReturnValueAsString( idProgram& program ) const { return ""; } virtual bool VerifyData( const char* data ) const { return false; } //HUMANHEAD END }; //HUMANHEAD: aob class idTypeDefString : public idTypeDef { public: idTypeDefString( const idTypeDef &other ); idTypeDefString( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ); void PushOntoStack( const char* parm, class hhThread* thread ) const; const char* GetReturnValueAsString( idProgram& program ) const; bool VerifyData( const char* data ) const; }; class idTypeDefVector : public idTypeDef { public: idTypeDefVector( const idTypeDef &other ); idTypeDefVector( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ); void PushOntoStack( const char* parm, class hhThread* thread ) const; const char* GetReturnValueAsString( idProgram& program ) const; bool VerifyData( const char* data ) const; }; class idTypeDefFloat : public idTypeDef { public: idTypeDefFloat( const idTypeDef &other ); idTypeDefFloat( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ); void PushOntoStack( const char* parm, class hhThread* thread ) const; const char* GetReturnValueAsString( idProgram& program ) const; bool VerifyData( const char* data ) const; }; class idTypeDefEntity : public idTypeDef { public: idTypeDefEntity( const idTypeDef &other ); idTypeDefEntity( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ); void PushOntoStack( const char* parm, class hhThread* thread ) const; const char* GetReturnValueAsString( idProgram& program ) const; bool VerifyData( const char* data ) const; }; class idTypeDefBool : public idTypeDef { public: idTypeDefBool( const idTypeDef &other ); idTypeDefBool( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ); void PushOntoStack( const char* parm, class hhThread* thread ) const; const char* GetReturnValueAsString( idProgram& program ) const; bool VerifyData( const char* data ) const; }; //HUMANHEAD END /*********************************************************************** idScriptObject In-game representation of objects in scripts. Use the idScriptVariable template (below) to access variables. ***********************************************************************/ class idScriptObject { private: idTypeDef *type; public: byte *data; idScriptObject(); ~idScriptObject(); void Save( idSaveGame *savefile ) const; // archives object for save game file void Restore( idRestoreGame *savefile ); // unarchives object from save game file void Free( void ); bool SetType( const char *typeName ); void ClearObject( void ); bool HasObject( void ) const; idTypeDef *GetTypeDef( void ) const; const char *GetTypeName( void ) const; const function_t *GetConstructor( void ) const; const function_t *GetDestructor( void ) const; const function_t *GetFunction( const char *name ) const; byte *GetVariable( const char *name, etype_t etype ) const; }; /*********************************************************************** idScriptVariable Helper template that handles looking up script variables stored in objects. If the specified variable doesn't exist, or is the wrong data type, idScriptVariable will cause an error. ***********************************************************************/ template class idScriptVariable { private: type *data; public: idScriptVariable(); bool IsLinked( void ) const; void Unlink( void ); void LinkTo( idScriptObject &obj, const char *name ); idScriptVariable &operator=( const returnType &value ); operator returnType() const; }; template ID_INLINE idScriptVariable::idScriptVariable() { data = NULL; } template ID_INLINE bool idScriptVariable::IsLinked( void ) const { return ( data != NULL ); } template ID_INLINE void idScriptVariable::Unlink( void ) { data = NULL; } template ID_INLINE void idScriptVariable::LinkTo( idScriptObject &obj, const char *name ) { data = ( type * )obj.GetVariable( name, etype ); if ( !data ) { gameLocal.Error( "Missing '%s' field in script object '%s'", name, obj.GetTypeName() ); } } template ID_INLINE idScriptVariable &idScriptVariable::operator=( const returnType &value ) { // check if we attempt to access the object before it's been linked assert( data ); // make sure we don't crash if we don't have a pointer if ( data ) { *data = ( type )value; } return *this; } template ID_INLINE idScriptVariable::operator returnType() const { // check if we attempt to access the object before it's been linked assert( data ); // make sure we don't crash if we don't have a pointer if ( data ) { return ( const returnType )*data; } else { // reasonably safe value return ( const returnType )0; } } /*********************************************************************** Script object variable access template instantiations These objects will automatically handle looking up of the current value of a variable in a script object. They can be stored as part of a class for up-to-date values of the variable, or can be used in functions to sample the data for non-dynamic values. ***********************************************************************/ typedef idScriptVariable idScriptBool; typedef idScriptVariable idScriptFloat; typedef idScriptVariable idScriptInt; typedef idScriptVariable idScriptVector; typedef idScriptVariable idScriptString; /*********************************************************************** idCompileError Causes the compiler to exit out of compiling the current function and display an error message with line and file info. ***********************************************************************/ class idCompileError : public idException { public: idCompileError( const char *text ) : idException( text ) {} }; /*********************************************************************** idVarDef Define the name, type, and location of variables, functions, and objects defined in script. ***********************************************************************/ typedef union varEval_s { idScriptObject **objectPtrPtr; char *stringPtr; float *floatPtr; idVec3 *vectorPtr; function_t *functionPtr; int *intPtr; byte *bytePtr; int *entityNumberPtr; int virtualFunction; int jumpOffset; int stackOffset; // offset in stack for local variables int argSize; varEval_s *evalPtr; int ptrOffset; INT_PTR highPtr; } varEval_t; class idVarDef { friend class idVarDefName; public: int num; varEval_t value; idVarDef * scope; // function, namespace, or object the var was defined in int numUsers; // number of users if this is a constant typedef enum { uninitialized, initializedVariable, initializedConstant, stackVariable } initialized_t; initialized_t initialized; public: idVarDef( idTypeDef *typeptr = NULL ); ~idVarDef(); const char * Name( void ) const; const char * GlobalName( void ) const; void SetTypeDef( idTypeDef *_type ) { typeDef = _type; } idTypeDef * TypeDef( void ) const { return typeDef; } etype_t Type( void ) const { return ( typeDef != NULL ) ? typeDef->Type() : ev_void; } int DepthOfScope( const idVarDef *otherScope ) const; void SetFunction( function_t *func ); void SetObject( idScriptObject *object ); void SetValue( const eval_t &value, bool constant ); void SetString( const char *string, bool constant ); idVarDef * Next( void ) const { return next; } // next var def with same name void PrintInfo( idFile *file, int instructionPointer ) const; private: idTypeDef * typeDef; idVarDefName * name; // name of this var idVarDef * next; // next var with the same name }; /*********************************************************************** idVarDefName ***********************************************************************/ class idVarDefName { public: idVarDefName( void ) { defs = NULL; } idVarDefName( const char *n ) { name = n; defs = NULL; } const char * Name( void ) const { return name; } idVarDef * GetDefs( void ) const { return defs; } void AddDef( idVarDef *def ); void RemoveDef( idVarDef *def ); private: idStr name; idVarDef * defs; }; /*********************************************************************** Variable and type defintions ***********************************************************************/ extern idTypeDef type_void; extern idTypeDef type_scriptevent; extern idTypeDef type_namespace; //HUMANHEAD: aob - changed types to inherited types extern idTypeDefString type_string; extern idTypeDefFloat type_float; extern idTypeDefVector type_vector; extern idTypeDefEntity type_entity; //HUMANHEAD END extern idTypeDef type_field; extern idTypeDef type_function; extern idTypeDef type_virtualfunction; extern idTypeDef type_pointer; extern idTypeDef type_object; extern idTypeDef type_jumpoffset; // only used for jump opcodes extern idTypeDef type_argsize; // only used for function call and thread opcodes //HUMANHEAD: aob - changed types to inherited types extern idTypeDefBool type_boolean; //HUMANHEAD END extern idVarDef def_void; extern idVarDef def_scriptevent; extern idVarDef def_namespace; extern idVarDef def_string; extern idVarDef def_float; extern idVarDef def_vector; extern idVarDef def_entity; extern idVarDef def_field; extern idVarDef def_function; extern idVarDef def_virtualfunction; extern idVarDef def_pointer; extern idVarDef def_object; extern idVarDef def_jumpoffset; // only used for jump opcodes extern idVarDef def_argsize; // only used for function call and thread opcodes extern idVarDef def_boolean; typedef struct statement_s { unsigned short op; idVarDef *a; idVarDef *b; idVarDef *c; unsigned short linenumber; unsigned short file; } statement_t; /*********************************************************************** idProgram Handles compiling and storage of script data. Multiple idProgram objects would represent seperate programs with no knowledge of each other. Scripts meant to access shared data and functions should all be compiled by a single idProgram. ***********************************************************************/ class idProgram { private: idStrList fileList; idStr filename; int filenum; int numVariables; byte variables[ MAX_GLOBALS ]; idStaticList variableDefaults; idStaticList functions; idStaticList statements; idList types; idList varDefNames; idHashIndex varDefNameHash; idList varDefs; idVarDef *sysDef; int top_functions; int top_statements; int top_types; int top_defs; int top_files; void CompileStats( void ); public: idVarDef *returnDef; idVarDef *returnStringDef; idProgram(); ~idProgram(); // save games void Save( idSaveGame *savefile ) const; bool Restore( idRestoreGame *savefile ); int CalculateChecksum( void ) const; // Used to insure program code has not // changed between savegames void Startup( const char *defaultScript ); void Restart( void ); bool CompileText( const char *source, const char *text, bool console ); const function_t *CompileFunction( const char *functionName, const char *text ); void CompileFile( const char *filename ); void BeginCompilation( void ); void FinishCompilation( void ); void DisassembleStatement( idFile *file, int instructionPointer ) const; void Disassemble( void ) const; void FreeData( void ); const char *GetFilename( int num ); int GetFilenum( const char *name ); int GetLineNumberForStatement( int index ); const char *GetFilenameForStatement( int index ); idTypeDef *AllocType( idTypeDef &type ); idTypeDef *AllocType( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ); idTypeDef *GetType( idTypeDef &type, bool allocate ); idTypeDef *FindType( const char *name ); idVarDef *AllocDef( idTypeDef *type, const char *name, idVarDef *scope, bool constant ); idVarDef *GetDef( const idTypeDef *type, const char *name, const idVarDef *scope ) const; void FreeDef( idVarDef *d, const idVarDef *scope ); idVarDef *FindFreeResultDef( idTypeDef *type, const char *name, idVarDef *scope, const idVarDef *a, const idVarDef *b ); idVarDef *GetDefList( const char *name ) const; void AddDefToNameList( idVarDef *def, const char *name ); function_t *FindFunction( const char *name ) const; // returns NULL if function not found function_t *FindFunction( const char *name, const idTypeDef *type ) const; // returns NULL if function not found function_t &AllocFunction( idVarDef *def ); function_t *GetFunction( int index ); int GetFunctionIndex( const function_t *func ); void SetEntity( const char *name, idEntity *ent ); statement_t *AllocStatement( void ); statement_t &GetStatement( int index ); int NumStatements( void ) { return statements.Num(); } int GetReturnedInteger( void ); //HUMANHEAD: aob - need to return other types float GetReturnedFloat( void ); bool GetReturnedBool( void ); idVec3 GetReturnedVector( void ); idStr GetReturnedString( void ); int GetReturnedEntity( void ); //HUMANHEAD END void ReturnFloat( float value ); void ReturnInteger( int value ); void ReturnVector( idVec3 const &vec ); void ReturnString( const char *string ); void ReturnEntity( idEntity *ent ); int NumFilenames( void ) { return fileList.Num( ); } }; /* ================ idProgram::GetStatement ================ */ ID_INLINE statement_t &idProgram::GetStatement( int index ) { return statements[ index ]; } /* ================ idProgram::GetFunction ================ */ ID_INLINE function_t *idProgram::GetFunction( int index ) { return &functions[ index ]; } /* ================ idProgram::GetFunctionIndex ================ */ ID_INLINE int idProgram::GetFunctionIndex( const function_t *func ) { return func - &functions[0]; } /* ================ idProgram::GetReturnedInteger ================ */ ID_INLINE int idProgram::GetReturnedInteger( void ) { // HUMANHEAD pdm: Changed to reference the floatPtr, since we send ints as floats return static_cast(*returnDef->value.floatPtr); } /* ================ idProgram::GetReturnedFloat HUMANHEAD: aob ================ */ ID_INLINE float idProgram::GetReturnedFloat( void ) { return *returnDef->value.floatPtr; } /* ================ idProgram::GetReturnedBool HUMANHEAD: aob ================ */ ID_INLINE bool idProgram::GetReturnedBool( void ) { // HUMANHEAD pdm: Changed to reference the floatPtr, since we send ints as floats return (*(returnDef->value.floatPtr)) != 0.0f; } /* ================ idProgram::GetReturnedVector HUMANHEAD: aob ================ */ ID_INLINE idVec3 idProgram::GetReturnedVector( void ) { return *returnDef->value.vectorPtr; } /* ================ idProgram::GetReturnedString HUMANHEAD: aob ================ */ ID_INLINE idStr idProgram::GetReturnedString( void ) { return idStr( *returnDef->value.stringPtr ); } /* ================ idProgram::GetReturnedEntity HUMANHEAD: aob ================ */ ID_INLINE int idProgram::GetReturnedEntity( void ) { return *returnDef->value.entityNumberPtr; } /* ================ idProgram::ReturnFloat ================ */ ID_INLINE void idProgram::ReturnFloat( float value ) { *returnDef->value.floatPtr = value; } /* ================ idProgram::ReturnInteger ================ */ ID_INLINE void idProgram::ReturnInteger( int value ) { *returnDef->value.intPtr = value; } /* ================ idProgram::ReturnVector ================ */ ID_INLINE void idProgram::ReturnVector( idVec3 const &vec ) { *returnDef->value.vectorPtr = vec; } /* ================ idProgram::ReturnString ================ */ ID_INLINE void idProgram::ReturnString( const char *string ) { idStr::Copynz( returnStringDef->value.stringPtr, string, MAX_STRING_LEN ); } /* ================ idProgram::GetFilename ================ */ ID_INLINE const char *idProgram::GetFilename( int num ) { return fileList[ num ]; } /* ================ idProgram::GetLineNumberForStatement ================ */ ID_INLINE int idProgram::GetLineNumberForStatement( int index ) { return statements[ index ].linenumber; } /* ================ idProgram::GetFilenameForStatement ================ */ ID_INLINE const char *idProgram::GetFilenameForStatement( int index ) { return GetFilename( statements[ index ].file ); } #endif /* !__SCRIPT_PROGRAM_H__ */