/***************************************************************************** ** ** ** Neversoft Entertainment ** ** ** ** Copyright (C) 1999 - All Rights Reserved ** ** ** ****************************************************************************** ** ** ** Project: GEL (Game Engine Library) ** ** ** ** Module: Objects (OBJ) ** ** ** ** File name: object.cpp ** ** ** ** Created: 05/27/99 - mjb ** ** ** ** Description: Game object code ** ** ** *****************************************************************************/ // start autoduck documentation // @DOC object.cpp // @module object | None // @subindex Scripting Database // @index script | object /***************************************************************************** ** Includes ** *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include /***************************************************************************** ** Externals ** *****************************************************************************/ /***************************************************************************** ** Defines ** *****************************************************************************/ /***************************************************************************** ** DBG Defines ** *****************************************************************************/ namespace Script { extern void PrintContents(CStruct *p_structure, int indent); } namespace Obj { /***************************************************************************** ** Private Types ** *****************************************************************************/ // temp // temp REMOVE THIS WHEN script.h is implemented // temp //class CScript //{ //}; // temp // temp // temp /***************************************************************************** ** Private Data ** *****************************************************************************/ /***************************************************************************** ** Public Data ** *****************************************************************************/ /***************************************************************************** ** Private Prototypes ** *****************************************************************************/ /***************************************************************************** ** Private Functions ** *****************************************************************************/ /***************************************************************************** ** Public Functions ** *****************************************************************************/ /* Creates CObject, does not give it an ID or register it. */ CObject::CObject() : m_node(this) { m_id = CBaseManager::vNO_OBJECT_ID; m_type = CBaseManager::vNO_OBJECT_TYPE; #ifndef __SCRIPT_EVENT_TABLE__ mp_event_handler_table = NULL; #endif mp_tags = NULL; mp_script = NULL; mp_manager = NULL; m_object_flags = 0; m_ref_count = 0; m_stamp = 0; } /* Creates CObject, registers it with manager, giving it automatic ID. */ CObject::CObject( CBaseManager* p_obj_manager ) : m_node(this) //: manager( obj_manager ) { Dbg_Assert(p_obj_manager); m_id = CBaseManager::vNO_OBJECT_ID; m_type = CBaseManager::vNO_OBJECT_TYPE; p_obj_manager->RegisterObject( *this ); // add to manager's object list #ifndef __SCRIPT_EVENT_TABLE__ mp_event_handler_table = NULL; #endif mp_tags = NULL; mp_script = NULL; mp_manager = NULL; m_object_flags = 0; m_ref_count = 0; } /* Destroying CObject disconnects it from manager, stops all scripts running on it. */ CObject::~CObject() { #ifdef __NOPT_ASSERT__ if (GetLockAssert()) { if (mp_script) { Dbg_MsgAssert(0,("\n%s\n Object %s at %p has been deleted while updating a script running on it, maybe goal manager callback? See Mick.",mp_script->GetScriptInfo(),Script::FindChecksumName(GetID()),this)); } Dbg_MsgAssert(0,("Object %s at %p has been deleted while updating a script running on it, maybe goal manager callback? See Mick.",Script::FindChecksumName(GetID()),this)); } #endif Dbg_MsgAssert(!IsLocked(), ("can't destroy CObject, is locked")); if (mp_tags) delete mp_tags; #ifndef __SCRIPT_EVENT_TABLE__ if (mp_event_handler_table) { // Remove the references to the event handler from the tracker mp_event_handler_table->unregister_all(this); if (mp_event_handler_table->m_in_immediate_use_counter) { // table still in use by its pass_event() function, // so leave it up to that function to destroy the table mp_event_handler_table->m_valid = false; } else { delete mp_event_handler_table; } } #endif if (mp_manager) { mp_manager->UnregisterObject( *this ); } if (mp_script) { delete mp_script; mp_script = NULL; } // Stop any scripts that have this object as their parent. // Note: This won't actually delete the scripts, to prevent dangling pointers. Script::StopAllScriptsUsingThisObject(this); } /* Used by object managers when they delete all but a few objects (which have been locked). */ void CObject::DestroyIfUnlocked() { if ( !IsLocked() ) { delete this; } } /* Sets the global ID of this CObject. A CObject needs an ID in order to function in the system. If no ID is assigned, it will automatically be assigned one when registered with a manager. Calling this function on a CObject that already has an ID will attempt to change its ID globally (whereever that ID is used). */ void CObject::SetID(uint32 id) { if (m_id != CBaseManager::vNO_OBJECT_ID && mp_manager) { mp_manager->ReregisterObject(*this, id); } m_id = id; SetChecksumTag(CRCD(0x40c698af, "id"), m_id); } /* Type is pretty much just the checksum of the class, minus the "C" */ void CObject::SetType(sint type) { Dbg_MsgAssert(m_type == CBaseManager::vNO_OBJECT_TYPE, ("CObject already assigned a type")); m_type = type; SetChecksumTag(CRCD(0x7321a8d6, "type"), m_type); } #ifndef __SCRIPT_EVENT_TABLE__ /* Sets up the table that specifies which scripts to run in response to which events. See object scripting document. */ void CObject::SetEventHandlers(Script::CArray *pArray, EReplaceEventHandlers replace) { if (!mp_event_handler_table) { Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().FrontEndHeap()); mp_event_handler_table = new CEventHandlerTable(); Mem::Manager::sHandle().PopContext(); } else { mp_event_handler_table->unregister_all(this); } mp_event_handler_table->add_from_script(pArray, replace); // mp_event_handler_table->compress_table(); mp_event_handler_table->register_all(this); } /* Removes an entry in the event table with the given type id */ void CObject::RemoveEventHandler(uint32 type) { if (!mp_event_handler_table) return; mp_event_handler_table->remove_entry(type); // Mick: by not compressing the event handler table after removing entries // we should minimize the amount of allocs needed // new event handlers can just re-use these "removed" sloes // mp_event_handler_table->compress_table(); // Refresh the Obj::Tracker Obj::CTracker::Instance()->UnregisterEventReceiver(type, this); } /* Removes all entries in the event table with the given group id */ void CObject::RemoveEventHandlerGroup(uint32 group) { if (!mp_event_handler_table) return; mp_event_handler_table->unregister_all(this); mp_event_handler_table->remove_group(group); // Mick: by not compressing the event handler table after removing entries // we should minimize the amount of allocs needed // new event handlers can just re-use these "removed" sloes // mp_event_handler_table->compress_table(); mp_event_handler_table->register_all(this); } #else /* Sets up the table that specifies which scripts to run in response to which events. See object scripting document. */ void CObject::SetEventHandlers(Script::CArray *pArray, EReplaceEventHandlers replace) { // TEMP - Pass into script object. Eventually handled soley by script with no need for object AllocateScriptIfNeeded(); mp_script->SetEventHandlers(pArray, replace); } /* Removes an entry in the event table with the given type id */ void CObject::RemoveEventHandler(uint32 type) { if (!mp_script) { return; } mp_script->RemoveEventHandler(type ); } /* Removes all entries in the event table with the given group id */ void CObject::RemoveEventHandlerGroup(uint32 group) { if (!mp_script) { return; } mp_script->RemoveEventHandlerGroup(group); } #endif void CObject::SetIntegerTag(uint32 name, int value) { allocate_tags_if_needed(); mp_tags->AddInteger(name, value); } void CObject::SetChecksumTag(uint32 name, uint32 value) { allocate_tags_if_needed(); mp_tags->AddChecksum(name, value); } void CObject::RemoveFlagTag(uint32 name) { if (mp_tags) mp_tags->RemoveFlag(name); } bool CObject::GetIntegerTag(uint32 name, int *pResult) const { if (mp_tags) return mp_tags->GetInteger(name, pResult); return false; } bool CObject::GetChecksumTag(uint32 name, uint32 *pResult) const { if (mp_tags) return mp_tags->GetChecksum(name, pResult); return false; } bool CObject::ContainsFlagTag(uint32 name) const { if (mp_tags) return mp_tags->ContainsFlag(name); return false; } // Add a vector to the tag structure with name "name", and copy in the vector "v" void CObject::SetVectorTag(uint32 name, Mth::Vector v) { allocate_tags_if_needed(); mp_tags->AddVector(name, v[X], v[Y], v[Z]); } // get the value a vector tag. // returning false if not found bool CObject::GetVectorTag(uint32 name, Mth::Vector *pResult) const { if (mp_tags) return mp_tags->GetVector(name, pResult); return false; } #ifndef __SCRIPT_EVENT_TABLE__ void CObject::SetOnExceptionScriptChecksum(uint32 OnExceptionScriptChecksum) { mOnExceptionScriptChecksum = OnExceptionScriptChecksum; } uint32 CObject::GetOnExceptionScriptChecksum() const { return mOnExceptionScriptChecksum; } #else // Todo - Pass these to the script #endif void CObject::SetTagsFromScript(Script::CStruct *pStruct) { allocate_tags_if_needed(); mp_tags->AppendStructure(pStruct); //printf("Set tags of object %s to:\n", Script::FindChecksumName(m_id)); //Script::PrintContents(mp_tags, 4); } void CObject::RemoveTagsFromScript(Script::CArray *pNameArray) { if (!mp_tags) return; for (uint i = 0; i < pNameArray->GetSize(); i++) { uint32 name_crc = pNameArray->GetChecksum(i); mp_tags->RemoveComponent(name_crc); mp_tags->RemoveFlag(name_crc); } if (mp_tags->IsEmpty()) { delete mp_tags; mp_tags = NULL; } } void CObject::CopyTagsToScriptStruct(Script::CStruct *pStruct) { Dbg_Assert(pStruct); if (mp_tags) { pStruct->AppendStructure(mp_tags); //printf("Fetching tags of object %s:\n", Script::FindChecksumName(m_id)); //Script::PrintContents(pStruct, 4); } } /* Property setting script commands enter through this function. */ void CObject::SetProperties(Script::CStruct *pProps) { bool replace_handlers = pProps->ContainsFlag("replace_handlers"); Script::CArray *p_event_handler_table; if (pProps->GetArray("event_handlers", &p_event_handler_table)) { #ifdef __SCRIPT_EVENT_TABLE__ CObject::SetEventHandlers(p_event_handler_table, EReplaceEventHandlers(replace_handlers)); #else CObject::SetEventHandlers(p_event_handler_table, EReplaceEventHandlers(replace_handlers)); #endif } /* else if (pProps->GetArray("event_handler", &p_event_handler_table)) { // just a single entry (makes for easier-to-read script) CObject::SetEventHandlers(p_event_handler_table, replace_handlers, true); } */ Script::CStruct *p_tags; if (pProps->GetStructure("tags", &p_tags)) SetTagsFromScript(p_tags); Script::CArray *p_remove_tags; if (pProps->GetArray("remove_tags", &p_remove_tags)) RemoveTagsFromScript(p_remove_tags); } /******************************************************************/ /* CObject::CallMemberFunction */ /* Call a member function, based on a checksum */ /* This is usually the checksum of the name of the function */ /* but can actually be any number, as it just uses a switch */ /* note this is a virtual function, so the same checksum */ /* can do differnet things for different objects */ /* */ /* */ /******************************************************************/ bool CObject::CallMemberFunction( uint32 Checksum, Script::CScriptStructure *pParams, Script::CScript *pScript ) { Dbg_MsgAssert(pScript,("NULL pScript")); switch(Checksum) { case CRCC(0x3611c136, "GetTags"): CopyTagsToScriptStruct(pScript->GetParams()); break; case CRCC( 0xa58079eb, "SetTags" ): SetTagsFromScript( pParams ); break; case 0xc6870028:// "Die" MarkAsDead( ); break; case 0xb3c262ec:// "DisassociateFromObject" pScript->DisassociateWithObject(this); break; // @script | Obj_GetId | case 0x500eb224: // Obj_GetId Dbg_Assert( pScript && pScript->GetParams() ); pScript->GetParams()->AddChecksum( "objId", m_id ); break; // @script | Obj_FlagSet | Check to see if a flag has been set. Flags can // be defined anywhere, but you should keep them in your personal scripts file. // It is important that you prefix all flags with your initials to ensure that // there are no conflicts with the other designers. // Example 1: // MJD_LAMP_GOT_BROKEN = 14 // MJD_LAMP_GOT_HIT = 15 // MJD_LAMP_GOT_DISABLED = 16 // if Obj_FlagSet 15 // Obj_ClearFlag MJD_LAMP_GOT_HIT // WiggleProfusely // endif // Example 2: // if Obj_FlagSet MJD_LAMP_GOT_HIT clear // WiggleProfusely // endif // Example 3: // If Obj_FlagSet JKU_FLAG_PED_START // JKU_FLAG_PED_START would be defined in JKU_Scripts.q // Printf “Yes” // endif // @flag all | Clear all flags // @flag clear | Clear the flag // @flag reset | I just added a 'reset' flag you can send in to clear // the flag after checking it, if it's set case 0x4babc987: // Obj_FlagSet { uint32 scriptFlags = mScriptFlags; uint32 Flags = 0; Flags = GetFlags( pParams, pScript ); if ( !Flags ) { Dbg_MsgAssert( 0,( "\n%s\nObj_FlagSet command requires a flag to be specified.\n(Either an integer or a name defined to be an integer)",pScript->GetScriptInfo())); return ( false ); } if ( pParams->ContainsFlag( 0x1a4e0ef9 ) ) // clear { mScriptFlags &= ~( Flags ); } if ( scriptFlags & Flags ) { return true; } else { return false; } break; } // @script | Obj_FlagNotSet | Check to see if a flag has not been set. case 0x53ebee03: // Obj_FlagNotSet { uint32 Flags = 0; Flags = GetFlags( pParams, pScript ); if ( !Flags ) { Dbg_MsgAssert( 0,( "\n%s\nObj_FlagNotSet command requires a flag to be specified.\n(Either an integer or a name defined to be an integer)",pScript->GetScriptInfo())); return ( false ); } if ( mScriptFlags & ( Flags ) ) { return false; } else { return true; } break; } // @script | Obj_ClearFlag | Object member function which clears the specified flag or flags. // There are 3 ways of using it, it can clear just one flag, or an array of flags, // or all the flags. // Example 1: // Obj_ClearFlag JKU_FLAG_PED_START // Set the flag to 0 // Example 2: // Obj_ClearFlag [ JKU_FLAG_PED_START JKU_FLAG_PED_STOP ] // Clears an array of flags // Example 3: // Obj_ClearFlag All // Clears all the flags. // @flag all | Clear all the flags case 0x6c2b67f9: // Obj_ClearFlag { if (pParams->ContainsFlag(0xc4e78e22/*All*/)) { mScriptFlags=0; return true; } uint32 Flags = 0; Flags = GetFlags( pParams, pScript ); if ( !Flags ) { Dbg_MsgAssert( 0,( "\n%s\nObj_ClearFlag command requires a flag to be specified.\n(Either an integer or a name defined to be an integer)",pScript->GetScriptInfo())); return ( false ); } mScriptFlags &= ~Flags; break; } // @script | Obj_SetFlag | Sets the flag (or an array of flags) on an object. // Same parameters as Obj_ClearFlag (except doesn't recognize the // 'all' parameter). case 0xbe563426: // Obj_SetFlag { uint32 Flags = 0; Flags = GetFlags( pParams, pScript ); if ( !Flags ) { Dbg_MsgAssert( 0,( "\n%s\nObj_SetFlag command requires a flag to be specified.\n(Either an integer or a name defined to be an integer)",pScript->GetScriptInfo())); return ( false ); } mScriptFlags |= Flags; break; } // @script | Obj_KillSpawnedScript | Kills a spawned script. Can be passeed a name or id. // @parm name | name | Name of the script you want to spawn (no quotes) // @parm name | id | id of the script you want to spawn (no quotes) case 0xfbd89cd5: // Obj_KillSpawnedScript { uint32 ScriptChecksum=0; if (pParams->GetChecksum(CRCD(0xa1dc81f9,"Name"),&ScriptChecksum)) { // Got a script name, so kill all spawned scripts that ran that script. // BUT NOT THE SCRIPT CALLING THIS! Script::KillSpawnedScriptsWithObjectAndName( this, ScriptChecksum, pScript ); return true; } uint32 Id=0; if (pParams->GetChecksum(CRCD(0x40c698af,"Id"),&Id)) { // They specified an Id, so kill all spawned scripts with this Id, // BUT NOT THE SCRIPT CALLING THIS! Script::KillSpawnedScriptsWithObjectAndId( this, Id, pScript ); return ( true ); } Dbg_MsgAssert( 0,( "\n%s\nMust specify Name or ID on Obj_KillSpawnedScript", pScript->GetScriptInfo() )); return true; break; } // @script | Obj_SpawnScript | Causes the object to run a script, in parallel // to whatever script is running on the object. // @flag ScriptName | Name of the script you want to spawn (no quotes) // @parmopt name | Params | {} | Any parameters you want to pass to the script being // spawned. Must surround params in { } case 0x23a4e5c2: // Obj_SpawnScript { Script::CComponent* p_component = pParams->GetNextComponent(); if ( p_component && p_component->mType == ESYMBOLTYPE_NAME ) { uint32 scriptChecksum = p_component->mChecksum; // The spawned script can optionally be given an Id, so that it can be deleted // by KillSpawnedScript. uint32 Id=0; // keep the same ID as the parent if not specified... Id = Script::FindSpawnedScriptID(pScript); pParams->GetChecksum("Id",&Id); Script::CScriptStructure *pScriptParams = NULL; pParams->GetStructure( "Params", &pScriptParams ); #ifdef __NOPT_ASSERT__ Script::CScript *p_script=SpawnScriptPlease( scriptChecksum, pScriptParams, Id, pParams->ContainsFlag(CRCD(0x8757d0bb, "PauseWithObject")) ); p_script->SetCommentString("Created by Obj_SpawnScript"); p_script->SetOriginatingScriptInfo(pScript->GetCurrentLineNumber(),pScript->mScriptChecksum); #else SpawnScriptPlease( scriptChecksum, pScriptParams, Id ); #endif } break; } // @script | Obj_SwitchScript | Causes the object to replace the current script // attached to it with the script specified by ScriptName. // Can use the pass params just like Obj_SpawnScript. // @flag ScriptName | Name of the script you want to spawn (no quotes) case 0x714937c7: // Obj_SwitchScript { uint32 scriptChecksum; if ( pParams->GetChecksum( NONAME, &scriptChecksum ) ) { Script::CScriptStructure *pScriptParams = NULL; pParams->GetStructure( "Params", &pScriptParams ); SwitchScript( scriptChecksum, pScriptParams ); } break; } // case CRCC(0x6df6caef,"SetProperties"): case CRCC(0x6c63c7c5,"SetProps"): { // Lowest level SetProperties, allowing ANY object to set event handlers SetProperties(pParams); break; } /* case CRCC(0x1127430c, "ClearEventHandler"): { uint32 type; pParams->GetChecksum(NO_NAME, &type, Script::ASSERT); RemoveEventHandler(type); break; } case CRCC(0x8968da7f, "ClearEventHandlerGroup"): { uint32 group = CEventHandlerTable::vDEFAULT_GROUP; pParams->GetChecksum(NO_NAME, &group); RemoveEventHandlerGroup(group); break; } // @script | OnExceptionRun | run the specified script on exception // @uparm name | script name to run // can be called without a parameter to clear it // case 0x2c0c9e7b: // OnExceptionRun case CRCC(0x2c0c9e7b,"OnExceptionRun"): { uint32 OnExceptionScriptChecksum = 0; pParams->GetChecksum( NONAME, &OnExceptionScriptChecksum); #ifdef __SCRIPT_EVENT_TABLE__ if (mp_script) { mp_script->SetOnExceptionScriptChecksum(OnExceptionScriptChecksum); } #else SetOnExceptionScriptChecksum(OnExceptionScriptChecksum); #endif break; } case CRCC(0xbefaa466,"OnExitRun"): { uint32 OnExitScriptChecksum = 0; pParams->GetChecksum( NONAME, &OnExitScriptChecksum); #ifdef __SCRIPT_EVENT_TABLE__ if (mp_script) { mp_script->SetOnExitScriptChecksum(OnExitScriptChecksum); } #else SetOnExitScriptChecksum(OnExitScriptChecksum); #endif break; } */ case 0x20d125d7: // Obj_Visible m_object_flags &= ~vINVISIBLE; break; case 0x3578e5a9: // Obj_Invisible m_object_flags |= vINVISIBLE; break; default: Dbg_MsgAssert(0,("\n%s\nNo CObject member function found for '%s'",pScript->GetScriptInfo(),Script::FindChecksumName(Checksum))); } return true; } uint32 CObject::GetFlags( Script::CScriptStructure *pParams, Script::CScript *pScript ) const { uint32 Flags = 0; int Flag = 0; // Scan through any array of flags specified. Script::CArray *pArray=NULL; pParams->GetArray(NONAME,&pArray); if (pArray) { for (uint32 i=0; iGetSize(); ++i) { uint32 Checksum=pArray->GetNameChecksum(i); int Flag=Script::GetInteger(Checksum); Dbg_MsgAssert(Flag>=0 && Flag<32,("\n%s\nBad flag value %s=%d, value must be between 0 and 31",pScript->GetScriptInfo(),Script::FindChecksumName(Checksum),Flag)); Flags |= ( 1 << Flag ); } } else if ( pParams->GetInteger( NONAME, &Flag ) ) { Dbg_MsgAssert(Flag>=0 && Flag<32,("\n%s\nBad flag value of %d, value must be between 0 and 31",pScript->GetScriptInfo(),Flag)); Flags = ( 1 << Flag ); } return Flags; } /* If an event is targeted specifically to this CObject (using the same ID), it will be passed through this function. */ bool CObject::PassTargetedEvent(CEvent *pEvent, bool broadcast) { #ifdef __SCRIPT_EVENT_TABLE__ if (!mp_script) { return true; } #endif Obj::CSmtPtr p = this; #ifdef __SCRIPT_EVENT_TABLE__ mp_script->PassTargetedEvent(pEvent, broadcast); #else if (mp_event_handler_table) mp_event_handler_table->pass_event(pEvent, this, broadcast); #endif return (p != NULL); } // Send myself an event. Just a useful shortcut for a commonly done thing void CObject::SelfEvent(uint32 event, Script::CStruct* pParams) { Obj::CTracker::Instance()->LaunchEvent(event,GetID(),GetID(),pParams); } void CObject::BroadcastEvent(uint32 event, Script::CStruct *pData, float radius) { // no target // radius not implemented yet Obj::CTracker::Instance()->LaunchEvent( event, 0xffffffff, GetID(), pData, true /*, radius */ ); } /* Has the same effect as deleting the CObject, except the actual deletion is deferred until next frame. So that objects can be killed and not mess up list traversal */ void CObject::MarkAsDead( void ) { // make sure we don't continue running anything on this script! if ( mp_script ) { mp_script->Block( ); } // The following line will set the mp_object of any referring scripts to NULL Script::StopAllScriptsUsingThisObject(this); // Mick: we don't want any other scripts to continue running on a dead object Dbg_MsgAssert( mp_manager,( "No object manager associated with this object..." )); // who locks an object? SetLockOff(); // mp_manager will be cleared by UnregisterObject() CBaseManager *p_manager = mp_manager; p_manager->UnregisterObject( *this ); p_manager->KillObject( *this ); // add object to kill list, to be purged next frame... m_object_flags |= ( vDEAD ); } /******************************************************************/ /* */ /* */ /******************************************************************/ void CObject::allocate_tags_if_needed() { if (!mp_tags) { Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().FrontEndHeap()); mp_tags = new Script::CStruct(); Mem::Manager::sHandle().PopContext(); } } /******************************************************************/ /* */ /* */ /******************************************************************/ void CObject::AllocateScriptIfNeeded() { if (!mp_script) { Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().ScriptHeap()); mp_script = new Script::CScript(); mp_script->SetScript(CRCD(0x3f5cdb8a,"empty_script"),NULL,this); Mem::Manager::sHandle().PopContext(); } } /******************************************************************/ /* */ /* */ /******************************************************************/ void CObject::SwitchScript( uint32 scriptChecksum, Script::CScriptStructure *pParams ) { if ( mp_script ) { mp_script->SetScript( scriptChecksum, pParams, this ); } else { mp_script = new Script::CScript; mp_script->SetScript( scriptChecksum, pParams, this ); #ifdef __NOPT_ASSERT__ mp_script->SetCommentString("Created in CObject::SwitchScript(...)"); #endif } if ( !mp_script->GotScript( ) ) { Dbg_MsgAssert( 0,( "Couldn't find script specified: %s", Script::FindChecksumName( scriptChecksum ) )); } } /******************************************************************/ /* */ /* */ /******************************************************************/ Script::CScript *CObject::SpawnScriptPlease( uint32 scriptChecksum, Script::CScriptStructure *pParams, int Id, bool pause_with_object ) { Script::CScript *pScript; pScript = Script::SpawnScript( scriptChecksum, pParams, 0, NULL, -1, Id, false, false, false, pause_with_object ); // K: The 0,NULL means no callback specified. pScript->mpObject = this; return pScript; } /******************************************************************/ /* */ /* */ /******************************************************************/ // spawn and immediatly run a script // script will be deleted after it terminates void CObject::SpawnAndRunScript ( uint32 ScriptChecksum, int node, bool net_script, bool permanent, Script::CStruct *p_params ) { // Send this event to other clients if applicable if( net_script ) { // Ken: TODO: Currently p_params are not being passed on in net games, fix if necessary ... // Currently p_params is only used to store the contents of any ModelTriggerScriptParams // that may be specified in an object's node and which are required to be passed on to // any TriggerScript in it's local node array. (Used by a goal in London) // (Note: The NULL below means a NULL p_object) Script::SendSpawnScript( ScriptChecksum, NULL, node, permanent ); } Script::CScript* pScript = Script::SpawnScript( ScriptChecksum, p_params, 0, NULL, node ); #ifdef __NOPT_ASSERT__ pScript->SetCommentString( "Spawned by CObject::SpawnAndRun(...)" ); #endif pScript->mpObject = this; pScript->Update(); } /******************************************************************/ /* */ /* */ /******************************************************************/ void CObject::SpawnAndRunScript( const char *pScriptName, int node, bool net_script, bool permanent, Script::CStruct *p_params ) { SpawnAndRunScript(Script::GenerateCRC(pScriptName),node, net_script, permanent, p_params ); } /******************************************************************/ /* */ /* */ /******************************************************************/ void CObject::CallScript( uint32 ScriptChecksum, Script::CStruct *pParams ) { if ( !mp_script ) { mp_script = new Script::CScript; // K: Added this in case the script being called contains member functions, which // it does when a two player trick-attack game is started. mp_script->mpObject=this; } mp_script->Interrupt(ScriptChecksum, pParams); } /******************************************************************/ /* */ /* */ /******************************************************************/ void DestroyIfUnlocked( Obj::CObject* obj, void* data ) { obj->DestroyIfUnlocked(); } /******************************************************************/ /* */ /* */ /******************************************************************/ void SetLockOff( CObject* obj, void* data ) { obj->SetLockOff(); } void CObject::GetDebugInfo(Script::CStruct *p_info) { #ifdef __DEBUG_CODE__ // CObject stuff Script::CStruct *p_scripts=new Script::CStruct; Script::CScript *p_script=Script::GetNextScript(NULL); while (p_script) { if (p_script->mpObject==this) { Script::CStruct *p_script_info=new Script::CStruct; #ifdef __NOPT_ASSERT__ // Convert to microseconds by dividing by 150 p_script_info->AddInteger("CPUTime",p_script->m_last_time/150); #endif p_script_info->AddChecksum("m_unique_id",p_script->GetUniqueId()); if (p_script->mIsSpawned) { p_script_info->AddChecksum(NONAME,CRCD(0xf697fda7,"Spawned")); } #ifdef __SCRIPT_EVENT_TABLE__ if (p_script->GetEventHandlerTable()) { p_script->GetEventHandlerTable()->GetDebugInfo(p_script_info); } #endif p_scripts->AddStructurePointer(p_script->GetBaseScript(),p_script_info); } p_script=Script::GetNextScript(p_script); } p_info->AddStructurePointer("Scripts",p_scripts); p_info->AddChecksum("m_id",m_id); if (mp_tags) { p_info->AddStructure("mp_tags",mp_tags); } else { p_info->AddChecksum("mp_tags",CRCD(0xda3403b0,"NULL")); } #ifndef __SCRIPT_EVENT_TABLE__ if (mp_event_handler_table) { mp_event_handler_table->GetDebugInfo(p_info); } #endif #endif } // Leftover from when this function was more complex // just retained for convenience CObject *ResolveToObject(uint32 id) { return Obj::CTracker::Instance()->GetObject(id); } } // namespace Obj