// SpectatorStateEngine.cpp *****************************************//
// Copyright Microsoft Corporation, 2001                             //
// Created     Owner     Modification                                //
// --------    ------    -------------                               //
// 12/12/2001  sdemar    class definition for spectator state engine //
//*******************************************************************//
#include "SpectatorStateEngine.hpp"
using namespace MSRSpectator;
#include "SpectatorDebug.h"
#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;

#include "MW4.hpp"
#include "MWApplication.hpp"
#include "GameOS\GameOS.hpp"
#include "Mech.hpp"


CSpectatorStateEngine::CSpectatorStateEngine() :
	m_entityA(0),	              
	m_entityB(0),	              
	m_entityC(0),	              
	m_entityPointLeader(0),	              
	m_entityTargeted(0),	              
	m_entityInflicting(0),	              
	m_entityCurHero(0),	              
	m_entityCurEnemy(0),	 	              
	m_entityPrevHero(0),	              
	m_entityPrevEnemy(0),             
	m_fIsDisabled(false),	              
	m_fIsDying(false),	
	m_fIsResurrecting(false),
	m_dataTest(0)
{
	m_curState = STATE_ERR; // jcem - RESET;
	m_prevState = STATE_ERR; // jcem - UNINITIALIZED;
	m_idleTimer.Initialize((double)IDLE_TIMER_DUR);
	m_targetedTimer.Initialize(0.0);

    // jcem - initialize to default valus
	LoadINIData("helloMSRSpectator", DATA_TEST );
	// loading interface overide dat
	LoadINIData("1", HUD_NAME_DISPLAY );
	LoadINIData("0", HUD_CHAT_DISPLAY );

	// loading 3D camera offset point data
	LoadINIData("4.5", OVER_SHOULDER_HERO_OFFSET_X );
	LoadINIData("1.0", OVER_SHOULDER_HERO_OFFSET_Y );
	LoadINIData("-10.0", OVER_SHOULDER_HERO_OFFSET_Z );
	LoadINIData("25.0", OVER_SHOULDER_ENEMY_OFFSET_X );
	LoadINIData("-5.0", OVER_SHOULDER_ENEMY_OFFSET_Y );
	LoadINIData("5.0", OVER_SHOULDER_ENEMY_OFFSET_Z );
	LoadINIData("0.7", SIDE_SHOT_DELTA_X );
	LoadINIData("5.0", SIDE_SHOT_DELTA_Y );
	LoadINIData("10.0", SIDE_SHOT_HEAD_Y );
	LoadINIData("6.0", FRTSHOT_HEAD_Y );
	LoadINIData("3.0", FRTSHOT_CAM_Y );
	LoadINIData("15.0", FRTSHOT_DIST );
	LoadINIData("1.0", FIXED_TRACK_X );
	LoadINIData("15.0", FIXED_TRACK_Y );
	LoadINIData("25.0", FIXED_TRACK_Z );
	LoadINIData("0.0", DEATH_SEQUENCE_X );
	LoadINIData("4.0", DEATH_SEQUENCE_Y );
	LoadINIData("-50.0", DEATH_SEQUENCE_Z );
	LoadINIData("1.3", DEATH_ANIM_DELAY );
	LoadINIData("2.7", DEATH_ANIM_DUR );
// jcem - initialize to default valus
}


CSpectatorStateEngine::~CSpectatorStateEngine()
{
	m_entityA = 0;	              
	m_entityB = 0;                
	m_entityC = 0;                
	m_entityPointLeader = 0;
	m_entityTargeted = 0;
	m_entityInflicting = 0;
	m_entityCurHero = 0;
	m_entityCurEnemy = 0;
	m_entityPrevHero = 0;
	m_entityPrevEnemy = 0;

	// memory cleanup
	delete [] m_dataTest;
	m_dataTest = 0;
}


void CSpectatorStateEngine::InitStateEngine(double delay)
{
	m_entityA = 0;	              
	m_entityB = 0;                
	m_entityC = 0;                
	m_entityPointLeader = 0;
	m_entityTargeted = 0;
	m_entityInflicting = 0;
	m_entityCurHero = 0;
	m_entityCurEnemy = 0;
	m_entityPrevHero = 0;
	m_entityPrevEnemy = 0;
	m_fIsDisabled = false;
	m_fIsDying = false;
	m_fIsResurrecting = false;
    if (delay <= 0.0) {
	    m_curState = STATE_ERR; // jcem - RESET;
	    m_prevState = STATE_ERR; // jcem - UNINITIALIZED;
    } else {
	    m_curState = RESET;
	    m_prevState = UNINITIALIZED;
    }
	m_idleTimer.Expire();
	m_shotTransTimer.Initialize(delay);
	m_targetedTimer.Initialize(0.0);
	
	// Looks like we can't read the ini file after startup.  Something else has access to it now.
	// NotationFile startup_ini("options.ini", NotationFile::Standard, true);
	// LoadOptionsINI(&startup_ini);
	
}


void CSpectatorStateEngine::DeleteInstance(CSpectatorStateEngine* p)
{
	if (p)
	{
		delete p;
		p = 0;
	}
}


bool CSpectatorStateEngine::SetLeader(Replicator* rep)
{
	Entity* ent = Cast_Object(Entity*,rep);
	// make sure were looking at a mech player and not the game server player (the camera)
	if (ent->IsDerivedFrom(Mech::DefaultData) == true)
	{
		if (m_entityPointLeader != rep)
		{
			m_entityPointLeader = rep;
			return true;
		} 
		else 
			return false;
	}

	return false;
}


bool CSpectatorStateEngine::HasHero(Replicator** rep) const
{
	if ( m_entityA )
	{
		*rep = m_entityA;
		return true;
	}
	else
	{
		return false;
	}
}



bool CSpectatorStateEngine::HeroHasEngaged(Replicator** rep) const
{
	if ( m_entityB )
	{
		*rep = m_entityB;
		return true;
	}
	else
	{
		return false;
	}
}


bool CSpectatorStateEngine::HasThirdParty(Replicator** rep) const
{
	if ( m_entityC )
	{
		*rep = m_entityC;
		return true;
	}
	else
	{
		return false;
	}
}


bool CSpectatorStateEngine::HasInflicting(Replicator** rep) const
{
	if ( m_entityInflicting )
	{
		*rep = m_entityInflicting;
		return true;
	}
	else
	{
		return false;
	}
}


void CSpectatorStateEngine::SetAttack(Replicator* inflicting, Replicator* victim)
{
    if (m_curState == STATE_ERR) // jcem
        return;
	if (m_entityA == victim)
	{
		// our hero is taking damage, make sure its a mech
		Entity* entInflicting;
		entInflicting = Cast_Object(Entity*, inflicting);
		if ( entInflicting->IsDerivedFrom(Mech::DefaultData) && entInflicting != m_entityA )
		{
			m_entityInflicting = inflicting;
			if ( !m_entityB )
			{
				// Not really our target but this helps keep the camera more interesting
				// by giving it a proxy enemy to pay attention to.  I was finding that 
				// the camera stayed in a no enemy state too long if the hero was a bad shot.
				// But it turns out he gets hit alot, so this helped keep things interesting.
				m_entityTargeted = inflicting;
				m_targetedTimer.Initialize(0.8);
			}

			m_idleTimer.Initialize(IDLE_TIMER_DUR);
		}
	}
	else if (m_entityA == inflicting) 
	{
		// set our current engagement target
		if ( m_targetedTimer.CheckExpired())
		{
			m_entityTargeted = victim;
			m_targetedTimer.Initialize(0.8);
		}
		m_idleTimer.Initialize(IDLE_TIMER_DUR);
	}
}


bool CSpectatorStateEngine::fIsSamePairing(Replicator* hero, Replicator* enemy)
{
	if (m_entityCurHero == hero && m_entityCurEnemy == enemy)
		return true;
	else
	{
		m_entityPrevHero = m_entityCurHero;
		m_entityCurHero = hero;

		m_entityPrevEnemy = m_entityCurEnemy;
		m_entityCurEnemy = enemy;

		return false;
	}
}


bool CSpectatorStateEngine::GetPrevHero(Replicator** prevHero) const
{
	if (m_entityPrevHero)
	{
		*prevHero = m_entityPrevHero;
		return true;
	}
	else
	{
		return false;
	}
}


bool CSpectatorStateEngine::GetPrevEnemy(Replicator** prevEnemy) const
{
	if (m_entityPrevEnemy)
	{
		*prevEnemy = m_entityPrevEnemy;
		return true;
	}
	else
	{
		return false;
	}
}


void CSpectatorStateEngine::GetCurGameData()
{
	// gathers and stores game data for testing combatant situation
	// returns success

	// update hero death status
	if (m_entityA)
	{
		Replicator* tempRep = m_entityA;
		Mech* tempMech = Cast_Object(Mech*, tempRep);
		if (tempMech->IsDestroyed() && !m_fIsDying)
		{
			m_fIsDying = true;
			// m_fIsResurrecting = false;
			// m_entityKiller = 0;  // need to force a reset here
		}
	}
}


int CSpectatorStateEngine::ResetSpectator(void) 
{
	// define new playerA and reset state conditions
	if (m_entityPointLeader) {
		m_entityA = m_entityPointLeader;
        //m_entityPointLeader = NULL; // jcem
		m_entityB = 0;
		m_entityC = 0;     
		m_entityKiller = 0;
		m_entityInflicting = 0;
		m_idleTimer.Initialize(IDLE_TIMER_DUR);
		m_stallTimer.Expire();
		//m_deathTimer.Expire();
		m_fIsDying = false;
		m_fIsResurrecting = false;
		m_fIsDisabled = false;
		return SOLE;
	} else {
		m_entityA = 0;
		m_entityB = 0;
		m_entityC = 0;     
		m_entityKiller = 0;
		m_entityInflicting = 0;
		m_fIsDying = false;
		m_fIsResurrecting = false;
		m_fIsDisabled = false;
		m_idleTimer.Expire();
		m_stallTimer.Expire();
		//m_deathTimer.Expire();
		return RESET;
	}
}


bool CSpectatorStateEngine::A_DisabledStateChange(void)
{
	if (m_fIsDisabled) {
		if (m_idleTimer.CheckExpired()) {
			// Player activity below interest threshold, time for new hero
			// may want to increment idle timer quicker here ??
			m_entityA = 0;
			m_entityB = 0;
			m_entityC = 0;
			//m_entityTargeted = 0;
			//m_entityInflicting = 0;
			m_fIsDisabled = false;
			//m_fIsDying = false;
			m_curState = RESET;
			return true;
		}
	}
	return false;
}


bool CSpectatorStateEngine::A_DyingStateChange(void)
{
	if (m_fIsDying) 
	{
		if (m_curState != DYING)
		{
			m_deathTimer.Initialize(DEATH_TIMER_DUR);
			m_curState = DYING;

			if ( m_entityInflicting && m_entityInflicting != m_entityA )
			{
				// we have a victor for battle, promote attacker to A viewing dying
				m_entityKiller = m_entityInflicting;
			}
			/*
			else if (m_entityB)
			{
				// award it to B for at least being in the fight
				m_entityKiller = m_entityB;
			}
			*/

		return true;
		}
	}
	return false;
}


bool CSpectatorStateEngine::A_ShootingStateChange(void) 
{
	switch( m_curState ) 
	{
		case SOLE :
			if (m_entityTargeted) {
				m_entityB = m_entityTargeted;
				m_entityTargeted = 0;
				m_idleTimer.Initialize(IDLE_TIMER_DUR);
				m_curState = DUO;
				return true;
			} else {
				if (m_idleTimer.CheckExpired()) {
					m_entityB = 0;
					m_entityC = 0;
					m_fIsDisabled = false;
					//m_fIsDying = false;
					m_idleTimer.Expire();
					m_curState = SOLE;
					return true;
				}
			}
			// no state change
			return true;

		case DUO :
			if (m_entityTargeted) {
				if (m_entityTargeted != m_entityB) {
					m_entityB = m_entityTargeted;
					m_entityTargeted = 0;
					m_idleTimer.Initialize(IDLE_TIMER_DUR);
					return true;
				} else {
					// still in current battle with B
					m_idleTimer.Initialize(IDLE_TIMER_DUR);
					return true;
				}
			} else {
				if (m_idleTimer.CheckExpired()) {
					m_entityB = 0;
					m_fIsDisabled = false;
					//m_fIsDying = false;
					m_idleTimer.Initialize(IDLE_TIMER_DUR);
					m_curState = SOLE;
					return true;
				}
			}
			// no state change
			return true;

		case MULTI :
			if (m_entityTargeted) {
				if (m_entityTargeted != m_entityB) {
					m_entityB = m_entityTargeted;
					m_entityC = 0;
					m_entityTargeted = 0;
					m_fIsDisabled = false;
					//m_fIsDying = false;
					m_idleTimer.Initialize(IDLE_TIMER_DUR);
					m_curState = DUO;
					return true;
				} else {
					// still in current battle with B
					m_idleTimer.Initialize(IDLE_TIMER_DUR);
					if (m_multiTimer.CheckExpired()) {
						m_entityC = 0;
						m_stallTimer.Initialize(STALL_TIMER_DUR);
						m_curState = DUO;
						return true;
					}
				}
				// no state change
				return true;
			} else {
				if (m_idleTimer.CheckExpired()) {
					m_entityA = 0;
					m_entityB = 0;
					m_entityC = 0;
					m_fIsDisabled = false;
					//m_fIsDying = false;
					m_idleTimer.Expire();
					m_multiTimer.Expire();
					m_stallTimer.Expire();
					m_curState = RESET;
					return true;
				} else {
					if (m_multiTimer.CheckExpired()) {
						m_entityC = 0;
						// We don't want the camera banging back and forth between DUO and MULTI
						// conditions so we put a little timer to stall in here.
						m_stallTimer.Initialize(STALL_TIMER_DUR);
						m_curState = DUO;
						return true;
					} 
					else
					{
						Replicator* tempRep = m_entityC;
						Mech* tempMech = Cast_Object(Mech*, tempRep);
						if (tempMech->IsDestroyed())
						{
							m_entityC = 0;
							m_stallTimer.Expire();
							m_curState = DUO;
							return true;
						}
					}
				}
			}
			// no state change
			return true;

		default: return false;  // invalid state
	}
}



bool CSpectatorStateEngine::SpectatorExecute() 
{
    if (m_curState == STATE_ERR) // jcem
        return false; // when inc case of no-spectator(non-network or non-server game)
	// main execution of state engine

	// a transition has occured
	
	// first poll game for entity conditions.
	GetCurGameData();

	// finishing up death sequence, dying has just been respawned
	if (m_entityA)
	{
		Replicator* tempRep = m_entityA;
		Mech* tempMech = Cast_Object(Mech*, tempRep);
		if ( m_curState == DYING)
		{
            if (m_fIsResurrecting || m_deathTimer.CheckExpired()) {
			    if (m_entityKiller)
				    m_entityA = m_entityKiller;
			    //else if (m_entityInflicting)
			    //	m_entityA = m_entityInflicting;
			    else
				    m_entityA = 0;

			    m_entityKiller = 0;
			    m_entityInflicting = 0;
			    m_entityTargeted = 0;
			    m_entityB = 0;
			    m_entityC = 0;
			    m_fIsDisabled = false;
			    m_fIsDying = false;
			    m_fIsResurrecting = false;

			    if (m_entityA)
			    {
				    m_curState = SOLE;
				    m_idleTimer.Initialize(IDLE_TIMER_DUR);
			    }
			    else
			    {
				    m_curState = RESET;
			    }

			    return true;
            } else {
            }
		}
	}

	// clear our enemy if he has died
	if (m_entityB)
	{
		Replicator* tempRep = m_entityB;
		Mech* tempB = Cast_Object(Mech*, tempRep);
		if ( tempB->IsDestroyed()) //  && tempB == m_curMechReSpawned
		{
			m_entityB = 0;
		}
	}


	// now its time to pass through all the state tests
	if (m_curState == RESET) {
		m_curState = ResetSpectator();
		return true;

	} else if (m_curState == SOLE) {

		if (A_DisabledStateChange()) {
			return true;
		}

		if (A_DyingStateChange()) {
			return true;
		}

		if (A_ShootingStateChange()) {
			return true;
		}

	} else if (m_curState == DUO) {
		
		if ((m_entityInflicting) && (m_entityInflicting != m_entityB)) {
			if (m_stallTimer.CheckExpired()) {
				m_entityC = m_entityInflicting;
				m_multiTimer.Initialize(IDLE_TIMER_DUR);
				m_curState = MULTI;
				return true;
			} else {
				// We just left a multi confict camera, wait a few seconds before 
				// jumping back into a multi camera again.  So as not to be too jerky.
				// Do nothing.
			}

		} 
		
		if (A_DisabledStateChange()) {
			return true;
		}

		if (A_DyingStateChange()) {
			return true;
		}

		if (A_ShootingStateChange()) {
			return true;
		}

	} else if (m_curState == MULTI) {

		if ((m_entityInflicting) && (m_entityInflicting != m_entityB)) {
			if (m_entityInflicting == m_entityC) {
				if (m_multiTimer.CheckExpired()) {
					m_entityC = 0;
					m_multiTimer.Expire();
					m_stallTimer.Initialize(STALL_TIMER_DUR);
					m_curState = DUO;
					return true;
				}
			} else {
				if (m_stallTimer.CheckExpired()) {
					m_entityC = m_entityInflicting;
					m_stallTimer.Initialize(STALL_TIMER_DUR);
					m_multiTimer.Initialize(MULTI_TIMER_DUR);
					// no state change
					return true;
				}
				// no state change
				return true;
			}
		}
			
		if (A_DisabledStateChange()) {
			return true;
		}

		if (A_DyingStateChange()) {
			return true;
		}

		if (A_ShootingStateChange()) {
			return true;
		}
	}

	return false;  // state type encountered invalid, no state change excuted
}



void CSpectatorStateEngine::UpdateOldState()
{
	if (m_prevState != m_curState)
		if (m_curState >= UNINITIALIZED && m_curState <= MULTI)
			m_prevState = m_curState;
}


int CSpectatorStateEngine::GetCurState() const
{
	return m_curState;
}


bool CSpectatorStateEngine::fInDyingSequence()
{
	return ( m_curState == DYING || !m_deathTimer.CheckExpired());
}


bool CSpectatorStateEngine::fTimeEnoughForNewShot()
{
	return m_shotTransTimer.CheckExpired();
}


void CSpectatorStateEngine::UpdateShotTimer()
{
	m_shotTransTimer.Initialize(1.5);
}


void CSpectatorStateEngine::InitDeathDelayTimer()
{
	m_deathTransDelayTimer.Initialize(m_DeathAnimDelay);
}


void CSpectatorStateEngine::InitDeathTransTimer()
{
	m_deathTransTimer.Initialize(m_DeathAnimDur);
}


double CSpectatorStateEngine::GetDeathTransTimeRemaining()
{
	return m_deathTransTimer.GetTimeRemaining();
}


double CSpectatorStateEngine::GetDeathDelayTimeRemaining()
{
	return m_deathTransDelayTimer.GetTimeRemaining();
}


void CSpectatorStateEngine::ExpireDeathTimer()
{
	m_deathTimer.Expire();
}


void CSpectatorStateEngine::TestInstance(void) const
{
	// stubbed, required for Check_Object()
}



void CSpectatorStateEngine::LoadINIData(const char * szData, int targetMember )
{
	switch ( targetMember )
	{
	case DATA_TEST:				// data is in string format
		if (m_dataTest)
			delete [] m_dataTest;
		m_dataTest = new char[strlen(szData)+1];
		strcpy(m_dataTest, szData);
		break;

	case HUD_NAME_DISPLAY:
		m_allowHudNameDisplay = atoi(szData);
		break;

	case HUD_CHAT_DISPLAY:
		m_allowHudChatDisplay = atoi(szData);
		break;

	// point data is float format so we need to translate from string to float
	case OVER_SHOULDER_HERO_OFFSET_X:
		m_overShoulderHeroOffset_x = float(atof(szData));
		break;

	case OVER_SHOULDER_HERO_OFFSET_Y:
		m_overShoulderHeroOffset_y = float(atof(szData));
		break;
		
	case OVER_SHOULDER_HERO_OFFSET_Z:
		m_overShoulderHeroOffset_z = float(atof(szData));
		break;
		
	case OVER_SHOULDER_ENEMY_OFFSET_X:
		m_overShoulderEnemyOffset_x = float(atof(szData));
		break;
		
	case OVER_SHOULDER_ENEMY_OFFSET_Y:
		m_overShoulderEnemyOffset_y = float(atof(szData));
		break;
		
	case OVER_SHOULDER_ENEMY_OFFSET_Z:
		m_overShoulderEnemyOffset_z = float(atof(szData));
		break;
		
	case SIDE_SHOT_DELTA_X:
		m_sideShotDelta_X = float(atof(szData));
		break;
		
	case SIDE_SHOT_DELTA_Y:
		m_sideShotDelta_Y = float(atof(szData));
		break;
		
	case SIDE_SHOT_HEAD_Y:
		m_sideShotHead_Y = float(atof(szData));
		break;

	case FRTSHOT_HEAD_Y:
		m_FrtShot_HeadY = float(atof(szData));
		break;

	case FRTSHOT_CAM_Y:
		m_FrtShot_CamY = float(atof(szData));
		break;

	case FRTSHOT_DIST:
		m_FrtShot_Dist = float(atof(szData));
		break;

	case FIXED_TRACK_X:
		m_FixedTrack_X = float(atof(szData));
		break;

	case FIXED_TRACK_Y:
		m_FixedTrack_Y = float(atof(szData));
		break;

	case FIXED_TRACK_Z:
		m_FixedTrack_Z = float(atof(szData));
		break;

	case DEATH_SEQUENCE_X:
		m_DeathSeq_X = float(atof(szData));
		break;

	case DEATH_SEQUENCE_Y:
		m_DeathSeq_Y = float(atof(szData));
		break;

	case DEATH_SEQUENCE_Z:
		m_DeathSeq_Z = float(atof(szData));
		break;

	case DEATH_ANIM_DELAY:
		m_DeathAnimDelay = float(atof(szData));
		break;

	case DEATH_ANIM_DUR:
		m_DeathAnimDur = float(atof(szData));
		break;

	}

}


void CSpectatorStateEngine::LoadOptionsINI(NotationFile* optionsINI)
{
	Page *page=optionsINI->FindPage("msr spectator stuff");
	if(page!=NULL)
	{
		char *s;
		if (page->GetEntry("testMSR",(const char **)&s, false))
			LoadINIData(s, DATA_TEST );

		// loading interface overide dat
		if (page->GetEntry("allowHudNameDisplay",(const char **)&s, false))
			LoadINIData(s, HUD_NAME_DISPLAY );
		if (page->GetEntry("allowHudChatDisplay",(const char **)&s, false))
			LoadINIData(s, HUD_CHAT_DISPLAY );

		// loading 3D camera offset point data
		if (page->GetEntry("overShoulderHeroOffset_x",(const char **)&s, false))
			LoadINIData(s, OVER_SHOULDER_HERO_OFFSET_X );
		if (page->GetEntry("overShoulderHeroOffset_y",(const char **)&s, false))
			LoadINIData(s, OVER_SHOULDER_HERO_OFFSET_Y );
		if (page->GetEntry("overShoulderHeroOffset_z",(const char **)&s, false))
			LoadINIData(s, OVER_SHOULDER_HERO_OFFSET_Z );
		if (page->GetEntry("overShoulderEnemyOffset_x",(const char **)&s, false))
			LoadINIData(s, OVER_SHOULDER_ENEMY_OFFSET_X );
		if (page->GetEntry("overShoulderEnemyOffset_y",(const char **)&s, false))
			LoadINIData(s, OVER_SHOULDER_ENEMY_OFFSET_Y );
		if (page->GetEntry("overShoulderEnemyOffset_z",(const char **)&s, false))
			LoadINIData(s, OVER_SHOULDER_ENEMY_OFFSET_Z );
		if (page->GetEntry("sideShotDelta_X",(const char **)&s, false))
			LoadINIData(s, SIDE_SHOT_DELTA_X );
		if (page->GetEntry("sideShotDelta_Y",(const char **)&s, false))
			LoadINIData(s, SIDE_SHOT_DELTA_Y );
		if (page->GetEntry("sideShotHead_Y",(const char **)&s, false))
			LoadINIData(s, SIDE_SHOT_HEAD_Y );
		if (page->GetEntry("FrtShot_HeadY",(const char **)&s, false))
			LoadINIData(s, FRTSHOT_HEAD_Y );
		if (page->GetEntry("FrtShot_CamY",(const char **)&s, false))
			LoadINIData(s, FRTSHOT_CAM_Y );
		if (page->GetEntry("FrtShot_Dist",(const char **)&s, false))
			LoadINIData(s, FRTSHOT_DIST );
		if (page->GetEntry("FixedTrack_X",(const char **)&s, false))
			LoadINIData(s, FIXED_TRACK_X );
		if (page->GetEntry("FixedTrack_Y",(const char **)&s, false))
			LoadINIData(s, FIXED_TRACK_Y );
		if (page->GetEntry("FixedTrack_Z",(const char **)&s, false))
			LoadINIData(s, FIXED_TRACK_Z );
		if (page->GetEntry("DeathSeq_X",(const char **)&s, false))
			LoadINIData(s, DEATH_SEQUENCE_X );
		if (page->GetEntry("DeathSeq_Y",(const char **)&s, false))
			LoadINIData(s, DEATH_SEQUENCE_Y );
		if (page->GetEntry("DeathSeq_Z",(const char **)&s, false))
			LoadINIData(s, DEATH_SEQUENCE_Z );
		if (page->GetEntry("DeathAnimDelay",(const char **)&s, false))
			LoadINIData(s, DEATH_ANIM_DELAY );
		if (page->GetEntry("DeathAnimDur",(const char **)&s, false))
			LoadINIData(s, DEATH_ANIM_DUR );
    }
}


const int CSpectatorStateEngine::GetIntINIData(int dataMember) const
{
	switch( dataMember )
	{   
	case HUD_NAME_DISPLAY : return m_allowHudNameDisplay;
	case HUD_CHAT_DISPLAY : return m_allowHudChatDisplay;

	default: return -1; // error, data not present
	}
}


const char * CSpectatorStateEngine::GetStringINIData(int dataMember) const
{
	switch( dataMember )
	{   
	case DATA_TEST : return m_dataTest;

	default: return "";
	}
}


const float CSpectatorStateEngine::GetFloatINIData(int dataMember) const
{
	switch( dataMember )
	{   
	case OVER_SHOULDER_HERO_OFFSET_X:	return m_overShoulderHeroOffset_x;
	case OVER_SHOULDER_HERO_OFFSET_Y:	return m_overShoulderHeroOffset_y;
	case OVER_SHOULDER_HERO_OFFSET_Z:	return m_overShoulderHeroOffset_z;

	case OVER_SHOULDER_ENEMY_OFFSET_X:	return m_overShoulderEnemyOffset_x;
	case OVER_SHOULDER_ENEMY_OFFSET_Y:	return m_overShoulderEnemyOffset_y;
	case OVER_SHOULDER_ENEMY_OFFSET_Z:	return m_overShoulderEnemyOffset_z;

	case FRTSHOT_HEAD_Y:		return m_FrtShot_HeadY;
	case FRTSHOT_CAM_Y:			return m_FrtShot_CamY;
	case FRTSHOT_DIST:			return m_FrtShot_Dist;
		
	case SIDE_SHOT_DELTA_X:		return m_sideShotDelta_X;
	case SIDE_SHOT_DELTA_Y:		return m_sideShotDelta_Y;
	case SIDE_SHOT_HEAD_Y:		return m_sideShotHead_Y;

	case FIXED_TRACK_X:			return m_FixedTrack_X;
	case FIXED_TRACK_Y:			return m_FixedTrack_Y;
	case FIXED_TRACK_Z:			return m_FixedTrack_Z;

	case DEATH_SEQUENCE_X:		return m_DeathSeq_X;
	case DEATH_SEQUENCE_Y:		return m_DeathSeq_Y;
	case DEATH_SEQUENCE_Z:		return m_DeathSeq_Z;
	case DEATH_ANIM_DELAY:		return m_DeathAnimDelay;
	case DEATH_ANIM_DUR:		return m_DeathAnimDur;

	default: return 0.0;
	}
}



Replicator* CSpectatorStateEngine::GetEntityA() const
{
	return m_entityA;
}


Replicator* CSpectatorStateEngine::GetEntityKiller() const
{
	return m_entityKiller;
}


void CSpectatorStateEngine::SignalReSpawning(Mech* curSpawn)
{
    if (m_curState == STATE_ERR) // jcem
        return;

	m_curMechReSpawned = curSpawn;

	if (m_curState == DYING && m_fIsDying)
	{
		Mech* tempA = Cast_Object(Mech*, m_entityA);
		if (tempA == curSpawn)
		{
			m_fIsResurrecting = true;
		}
	}

	Mech* tempB = Cast_Object(Mech*, m_entityB);
	if (tempB == curSpawn)
	{
		if (m_entityInflicting == m_entityB)
			m_entityInflicting = 0;

		// if (m_entityKiller = m_entityB)
		//	m_entityKiller = 0;

		m_entityB = 0;
			
		m_curState = SOLE;
	}
}


void CSpectatorStateEngine::GetCurReSpawn(Mech** aMech)
{
	if (m_curMechReSpawned)
		*aMech = m_curMechReSpawned;
	else
		*aMech = NULL;
}


void CSpectatorStateEngine::DumpData(void) const
{	

	/*
	SpecDebug1("=== Spectator Data Dump =====");
	char tempMsg[80];               // our formatted message string
	char intBuff[sizeof(int) + 1];  // our hex time string
	int  decimal, sign;             // index for float decimal point, float sign
	char *timeBuff;                 // our formatted time string (less remainder)
	Mech* mechTemp = NULL;

	// display the current game time in seconds
	timeBuff = _fcvt( gos_GetElapsedTime(), 7, &decimal, &sign );
	//timeBuff[decimal-1] = '\n';
	timeBuff[decimal] = '\0';
	strcpy(tempMsg, "Time: ");
	strcat(tempMsg, timeBuff);
	SpecDebug1(tempMsg);

	// display m_entityA pointer
	tempMsg[0] = '\0';
	strcpy(tempMsg, "m_entityA: ");
	strcat(tempMsg, _itoa((int)m_entityA, intBuff, 16));
	SpecDebug1(tempMsg);

	// display m_entityB pointer
	tempMsg[0] = '\0';
	strcpy(tempMsg, "m_entityB: ");
	strcat(tempMsg, _itoa((int)m_entityB, intBuff, 16));
	SpecDebug1(tempMsg);
	
	// display m_entityC pointer
	tempMsg[0] = '\0';
	strcpy(tempMsg, "m_entityC: ");
	strcat(tempMsg, _itoa((int)m_entityC, intBuff, 16));
	SpecDebug1(tempMsg);
	
	// display m_entityPointLeader pointer
	tempMsg[0] = '\0';
	strcpy(tempMsg, "m_entityPointLeader: ");
	strcat(tempMsg, _itoa((int)m_entityPointLeader, intBuff, 16));
	SpecDebug1(tempMsg);
	
	// display m_entityTargeted pointer
	tempMsg[0] = '\0';
	strcpy(tempMsg, "m_entityTargeted: ");
	strcat(tempMsg, _itoa((int)m_entityTargeted, intBuff, 16));
	SpecDebug1(tempMsg);
	
	// display m_entityInflicting pointer
	tempMsg[0] = '\0';
	strcpy(tempMsg, "m_entityInflicting: ");
	strcat(tempMsg, _itoa((int)m_entityInflicting, intBuff, 16));
	SpecDebug1(tempMsg);
	
	// display m_fIsDisabled
	tempMsg[0] = '\0';
	strcpy(tempMsg, "m_fIsDisabled: ");
	strcat(tempMsg, _itoa((int)m_fIsDisabled, intBuff, 16));
	SpecDebug1(tempMsg);
	
	// display m_fIsDying
	tempMsg[0] = '\0';
	strcpy(tempMsg, "m_fIsDying: ");
	strcat(tempMsg, _itoa((int)m_fIsDying, intBuff, 16));
	SpecDebug1(tempMsg);

	SpecDebug1("=============================");
	*/
}




