// CameraStateEngine.cpp ********************************************// // Copyright Microsoft Corporation, 2001 // // Created Owner Modification // // -------- ------ ------------- // // 3/7/2001 sdemar class definition for spectator state engine // //*******************************************************************// #include "CameraStateEngine.h" using namespace MSRSpectator; #include "SpectatorDebug.h" #include #include #include using namespace std; #include "MW4.hpp" #include "MWApplication.hpp" #include "GameOS\GameOS.hpp" #include "Mech.hpp" CCameraStateEngine::CCameraStateEngine() : m_cameraState(STATE_STD_OBSERVERMODE), m_cameraDist(NO_RANGE), m_fSelectState(false), m_distanceBetween(0.0f), m_fNewShot(true), m_fPrevWasOverShoulder(false) { m_stateTimer.Initialize(3); m_dampTimer.Expire(); } CCameraStateEngine::~CCameraStateEngine() { // stubbed } void CCameraStateEngine::TestInstance(void) const { // stubbed, required for Check_Object() } void CCameraStateEngine::ForceStateChange() { m_stateTimer.Expire(); m_fSelectState = true; NullSpectatorState(); } void CCameraStateEngine::NullSpectatorState() { if (m_stateTimer.CheckExpired()) m_stateTimer.Initialize(1.5); m_cameraState = STATE_STD_OBSERVERMODE; m_cameraDist = NO_RANGE; } void CCameraStateEngine::BumpStateTimer(double addAmt) { double timeRemaining = m_stateTimer.GetTimeRemaining(); if (timeRemaining > 0.0 && timeRemaining < addAmt) m_stateTimer.Initialize(timeRemaining + addAmt); else m_stateTimer.Initialize(addAmt); m_fSelectState = false; } double CCameraStateEngine::GetDampTimerRemaining() { return m_dampTimer.GetTimeRemaining(); } void CCameraStateEngine::InitDampTimer(double inTime) { m_dampTimer.Initialize(inTime); } void CCameraStateEngine::ExpireDampTimer() { m_dampTimer.Expire(); } int CCameraStateEngine::GetCameraStateToExecute(bool& stateChanged, int& cameraDist) { // NOTE, normally in a state engine, code would execute here per state. // However we want to keep the game specific code in the game components. // In our case that is camera work. So all we do here is monitor the // state timer condition as to whether its time for a new state. if (m_stateTimer.CheckExpired()) { m_fSelectState = true; } stateChanged = m_fSelectState; // And we return the camera state to the game engine so it can deal with // executing the current MW4 Spectator specific cameras. // NOTE: We execute once more on current camera because we may need to store // game parameters to transition between this and the upcoming camera. cameraDist = m_cameraDist; return m_cameraState; } void CCameraStateEngine::StateTransitionExecute(bool fIsSamePairing, float distanceBetween) { // Here is where we do some basic camera choosing based on distance. We also // randomly choose between cameras good at a given distance to break things up // a little more. Since we are depending on indeterminate action you will adjust this // section as appropriate for the kind of action you will encounter in your game. // If the spectator mode ever becomes a cached-time process this section will change // dramatically as you will be able to include logic for predictive decision making. // Such as being able to look ahead in the data stream to see an event of interest about to // happen somewhere in the world. In those situations you may want to deliberately move // or place a camera before the event occurs to get a more interesting shot. if (m_fSelectState == true) { m_fSelectState = false; if (distanceBetween <= MAX_SIDE_DIST) { if (rand() % 3 == 0) { // 33.3% m_stateTimer.Initialize(1.5); m_cameraState = STATE_FIXED_TRACKING_SHOT; m_cameraDist = MEDIUMSHOT; } else { // 66.6% m_stateTimer.Initialize(2.0); m_cameraState = STATE_SIDE_SHOT; m_cameraDist = NO_RANGE; } } else if ((MAX_SIDE_DIST < distanceBetween) && (distanceBetween <= 210.0f)) { // over shoulder shots require some attention. Its possible for our hero // to be engaging two or more enemys in random order. To keep the camera // from radically jogging from one to another enemy, we use a transitioning // shot. if (m_fPrevWasOverShoulder || ((rand() % 3) != 0)) { // 66.6% m_fPrevWasOverShoulder = false; m_stateTimer.Initialize(1.0); m_cameraState = STATE_FRONT_SHOT; m_cameraDist = CLOSESHOT; } else { // 33.3% m_fPrevWasOverShoulder = true; m_stateTimer.Initialize(3.0); m_cameraState = STATE_OVERSHOULDER_SHOT; m_cameraDist = MEDIUMSHOT; } } else if ((210.0f < distanceBetween) && (distanceBetween <= 290.0f)) { int cameraState, cameraDist; do { switch(rand() % 3) { case 0: cameraState = STATE_FRONT_SHOT; break; case 1: cameraState = STATE_OVERSHOULDER_SHOT; break; default: cameraState = STATE_FIXED_TRACKING_SHOT; break; } switch(rand() % 3) { case 0: cameraDist = CLOSESHOT; break; case 1: cameraDist = MEDIUMSHOT; break; default: cameraDist = LONGSHOT; break; } } while(((cameraState == m_cameraState) && (cameraDist == m_cameraDist)) || ((cameraState == STATE_OVERSHOULDER_SHOT) && m_fPrevWasOverShoulder)); switch(cameraState) { default: m_fPrevWasOverShoulder = false; m_stateTimer.Initialize(2.0); break; case STATE_STD_OBSERVERMODE: m_fPrevWasOverShoulder = true; m_stateTimer.Initialize(3.0); break; } m_cameraState = cameraState; //m_cameraDist = cameraDist; if (cameraState == STATE_FRONT_SHOT) { m_cameraDist = MEDIUMSHOT; } else { m_cameraDist = LONGSHOT; } } else { int cameraState, cameraDist; do { switch(rand() % 3) { case 0: cameraState = STATE_FRONT_SHOT; break; case 1: cameraState = STATE_OVERSHOULDER_SHOT; break; case 2: cameraState = STATE_FIXED_TRACKING_SHOT; default: cameraState = STATE_STD_OBSERVERMODE; break; } if (cameraState == STATE_STD_OBSERVERMODE) { cameraDist = NO_RANGE; } else { switch(rand() % 3) { case 0: cameraDist = CLOSESHOT; break; case 1: cameraDist = MEDIUMSHOT; break; default: cameraDist = LONGSHOT; break; } } } while(((cameraState == m_cameraState) && (cameraDist == m_cameraDist)) || ((cameraState == STATE_OVERSHOULDER_SHOT) && m_fPrevWasOverShoulder)); switch(cameraState) { default: m_fPrevWasOverShoulder = false; m_stateTimer.Initialize(1.5); break; case STATE_FIXED_TRACKING_SHOT: m_fPrevWasOverShoulder = false; m_stateTimer.Initialize(2.0); break; case STATE_STD_OBSERVERMODE: m_fPrevWasOverShoulder = true; m_stateTimer.Initialize(3.0); break; } m_cameraState = cameraState; //m_cameraDist = cameraDist; switch (cameraState) { case STATE_FIXED_TRACKING_SHOT: m_cameraDist = LONGSHOT; break; case STATE_FRONT_SHOT: m_cameraDist = CLOSESHOT; break; case STATE_OVERSHOULDER_SHOT: m_cameraDist = CLOSESHOT; break; case STATE_STD_OBSERVERMODE: m_cameraDist = NO_RANGE; break; } } } } bool CCameraStateEngine::GetIsTimeToSelectNewShot() { return m_fSelectState; } bool CCameraStateEngine::fIsValidSideDistance(float dist) const { return (dist >= 4.0f && dist <= MAX_SIDE_DIST); }