// Task Manager // // -- jweier // this include must remain at the top of every Icarus CPP file #include "stdafx.h" #include "IcarusImplementation.h" #include "BlockStream.h" #include "Sequence.h" #include "TaskManager.h" #include "Sequencer.h" #define ICARUS_VALIDATE(a) if ( a == false ) return TASK_FAILED; #define STL_ITERATE( a, b ) for ( a = b.begin(); a != b.end(); a++ ) #define STL_INSERT( a, b ) a.insert( a.end(), b ); /* ================================================= CTask ================================================= */ CTask::CTask( void ) { } CTask::~CTask( void ) { } CTask *CTask::Create( int GUID, CBlock *block ) { CTask *task = new CTask; //TODO: Emit warning if ( task == NULL ) return NULL; task->SetTimeStamp( 0 ); task->SetBlock( block ); task->SetGUID( GUID ); return task; } /* ------------------------- Free ------------------------- */ void CTask::Free( void ) { //NOTENOTE: The block is not consumed by the task, it is the sequencer's job to clean blocks up delete this; } /* ================================================= CTaskGroup ================================================= */ CTaskGroup::CTaskGroup( void ) { Init(); m_GUID = 0; m_parent = NULL; } CTaskGroup::~CTaskGroup( void ) { m_completedTasks.clear(); } /* ------------------------- SetGUID ------------------------- */ void CTaskGroup::SetGUID( int GUID ) { m_GUID = GUID; } /* ------------------------- Init ------------------------- */ void CTaskGroup::Init( void ) { m_completedTasks.clear(); m_numCompleted = 0; m_parent = NULL; } /* ------------------------- Add ------------------------- */ int CTaskGroup::Add( CTask *task ) { m_completedTasks[ task->GetGUID() ] = false; return TASK_OK; } /* ------------------------- MarkTaskComplete ------------------------- */ bool CTaskGroup::MarkTaskComplete( int id ) { if ( (m_completedTasks.find( id )) != m_completedTasks.end() ) { m_completedTasks[ id ] = true; m_numCompleted++; return true; } return false; } /* ================================================= CTaskManager ================================================= */ CTaskManager::CTaskManager( void ) { static int uniqueID = 0; m_id = uniqueID++; } CTaskManager::~CTaskManager( void ) { } /* ------------------------- Create ------------------------- */ CTaskManager *CTaskManager::Create( void ) { return new CTaskManager; } /* ------------------------- Init ------------------------- */ int CTaskManager::Init( CSequencer *owner ) { //TODO: Emit warning if ( owner == NULL ) return TASK_FAILED; m_tasks.clear(); m_owner = owner; m_ownerID = owner->GetOwnerID(); m_curGroup = NULL; m_GUID = 0; m_resident = false; return TASK_OK; } /* ------------------------- Free ------------------------- */ int CTaskManager::Free( void ) { taskGroup_v::iterator gi; tasks_l::iterator ti; assert(!m_resident); //don't free me, i'm currently running! //Clear out all pending tasks for ( ti = m_tasks.begin(); ti != m_tasks.end(); ti++ ) { (*ti)->Free(); } m_tasks.clear(); //Clear out all taskGroups for ( gi = m_taskGroups.begin(); gi != m_taskGroups.end(); gi++ ) { delete (*gi); } m_taskGroups.clear(); m_taskGroupNameMap.clear(); m_taskGroupIDMap.clear(); return TASK_OK; } /* ------------------------- Flush ------------------------- */ int CTaskManager::Flush( void ) { //FIXME: Rewrite return true; } /* ------------------------- AddTaskGroup ------------------------- */ CTaskGroup *CTaskManager::AddTaskGroup( const char *name, CIcarus* icarus ) { CTaskGroup *group; //Collect any garbage taskGroupName_m::iterator tgni; tgni = m_taskGroupNameMap.find( name ); if ( tgni != m_taskGroupNameMap.end() ) { group = (*tgni).second; //Clear it and just move on group->Init(); return group; } //Allocate a new one group = new CTaskGroup; //TODO: Emit warning assert( group ); if ( group == NULL ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Unable to allocate task group \"%s\"\n", name ); return NULL; } //Setup the internal information group->SetGUID( m_GUID++ ); //Add it to the list and associate it for retrieval later m_taskGroups.insert( m_taskGroups.end(), group ); m_taskGroupNameMap[ name ] = group; m_taskGroupIDMap[ group->GetGUID() ] = group; return group; } /* ------------------------- GetTaskGroup ------------------------- */ CTaskGroup *CTaskManager::GetTaskGroup( const char *name, CIcarus* icarus ) { taskGroupName_m::iterator tgi; tgi = m_taskGroupNameMap.find( name ); if ( tgi == m_taskGroupNameMap.end() ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_WARNING, "Could not find task group \"%s\"\n", name ); return NULL; } return (*tgi).second; } CTaskGroup *CTaskManager::GetTaskGroup( int id, CIcarus* icarus ) { taskGroupID_m::iterator tgi; tgi = m_taskGroupIDMap.find( id ); if ( tgi == m_taskGroupIDMap.end() ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_WARNING, "Could not find task group \"%d\"\n", id ); return NULL; } return (*tgi).second; } /* ------------------------- Update ------------------------- */ int CTaskManager::Update( CIcarus* icarus ) { if ( icarus->GetGame()->IsFrozen(m_ownerID) ) { return TASK_FAILED; } m_count = 0; //Needed for runaway init m_resident = true; int returnVal = Go(icarus); m_resident = false; return returnVal; } /* ------------------------- Check ------------------------- */ inline bool CTaskManager::Check( int targetID, CBlock *block, int memberNum ) const { if ( (block->GetMember( memberNum ))->GetID() == targetID ) return true; return false; } /* ------------------------- GetFloat ------------------------- */ int CTaskManager::GetFloat( int entID, CBlock *block, int &memberNum, float &value, CIcarus* icarus ) { char *name; int type; //See if this is a get() command replacement if ( Check( CIcarus::ID_GET, block, memberNum ) ) { //Update the member past the header id memberNum++; //get( TYPE, NAME ) type = (int) (*(float *) block->GetMemberData( memberNum++ )); name = (char *) block->GetMemberData( memberNum++ ); //TODO: Emit warning if ( type != CIcarus::TK_FLOAT ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Get() call tried to return a non-FLOAT parameter!\n" ); return false; } return icarus->GetGame()->GetFloat( entID, name, &value ); } //Look for a random() inline call if ( Check( CIcarus::ID_RANDOM, block, memberNum ) ) { float min, max; memberNum++; min = *(float *) block->GetMemberData( memberNum++ ); max = *(float *) block->GetMemberData( memberNum++ ); value = icarus->GetGame()->Random( min, max ); return true; } //Look for a tag() inline call if ( Check( CIcarus::ID_TAG, block, memberNum ) ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_WARNING, "Invalid use of \"tag\" inline. Not a valid replacement for type FLOAT\n" ); return false; } CBlockMember *bm = block->GetMember( memberNum ); if ( bm->GetID() == CIcarus::TK_INT ) { value = (float) (*(int *) block->GetMemberData( memberNum++ )); } else if ( bm->GetID() == CIcarus::TK_FLOAT ) { value = *(float *) block->GetMemberData( memberNum++ ); } else { assert(0); icarus->GetGame()->DebugPrint(IGameInterface::WL_WARNING, "Unexpected value; expected type FLOAT\n" ); return false; } return true; } /* ------------------------- GetVector ------------------------- */ int CTaskManager::GetVector( int entID, CBlock *block, int &memberNum, vec3_t &value, CIcarus* icarus ) { char *name; int type, i; //See if this is a get() command replacement if ( Check( CIcarus::ID_GET, block, memberNum ) ) { //Update the member past the header id memberNum++; //get( TYPE, NAME ) type = (int) (*(float *) block->GetMemberData( memberNum++ )); name = (char *) block->GetMemberData( memberNum++ ); //TODO: Emit warning if ( type != CIcarus::TK_VECTOR ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Get() call tried to return a non-VECTOR parameter!\n" ); } return icarus->GetGame()->GetVector( entID, name, value ); } //Look for a random() inline call if ( Check( CIcarus::ID_RANDOM, block, memberNum ) ) { float min, max; memberNum++; min = *(float *) block->GetMemberData( memberNum++ ); max = *(float *) block->GetMemberData( memberNum++ ); for ( i = 0; i < 3; i++ ) { value[i] = (float) icarus->GetGame()->Random( min, max ); //FIXME: Just truncating it for now.. should be fine though } return true; } //Look for a tag() inline call if ( Check( CIcarus::ID_TAG, block, memberNum ) ) { char *tagName; float tagLookup; memberNum++; ICARUS_VALIDATE ( Get( entID, block, memberNum, &tagName, icarus ) ); ICARUS_VALIDATE ( GetFloat( entID, block, memberNum, tagLookup, icarus ) ); if ( icarus->GetGame()->GetTag( entID, tagName, (int) tagLookup, value ) == false) { icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Unable to find tag \"%s\"!\n", tagName ); assert(0&&"Unable to find tag"); return TASK_FAILED; } return true; } //Check for a real vector here type = (int) (*(float *) block->GetMemberData( memberNum )); if ( type != CIcarus::TK_VECTOR ) { // icarus->GetGame()->DPrintf( WL_WARNING, "Unexpected value; expected type VECTOR\n" ); return false; } memberNum++; for ( i = 0; i < 3; i++ ) { if ( GetFloat( entID, block, memberNum, value[i], icarus ) == false ) return false; } return true; } /* ------------------------- Get ------------------------- */ int CTaskManager::GetID() { return m_id; } int CTaskManager::Get( int entID, CBlock *block, int &memberNum, char **value, CIcarus* icarus ) { static char tempBuffer[128]; //FIXME: EEEK! vec3_t vector; char *name, *tagName; float tagLookup; int type; //Look for a get() inline call if ( Check( CIcarus::ID_GET, block, memberNum ) ) { //Update the member past the header id memberNum++; //get( TYPE, NAME ) type = (int) (*(float *) block->GetMemberData( memberNum++ )); name = (char *) block->GetMemberData( memberNum++ ); //Format the return properly //FIXME: This is probably doing double formatting in certain cases... //FIXME: STRING MANAGEMENT NEEDS TO BE IMPLEMENTED, MY CURRENT SOLUTION IS NOT ACCEPTABLE!! switch ( type ) { case CIcarus::TK_STRING: if ( icarus->GetGame()->GetString( entID, name, value ) == false ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Get() parameter \"%s\" could not be found!\n", name ); return false; } return true; break; case CIcarus::TK_FLOAT: { float temp; if ( icarus->GetGame()->GetFloat( entID, name, &temp ) == false ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Get() parameter \"%s\" could not be found!\n", name ); return false; } sprintf( (char *) tempBuffer, "%f", temp ); *value = (char *) tempBuffer; } return true; break; case CIcarus::TK_VECTOR: { vec3_t vval; if ( icarus->GetGame()->GetVector( entID, name, vval ) == false ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Get() parameter \"%s\" could not be found!\n", name ); return false; } sprintf( (char *) tempBuffer, "%f %f %f", vval[0], vval[1], vval[2] ); *value = (char *) tempBuffer; } return true; break; default: icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Get() call tried to return an unknown type!\n" ); return false; break; } } //Look for a random() inline call if ( Check( CIcarus::ID_RANDOM, block, memberNum ) ) { float min, max, ret; memberNum++; min = *(float *) block->GetMemberData( memberNum++ ); max = *(float *) block->GetMemberData( memberNum++ ); ret = icarus->GetGame()->Random( min, max ); sprintf( (char *) tempBuffer, "%f", ret ); *value = (char *) tempBuffer; return true; } //Look for a tag() inline call if ( Check( CIcarus::ID_TAG, block, memberNum ) ) { memberNum++; ICARUS_VALIDATE ( Get( entID, block, memberNum, &tagName, icarus ) ); ICARUS_VALIDATE ( GetFloat( entID, block, memberNum, tagLookup, icarus ) ); if (icarus->GetGame()->GetTag( entID, tagName, (int) tagLookup, vector ) == false) { icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Unable to find tag \"%s\"!\n", tagName ); assert(0 && "Unable to find tag"); return false; } sprintf( (char *) tempBuffer, "%f %f %f", vector[0], vector[1], vector[2] ); *value = (char *) tempBuffer; return true; } //Get an actual piece of data CBlockMember *bm = block->GetMember( memberNum ); if ( bm->GetID() == CIcarus::TK_INT ) { float fval = (float) (*(int *) block->GetMemberData( memberNum++ )); sprintf( (char *) tempBuffer, "%f", fval ); *value = (char *) tempBuffer; return true; } else if ( bm->GetID() == CIcarus::TK_FLOAT ) { float fval = *(float *) block->GetMemberData( memberNum++ ); sprintf( (char *) tempBuffer, "%f", fval ); *value = (char *) tempBuffer; return true; } else if ( bm->GetID() == CIcarus::TK_VECTOR ) { vec3_t vval; memberNum++; for ( int i = 0; i < 3; i++ ) { if ( GetFloat( entID, block, memberNum, vval[i], icarus ) == false ) return false; sprintf( (char *) tempBuffer, "%f %f %f", vval[0], vval[1], vval[2] ); *value = (char *) tempBuffer; } return true; } else if ( ( bm->GetID() == CIcarus::TK_STRING ) || ( bm->GetID() == CIcarus::TK_IDENTIFIER ) ) { *value = (char *) block->GetMemberData( memberNum++ ); return true; } //TODO: Emit warning assert( 0 ); icarus->GetGame()->DebugPrint(IGameInterface::WL_WARNING, "Unexpected value; expected type STRING\n" ); return false; } /* ------------------------- Go ------------------------- */ int CTaskManager::Go( CIcarus* icarus ) { CTask *task = NULL; bool completed = false; //Check for run away scripts if ( m_count++ > RUNAWAY_LIMIT ) { assert(0); icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Runaway loop detected!\n" ); return TASK_FAILED; } //If there are tasks to complete, do so if ( m_tasks.empty() == false ) { //Get the next task task = PopTask( CSequence::POP_BACK ); assert( task ); if ( task == NULL ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Invalid task found in Go()!\n" ); return TASK_FAILED; } //If this hasn't been stamped, do so if ( task->GetTimeStamp() == 0 ) task->SetTimeStamp( icarus->GetGame()->GetTime() ); //Switch and call the proper function switch( task->GetID() ) { case CIcarus::ID_WAIT: Wait( task, completed, icarus ); //Push it to consider it again on the next frame if not complete if ( completed == false ) { PushTask( task, CSequence::PUSH_BACK ); return TASK_OK; } Completed( task->GetGUID() ); break; case CIcarus::ID_WAITSIGNAL: WaitSignal( task, completed , icarus); //Push it to consider it again on the next frame if not complete if ( completed == false ) { PushTask( task, CSequence::PUSH_BACK ); return TASK_OK; } Completed( task->GetGUID() ); break; case CIcarus::ID_PRINT: //print( STRING ) Print( task, icarus ); break; case CIcarus::ID_SOUND: //sound( name ) Sound( task, icarus ); break; case CIcarus::ID_MOVE: //move ( ORIGIN, ANGLES, DURATION ) Move( task, icarus ); break; case CIcarus::ID_ROTATE: //rotate( ANGLES, DURATION ) Rotate( task, icarus ); break; case CIcarus::ID_KILL: //kill( NAME ) Kill( task, icarus ); break; case CIcarus::ID_REMOVE: //remove( NAME ) Remove( task, icarus ); break; case CIcarus::ID_CAMERA: //camera( ? ) Camera( task, icarus ); break; case CIcarus::ID_SET: //set( NAME, ? ) Set( task, icarus ); break; case CIcarus::ID_USE: //use( NAME ) Use( task, icarus ); break; case CIcarus::ID_DECLARE://declare( TYPE, NAME ) DeclareVariable( task, icarus ); break; case CIcarus::ID_FREE: //free( NAME ) FreeVariable( task, icarus ); break; case CIcarus::ID_SIGNAL: //signal( NAME ) Signal( task, icarus ); break; case CIcarus::ID_PLAY: //play ( NAME ) Play( task, icarus ); break; default: assert(0); task->Free(); icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Found unknown task type!\n" ); return TASK_FAILED; break; } //Pump the sequencer for another task CallbackCommand( task, TASK_RETURN_COMPLETE , icarus); task->Free(); } //FIXME: A command surge limiter could be implemented at this point to be sure a script doesn't // execute too many commands in one cycle. This may, however, cause timing errors to surface. return TASK_OK; } /* ------------------------- SetCommand ------------------------- */ int CTaskManager::SetCommand( CBlock *command, int type, CIcarus* icarus ) { CTask *task = CTask::Create( m_GUID++, command ); //If this is part of a task group, add it in if ( m_curGroup ) { m_curGroup->Add( task ); } //TODO: Emit warning assert( task ); if ( task == NULL ) { icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Unable to allocate new task!\n" ); return TASK_FAILED; } PushTask( task, type ); return TASK_OK; } /* ------------------------- MarkTask ------------------------- */ int CTaskManager::MarkTask( int id, int operation, CIcarus* icarus ) { CTaskGroup *group = GetTaskGroup( id, icarus ); assert( group ); if ( group == NULL ) return TASK_FAILED; if ( operation == TASK_START ) { //Reset all the completion information group->Init(); group->SetParent( m_curGroup ); m_curGroup = group; } else if ( operation == TASK_END ) { assert( m_curGroup ); if ( m_curGroup == NULL ) return TASK_FAILED; m_curGroup = m_curGroup->GetParent(); } #ifdef _DEBUG else { assert(0); } #endif return TASK_OK; } /* ------------------------- Completed ------------------------- */ int CTaskManager::Completed( int id ) { taskGroup_v::iterator tgi; //Mark the task as completed for ( tgi = m_taskGroups.begin(); tgi != m_taskGroups.end(); tgi++ ) { //If this returns true, then the task was marked properly if ( (*tgi)->MarkTaskComplete( id ) ) break; } return TASK_OK; } /* ------------------------- CallbackCommand ------------------------- */ int CTaskManager::CallbackCommand( CTask *task, int returnCode, CIcarus* icarus ) { if ( m_owner->Callback( this, task->GetBlock(), returnCode, icarus ) == CSequencer::SEQ_OK, icarus ) return Go(icarus); assert(0); icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Command callback failure!\n" ); return TASK_FAILED; } /* ------------------------- RecallTask ------------------------- */ CBlock *CTaskManager::RecallTask( void ) { CTask *task; task = PopTask( CSequence::POP_BACK ); if ( task ) { // fixed 2/12/2 to free the task that has been popped (called from sequencer Recall) CBlock* retBlock = task->GetBlock(); task->Free(); return retBlock; // return task->GetBlock(); } return NULL; } /* ------------------------- PushTask ------------------------- */ int CTaskManager::PushTask( CTask *task, int flag ) { assert( (flag == CSequence::PUSH_FRONT) || (flag == CSequence::PUSH_BACK) ); switch ( flag ) { case CSequence::PUSH_FRONT: m_tasks.insert(m_tasks.begin(), task); return TASK_OK; break; case CSequence::PUSH_BACK: m_tasks.insert(m_tasks.end(), task); return TASK_OK; break; } //Invalid flag return CSequencer::SEQ_FAILED; } /* ------------------------- PopTask ------------------------- */ CTask *CTaskManager::PopTask( int flag ) { CTask *task; assert( (flag == CSequence::POP_FRONT) || (flag == CSequence::POP_BACK) ); if ( m_tasks.empty() ) return NULL; switch ( flag ) { case CSequence::POP_FRONT: task = m_tasks.front(); m_tasks.pop_front(); return task; break; case CSequence::POP_BACK: task = m_tasks.back(); m_tasks.pop_back(); return task; break; } //Invalid flag return NULL; } /* ------------------------- GetCurrentTask ------------------------- */ CBlock *CTaskManager::GetCurrentTask( void ) { CTask *task = PopTask( CSequence::POP_BACK ); if ( task == NULL ) return NULL; // fixed 2/12/2 to free the task that has been popped (called from sequencer Interrupt) CBlock* retBlock = task->GetBlock(); task->Free(); return retBlock; // return task->GetBlock(); } /* ================================================= Task Functions ================================================= */ int CTaskManager::Wait( CTask *task, bool &completed , CIcarus* icarus ) { CBlockMember *bm; CBlock *block = task->GetBlock(); char *sVal; float dwtime; int memberNum = 0; completed = false; bm = block->GetMember( 0 ); //Check if this is a task completion wait if ( bm->GetID() == CIcarus::TK_STRING ) { ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); if ( task->GetTimeStamp() == icarus->GetGame()->GetTime() ) { //Print out the debug info icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d wait(\"%s\"); [%d]", m_ownerID, sVal, task->GetTimeStamp() ); } CTaskGroup *group = GetTaskGroup( sVal , icarus); if ( group == NULL ) { //TODO: Emit warning completed = false; return TASK_FAILED; } completed = group->Complete(); } else //Otherwise it's a time completion wait { if ( Check( CIcarus::ID_RANDOM, block, memberNum ) ) {//get it random only the first time float min, max; dwtime = *(float *) block->GetMemberData( memberNum++ ); if ( dwtime == icarus->GetGame()->MaxFloat() ) {//we have not evaluated this random yet min = *(float *) block->GetMemberData( memberNum++ ); max = *(float *) block->GetMemberData( memberNum++ ); dwtime = icarus->GetGame()->Random( min, max ); //store the result in the first member bm->SetData( &dwtime, sizeof( dwtime ) , icarus); } } else { ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, dwtime, icarus ) ); } if ( task->GetTimeStamp() == icarus->GetGame()->GetTime() ) { //Print out the debug info icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d wait( %d ); [%d]", m_ownerID, (int) dwtime, task->GetTimeStamp() ); } if ( (task->GetTimeStamp() + dwtime) < (icarus->GetGame()->GetTime()) ) { completed = true; memberNum = 0; if ( Check( CIcarus::ID_RANDOM, block, memberNum ) ) {//set the data back to 0 so it will be re-randomized next time dwtime = icarus->GetGame()->MaxFloat(); bm->SetData( &dwtime, sizeof( dwtime ), icarus ); } } } return TASK_OK; } /* ------------------------- WaitSignal ------------------------- */ int CTaskManager::WaitSignal( CTask *task, bool &completed , CIcarus* icarus ) { CBlock *block = task->GetBlock(); char *sVal; int memberNum = 0; completed = false; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal , icarus) ); if ( task->GetTimeStamp() == icarus->GetGame()->GetTime() ) { //Print out the debug info icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d waitsignal(\"%s\"); [%d]", m_ownerID, sVal, task->GetTimeStamp() ); } if ( icarus->CheckSignal( sVal ) ) { completed = true; icarus->ClearSignal( sVal ); } return TASK_OK; } /* ------------------------- Print ------------------------- */ int CTaskManager::Print( CTask *task , CIcarus* icarus) { CBlock *block = task->GetBlock(); char *sVal; int memberNum = 0; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d print(\"%s\"); [%d]", m_ownerID, sVal, task->GetTimeStamp() ); icarus->GetGame()->CenterPrint( sVal ); Completed( task->GetGUID() ); return TASK_OK; } /* ------------------------- Sound ------------------------- */ int CTaskManager::Sound( CTask *task, CIcarus* icarus ) { CBlock *block = task->GetBlock(); char *sVal, *sVal2; int memberNum = 0; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal2, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d sound(\"%s\", \"%s\"); [%d]", m_ownerID, sVal, sVal2, task->GetTimeStamp() ); //Only instantly complete if the user has requested it if( icarus->GetGame()->PlaySound( task->GetGUID(), m_ownerID, sVal2, sVal ) ) Completed( task->GetGUID() ); return TASK_OK; } /* ------------------------- Rotate ------------------------- */ int CTaskManager::Rotate( CTask *task , CIcarus* icarus) { vec3_t vector; CBlock *block = task->GetBlock(); char *tagName; float tagLookup, duration; int memberNum = 0; //Check for a tag reference if ( Check( CIcarus::ID_TAG, block, memberNum ) ) { memberNum++; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &tagName, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, tagLookup, icarus ) ); if ( icarus->GetGame()->GetTag( m_ownerID, tagName, (int) tagLookup, vector ) == false ) { //TODO: Emit warning icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Unable to find tag \"%s\"!\n", tagName ); assert(0); return TASK_FAILED; } } else { //Get a normal vector ICARUS_VALIDATE( GetVector( m_ownerID, block, memberNum, vector, icarus ) ); } //Find the duration ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, duration, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d rotate( <%f,%f,%f>, %d); [%d]", m_ownerID, vector[0], vector[1], vector[2], (int) duration, task->GetTimeStamp() ); icarus->GetGame()->Lerp2Angles( task->GetGUID(), m_ownerID, vector, duration ); return TASK_OK; } /* ------------------------- Remove ------------------------- */ int CTaskManager::Remove( CTask *task, CIcarus* icarus ) { CBlock *block = task->GetBlock(); char *sVal; int memberNum = 0; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d remove(\"%s\"); [%d]", m_ownerID, sVal, task->GetTimeStamp() ); icarus->GetGame()->Remove( m_ownerID, sVal ); Completed( task->GetGUID() ); return TASK_OK; } /* ------------------------- Camera ------------------------- */ int CTaskManager::Camera( CTask *task , CIcarus* icarus) { CBlock *block = task->GetBlock(); vec3_t vector, vector2; float type, fVal, fVal2, fVal3; char *sVal; int memberNum = 0; //Get the camera function type ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, type, icarus ) ); switch ( (int) type ) { case CIcarus::TYPE_PAN: ICARUS_VALIDATE( GetVector( m_ownerID, block, memberNum, vector, icarus ) ); ICARUS_VALIDATE( GetVector( m_ownerID, block, memberNum, vector2, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( PAN, <%f %f %f>, <%f %f %f>, %f); [%d]", m_ownerID, vector[0], vector[1], vector[2], vector2[0], vector2[1], vector2[2], fVal, task->GetTimeStamp() ); icarus->GetGame()->CameraPan( vector, vector2, fVal ); break; case CIcarus::TYPE_ZOOM: ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal2, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( ZOOM, %f, %f); [%d]", m_ownerID, fVal, fVal2, task->GetTimeStamp() ); icarus->GetGame()->CameraZoom( fVal, fVal2 ); break; case CIcarus::TYPE_MOVE: ICARUS_VALIDATE( GetVector( m_ownerID, block, memberNum, vector, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( MOVE, <%f %f %f>, %f); [%d]", m_ownerID, vector[0], vector[1], vector[2], fVal, task->GetTimeStamp() ); icarus->GetGame()->CameraMove( vector, fVal ); break; case CIcarus::TYPE_ROLL: ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal2, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( ROLL, %f, %f); [%d]", m_ownerID, fVal, fVal2, task->GetTimeStamp() ); icarus->GetGame()->CameraRoll( fVal, fVal2 ); break; case CIcarus::TYPE_FOLLOW: ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal2, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( FOLLOW, \"%s\", %f, %f); [%d]", m_ownerID, sVal, fVal, fVal2, task->GetTimeStamp() ); icarus->GetGame()->CameraFollow( (const char *) sVal, fVal, fVal2 ); break; case CIcarus::TYPE_TRACK: ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal2, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( TRACK, \"%s\", %f, %f); [%d]", m_ownerID, sVal, fVal, fVal2, task->GetTimeStamp() ); icarus->GetGame()->CameraTrack( (const char *) sVal, fVal, fVal2 ); break; case CIcarus::TYPE_DISTANCE: ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal2, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( DISTANCE, %f, %f); [%d]", m_ownerID, fVal, fVal2, task->GetTimeStamp() ); icarus->GetGame()->CameraDistance( fVal, fVal2 ); break; case CIcarus::TYPE_FADE: ICARUS_VALIDATE( GetVector( m_ownerID, block, memberNum, vector, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal, icarus ) ); ICARUS_VALIDATE( GetVector( m_ownerID, block, memberNum, vector2, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal2, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal3, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( FADE, <%f %f %f>, %f, <%f %f %f>, %f, %f); [%d]", m_ownerID, vector[0], vector[1], vector[2], fVal, vector2[0], vector2[1], vector2[2], fVal2, fVal3, task->GetTimeStamp() ); icarus->GetGame()->CameraFade( vector[0], vector[1], vector[2], fVal, vector2[0], vector2[1], vector2[2], fVal2, fVal3 ); break; case CIcarus::TYPE_PATH: ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( PATH, \"%s\"); [%d]", m_ownerID, sVal, task->GetTimeStamp() ); icarus->GetGame()->CameraPath( sVal ); break; case CIcarus::TYPE_ENABLE: icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( ENABLE ); [%d]", m_ownerID, task->GetTimeStamp() ); icarus->GetGame()->CameraEnable(); break; case CIcarus::TYPE_DISABLE: icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( DISABLE ); [%d]", m_ownerID, task->GetTimeStamp() ); icarus->GetGame()->CameraDisable(); break; case CIcarus::TYPE_SHAKE: ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal, icarus ) ); ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal2, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d camera( SHAKE, %f, %f ); [%d]", m_ownerID, fVal, fVal2, task->GetTimeStamp() ); icarus->GetGame()->CameraShake( fVal, (int) fVal2 ); break; } Completed( task->GetGUID() ); return TASK_OK; } /* ------------------------- Move ------------------------- */ int CTaskManager::Move( CTask *task, CIcarus* icarus ) { vec3_t vector, vector2; CBlock *block = task->GetBlock(); float duration; int memberNum = 0; //Get the goal position ICARUS_VALIDATE( GetVector( m_ownerID, block, memberNum, vector, icarus ) ); //Check for possible angles field if ( GetVector( m_ownerID, block, memberNum, vector2, icarus ) == false ) { ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, duration, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d move( <%f %f %f>, %f ); [%d]", m_ownerID, vector[0], vector[1], vector[2], duration, task->GetTimeStamp() ); icarus->GetGame()->Lerp2Pos( task->GetGUID(), m_ownerID, vector, NULL, duration ); return TASK_OK; } //Get the duration and make the call ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, duration, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d move( <%f %f %f>, <%f %f %f>, %f ); [%d]", m_ownerID, vector[0], vector[1], vector[2], vector2[0], vector2[1], vector2[2], duration, task->GetTimeStamp() ); icarus->GetGame()->Lerp2Pos( task->GetGUID(), m_ownerID, vector, vector2, duration ); return TASK_OK; } /* ------------------------- Kill ------------------------- */ int CTaskManager::Kill( CTask *task, CIcarus* icarus ) { CBlock *block = task->GetBlock(); char *sVal; int memberNum = 0; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d kill( \"%s\" ); [%d]", m_ownerID, sVal, task->GetTimeStamp() ); icarus->GetGame()->Kill( m_ownerID, sVal ); Completed( task->GetGUID() ); return TASK_OK; } /* ------------------------- Set ------------------------- */ int CTaskManager::Set( CTask *task, CIcarus* icarus ) { CBlock *block = task->GetBlock(); char *sVal, *sVal2; int memberNum = 0; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal2, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d set( \"%s\", \"%s\" ); [%d]", m_ownerID, sVal, sVal2, task->GetTimeStamp() ); icarus->GetGame()->Set( task->GetGUID(), m_ownerID, sVal, sVal2 ); return TASK_OK; } /* ------------------------- Use ------------------------- */ int CTaskManager::Use( CTask *task , CIcarus* icarus) { CBlock *block = task->GetBlock(); char *sVal; int memberNum = 0; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d use( \"%s\" ); [%d]", m_ownerID, sVal, task->GetTimeStamp() ); icarus->GetGame()->Use( m_ownerID, sVal ); Completed( task->GetGUID() ); return TASK_OK; } /* ------------------------- DeclareVariable ------------------------- */ int CTaskManager::DeclareVariable( CTask *task , CIcarus* icarus) { CBlock *block = task->GetBlock(); char *sVal; int memberNum = 0; float fVal; ICARUS_VALIDATE( GetFloat( m_ownerID, block, memberNum, fVal, icarus ) ); ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d declare( %d, \"%s\" ); [%d]", m_ownerID, (int) fVal, sVal, task->GetTimeStamp() ); icarus->GetGame()->DeclareVariable( (int) fVal, sVal ); Completed( task->GetGUID() ); return TASK_OK; } /* ------------------------- FreeVariable ------------------------- */ int CTaskManager::FreeVariable( CTask *task, CIcarus* icarus ) { CBlock *block = task->GetBlock(); char *sVal; int memberNum = 0; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d free( \"%s\" ); [%d]", m_ownerID, sVal, task->GetTimeStamp() ); icarus->GetGame()->FreeVariable( sVal ); Completed( task->GetGUID() ); return TASK_OK; } /* ------------------------- Signal ------------------------- */ int CTaskManager::Signal( CTask *task, CIcarus* icarus ) { CBlock *block = task->GetBlock(); char *sVal; int memberNum = 0; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d signal( \"%s\" ); [%d]", m_ownerID, sVal, task->GetTimeStamp() ); icarus->Signal( (const char *) sVal ); Completed( task->GetGUID() ); return TASK_OK; } /* ------------------------- Play ------------------------- */ int CTaskManager::Play( CTask *task, CIcarus* icarus ) { CBlock *block = task->GetBlock(); char *sVal, *sVal2; int memberNum = 0; ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal, icarus ) ); ICARUS_VALIDATE( Get( m_ownerID, block, memberNum, &sVal2, icarus ) ); icarus->GetGame()->DebugPrint(IGameInterface::WL_DEBUG, "%4d play( \"%s\", \"%s\" ); [%d]", m_ownerID, sVal, sVal2, task->GetTimeStamp() ); icarus->GetGame()->Play( task->GetGUID(), m_ownerID, (const char *) sVal, (const char *) sVal2 ); return TASK_OK; } /* ------------------------- SaveCommand ------------------------- */ //FIXME: ARGH! This is duplicated from CSequence because I can't directly link it any other way... int CTaskManager::SaveCommand( CBlock *block ) { CIcarus *pIcarus = (CIcarus *)IIcarusInterface::GetIcarus(); unsigned char flags; int numMembers, bID, size; CBlockMember *bm; //Save out the block ID bID = block->GetBlockID(); pIcarus->BufferWrite( &bID, sizeof( bID ) ); //Save out the block's flags flags = block->GetFlags(); pIcarus->BufferWrite( &flags, sizeof( flags ) ); //Save out the number of members to read numMembers = block->GetNumMembers(); pIcarus->BufferWrite( &numMembers, sizeof( numMembers ) ); for ( int i = 0; i < numMembers; i++ ) { bm = block->GetMember( i ); //Save the block id bID = bm->GetID(); pIcarus->BufferWrite( &bID, sizeof( bID ) ); //Save out the data size size = bm->GetSize(); pIcarus->BufferWrite( &size, sizeof( size ) ); //Save out the raw data pIcarus->BufferWrite( bm->GetData(), size ); } return true; } /* ------------------------- Save ------------------------- */ void CTaskManager::Save() { CTaskGroup *taskGroup; const char *name; CBlock *block; DWORD timeStamp; bool completed; int id, numCommands; int numWritten; // Data saved here. // Taskmanager GUID. // Number of Tasks. // Tasks: // - GUID. // - Timestamp. // - Block/Command. // Number of task groups. // Task groups ID's. // Task groups (data). // - Parent. // - Number of Commands. // - Commands: // + ID. // + State of Completion. // - Number of Completed Commands. // Currently active group. // Task group names: // - String Size. // - String. // - ID. CIcarus *pIcarus = (CIcarus *)IIcarusInterface::GetIcarus(); //Save the taskmanager's GUID pIcarus->BufferWrite( &m_GUID, sizeof( m_GUID ) ); //Save out the number of tasks that will follow int iNumTasks = m_tasks.size(); pIcarus->BufferWrite( &iNumTasks, sizeof( iNumTasks ) ); //Save out all the tasks tasks_l::iterator ti; STL_ITERATE( ti, m_tasks ) { //Save the GUID id = (*ti)->GetGUID(); pIcarus->BufferWrite( &id, sizeof( id ) ); //Save the timeStamp (FIXME: Although, this is going to be worthless if time is not consistent...) timeStamp = (*ti)->GetTimeStamp(); pIcarus->BufferWrite( &timeStamp, sizeof( timeStamp ) ); //Save out the block block = (*ti)->GetBlock(); SaveCommand( block ); } //Save out the number of task groups int numTaskGroups = m_taskGroups.size(); pIcarus->BufferWrite( &numTaskGroups, sizeof( numTaskGroups ) ); //Save out the IDs of all the task groups numWritten = 0; taskGroup_v::iterator tgi; STL_ITERATE( tgi, m_taskGroups ) { id = (*tgi)->GetGUID(); pIcarus->BufferWrite( &id, sizeof( id ) ); numWritten++; } assert (numWritten == numTaskGroups); //Save out the task groups numWritten = 0; STL_ITERATE( tgi, m_taskGroups ) { //Save out the parent id = ( (*tgi)->GetParent() == NULL ) ? -1 : ((*tgi)->GetParent())->GetGUID(); pIcarus->BufferWrite( &id, sizeof( id ) ); //Save out the number of commands numCommands = (*tgi)->m_completedTasks.size(); pIcarus->BufferWrite( &numCommands, sizeof( numCommands ) ); //Save out the command map CTaskGroup::taskCallback_m::iterator tci; STL_ITERATE( tci, (*tgi)->m_completedTasks ) { //Write out the ID id = (*tci).first; pIcarus->BufferWrite( &id, sizeof( id ) ); //Write out the state of completion completed = (*tci).second; pIcarus->BufferWrite( &completed, sizeof( completed ) ); } //Save out the number of completed commands id = (*tgi)->m_numCompleted; pIcarus->BufferWrite( &id, sizeof( id ) ); numWritten++; } assert (numWritten == numTaskGroups); //Only bother if we've got tasks present if ( m_taskGroups.size() ) { //Save out the currently active group int curGroupID = ( m_curGroup == NULL ) ? -1 : m_curGroup->GetGUID(); pIcarus->BufferWrite( &curGroupID, sizeof( curGroupID ) ); } //Save out the task group name maps taskGroupName_m::iterator tmi; numWritten = 0; STL_ITERATE( tmi, m_taskGroupNameMap ) { name = ((*tmi).first).c_str(); //Make sure this is a valid string assert( ( name != NULL ) && ( name[0] != NULL ) ); int length = strlen( name ) + 1; //Save out the string size //icarus->GetGame()->WriteSaveData( 'TGNL', &length, sizeof ( length ) ); pIcarus->BufferWrite( &length, sizeof( length ) ); //Write out the string pIcarus->BufferWrite( (void *) name, length ); taskGroup = (*tmi).second; id = taskGroup->GetGUID(); //Write out the ID pIcarus->BufferWrite( &id, sizeof( id ) ); numWritten++; } assert (numWritten == numTaskGroups); } /* ------------------------- Load ------------------------- */ void CTaskManager::Load( CIcarus* icarus ) { unsigned char flags; CTaskGroup *taskGroup; CBlock *block; CTask *task; DWORD timeStamp; bool completed; void *bData; int id, numTasks, numMembers; int bID, bSize; // Data expected/loaded here. // Taskmanager GUID. // Number of Tasks. // Tasks: // - GUID. // - Timestamp. // - Block/Command. // Number of task groups. // Task groups ID's. // Task groups (data). // - Parent. // - Number of Commands. // - Commands: // + ID. // + State of Completion. // - Number of Completed Commands. // Currently active group. // Task group names: // - String Size. // - String. // - ID. CIcarus *pIcarus = (CIcarus *)IIcarusInterface::GetIcarus(); //Get the GUID pIcarus->BufferRead( &m_GUID, sizeof( m_GUID ) ); //Get the number of tasks to follow pIcarus->BufferRead( &numTasks, sizeof( numTasks ) ); //Reload all the tasks for ( int i = 0; i < numTasks; i++ ) { task = new CTask; assert( task ); //Get the GUID pIcarus->BufferRead( &id, sizeof( id ) ); task->SetGUID( id ); //Get the time stamp pIcarus->BufferRead( &timeStamp, sizeof( timeStamp ) ); task->SetTimeStamp( timeStamp ); // // BLOCK LOADING // //Get the block ID and create a new container pIcarus->BufferRead( &id, sizeof( id ) ); block = new CBlock; block->Create( id ); //Read the block's flags pIcarus->BufferRead( &flags, sizeof( flags ) ); block->SetFlags( flags ); //Get the number of block members pIcarus->BufferRead( &numMembers, sizeof( numMembers ) ); for ( int j = 0; j < numMembers; j++ ) { //Get the member ID pIcarus->BufferRead( &bID, sizeof( bID ) ); //Get the member size pIcarus->BufferRead( &bSize, sizeof( bSize ) ); //Get the member's data if ( ( bData = icarus->GetGame()->Malloc( bSize ) ) == NULL ) { assert( 0 ); return; } //Get the actual raw data pIcarus->BufferRead( bData, bSize ); //Write out the correct type switch ( bID ) { case CIcarus::TK_FLOAT: block->Write( CIcarus::TK_FLOAT, *(float *) bData, icarus ); break; case CIcarus::TK_IDENTIFIER: block->Write( CIcarus::TK_IDENTIFIER, (char *) bData , icarus); break; case CIcarus::TK_STRING: block->Write( CIcarus::TK_STRING, (char *) bData , icarus); break; case CIcarus::TK_VECTOR: block->Write( CIcarus::TK_VECTOR, *(vec3_t *) bData, icarus ); break; case CIcarus::ID_RANDOM: block->Write( CIcarus::ID_RANDOM, *(float *) bData, icarus );//ID_RANDOM ); break; case CIcarus::ID_TAG: block->Write( CIcarus::ID_TAG, (float) CIcarus::ID_TAG , icarus); break; case CIcarus::ID_GET: block->Write( CIcarus::ID_GET, (float) CIcarus::ID_GET , icarus); break; default: icarus->GetGame()->DebugPrint(IGameInterface::WL_ERROR, "Invalid Block id %d\n", bID); assert( 0 ); break; } //Get rid of the temp memory icarus->GetGame()->Free( bData ); } task->SetBlock( block ); STL_INSERT( m_tasks, task ); } //Load the task groups int numTaskGroups; //icarus->GetGame()->ReadSaveData( 'TG#G', &numTaskGroups, sizeof( numTaskGroups ) ); pIcarus->BufferRead( &numTaskGroups, sizeof( numTaskGroups ) ); if ( numTaskGroups == 0 ) return; int *taskIDs = new int[ numTaskGroups ]; //Get the task group IDs for ( i = 0; i < numTaskGroups; i++ ) { //Creat a new task group taskGroup = new CTaskGroup; assert( taskGroup ); //Get this task group's ID pIcarus->BufferRead( &taskIDs[i], sizeof( taskIDs[i] ) ); taskGroup->m_GUID = taskIDs[i]; m_taskGroupIDMap[ taskIDs[i] ] = taskGroup; STL_INSERT( m_taskGroups, taskGroup ); } //Recreate and load the task groups for ( i = 0; i < numTaskGroups; i++ ) { taskGroup = GetTaskGroup( taskIDs[i], icarus ); assert( taskGroup ); //Load the parent ID pIcarus->BufferRead( &id, sizeof( id ) ); if ( id != -1 ) taskGroup->m_parent = ( GetTaskGroup( id, icarus ) != NULL ) ? GetTaskGroup( id, icarus ) : NULL; //Get the number of commands in this group pIcarus->BufferRead( &numMembers, sizeof( numMembers ) ); //Get each command and its completion state for ( int j = 0; j < numMembers; j++ ) { //Get the ID pIcarus->BufferRead( &id, sizeof( id ) ); //Write out the state of completion pIcarus->BufferRead( &completed, sizeof( completed ) ); //Save it out taskGroup->m_completedTasks[ id ] = completed; } //Get the number of completed tasks pIcarus->BufferRead( &taskGroup->m_numCompleted, sizeof( taskGroup->m_numCompleted ) ); } //Reload the currently active group int curGroupID; pIcarus->BufferRead( &curGroupID, sizeof( curGroupID ) ); //Reload the map entries for ( i = 0; i < numTaskGroups; i++ ) { char name[1024]; int length; //Get the size of the string pIcarus->BufferRead( &length, sizeof( length ) ); //Get the string pIcarus->BufferRead( &name, length ); //Get the id pIcarus->BufferRead( &id, sizeof( id ) ); taskGroup = GetTaskGroup( id, icarus ); assert( taskGroup ); m_taskGroupNameMap[ name ] = taskGroup; m_taskGroupIDMap[ taskGroup->GetGUID() ] = taskGroup; } m_curGroup = ( curGroupID == -1 ) ? NULL : m_taskGroupIDMap[curGroupID]; delete[] taskIDs; }