/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
*/
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : Commando *
* *
* $Archive:: /Commando/Code/Combat/combat.cpp $*
* *
* $Author:: Bhayes $*
* *
* $Modtime:: 2/17/02 10:25a $*
* *
* $Revision:: 265 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "combat.h"
#include "ccamera.h"
#include "gameobjmanager.h"
#include "input.h"
#include "weaponmanager.h"
#include "wwprofile.h"
#include "scripts.h"
#include "pscene.h"
#include "damage.h"
#include "ww3d.h"
#include "assets.h"
#include "timemgr.h"
#include "soldier.h"
#include "SoundScene.H"
#include "weapons.h"
#include "vehicle.h"
#include "bones.h"
#include "humanstate.h"
#include "surfaceeffects.h"
#include "debug.h"
#include "backgroundmgr.h"
#include "cover.h"
#include "spawn.h"
#include "vehiclephys.h"
#include "building.h"
#include "objectives.h"
#include "conversationmgr.h"
#include "bullet.h"
#include "dazzle.h"
#include "messagewindow.h"
#include "hudinfo.h"
#include "weathermgr.h"
#include "thread.h"
#include "savegame.h"
#include "assetdep.h"
#include "saveloadstatus.h"
#include
#include "soundenvironment.h"
#include "weaponview.h"
#include "hud.h"
#include "mapmgr.h"
#include "gametype.h"
#include "staticnetworkobject.h"
#include "diaglog.h"
#include "combatdazzle.h"
#include "ffactorylist.h"
#include "definitionfactorymgr.h"
#include "definitionfactory.h"
#include "globalsettings.h"
#include "dx8wrapper.h"
#include "except.h"
#include "cheatmgr.h"
#include "systeminfolog.h"
#include "assetstatus.h"
#include "wwmemlog.h"
#include "unitcoordinationzonemgr.h"
#include "fastallocator.h"
#include "screenfademanager.h"
#include "animatedsoundmgr.h"
#include "render2dsentence.h"
#include "stylemgr.h"
#include "translatedb.h"
#include "string_ids.h"
const int DEFAULT_MAX_SHADOWS = 4;
/*
**
*/
CCameraClass * CombatManager::MainCamera = NULL;
SimpleSceneClass * CombatManager::BackgroundScene = NULL;
SoundEnvironmentClass * CombatManager::SoundEnvironment = NULL;
DazzleLayerClass * CombatManager::DazzleLayer = NULL;
GameObjReference CombatManager::TheStar;
bool CombatManager::IsStarDeterminingTarget = true;
//bool CombatManager::IAmServer = true;
//bool CombatManager::IAmClient = true;
bool CombatManager::IAmServer = false;
bool CombatManager::IAmClient = false;
bool CombatManager::IAmOnlyClient = false;
bool CombatManager::IAmOnlyServer = false;
int CombatManager::MyId = 0;
int CombatManager::SyncTime = 0;
CombatNetworkHandlerClass * CombatManager::NetworkHandler = NULL;
CombatMiscHandlerClass * CombatManager::MiscHandler = NULL;
MessageWindowClass * CombatManager::MessageWindow = NULL;
bool CombatManager::EnableSkeletonSliderDemo = false;
int CombatManager::DifficultyLevel = 1;
bool CombatManager::AutoTransitions = true;
int CombatManager::StarDamageDirection = 0;
bool CombatManager::AreObserversActive = true;
bool CombatManager::FirstPerson = true;
bool CombatManager::FirstPersonDefault = true;
bool CombatManager::IsFirstLoad = false;
int CombatManager::StarKillerID = 0;
bool CombatManager::IsGamePaused = false;
bool CombatManager::IsLevelInitialized = false;
StringClass CombatManager::StartScript;
StringClass CombatManager::RespawnScript;
bool CombatManager::AutosaveRequested = false;
DWORD CombatManager::LastRoundTripPingMs = 0;
DWORD CombatManager::AvgRoundTripPingMs = 0;
bool CombatManager::FriendlyFirePermitted = false;
bool CombatManager::BeaconPlacementEndsGame = false;
bool CombatManager::HitReticleEnabled = true;
bool CombatManager::IsGameplayPermitted = false;
int CombatManager::CombatMode = CombatManager::COMBAT_MODE_NONE;
int CombatManager::ReloadCount = 0;
StringClass CombatManager::LastLSDName;
int CombatManager::LoadProgress;
bool CombatManager::MultiplayRenderingAllowed = true;
static PhysicsSceneClass * GameScene = NULL;
/*
**
*/
void CombatManager::Init( bool render_available )
{
// Debug_Say(("CombatManager::Init\n"));
IsGameplayPermitted=false;
ConversationMgrClass::Initialize ();
MessageWindow = new MessageWindowClass;
MessageWindow->Initialize ();
ScriptManager::Init();
BonesManager::Init();
ArmorWarheadManager::Init();
CCameraClass::Init();
SurfaceEffectsManager::Init();
ObjectiveManager::Init();
CombatSoundManager::Init();
// create THE camera
MainCamera = new CCameraClass();
// create the dazzle layer
if (render_available) {
DazzleLayer = new DazzleLayerClass;
DazzleRenderObjClass::Set_Current_Dazzle_Layer(DazzleLayer);
} else {
DazzleRenderObjClass::Set_Current_Dazzle_Layer(NULL);
}
// Pass the main camera onto the 3D audio library as the
// listener's position.
SoundSceneClass *sound_scene = WWAudioClass::Get_Instance ()->Get_Sound_Scene ();
if (sound_scene != NULL) {
sound_scene->Attach_Listener_To_Obj (MainCamera);
}
HUDClass::Init(render_available);
ScreenFadeManager::Init();
FirstPerson = FirstPersonDefault;
}
/*
**
*/
void CombatManager::Shutdown( void )
{
// Debug_Say(("CombatManager::Shutdown\n"));
ScreenFadeManager::Shutdown();
HUDClass::Shutdown();
if ( GameScene != NULL ) {
// Debug_Say(( "Releasing the PScene with %d Refs\n", GameScene->Num_Refs() ));
GameScene->Release_Ref();
GameScene = NULL;
}
//
// Reset the audio library
//
if (WWAudioClass::Get_Instance () != NULL) {
SoundSceneClass *sound_scene = WWAudioClass::Get_Instance ()->Get_Sound_Scene ();
if (sound_scene != NULL) {
sound_scene->Attach_Listener_To_Obj (NULL);
}
}
if (DazzleLayer != NULL) {
delete DazzleLayer;
DazzleLayer = NULL;
DazzleRenderObjClass::Set_Current_Dazzle_Layer(NULL);
}
MainCamera->Release_Ref();
MainCamera = NULL;
CombatSoundManager::Shutdown();
ObjectiveManager::Shutdown();
SurfaceEffectsManager::Shutdown();
CCameraClass::Shutdown();
ArmorWarheadManager::Shutdown();
BonesManager::Shutdown();
ScriptManager::Shutdown();
if (MessageWindow != NULL) {
MessageWindow->Shutdown ();
delete MessageWindow;
MessageWindow = NULL;
}
ConversationMgrClass::Shutdown ();
// Debug_Say(( "Combat Shutdown %d refs\n", RefCountClass::Total_Refs() ));
}
void CombatManager::Scene_Init( void )
{
// Game scene is where the main action occurs!
GameScene = new PhysicsSceneClass;
GameScene->Set_Ambient_Light(Vector3(0.55f,0.55f,0.55f));
GameScene->Set_Ambient_Light(Vector3(1,1,1));
GameScene->Set_Fog_Color(Vector3(0.6f,0.6f,0.6f)); //Vector3(80.0f/255.0f,130.0f/255.0f,180.0f/255.0f));
// Do all 'Enable_All's, then all 'Disable_All's, then the individual pairs
COMBAT_SCENE->Enable_All_Collision_Detections( DEFAULT_COLLISION_GROUP );
COMBAT_SCENE->Enable_All_Collision_Detections( BULLET_COLLISION_GROUP );
COMBAT_SCENE->Enable_All_Collision_Detections( TERRAIN_COLLISION_GROUP );
COMBAT_SCENE->Enable_All_Collision_Detections( PhysicsSceneClass::COLLISION_GROUP_WORLD );
COMBAT_SCENE->Enable_All_Collision_Detections( SOLDIER_GHOST_COLLISION_GROUP );
COMBAT_SCENE->Enable_All_Collision_Detections( SOLDIER_COLLISION_GROUP );
COMBAT_SCENE->Disable_All_Collision_Detections( UNCOLLIDEABLE_GROUP );
COMBAT_SCENE->Disable_All_Collision_Detections( TERRAIN_ONLY_COLLISION_GROUP );
COMBAT_SCENE->Disable_All_Collision_Detections( TERRAIN_AND_BULLET_COLLISION_GROUP );
COMBAT_SCENE->Disable_All_Collision_Detections( BULLET_ONLY_COLLISION_GROUP );
COMBAT_SCENE->Enable_Collision_Detection( TERRAIN_ONLY_COLLISION_GROUP, TERRAIN_COLLISION_GROUP );
COMBAT_SCENE->Enable_Collision_Detection( TERRAIN_AND_BULLET_COLLISION_GROUP, TERRAIN_COLLISION_GROUP );
COMBAT_SCENE->Enable_Collision_Detection( TERRAIN_AND_BULLET_COLLISION_GROUP, BULLET_COLLISION_GROUP );
COMBAT_SCENE->Disable_Collision_Detection( BULLET_COLLISION_GROUP, BULLET_COLLISION_GROUP );
COMBAT_SCENE->Enable_Collision_Detection( BULLET_ONLY_COLLISION_GROUP, BULLET_COLLISION_GROUP );
COMBAT_SCENE->Disable_Collision_Detection( PhysicsSceneClass::COLLISION_GROUP_WORLD,PhysicsSceneClass::COLLISION_GROUP_WORLD );
COMBAT_SCENE->Disable_Collision_Detection( SOLDIER_GHOST_COLLISION_GROUP, SOLDIER_COLLISION_GROUP );
COMBAT_SCENE->Disable_Collision_Detection( SOLDIER_GHOST_COLLISION_GROUP, SOLDIER_GHOST_COLLISION_GROUP );
}
/*
** Note: The editor calls these per level functions only once per program execution.
** If you have code that requires a init/shutdown/reset call with each level load,
** notify Pat so he can add those calls manually
**
*/
void CombatManager::Pre_Load_Level( bool render_available )
{
MultiplayRenderingAllowed = true;
if ( !IS_MISSION && !I_Am_Server() ) {
MultiplayRenderingAllowed = false;
}
HUDClass::Enable( true );
HUDClass::Reset();
IsGamePaused = false;
GameObjObserverManager::Reset();
CoverManager::Init();
GameObjManager::Init();
BulletManager::Init();
cEncoderList::Clear_Entries();
cPacket::Init_Encoder();
BackgroundScene = NEW_REF (SimpleSceneClass, ());
SoundEnvironment = NEW_REF (SoundEnvironmentClass, ());
BackgroundMgrClass::Init (BackgroundScene, SoundEnvironment, render_available);
WeatherMgrClass::Init (SoundEnvironment);
WeaponViewClass::Init();
SmartGameObj::Set_Global_Sight_Range_Scale( 1.0f );
// SoundSystem::Set_Global_Listener_Scale( 1.0f );
//
// Map initialization (temporary -- until its more data driven)
//
/*MapMgrClass::Set_Map_Texture ("L1-MAP.TGA");
MapMgrClass::Set_Map_Center (Vector2 (308.0F, 414.0F));
MapMgrClass::Set_Map_Scale (Vector2 (0.53F, 0.54F));
MapMgrClass::Cloud_All_Cells ();*/
ScreenFadeManager::Enable_Letterbox( 0, 0 );
ScreenFadeManager::Set_Screen_Overlay_Opacity( 0, 0 );
HUDInfo::Set_HUD_Help_Text( L"" ); // Clear text
}
bool _preload_assets;
StringClass _load_map_name;
static class LoadThreadClass : public ThreadClass
{
public:
LoadThreadClass(const char *thread_name = "Game loader thread") : ThreadClass(thread_name, &Exception_Handler) {}
void Thread_Function() {
CombatManager::Set_Load_Progress( 0 );
WWMEMLOG(MEM_GAMEDATA);
WWLOG_PREPARE_TIME_AND_MEMORY("Game loader thread");
#ifndef PARAM_EDITING_ON
// Tell the datasafe to expect calls from this thread now.
GenericDataSafeClass::Set_Preferred_Thread(GetCurrentThreadId());
#endif // PARAM_EDITING_ON
CombatManager::Inc_Load_Progress();
// Reload the definition databases (to support level-specific temp ddb's)
INIT_STATUS("Free definition databases");
DefinitionMgrClass::Free_Definitions();
WWLOG_INTERMEDIATE("Free definitions");
INIT_STATUS("Load definition databases");
SaveGameManager::Load_Definitions();
WWLOG_INTERMEDIATE("Load definitions");
CombatManager::Inc_Load_Progress();
//
// Make sure the animated-sound system is setup. This needs
// to be done after the definition databases are loaded...
//
AnimatedSoundMgrClass::Initialize ();
StringClass filename_to_load( _load_map_name, true );
StringClass lsd_filename( _load_map_name,true );
// Prep the level loading
INIT_STATUS("Pre Load level");
PlayerInfoLog::Set_Current_Map_Name(_load_map_name);
SaveGameManager::Pre_Load_Game(_load_map_name, filename_to_load, lsd_filename);
CombatManager::Set_Last_LSD_Name( lsd_filename );
WWLOG_INTERMEDIATE("Preload game");
CombatManager::Inc_Load_Progress();
//
// Preload the assets
//
if ( _preload_assets ) {
INIT_STATUS("Preload assets");
AssetDependencyManager::Load_Always_Assets();
WWLOG_INTERMEDIATE("Preload always assets");
CombatManager::Inc_Load_Progress();
AssetDependencyManager::Load_Level_Assets( lsd_filename );
WWLOG_INTERMEDIATE("Preload level assets");
} else {
CombatManager::Inc_Load_Progress();
}
CombatManager::Inc_Load_Progress();
// Now load the level
INIT_STATUS("Load level");
SaveGameManager::Load_Game( filename_to_load );
WWLOG_INTERMEDIATE("Load game");
CombatManager::Inc_Load_Progress();
}
} thread;
void CombatManager::Load_Level_Threaded( const char * map_name, bool preload_assets )
{
//
// Turn off music and sound effects while loading
//
IsLevelInitialized = false;
WWAudioClass::Get_Instance ()->Enable_New_Sounds (false);
_preload_assets = preload_assets;
_load_map_name = map_name;
WWASSERT(!thread.Is_Running());
thread.Execute();
}
bool CombatManager::Is_Load_Level_Complete( void )
{
ThreadClass::Sleep_Ms(50);
return (thread.Is_Running() == false);
}
bool CombatManager::Is_Loading_Level( void )
{
return (thread.Is_Running());
}
/*
** Note: The editor calls these per level functions only once per program execution.
** If you have code that requires a init/shutdown/reset call with each level load,
** notify Pat so he can add those calls manually
**
*/
void CombatManager::Post_Load_Level( void )
{
// Dont reset SyncTime. Level from the editor should have it at 0, and levels from
// the game need it set to continue cinematics
// SyncTime = 0;
CombatMode = COMBAT_MODE_NONE;
Input::Flush();
HitReticleEnabled = true; // Default for on when you start each level
Clear_Star_Damage_Direction();
#if 0
// Re-init all objects loaded from editor
if ( CombatManager::Is_First_Load() ) {
Debug_Say(( "Re-Initing all game objects\n" ));
GameObjManager::Init_All();
}
#endif
//
// Build network wrappers for every static anim object in the level
//
StaticNetworkObjectClass::Generate_Static_Network_Objects ();
// Debug code to create a definition
#if 0
DefinitionFactoryClass * def_factory = (DefinitionFactoryClass *)DefinitionFactoryMgrClass::Find_Factory( CLASSID_GLOBAL_SETTINGS_DEF_HUMAN_ANIM_OVERRIDE );
if ( def_factory != NULL ) {
HumanAnimOverrideDef * def = (HumanAnimOverrideDef *)def_factory->Create();
if ( def != NULL ) {
def->Set_Name( "HAO Test" );
def->Set_ID (DefinitionMgrClass::Get_New_ID (def->Get_Class_ID ()));
def->WalkEmptyHands = "H_A_432A";
def->RunEmptyHands = "H_A_J43B";
DefinitionMgrClass::Register_Definition( def );
}
}
#endif
if (IsLevelInitialized == false && TheStar != NULL) {
IsLevelInitialized = true;
//
// Turn music and sound effects back on...
//
WWAudioClass::Get_Instance ()->Enable_New_Sounds (true);
}
//
// Generate the unit coordination zones
//
UnitCoordinationZoneMgr::Build_Zones ();
return ;
}
/*
** Note: The editor calls these per level functions only once per program execution.
** If you have code that requires a init/shutdown/reset call with each level load,
** notify Pat so he can add those calls manually
**
*/
void CombatManager::Unload_Level( void )
{
// Display please wait screen.....
Render2DSentenceClass backdropText;
backdropText.Set_Texture_Size_Hint( 256 );
FontCharsClass *font = StyleMgrClass::Peek_Font( StyleMgrClass::FONT_INGAME_BIG_TXT );
if (font != NULL) {
backdropText.Set_Font( font );
WideStringClass wide_str = TRANSLATE( IDS_MP_LOADING );
backdropText.Build_Sentence( wide_str );
Vector2 extents = backdropText.Get_Text_Extents( wide_str );
float x = (Render2DClass::Get_Screen_Resolution().Right - extents.X) / 2.0f;
float y = (Render2DClass::Get_Screen_Resolution().Bottom - extents.Y) / 2.0f;
backdropText.Set_Location( Vector2( (int)x, (int)y ) );
backdropText.Draw_Sentence( 0xFF00FF00 ); // Green
WW3D::Begin_Render( true, true, Vector3(0.0f,0.0f,0.0f), NULL);
backdropText.Render();
WW3D::End_Render();
}
WWLOG_PREPARE_TIME_AND_MEMORY("Unload level");
WWDEBUG_SAY(("CombatManager::Unload_Level\n"));
SystemInfoLog::Set_State_Exiting();
WWLOG_INTERMEDIATE("SystemInfoLog::Set_State_Exiting()");
// Don't log load-on-demands after the game is over
AssetStatusClass::Peek_Instance()->Enable_Load_On_Demand_Reporting(false);
WWLOG_INTERMEDIATE("AssetStatusClass::Peek_Instance()->Enable_Load_On_Demand_Reporting(false)");
//
// Free the static anim phys object network wrappers
//
StaticNetworkObjectClass::Free_Static_Network_Objects ();
WWLOG_INTERMEDIATE("StaticNetworkObjectClass::Free_Static_Network_Objects ()");
WeaponViewClass::Shutdown();
WWLOG_INTERMEDIATE("WeaponViewClass::Shutdown()");
GameObjManager::Shutdown();
WWLOG_INTERMEDIATE("GameObjManager::Shutdown()");
CoverManager::Shutdown();
WWLOG_INTERMEDIATE("CoverManager::Shutdown()");
BulletManager::Shutdown();
WWLOG_INTERMEDIATE("BulletManager::Shutdown()");
ObjectiveManager::Reset();
WWLOG_INTERMEDIATE("ObjectiveManager::Reset()");
WeatherMgrClass::Shutdown();
WWLOG_INTERMEDIATE("WeatherMgrClass::Shutdown()");
BackgroundMgrClass::Shutdown();
WWLOG_INTERMEDIATE("BackgroundMgrClass::Shutdown()");
REF_PTR_RELEASE (SoundEnvironment);
WWLOG_INTERMEDIATE("REF_PTR_RELEASE (SoundEnvironment)");
REF_PTR_RELEASE (BackgroundScene);
WWLOG_INTERMEDIATE("REF_PTR_RELEASE (BackgroundScene)");
WW3DAssetManager::Get_Instance()->Free_Assets(); // Free all assets
WWLOG_INTERMEDIATE("WW3DAssetManager::Get_Instance()->Free_Assets()");
WWLOG_INTERMEDIATE("Delete factories");
//
// Kill the background music and flush the cache
//
if (WWAudioClass::Get_Instance () != NULL) {
WWAudioClass::Get_Instance ()->Set_Background_Music (NULL);
WWAudioClass::Get_Instance ()->Flush_Cache ();
}
WWLOG_INTERMEDIATE("Flush audio cache");
SystemInfoLog::Reset_State();
WWLOG_INTERMEDIATE("SystemInfoLog::Reset_State()");
if (MessageWindow != NULL) {
MessageWindow->Clear();
MessageWindow->Clear_Log();
}
//
// Shutdown the animated-sound system
//
AnimatedSoundMgrClass::Shutdown();
WWLOG_INTERMEDIATE("AnimatedSoundMgrClass::Shutdown");
return ;
}
/*
**
*/
PhysicsSceneClass * CombatManager::Get_Scene( void )
{
return PhysicsSceneClass::Get_Instance();
}
/*
** Note: Generate_Control and Think are separated because network update needs
** to happen in-between them.
*/
/*
**
*/
void CombatManager::Generate_Control( void )
{
WWPROFILE( "Generate Control" );
// First, generate input control for all necessary game objects and
// possibly send those control to the server
GameObjManager::Generate_Control();
}
/*
**
*/
void CombatManager::Handle_Input()
{
if ( Input::Get_State( INPUT_FUNCTION_FIRST_PERSON_TOGGLE ) ) {
Set_First_Person( !Is_First_Person() );
if ( COMBAT_STAR ) {
Vector3 pos;
COMBAT_STAR->Get_Position( &pos );
DIAG_LOG(( "SWPE", "%1.2f; %1.2f; %1.2f; %s ", pos.X, pos.Y, pos.Z, Is_First_Person() ? "First" : "Third" ));
}
}
}
/*
**
*/
void CombatManager::Think()
{
SyncTime += (int)((TimeManager::Get_Frame_Seconds() * 1000.0f) + 0.5f);
WWPROFILE( "CombatManager Think" );
IsGameplayPermitted=NetworkHandler->Is_Gameplay_Permitted();
{ WWPROFILE( "Input" );
Handle_Input();
}
// GroupControllerManager::Update();
//
// Display debug boxes for the coordinate zones as necessary
//
if ( SoldierGameObj::Is_Ghost_Collision_Debug_Display_Enabled() ) {
UnitCoordinationZoneMgr::Display_Debug_Boxes();
}
{ WWPROFILE( "Bullets" );
BulletManager::Update();
}
ObjectiveManager::Update( TimeManager::Get_Frame_Seconds() );
// Now, Process all objects logically
ConversationMgrClass::Think();
{ WWPROFILE( "Game Obj Think" );
GameObjManager::Think();
// Now, Process all objects physically
}{ WWPROFILE( "Scene" );
COMBAT_SCENE->Update( TimeManager::Get_Frame_Seconds(), 0 );
}{ WWPROFILE( "Star" );
Update_Star();
// In normal mode, the camera must think before Post_Think, since the
// camera update calls Set_Targeting on the star, which must feed Update_Animation
}{ WWPROFILE( "Camera 1" );
if ( !MainCamera->Is_Using_Host_Model() ) {
MainCamera->Update();
}
// Now, Post Process all objects logically
}{ WWPROFILE( "Post Think" );
GameObjManager::Post_Think();
}
// In host_model mode, the camera must think after Post_Think, so the host model has
// a chance to determine where the camera should be
if ( MainCamera->Is_Using_Host_Model() ) {
MainCamera->Update();
}
// The targeting comes from the update weapons in the post_think
Update_Star_Targeting();
Do_Skeleton_Slider_Demo();
{ WWPROFILE( "Message Window" );
MessageWindow->On_Frame_Update();
}
SpawnManager::Update();
{ WWPROFILE( "Sound Environment" );
if ( SoundEnvironment != NULL ) {
SoundEnvironment->Update (COMBAT_SCENE, MainCamera);
}
}
{ WWPROFILE( "Background" );
BackgroundMgrClass::Update (COMBAT_SCENE, MainCamera);
}
{ WWPROFILE( "Weather" );
WeatherMgrClass::Update (COMBAT_SCENE, MainCamera);
}
HUDClass::Think();
WeaponViewClass::Think();
ScreenFadeManager::Think();
}
/*
**
*/
void CombatManager::Render()
{
if ( COMBAT_STAR != NULL ) {
MultiplayRenderingAllowed = true;
}
if ( MultiplayRenderingAllowed ) {
SystemInfoLog::Record_Frame();
{
WWPROFILE( "Camera Shakes" );
COMBAT_SCENE->Apply_Camera_Shakes (*MainCamera);
}
DazzleRenderObjClass::Install_Dazzle_Visibility_Handler(&_TheCombatDazzleHandler);
{
WWPROFILE( "Combat Render BG" );
WW3D::Render (BackgroundScene, MainCamera);
}
{
WWPROFILE( "Combat Render FG" );
WW3D::Render(COMBAT_SCENE, MainCamera);
}
{
WWPROFILE( "DazzleRenderer" );
DazzleLayerClass * dlayer = COMBAT_DAZZLE_LAYER;
if (dlayer != NULL) {
dlayer->Render(COMBAT_CAMERA);
}
}
DazzleRenderObjClass::Install_Dazzle_Visibility_Handler(NULL);
HUDClass::Render();
ScreenFadeManager::Render();
}
}
/*
**
*/
enum {
CHUNKID_THE_STAR = 916991712,
CHUNKID_FIRST_LOAD,
CHUNKID_NOT_FIRST_LOAD, // Delete this one, ( and change default to false )
CHUNKID_VARIABLES,
CHUNKID_CCAMERA,
MICROCHUNKID_FIRST_LOAD = 1,
MICROCHUNKID_DIFFICULTY_LEVEL = 2,
MICROCHUNKID_SYNC_TIME = 3,
MICROCHUNKID_START_SCRIPT,
MICROCHUNKID_RESPAWN_SCRIPT,
MICROCHUNKID_RELOAD_COUNT,
MICROCHUNKID_CHEAT_HISTORY,
MICROCHUNKID_FIRST_PERSON,
};
bool CombatManager::Save( ChunkSaveClass &csave )
{
csave.Begin_Chunk( CHUNKID_THE_STAR );
TheStar.Save( csave );
csave.End_Chunk();
csave.Begin_Chunk( CHUNKID_VARIABLES );
bool first_load = !Are_Observers_Active();
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_FIRST_LOAD, first_load );
if ( !first_load ) {
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DIFFICULTY_LEVEL, DifficultyLevel );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_FIRST_PERSON, FirstPerson );
}
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SYNC_TIME, SyncTime );
WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_START_SCRIPT, StartScript );
WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_RESPAWN_SCRIPT, RespawnScript );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_RELOAD_COUNT, ReloadCount );
#ifndef PARAM_EDITING_ON
int cheat_history = CheatMgrClass::Get_Instance()->Get_History();
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CHEAT_HISTORY, cheat_history );
#endif //PARAM_EDITING_ON
csave.End_Chunk();
if ( COMBAT_CAMERA != NULL ) {
csave.Begin_Chunk( CHUNKID_CCAMERA );
COMBAT_CAMERA->Save( csave );
csave.End_Chunk();
}
return true;
}
bool CombatManager::Load( ChunkLoadClass &cload )
{
ReloadCount = 0; // Legacy
IsFirstLoad = true; // Default
int legacy_dificulty_level = DifficultyLevel;
int cheat_history = 0;
FirstPerson = FirstPersonDefault;
while (cload.Open_Chunk()) {
switch(cload.Cur_Chunk_ID()) {
case CHUNKID_THE_STAR:
TheStar.Load( cload );
break;
case CHUNKID_VARIABLES:
while (cload.Open_Micro_Chunk()) {
switch(cload.Cur_Micro_Chunk_ID()) {
READ_MICRO_CHUNK( cload, MICROCHUNKID_FIRST_LOAD, IsFirstLoad );
READ_MICRO_CHUNK( cload, MICROCHUNKID_DIFFICULTY_LEVEL, DifficultyLevel );
READ_MICRO_CHUNK( cload, MICROCHUNKID_SYNC_TIME, SyncTime );
READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_START_SCRIPT, StartScript );
READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_RESPAWN_SCRIPT, RespawnScript );
READ_MICRO_CHUNK( cload, MICROCHUNKID_RELOAD_COUNT, ReloadCount );
READ_MICRO_CHUNK( cload, MICROCHUNKID_CHEAT_HISTORY, cheat_history );
READ_MICRO_CHUNK( cload, MICROCHUNKID_FIRST_PERSON, FirstPerson );
default:
Debug_Say(( "Unrecognized CombatManager variable chunkID\n" ));
break;
}
cload.Close_Micro_Chunk();
}
break;
case CHUNKID_CCAMERA:
if ( COMBAT_CAMERA != NULL ) {
COMBAT_CAMERA->Load( cload );
}
break;
default:
Debug_Say(( "Unrecognized CombatManager chunkID\n" ));
break;
}
cload.Close_Chunk();
}
if ( IsFirstLoad ) {
DifficultyLevel = legacy_dificulty_level;
ReloadCount = 0;
CheatMgrClass::Get_Instance()->Reset_History();
} else {
ReloadCount++; // Count another load!
CheatMgrClass::Get_Instance()->Set_History( cheat_history );
CheatMgrClass::Get_Instance()->Update_History();
}
return true;
}
/*
**
*/
bool CombatManager::Can_Damage(ArmedGameObj * p_armed_damager, PhysicalGameObj * p_phys_victim)
{
if (NetworkHandler != NULL) {
return NetworkHandler->Can_Damage(p_armed_damager, p_phys_victim);
} else {
return true;
}
}
float CombatManager::Get_Damage_Factor(ArmedGameObj * p_armed_damager, PhysicalGameObj * p_phys_victim)
{
if (NetworkHandler != NULL) {
return NetworkHandler->Get_Damage_Factor(p_armed_damager, p_phys_victim);
} else {
return 1.0f;
}
}
void CombatManager::On_Soldier_Kill(SoldierGameObj * p_soldier, SoldierGameObj * p_victim)
{
WWASSERT(p_soldier != NULL);
WWASSERT(p_victim != NULL);
if (NetworkHandler != NULL) {
NetworkHandler->On_Soldier_Kill(p_soldier, p_victim);
}
}
void CombatManager::On_Soldier_Death(SoldierGameObj * p_soldier)
{
WWASSERT(p_soldier != NULL);
if (NetworkHandler != NULL) {
NetworkHandler->On_Soldier_Death(p_soldier);
}
}
bool CombatManager::Is_Gameplay_Permitted(void)
{
if (NetworkHandler == NULL) {
return true;
} else {
return IsGameplayPermitted;
// return NetworkHandler->Is_Gameplay_Permitted();
}
}
/*
** Misc Handler
*/
void CombatManager::Mission_Complete( bool success )
{
if (MiscHandler != NULL) {
MiscHandler->Mission_Complete( success );
}
}
void CombatManager::Star_Killed( void )
{
if (MiscHandler != NULL) {
MiscHandler->Star_Killed();
}
}
/*
**
*/
void CombatManager::Set_Camera_Profile( const char * profile_name )
{
if ( profile_name == NULL ) {
COMBAT_CAMERA->Use_Default_Profile();
} else {
COMBAT_CAMERA->Use_Profile( profile_name );
}
}
/*
**
*/
void CombatManager::Set_The_Star( SoldierGameObj *target, bool is_star_determining_target )
{
if ( TheStar != target ) {
HUDClass::Reset(); // Reset the HUD (clear damage and powerups)
}
TheStar = target;
IsStarDeterminingTarget = is_star_determining_target;
if ( target != NULL ) {
COMBAT_CAMERA->Force_Heading( target->Get_Facing() );
}
HUDClass::Force_Weapon_Chart_Update();
WeaponViewClass::Reset();
if (IsLevelInitialized == false) {
IsLevelInitialized = true;
//
// Turn music and sound effects back on...
//
WWAudioClass::Get_Instance ()->Enable_New_Sounds (true);
}
}
/*
**
*/
void CombatManager::Update_Star( void )
{
SoldierGameObj * star = COMBAT_STAR;
if ( star == NULL ) {
return;
}
if ( star->Is_Destroyed() ) {
Set_Combat_Mode( COMBAT_MODE_CORPSE );
} else if ( star->Is_Dead() ) {
Set_Combat_Mode( COMBAT_MODE_DIEING );
} else if ( star->Get_Profile_Vehicle() != NULL ) {
Set_Combat_Mode( COMBAT_MODE_IN_VEHICLE );
} else if ( star->Is_Sniping() ) {
Set_Combat_Mode( COMBAT_MODE_SNIPING );
} else if ( star->Use_Ladder_View() ) {
Set_Combat_Mode( COMBAT_MODE_ON_LADDER );
} else if ( Is_First_Person() ) {
Set_Combat_Mode( COMBAT_MODE_FIRST_PERSON );
} else {
Set_Combat_Mode( COMBAT_MODE_THIRD_PERSON );
}
Update_Combat_Mode();
//
// Update the map
//
Vector3 star_pos;
star->Get_Position (&star_pos);
MapMgrClass::Clear_Cloud_Cell (star_pos);
return ;
}
void CombatManager::Update_Star_Targeting( void )
{
WWPROFILE( "Targeting" );
SmartGameObj * star = NULL;
if ( COMBAT_STAR != NULL ) {
SoldierGameObj * soldier = COMBAT_STAR;
WWASSERT(soldier != NULL);
star = soldier;
if ( soldier->Get_Vehicle() ) {
star = soldier->Get_Vehicle();
}
// Now, if the star has a weapon, gather the information needing to be displayed
// such as where the bullets will hit, what we are targeting, distance, etc.
HUDInfo::Set_Weapon_Target_Object( NULL );
WeaponClass * weapon = star->Get_Weapon();
if ( weapon ) {
WWPROFILE( "Display_Targeting" );
weapon->Display_Targeting();
}
}
}
bool CombatManager::Is_In_Camera_Frustrum(Vector3 & position)
{
WWASSERT(COMBAT_CAMERA != NULL);
Vector3 projected_mid_point;
bool is_visible = (COMBAT_CAMERA->Project(projected_mid_point, position) == CameraClass::INSIDE_FRUSTUM);
return is_visible;
}
void CombatManager::Do_Skeleton_Slider_Demo( void )
{
if (( EnableSkeletonSliderDemo == false ) ||
( COMBAT_CAMERA->Is_2D_Targeting() == false )) {
return;
}
if ( COMBAT_STAR != NULL ) {
Vector2 sliders = COMBAT_CAMERA->Get_Camera_Target_2D_Offset();
// Slide is 0-1, height * widht should be -scale - scale
sliders.X = (sliders.X - 0.5f) * 2;
sliders.Y = (sliders.Y - 0.5f) * -2;
float scale = 1;
float height = sliders.Y * scale;
float width = sliders.X * scale;
// Debug_Say(( "Height %f, width %f\n", height, width ));
COMBAT_STAR->Adjust_Skeleton( height, width );
}
}
/*
**
*/
void Vehicle_Panic( VehicleGameObj * vehicle )
{
VehiclePhysClass * rbody = vehicle->Peek_Vehicle_Phys();
if (rbody != NULL) {
#if 1
// Try to put the vehicle up-right in its current position
Matrix3D tm = rbody->Get_Transform();
Vector3 position;
Vector3 forward;
tm.Get_Translation(&position);
tm.Get_X_Vector(&forward);
if (forward.Z > 0.707f) {
tm.Get_Z_Vector(&forward);
}
forward.Z = 0.0f;
position.Z += 3.0f;
Matrix3D new_tm;
new_tm.Obj_Look_At(position,position+forward,0.0f);
rbody->Set_Transform(new_tm);
#endif
}
}
/*
** Combat Mode Management
*/
void CombatManager::Set_Combat_Mode( int mode )
{
// I don't know how to handle loading a saved game in cinematics, so postpone
// this mode change until the camera is not host controlled?
if ( COMBAT_CAMERA && COMBAT_CAMERA->Is_Using_Host_Model() ) {
return;
}
if ( mode != CombatMode ) {
//Debug_Say(( "Switching CombatMode to %d\n", mode ));
// When changing to or from ladder, lerp
if ( ( CombatMode == COMBAT_MODE_ON_LADDER ) || ( mode == COMBAT_MODE_ON_LADDER ) ) {
COMBAT_CAMERA->Set_Lerp_Time( 0.5f );
}
CombatMode = mode;
// Pause game in single player corpse mode
// IsGamePaused = (CombatMode == COMBAT_MODE_CORPSE) && IS_SOLOPLAY;
SoldierGameObj * star = COMBAT_STAR;
switch ( CombatMode ) {
case COMBAT_MODE_NONE:
break;
case COMBAT_MODE_FIRST_PERSON:
COMBAT_CAMERA->Set_Is_Star_Sniping( false );
COMBAT_CAMERA->Use_Profile( "First_Person" );
COMBAT_CAMERA->Set_Profile_Distance( 0 );
star->Peek_Model()->Set_Hidden( true );
WeaponViewClass::Enable( true );
break;
case COMBAT_MODE_ON_LADDER:
case COMBAT_MODE_THIRD_PERSON:
star->Peek_Model()->Set_Hidden( false );
COMBAT_CAMERA->Set_Is_Star_Sniping( false );
COMBAT_CAMERA->Use_Default_Profile();
WeaponViewClass::Enable( false );
break;
case COMBAT_MODE_SNIPING:
COMBAT_CAMERA->Set_Is_Star_Sniping( true );
star->Peek_Model()->Set_Hidden( true );
COMBAT_CAMERA->Use_Profile( "Sniper" );
COMBAT_CAMERA->Set_Profile_Height( star->Get_Weapon_Height() );
COMBAT_CAMERA->Set_Profile_Distance( -star->Get_Weapon_Length() );
COMBAT_CAMERA->Enable_2D_Targeting( false );
WeaponViewClass::Enable( false );
break;
case COMBAT_MODE_IN_VEHICLE:
{
VehicleGameObj * vehicle = star->Get_Profile_Vehicle();
WWASSERT( vehicle );
COMBAT_CAMERA->Set_Is_Star_Sniping( false );
if ( vehicle->Get_Profile() != NULL ) {
COMBAT_CAMERA->Use_Profile( vehicle->Get_Profile() );
} else {
COMBAT_CAMERA->Use_Default_Profile();
}
WeaponViewClass::Enable( false );
}
break;
case COMBAT_MODE_DIEING:
star->Peek_Model()->Set_Hidden( false );
COMBAT_CAMERA->Set_Is_Star_Sniping( false );
COMBAT_CAMERA->Use_Profile( "Death" );
COMBAT_CAMERA->Set_Lerp_Time( 0.5f );
WeaponViewClass::Enable( false );
break;
case COMBAT_MODE_CORPSE:
break;
case COMBAT_MODE_SNAP_SHOT:
break;
default:
Debug_Say(( "Bad CombatMode %d\n", CombatMode ));
CombatMode = COMBAT_MODE_NONE;
break;
}
}
}
void CombatManager::Update_Combat_Mode( void )
{
SoldierGameObj * star = COMBAT_STAR;
Vector3 pos;
star->Get_Position( &pos );
COMBAT_CAMERA->Set_Anchor_Position( pos );
//XXX
//COMBAT_CAMERA->Enable_2D_Targeting(true);
switch ( CombatMode ) {
case COMBAT_MODE_NONE:
break;
case COMBAT_MODE_FIRST_PERSON:
star->Peek_Model()->Set_Hidden( true ); // Putting it here, because vehicles are turning it back on
COMBAT_CAMERA->Set_Profile_Height( star->Get_Weapon_Height() ); // This is every frame for crouching
// COMBAT_CAMERA->Enable_2D_Targeting( Input::Get_State(INPUT_FUNCTION_CURSOR_TARGETING) );
COMBAT_CAMERA->Enable_2D_Targeting( false );
break;
case COMBAT_MODE_ON_LADDER:
case COMBAT_MODE_THIRD_PERSON:
COMBAT_CAMERA->Enable_2D_Targeting( Input::Get_State(INPUT_FUNCTION_CURSOR_TARGETING ) );
if ( star->Is_On_Ladder() ) {
COMBAT_CAMERA->Force_Heading( star->Get_Facing() );
}
break;
case COMBAT_MODE_SNIPING:
COMBAT_CAMERA->Set_Profile_Height( star->Get_Weapon_Height() ); // This is every frame for crouching
break;
case COMBAT_MODE_IN_VEHICLE:
{
VehicleGameObj * vehicle = star->Get_Profile_Vehicle();
WWASSERT( vehicle );
#ifdef WWDEBUG
if ( Input::Get_State( INPUT_FUNCTION_PANIC ) ) {
Vehicle_Panic( vehicle );
}
#endif
Vector3 pos;
vehicle->Get_Position( &pos );
COMBAT_CAMERA->Set_Anchor_Position( pos );
// bool target_2d = ( !vehicle->Use_2D_Aiming() ^ Input::Get_State(INPUT_FUNCTION_CURSOR_TARGETING) ^ VehicleGameObj::Is_Target_Steering() );
bool target_2d = (Input::Get_State(INPUT_FUNCTION_CURSOR_TARGETING) ^ VehicleGameObj::Is_Target_Steering() );
// This can be used to always for the V key down for vehicles
if ( VehicleGameObj::Get_Camera_Locked_To_Turret() ) {
target_2d = !target_2d;
}
if ( !vehicle->Use_2D_Aiming() ) {
target_2d = true;
}
if ( vehicle->Get_Gunner() == COMBAT_STAR ) {
target_2d = true;
}
if ( target_2d ) {
COMBAT_CAMERA->Enable_2D_Targeting( false );
} else {
COMBAT_CAMERA->Enable_2D_Targeting( true );
// Lateral velocity offset camera code
float desired_heading = vehicle->Get_Facing();;
VehiclePhysClass * vehiclephys = vehicle->Peek_Physical_Object()->As_VehiclePhysClass();
if (vehiclephys != NULL) {
Vector3 vel,localvel;
vehiclephys->Get_Velocity(&vel);
Matrix3D invtm;
vehiclephys->Get_Transform().Get_Orthogonal_Inverse(invtm);
Matrix3D::Rotate_Vector(invtm,vel,&localvel);
// float lateralvel = localvel.Y;
float heading_offset = WWMath::Atan2(localvel.Y,localvel.X);
heading_offset = WWMath::Clamp(heading_offset,DEG_TO_RADF(-45.0f),DEG_TO_RADF(45.0f));
float offset_scale = localvel.X / 5.0f;
offset_scale = WWMath::Clamp(offset_scale,0.0f,1.0f);
heading_offset *= offset_scale;
desired_heading += heading_offset;
}
COMBAT_CAMERA->Force_Heading( desired_heading );
COMBAT_CAMERA->Set_Tilt( 0 );
}
}
break;
case COMBAT_MODE_DIEING:
// Make the camera look towards the star killer
if ( StarKillerID != 0 ) {
PhysicalGameObj * killer = GameObjManager::Find_PhysicalGameObj( StarKillerID );
if ( killer ) {
Vector3 star_pos;
Vector3 killer_pos;
COMBAT_STAR->Get_Position( &star_pos );
killer->Get_Position( &killer_pos );
Vector3 dif = killer_pos - star_pos;
float heading = WWMath::Atan2(dif.Y,dif.X);
COMBAT_CAMERA->Force_Heading( heading );
}
}
break;
case COMBAT_MODE_CORPSE:
break;
case COMBAT_MODE_SNAP_SHOT:
break;
}
}
void CombatManager::Register_Star_Killer( ArmedGameObj * killer )
{
if ( killer != NULL ) {
StarKillerID = killer->Get_ID();
} else {
StarKillerID = 0;
}
}