/* ** 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; } }