656 lines
13 KiB
C++
656 lines
13 KiB
C++
|
//Anything above this #include will be ignored by the compiler
|
||
|
#include "../qcommon/exe_headers.h"
|
||
|
|
||
|
// ICARUS Instance
|
||
|
//
|
||
|
// -- jweier
|
||
|
|
||
|
// this include must remain at the top of every Icarus CPP file
|
||
|
#include "icarus.h"
|
||
|
|
||
|
#include <assert.h>
|
||
|
|
||
|
class CSequencer;
|
||
|
class CTaskManager;
|
||
|
|
||
|
//We can't put these on entity fields since all that stuff is in C
|
||
|
//which can't be changed due to VMs. So we'll use a global array
|
||
|
//and access by the entity index given.
|
||
|
CSequencer *gSequencers[MAX_GENTITIES];
|
||
|
CTaskManager *gTaskManagers[MAX_GENTITIES];
|
||
|
|
||
|
// Instance
|
||
|
|
||
|
ICARUS_Instance::ICARUS_Instance( void )
|
||
|
{
|
||
|
m_GUID = 0;
|
||
|
|
||
|
//to be safe
|
||
|
memset(gSequencers,0, sizeof(gSequencers));
|
||
|
memset(gTaskManagers,0, sizeof(gTaskManagers));
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequencerAlloc = 0;
|
||
|
m_DEBUG_NumSequencerFreed = 0;
|
||
|
m_DEBUG_NumSequencerResidual = 0;
|
||
|
|
||
|
m_DEBUG_NumSequenceAlloc = 0;
|
||
|
m_DEBUG_NumSequenceFreed = 0;
|
||
|
m_DEBUG_NumSequenceResidual = 0;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
ICARUS_Instance::~ICARUS_Instance( void )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Create
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
ICARUS_Instance *ICARUS_Instance::Create( interface_export_t *ie )
|
||
|
{
|
||
|
ICARUS_Instance *instance = new ICARUS_Instance;
|
||
|
instance->m_interface = ie;
|
||
|
#ifndef __linux__
|
||
|
OutputDebugString( "ICARUS Instance successfully created\n" );
|
||
|
#endif
|
||
|
return instance;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Free
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::Free( void )
|
||
|
{
|
||
|
sequencer_l::iterator sri;
|
||
|
|
||
|
//Delete any residual sequencers
|
||
|
STL_ITERATE( sri, m_sequencers )
|
||
|
{
|
||
|
delete (*sri);
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequencerResidual++;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
m_sequencers.clear();
|
||
|
//all these are deleted now so clear the global map.
|
||
|
memset(gSequencers,0, sizeof(gSequencers));
|
||
|
memset(gTaskManagers,0, sizeof(gTaskManagers));
|
||
|
m_signals.clear();
|
||
|
|
||
|
sequence_l::iterator si;
|
||
|
|
||
|
//Delete any residual sequences
|
||
|
STL_ITERATE( si, m_sequences )
|
||
|
{
|
||
|
delete (*si);
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequenceResidual++;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
m_sequences.clear();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Delete
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::Delete( void )
|
||
|
{
|
||
|
|
||
|
Free();
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
char buffer[1024];
|
||
|
|
||
|
OutputDebugString( "\nICARUS Instance Debug Info:\n---------------------------\n" );
|
||
|
|
||
|
sprintf( (char *) buffer, "Sequencers Allocated:\t%d\n", m_DEBUG_NumSequencerAlloc );
|
||
|
OutputDebugString( (const char *) &buffer );
|
||
|
|
||
|
sprintf( (char *) buffer, "Sequencers Freed:\t\t%d\n", m_DEBUG_NumSequencerFreed );
|
||
|
OutputDebugString( (const char *) &buffer );
|
||
|
|
||
|
sprintf( (char *) buffer, "Sequencers Residual:\t%d\n\n", m_DEBUG_NumSequencerResidual );
|
||
|
OutputDebugString( (const char *) &buffer );
|
||
|
|
||
|
sprintf( (char *) buffer, "Sequences Allocated:\t%d\n", m_DEBUG_NumSequenceAlloc );
|
||
|
OutputDebugString( (const char *) &buffer );
|
||
|
|
||
|
sprintf( (char *) buffer, "Sequences Freed:\t\t%d\n", m_DEBUG_NumSequenceFreed );
|
||
|
OutputDebugString( (const char *) &buffer );
|
||
|
|
||
|
sprintf( (char *) buffer, "Sequences Residual:\t\t%d\n\n", m_DEBUG_NumSequenceResidual );
|
||
|
OutputDebugString( (const char *) &buffer );
|
||
|
|
||
|
OutputDebugString( "\n" );
|
||
|
|
||
|
#endif
|
||
|
|
||
|
delete this;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
GetSequencer
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
CSequencer *ICARUS_Instance::GetSequencer( int ownerID )
|
||
|
{
|
||
|
CSequencer *sequencer = CSequencer::Create();
|
||
|
CTaskManager *taskManager = CTaskManager::Create();
|
||
|
|
||
|
sequencer->Init( ownerID, m_interface, taskManager, this );
|
||
|
|
||
|
taskManager->Init( sequencer );
|
||
|
|
||
|
STL_INSERT( m_sequencers, sequencer );
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequencerAlloc++;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return sequencer;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
DeleteSequencer
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
void ICARUS_Instance::DeleteSequencer( CSequencer *sequencer )
|
||
|
{
|
||
|
// added 2/12/2 to properly delete blocks that were passed to the task manager
|
||
|
sequencer->Recall();
|
||
|
|
||
|
CTaskManager *taskManager = sequencer->GetTaskManager();
|
||
|
|
||
|
if ( taskManager )
|
||
|
{
|
||
|
taskManager->Free();
|
||
|
delete taskManager;
|
||
|
}
|
||
|
|
||
|
m_sequencers.remove( sequencer );
|
||
|
|
||
|
sequencer->Free();
|
||
|
delete sequencer;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequencerFreed++;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
GetSequence
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
CSequence *ICARUS_Instance::GetSequence( void )
|
||
|
{
|
||
|
CSequence *sequence = CSequence::Create();
|
||
|
|
||
|
//Assign the GUID
|
||
|
sequence->SetID( m_GUID++ );
|
||
|
sequence->SetOwner( this );
|
||
|
|
||
|
STL_INSERT( m_sequences, sequence );
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequenceAlloc++;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return sequence;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
GetSequence
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
CSequence *ICARUS_Instance::GetSequence( int id )
|
||
|
{
|
||
|
sequence_l::iterator si;
|
||
|
STL_ITERATE( si, m_sequences )
|
||
|
{
|
||
|
if ( (*si)->GetID() == id )
|
||
|
return (*si);
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
DeleteSequence
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
void ICARUS_Instance::DeleteSequence( CSequence *sequence )
|
||
|
{
|
||
|
m_sequences.remove( sequence );
|
||
|
|
||
|
delete sequence;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
m_DEBUG_NumSequenceFreed++;
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
AllocateSequences
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::AllocateSequences( int numSequences, int *idTable )
|
||
|
{
|
||
|
CSequence *sequence;
|
||
|
|
||
|
for ( int i = 0; i < numSequences; i++ )
|
||
|
{
|
||
|
//If the GUID of this sequence is higher than the current, take this a the "current" GUID
|
||
|
if ( idTable[i] > m_GUID )
|
||
|
m_GUID = idTable[i];
|
||
|
|
||
|
//Allocate the container sequence
|
||
|
if ( ( sequence = GetSequence() ) == NULL )
|
||
|
return false;
|
||
|
|
||
|
//Override the given GUID with the real one
|
||
|
sequence->SetID( idTable[i] );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
SaveSequenceIDTable
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::SaveSequenceIDTable( void )
|
||
|
{
|
||
|
//Save out the number of sequences to follow
|
||
|
int numSequences = m_sequences.size();
|
||
|
m_interface->I_WriteSaveData( '#SEQ', &numSequences, sizeof( numSequences ) );
|
||
|
|
||
|
//Sequences are saved first, by ID and information
|
||
|
sequence_l::iterator sqi;
|
||
|
|
||
|
//First pass, save all sequences ID for reconstruction
|
||
|
int *idTable = new int[ numSequences ];
|
||
|
int itr = 0;
|
||
|
|
||
|
if ( idTable == NULL )
|
||
|
return false;
|
||
|
|
||
|
STL_ITERATE( sqi, m_sequences )
|
||
|
{
|
||
|
idTable[itr++] = (*sqi)->GetID();
|
||
|
}
|
||
|
|
||
|
m_interface->I_WriteSaveData( 'SQTB', idTable, sizeof( int ) * numSequences );
|
||
|
|
||
|
delete[] idTable;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
SaveSequences
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::SaveSequences( void )
|
||
|
{
|
||
|
//Save out a listing of all the used sequences by ID
|
||
|
SaveSequenceIDTable();
|
||
|
|
||
|
//Save all the information in order
|
||
|
sequence_l::iterator sqi;
|
||
|
STL_ITERATE( sqi, m_sequences )
|
||
|
{
|
||
|
(*sqi)->Save();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
SaveSequencers
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::SaveSequencers( void )
|
||
|
{
|
||
|
//Save out the number of sequences to follow
|
||
|
int numSequencers = m_sequencers.size();
|
||
|
m_interface->I_WriteSaveData( '#SQR', &numSequencers, sizeof( numSequencers ) );
|
||
|
|
||
|
//The sequencers are then saved
|
||
|
sequencer_l::iterator si;
|
||
|
STL_ITERATE( si, m_sequencers )
|
||
|
{
|
||
|
(*si)->Save();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
SaveSignals
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::SaveSignals( void )
|
||
|
{
|
||
|
int numSignals = m_signals.size();
|
||
|
|
||
|
m_interface->I_WriteSaveData( 'ISIG', &numSignals, sizeof( numSignals ) );
|
||
|
|
||
|
signal_m::iterator si;
|
||
|
STL_ITERATE( si, m_signals )
|
||
|
{
|
||
|
//m_interface->I_WriteSaveData( 'ISIG', &numSignals, sizeof( numSignals ) );
|
||
|
const char *name = ((*si).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
|
||
|
m_interface->I_WriteSaveData( 'SIG#', &length, sizeof ( length ) );
|
||
|
|
||
|
//Write out the string
|
||
|
m_interface->I_WriteSaveData( 'SIGN', (void *) name, length );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Save
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::Save( void )
|
||
|
{
|
||
|
//Save out a ICARUS save block header with the ICARUS version
|
||
|
double version = ICARUS_VERSION;
|
||
|
m_interface->I_WriteSaveData( 'ICAR', &version, sizeof( version ) );
|
||
|
|
||
|
//Save out the signals
|
||
|
if ( SaveSignals() == false )
|
||
|
return false;
|
||
|
|
||
|
//Save out the sequences
|
||
|
if ( SaveSequences() == false )
|
||
|
return false;
|
||
|
|
||
|
//Save out the sequencers
|
||
|
if ( SaveSequencers() == false )
|
||
|
return false;
|
||
|
|
||
|
m_interface->I_WriteSaveData( 'IEND', &version, sizeof( version ) );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
LoadSignals
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::LoadSignals( void )
|
||
|
{
|
||
|
int numSignals;
|
||
|
|
||
|
m_interface->I_ReadSaveData( 'ISIG', &numSignals, sizeof( numSignals ) );
|
||
|
|
||
|
for ( int i = 0; i < numSignals; i++ )
|
||
|
{
|
||
|
char buffer[1024];
|
||
|
int length;
|
||
|
|
||
|
//Get the size of the string
|
||
|
m_interface->I_ReadSaveData( 'SIG#', &length, sizeof( length ) );
|
||
|
|
||
|
assert( length < sizeof( buffer ) );
|
||
|
|
||
|
//Get the string
|
||
|
m_interface->I_ReadSaveData( 'SIGN', &buffer, length );
|
||
|
|
||
|
//Turn it on and add it to the system
|
||
|
Signal( (const char *) &buffer );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
LoadSequence
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::LoadSequence( void )
|
||
|
{
|
||
|
CSequence *sequence = GetSequence();
|
||
|
|
||
|
//Load the sequence back in
|
||
|
sequence->Load();
|
||
|
|
||
|
//If this sequence had a higher GUID than the current, save it
|
||
|
if ( sequence->GetID() > m_GUID )
|
||
|
m_GUID = sequence->GetID();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
LoadSequence
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::LoadSequences( void )
|
||
|
{
|
||
|
CSequence *sequence;
|
||
|
int numSequences;
|
||
|
|
||
|
//Get the number of sequences to read in
|
||
|
m_interface->I_ReadSaveData( '#SEQ', &numSequences, sizeof( numSequences ) );
|
||
|
|
||
|
int *idTable = new int[ numSequences ];
|
||
|
|
||
|
if ( idTable == NULL )
|
||
|
return false;
|
||
|
|
||
|
//Load the sequencer ID table
|
||
|
m_interface->I_ReadSaveData( 'SQTB', idTable, sizeof( int ) * numSequences );
|
||
|
|
||
|
//First pass, allocate all container sequences and give them their proper IDs
|
||
|
if ( AllocateSequences( numSequences, idTable ) == false )
|
||
|
return false;
|
||
|
|
||
|
//Second pass, load all sequences
|
||
|
for ( int i = 0; i < numSequences; i++ )
|
||
|
{
|
||
|
//Get the proper sequence for this load
|
||
|
if ( ( sequence = GetSequence( idTable[i] ) ) == NULL )
|
||
|
return false;
|
||
|
|
||
|
//Load the sequence
|
||
|
if ( ( sequence->Load() ) == false )
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//Free the idTable
|
||
|
delete[] idTable;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
LoadSequencers
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::LoadSequencers( void )
|
||
|
{
|
||
|
CSequencer *sequencer;
|
||
|
int numSequencers;
|
||
|
|
||
|
//Get the number of sequencers to load
|
||
|
m_interface->I_ReadSaveData( '#SQR', &numSequencers, sizeof( &numSequencers ) );
|
||
|
|
||
|
//Load all sequencers
|
||
|
for ( int i = 0; i < numSequencers; i++ )
|
||
|
{
|
||
|
//NOTENOTE: The ownerID will be replaced in the loading process
|
||
|
if ( ( sequencer = GetSequencer( -1 ) ) == NULL )
|
||
|
return false;
|
||
|
|
||
|
if ( sequencer->Load() == false )
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Load
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
int ICARUS_Instance::Load( void )
|
||
|
{
|
||
|
//Clear out any old information
|
||
|
Free();
|
||
|
|
||
|
//Check to make sure we're at the ICARUS save block
|
||
|
double version;
|
||
|
m_interface->I_ReadSaveData( 'ICAR', &version, sizeof( version ) );
|
||
|
|
||
|
//Versions must match!
|
||
|
if ( version != ICARUS_VERSION )
|
||
|
{
|
||
|
m_interface->I_DPrintf( WL_ERROR, "save game data contains outdated ICARUS version information!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//Load all signals
|
||
|
if ( LoadSignals() == false )
|
||
|
{
|
||
|
m_interface->I_DPrintf( WL_ERROR, "failed to load signals from save game!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//Load in all sequences
|
||
|
if ( LoadSequences() == false )
|
||
|
{
|
||
|
m_interface->I_DPrintf( WL_ERROR, "failed to load sequences from save game!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//Load in all sequencers
|
||
|
if ( LoadSequencers() == false )
|
||
|
{
|
||
|
m_interface->I_DPrintf( WL_ERROR, "failed to load sequencers from save game!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
m_interface->I_ReadSaveData( 'IEND', &version, sizeof( version ) );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
Signal
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
void ICARUS_Instance::Signal( const char *identifier )
|
||
|
{
|
||
|
m_signals[ identifier ] = 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
CheckSignal
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
bool ICARUS_Instance::CheckSignal( const char *identifier )
|
||
|
{
|
||
|
signal_m::iterator smi;
|
||
|
|
||
|
smi = m_signals.find( identifier );
|
||
|
|
||
|
if ( smi == m_signals.end() )
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
-------------------------
|
||
|
ClearSignal
|
||
|
-------------------------
|
||
|
*/
|
||
|
|
||
|
void ICARUS_Instance::ClearSignal( const char *identifier )
|
||
|
{
|
||
|
m_signals.erase( identifier );
|
||
|
}
|