Files
firestorm/Gameleap/code/mw4/Code/MSRSpectator/CameraStateEngine.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

300 lines
8.9 KiB
C++

// 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 <stdlib.h>
#include <string>
#include <iostream>
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);
}