diff --git a/.github/prompts/clone-references.prompt.md b/.github/prompts/clone-references.prompt.md deleted file mode 100644 index 6855957c090..00000000000 --- a/.github/prompts/clone-references.prompt.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: clone-references-from-gitmodules -description: Clone selected Git submodules from .gitmodules into local directories for reference purposes -argument-hint: The specific submodule paths to clone (e.g., 'references/') or 'all' for all submodules; prefix with '--exclude=' to skip items ---- - -# Clone Git References from .gitmodules - -You are assisting with cloning Git submodules to local reference directories, preserving original repositories as standalone clones rather than formal Git submodules. - -## Task -Clone one or more Git submodules defined in `.gitmodules` into their designated local directories. The goal is to have reference implementations available without registering them as formal git submodules. - -## Steps - -1. **Parse .gitmodules**: Identify submodule entries matching the specified scope (e.g., all submodules under `references/` or a specific list). - -2. **Create target directories**: Ensure parent directories exist for all target clones. - -3. **Clone repositories**: For each submodule, use `git clone --depth 1` (shallow clone for speed) from the URL specified in `.gitmodules` to the designated path. - -4. **Handle conflicts**: If a path already exists, skip with `|| true` or prompt for overwrite. - -5. **Verify**: List the cloned directories to confirm successful completion. - -## Context - -The user is typically: -- Setting up a development environment with external reference repositories -- Bootstrapping a project that relies on reference implementations (e.g., Linux port references, modernization examples) -- Using `.gitmodules` as the source of truth for repository URLs and paths - -## Template Command - -```bash -# Clone specific submodules from .gitmodules (or those matching a scope prefix) -mkdir -p && \ -git clone --depth 1 || true && \ -git clone --depth 1 || true && \ -# ... repeat for each submodule -ls -la -``` - -## Notes - -- Use `--depth 1` to clone only the latest commit (faster and smaller). -- Use `|| true` to ignore errors if paths already exist. -- Preserve the directory structure defined in `.gitmodules` (e.g., `references/fighter19-dxvk-port`). -- Do not register these as formal git submodules unless explicitly required. diff --git a/CMakePresets.json b/CMakePresets.json index 97bca6e96ad..a15058115b1 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -195,7 +195,7 @@ }, { "name": "linux64-deploy", - "displayName": "Linux 64-bit DXVK/SDL3/MiniAudio Release", + "displayName": "Linux 64-bit DXVK/SDL3/OpenAL Release", "inherits": "default-vcpkg", "generator": "Ninja", "hidden": false, @@ -205,8 +205,8 @@ "CMAKE_BUILD_TYPE": "RelWithDebInfo", "SAGE_USE_DX8": "OFF", "SAGE_USE_SDL3": "ON", - "SAGE_USE_OPENAL": "OFF", - "SAGE_USE_MINIAUDIO": "ON", + "SAGE_USE_OPENAL": "ON", + "SAGE_USE_MINIAUDIO": "OFF", "SAGE_USE_GLM": "ON", "SAGE_UPDATE_CHECK": "ON", "RTS_CRASHDUMP_ENABLE": "OFF", @@ -406,8 +406,8 @@ { "name": "linux64-deploy", "configurePreset": "linux64-deploy", - "displayName": "Build Linux 64-bit DXVK/SDL3/MiniAudio Release", - "description": "Build Linux 64-bit with DXVK graphics, SDL3 windowing, and MiniAudio audio" + "displayName": "Build Linux 64-bit DXVK/SDL3/OpenAL Release", + "description": "Build Linux 64-bit with DXVK graphics, SDL3 windowing, and OpenAL audio" }, { "name": "linux64-openal", diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index 5c467b01d7d..c3932edc92b 100644 --- a/Core/GameEngine/CMakeLists.txt +++ b/Core/GameEngine/CMakeLists.txt @@ -148,7 +148,7 @@ set(GAMEENGINE_SRC Include/GameClient/ClientInstance.h Include/GameClient/ClientRandomValue.h Include/GameClient/Color.h -# Include/GameClient/CommandXlat.h + Include/GameClient/CommandXlat.h # Include/GameClient/ControlBar.h # Include/GameClient/ControlBarResizer.h # Include/GameClient/ControlBarScheme.h @@ -190,10 +190,10 @@ set(GAMEENGINE_SRC Include/GameClient/GlobalLanguage.h Include/GameClient/GraphDraw.h # Include/GameClient/GUICallbacks.h -# Include/GameClient/GUICommandTranslator.h + Include/GameClient/GUICommandTranslator.h Include/GameClient/HeaderTemplate.h -# Include/GameClient/HintSpy.h -# Include/GameClient/HotKey.h + Include/GameClient/HintSpy.h + Include/GameClient/HotKey.h Include/GameClient/Image.h Include/GameClient/IMEManager.h # Include/GameClient/InGameUI.h @@ -202,22 +202,22 @@ set(GAMEENGINE_SRC Include/GameClient/LanguageFilter.h Include/GameClient/Line2D.h Include/GameClient/LoadScreen.h -# Include/GameClient/LookAtXlat.h + Include/GameClient/LookAtXlat.h Include/GameClient/MapUtil.h # Include/GameClient/MessageBox.h -# Include/GameClient/MetaEvent.h + Include/GameClient/MetaEvent.h Include/GameClient/Module/AnimatedParticleSysBoneClientUpdate.h Include/GameClient/Module/BeaconClientUpdate.h Include/GameClient/Module/SwayClientUpdate.h Include/GameClient/Mouse.h Include/GameClient/ParabolicEase.h Include/GameClient/ParticleSys.h -# Include/GameClient/PlaceEventTranslator.h + Include/GameClient/PlaceEventTranslator.h Include/GameClient/ProcessAnimateWindow.h Include/GameClient/RadiusDecal.h Include/GameClient/RayEffect.h Include/GameClient/SelectionInfo.h -# Include/GameClient/SelectionXlat.h + Include/GameClient/SelectionXlat.h # Include/GameClient/Shadow.h # Include/GameClient/Shell.h # Include/GameClient/ShellHooks.h @@ -232,7 +232,7 @@ set(GAMEENGINE_SRC Include/GameClient/Water.h Include/GameClient/WindowLayout.h Include/GameClient/WindowVideoManager.h -# Include/GameClient/WindowXlat.h + Include/GameClient/WindowXlat.h Include/GameClient/WinInstanceData.h # Include/GameLogic/AI.h # Include/GameLogic/AIDock.h @@ -705,7 +705,7 @@ set(GAMEENGINE_SRC # Source/GameClient/Eva.cpp Source/GameClient/FXList.cpp # Source/GameClient/GameClient.cpp -# Source/GameClient/GameClientDispatch.cpp + Source/GameClient/GameClientDispatch.cpp Source/GameClient/GameText.cpp Source/GameClient/GlobalLanguage.cpp Source/GameClient/GraphDraw.cpp @@ -809,15 +809,15 @@ set(GAMEENGINE_SRC Source/GameClient/LanguageFilter.cpp Source/GameClient/Line2D.cpp Source/GameClient/MapUtil.cpp -# Source/GameClient/MessageStream/CommandXlat.cpp -# Source/GameClient/MessageStream/GUICommandTranslator.cpp -# Source/GameClient/MessageStream/HintSpy.cpp -# Source/GameClient/MessageStream/HotKey.cpp -# Source/GameClient/MessageStream/LookAtXlat.cpp -# Source/GameClient/MessageStream/MetaEvent.cpp -# Source/GameClient/MessageStream/PlaceEventTranslator.cpp -# Source/GameClient/MessageStream/SelectionXlat.cpp -# Source/GameClient/MessageStream/WindowXlat.cpp + Source/GameClient/MessageStream/CommandXlat.cpp + Source/GameClient/MessageStream/GUICommandTranslator.cpp + Source/GameClient/MessageStream/HintSpy.cpp + Source/GameClient/MessageStream/HotKey.cpp + Source/GameClient/MessageStream/LookAtXlat.cpp + Source/GameClient/MessageStream/MetaEvent.cpp + Source/GameClient/MessageStream/PlaceEventTranslator.cpp + Source/GameClient/MessageStream/SelectionXlat.cpp + Source/GameClient/MessageStream/WindowXlat.cpp Source/GameClient/ParabolicEase.cpp Source/GameClient/RadiusDecal.cpp Source/GameClient/SelectionInfo.cpp diff --git a/Core/GameEngine/Include/Common/FileSystem.h b/Core/GameEngine/Include/Common/FileSystem.h index 5c1f8d04a8c..322780017a5 100644 --- a/Core/GameEngine/Include/Common/FileSystem.h +++ b/Core/GameEngine/Include/Common/FileSystem.h @@ -63,7 +63,7 @@ // Type Defines //---------------------------------------------------------------------------- -typedef std::set > FilenameList; +typedef std::set/**/> FilenameList; typedef FilenameList::iterator FilenameListIter; typedef UnsignedByte FileInstance; @@ -174,7 +174,7 @@ class FileSystem : public SubsystemInterface typedef std::hash_map< rts::string_key, FileExistData, rts::string_key_hash, - rts::string_key_equal > FileExistMap; + rts::string_key_equal/**/> FileExistMap; mutable FileExistMap m_fileExist; mutable FastCriticalSectionClass m_fileExistMutex; diff --git a/Core/GameEngine/Include/Common/GameAudio.h b/Core/GameEngine/Include/Common/GameAudio.h index 60cb8e214ae..aaee581ba62 100644 --- a/Core/GameEngine/Include/Common/GameAudio.h +++ b/Core/GameEngine/Include/Common/GameAudio.h @@ -66,7 +66,7 @@ struct AudioRequest; struct AudioSettings; struct MiscAudio; -typedef std::hash_map, rts::equal_to > AudioEventInfoHash; +typedef std::hash_map, rts::equal_to/**/> AudioEventInfoHash; typedef AudioEventInfoHash::iterator AudioEventInfoHashIt; typedef UnsignedInt AudioHandle; @@ -219,6 +219,8 @@ class AudioManager : public SubsystemInterface virtual UnsignedInt getNum2DSamples() const = 0; virtual UnsignedInt getNum3DSamples() const = 0; virtual UnsignedInt getNumStreams() const = 0; + virtual UnsignedInt getNumAvailable2DSamples() const = 0; + virtual UnsignedInt getNumAvailable3DSamples() const = 0; // Device Dependent calls to determine sound prioritization info virtual Bool doesViolateLimit( AudioEventRTS *event ) const = 0; @@ -339,7 +341,7 @@ class AudioManager : public SubsystemInterface AudioEventInfoHash m_allAudioEventInfo; AudioHandle theAudioHandlePool; - std::list > m_adjustedVolumes; + std::list/**/> m_adjustedVolumes; Real m_musicVolume; Real m_soundVolume; diff --git a/Core/GameEngine/Include/Common/GameSounds.h b/Core/GameEngine/Include/Common/GameSounds.h index 83c846957ac..f684f11edda 100644 --- a/Core/GameEngine/Include/Common/GameSounds.h +++ b/Core/GameEngine/Include/Common/GameSounds.h @@ -69,15 +69,6 @@ class SoundManager : public SubsystemInterface virtual void addAudioEvent(AudioEventRTS *&eventToAdd); // pre-copied - virtual void notifyOf2DSampleStart(); - virtual void notifyOf3DSampleStart(); - - virtual void notifyOf2DSampleCompletion(); - virtual void notifyOf3DSampleCompletion(); - - virtual Int getAvailableSamples(); - virtual Int getAvailable3DSamples(); - // empty string means that this sound wasn't found or some error occurred. CHECK FOR EMPTY STRING. virtual AsciiString getFilenameForPlayFromAudioEvent( const AudioEventRTS *eventToGetFrom ); @@ -87,12 +78,4 @@ class SoundManager : public SubsystemInterface protected: virtual Bool violatesVoice( AudioEventRTS *event ); virtual Bool isInterrupting( AudioEventRTS *event ); - - - protected: - UnsignedInt m_num2DSamples; - UnsignedInt m_num3DSamples; - - UnsignedInt m_numPlaying2DSamples; - UnsignedInt m_numPlaying3DSamples; }; diff --git a/Core/GameEngine/Include/Common/STLTypedefs.h b/Core/GameEngine/Include/Common/STLTypedefs.h index 0dc2ede1dc3..68a195c45a8 100644 --- a/Core/GameEngine/Include/Common/STLTypedefs.h +++ b/Core/GameEngine/Include/Common/STLTypedefs.h @@ -108,8 +108,8 @@ typedef std::vector::iterator VecNamedRequestsIt; typedef std::vector BoolVector; typedef std::vector::iterator BoolVectorIterator; -typedef std::map< NameKeyType, Real, std::less > ProductionChangeMap; -typedef std::map< NameKeyType, VeterancyLevel, std::less > ProductionVeterancyMap; +typedef std::map< NameKeyType, Real, std::less/**/> ProductionChangeMap; +typedef std::map< NameKeyType, VeterancyLevel, std::less/**/> ProductionVeterancyMap; // Some useful, common hash and equal_to functors for use with hash_map namespace rts diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/CommandXlat.h b/Core/GameEngine/Include/GameClient/CommandXlat.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameClient/CommandXlat.h rename to Core/GameEngine/Include/GameClient/CommandXlat.h diff --git a/Core/GameEngine/Include/GameClient/FXList.h b/Core/GameEngine/Include/GameClient/FXList.h index 2d08f0335ec..279ebe9e3ce 100644 --- a/Core/GameEngine/Include/GameClient/FXList.h +++ b/Core/GameEngine/Include/GameClient/FXList.h @@ -209,7 +209,7 @@ class FXListStore : public SubsystemInterface private: // use the hashing function for Ints. - typedef std::hash_map< NameKeyType, FXList, rts::hash, rts::equal_to > FXListMap; + typedef std::hash_map< NameKeyType, FXList, rts::hash, rts::equal_to/**/> FXListMap; FXListMap m_fxmap; diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/GUICommandTranslator.h b/Core/GameEngine/Include/GameClient/GUICommandTranslator.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameClient/GUICommandTranslator.h rename to Core/GameEngine/Include/GameClient/GUICommandTranslator.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/HintSpy.h b/Core/GameEngine/Include/GameClient/HintSpy.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameClient/HintSpy.h rename to Core/GameEngine/Include/GameClient/HintSpy.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/HotKey.h b/Core/GameEngine/Include/GameClient/HotKey.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameClient/HotKey.h rename to Core/GameEngine/Include/GameClient/HotKey.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/LookAtXlat.h b/Core/GameEngine/Include/GameClient/LookAtXlat.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameClient/LookAtXlat.h rename to Core/GameEngine/Include/GameClient/LookAtXlat.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/MetaEvent.h b/Core/GameEngine/Include/GameClient/MetaEvent.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameClient/MetaEvent.h rename to Core/GameEngine/Include/GameClient/MetaEvent.h diff --git a/Core/GameEngine/Include/GameClient/ParticleSys.h b/Core/GameEngine/Include/GameClient/ParticleSys.h index 725a93a19bf..b44e63cc824 100644 --- a/Core/GameEngine/Include/GameClient/ParticleSys.h +++ b/Core/GameEngine/Include/GameClient/ParticleSys.h @@ -743,8 +743,8 @@ class ParticleSystemManager : public SubsystemInterface, typedef std::list ParticleSystemList; typedef ParticleSystemList::iterator ParticleSystemListIt; - typedef std::hash_map, rts::equal_to > ParticleSystemIDMap; - typedef std::hash_map, rts::equal_to > TemplateMap; + typedef std::hash_map, rts::equal_to/**/> ParticleSystemIDMap; + typedef std::hash_map, rts::equal_to/**/> TemplateMap; ParticleSystemManager(); virtual ~ParticleSystemManager() override; diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/PlaceEventTranslator.h b/Core/GameEngine/Include/GameClient/PlaceEventTranslator.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameClient/PlaceEventTranslator.h rename to Core/GameEngine/Include/GameClient/PlaceEventTranslator.h diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/SelectionXlat.h b/Core/GameEngine/Include/GameClient/SelectionXlat.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameClient/SelectionXlat.h rename to Core/GameEngine/Include/GameClient/SelectionXlat.h diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index 600254ff062..689c28dc420 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -33,7 +33,9 @@ #include "Common/GameType.h" #include "Common/Snapshot.h" #include "Lib/BaseType.h" +#include "WW3D2/camera.h" #include "WW3D2/coltype.h" ///< we don't generally do this, but we need the W3D collision types +#include "WWMath/plane.h" #include "WWMath/wwmath.h" #define DEFAULT_VIEW_WIDTH 640 @@ -120,11 +122,12 @@ class View : public Snapshot Bool (*callback)( Drawable *draw, void *userData ), void *userData ) = 0; - /** project the 4 corners of this view into the world and return each point as a parameter, - the world points are at the requested Z */ - virtual void getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, + /// Project the 4 corners of this view into the world and return each point as a parameter, + /// the world points are at the requested Z. Returns whether all corner view rays intersect + /// with the Z plane. + virtual PlaneClass::IntersectionResType getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, Coord3D *bottomRight, Coord3D *bottomLeft, - Real z ); + Real z, ViewportClass viewPort = ViewportClass() ); virtual void setWidth( Int width ) { m_width = width; } virtual Int getWidth() { return m_width; } @@ -240,8 +243,12 @@ class View : public Snapshot Bool worldToScreen( const Coord3D *w, ICoord2D *s ) { return worldToScreenTriReturn( w, s ) == WTS_INSIDE_FRUSTUM; } ///< Transform world coordinate "w" into screen coordinate "s" virtual WorldToScreenReturn worldToScreenTriReturn(const Coord3D *w, ICoord2D *s ) = 0; ///< Like worldToScreen(), but with a more informative return value - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) = 0; ///< transform screen coord to a point on the 3D terrain - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) = 0; ///< transform screen point to world point at the specified world Z value + + /// Transform screen point to the viewed world position on the 3D terrain. Returns true when intersection exists. + virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) = 0; + + /// Transform screen point to the viewed world position at the specified world Z height. Returns the type of the intersection. + virtual PlaneClass::IntersectionResType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) = 0; virtual void getLocation ( ViewLocation *location ); ///< write the view's current location in to the view location object virtual void setLocation ( const ViewLocation *location ); ///< set the view's current location from to the view location object @@ -405,8 +412,8 @@ class ViewDummy : public View { return WTS_INVALID; } - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) override {} - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override {} + virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) override { return false; } + virtual PlaneClass::IntersectionResType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) override { return PlaneClass::NO_INTERSECTION; } virtual void drawView() override {} virtual void updateView() override {} virtual void stepView() override {} diff --git a/Core/GameEngine/Include/GameClient/WindowVideoManager.h b/Core/GameEngine/Include/GameClient/WindowVideoManager.h index e6a648b93a7..749965eafb1 100644 --- a/Core/GameEngine/Include/GameClient/WindowVideoManager.h +++ b/Core/GameEngine/Include/GameClient/WindowVideoManager.h @@ -156,7 +156,7 @@ class WindowVideoManager : public SubsystemInterface } }; - typedef std::hash_map< ConstGameWindowPtr, WindowVideo *, hashConstGameWindowPtr, std::equal_to > WindowVideoMap; + typedef std::hash_map< ConstGameWindowPtr, WindowVideo *, hashConstGameWindowPtr, std::equal_to/**/> WindowVideoMap; WindowVideoMap m_playingVideos; ///< List of currently playin Videos //WindowVideoMap m_pausedVideos; ///< List of currently paused Videos diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/WindowXlat.h b/Core/GameEngine/Include/GameClient/WindowXlat.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameClient/WindowXlat.h rename to Core/GameEngine/Include/GameClient/WindowXlat.h diff --git a/Core/GameEngine/Source/Common/Audio/GameAudio.cpp b/Core/GameEngine/Source/Common/Audio/GameAudio.cpp index c1df413bb7a..8daa245df69 100644 --- a/Core/GameEngine/Source/Common/Audio/GameAudio.cpp +++ b/Core/GameEngine/Source/Common/Audio/GameAudio.cpp @@ -443,7 +443,7 @@ AudioHandle AudioManager::addAudioEvent(const AudioEventRTS *eventToAdd) eventToAdd->setPlayingAudioIndex( audioEvent->getPlayingAudioIndex() ); audioEvent->generatePlayInfo(); // generate pitch shift and volume shift now as well - std::list >::iterator it; + std::list/**/>::iterator it; for (it = m_adjustedVolumes.begin(); it != m_adjustedVolumes.end(); ++it) { if (it->first == audioEvent->getEventName()) { audioEvent->setVolume(it->second); @@ -601,7 +601,7 @@ void AudioManager::setAudioEventVolumeOverride( AsciiString eventToAffect, Real adjustVolumeOfPlayingAudio(eventToAffect, newVolume); } - std::list >::iterator it; + std::list/**/>::iterator it; for (it = m_adjustedVolumes.begin(); it != m_adjustedVolumes.end(); ++it) { if (it->first == eventToAffect) { if (newVolume == -1.0f) { diff --git a/Core/GameEngine/Source/Common/Audio/GameSounds.cpp b/Core/GameEngine/Source/Common/Audio/GameSounds.cpp index c1f1afeedfe..542135d7506 100644 --- a/Core/GameEngine/Source/Common/Audio/GameSounds.cpp +++ b/Core/GameEngine/Source/Common/Audio/GameSounds.cpp @@ -92,8 +92,7 @@ void SoundManager::update() //------------------------------------------------------------------------------------------------- void SoundManager::reset() { - m_numPlaying2DSamples = 0; - m_numPlaying3DSamples = 0; + } //------------------------------------------------------------------------------------------------- @@ -135,11 +134,6 @@ Real SoundManager::getCameraAudibleDistance() //------------------------------------------------------------------------------------------------- void SoundManager::addAudioEvent(AudioEventRTS *&eventToAdd) { - if (m_num2DSamples == 0 && m_num3DSamples == 0) { - m_num2DSamples = TheAudio->getNum2DSamples(); - m_num3DSamples = TheAudio->getNum3DSamples(); - } - if (canPlayNow(eventToAdd)) { #ifdef INTENSIVE_AUDIO_DEBUG DEBUG_LOG((" - appended to request list with handle '%d'.", (UnsignedInt) eventToAdd->getPlayingHandle())); @@ -153,46 +147,6 @@ void SoundManager::addAudioEvent(AudioEventRTS *&eventToAdd) } } -//------------------------------------------------------------------------------------------------- -void SoundManager::notifyOf2DSampleStart() -{ - ++m_numPlaying2DSamples; -} - -//------------------------------------------------------------------------------------------------- -void SoundManager::notifyOf3DSampleStart() -{ - ++m_numPlaying3DSamples; -} - -//------------------------------------------------------------------------------------------------- -void SoundManager::notifyOf2DSampleCompletion() -{ - if (m_numPlaying2DSamples > 0) { - --m_numPlaying2DSamples; - } -} - -//------------------------------------------------------------------------------------------------- -void SoundManager::notifyOf3DSampleCompletion() -{ - if (m_numPlaying3DSamples > 0) { - --m_numPlaying3DSamples; - } -} - -//------------------------------------------------------------------------------------------------- -Int SoundManager::getAvailableSamples() -{ - return (m_num2DSamples - m_numPlaying2DSamples); -} - -//------------------------------------------------------------------------------------------------- -Int SoundManager::getAvailable3DSamples() -{ - return (m_num3DSamples - m_numPlaying3DSamples); -} - //------------------------------------------------------------------------------------------------- AsciiString SoundManager::getFilenameForPlayFromAudioEvent( const AudioEventRTS *eventToGetFrom ) { @@ -272,18 +226,19 @@ Bool SoundManager::canPlayNow( AudioEventRTS *event ) if (event->isPositionalAudio()) { - if (m_numPlaying3DSamples < m_num3DSamples) + if (TheAudio->getNumAvailable3DSamples() > 0) { return true; } #ifdef INTENSIVE_AUDIO_DEBUG - DEBUG_LOG(("- %d samples playing, %d samples available", m_numPlaying3DSamples, m_num3DSamples)); + DEBUG_LOG(("- %d samples playing, %d samples available", + TheAudio->getNum3DSamples() - TheAudio->getNumAvailable3DSamples(), TheAudio->getNum3DSamples())); #endif } else { // its a UI sound (and thus, 2-D) - if (m_numPlaying2DSamples < m_num2DSamples) + if (TheAudio->getNumAvailable2DSamples() > 0) { return true; } diff --git a/Core/GameEngine/Source/Common/System/GameMemory.cpp b/Core/GameEngine/Source/Common/System/GameMemory.cpp index 7ea2f799b8c..74d210d18fa 100644 --- a/Core/GameEngine/Source/Common/System/GameMemory.cpp +++ b/Core/GameEngine/Source/Common/System/GameMemory.cpp @@ -184,7 +184,7 @@ DECLARE_PERF_TIMER(MemoryPoolInitFilling) Int used, peak, waste, peakwaste; UsedNPeak() : used(0), peak(0), waste(0), peakwaste(0) { } }; - typedef std::map< const char*, UsedNPeak, std::less > UsedNPeakMap; + typedef std::map< const char*, UsedNPeak, std::less/**/> UsedNPeakMap; static UsedNPeakMap TheUsedNPeakMap; static Int doingIntenseDMA = 0; #endif diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClientDispatch.cpp b/Core/GameEngine/Source/GameClient/GameClientDispatch.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/GameClientDispatch.cpp rename to Core/GameEngine/Source/GameClient/GameClientDispatch.cpp diff --git a/Core/GameEngine/Source/GameClient/MapUtil.cpp b/Core/GameEngine/Source/GameClient/MapUtil.cpp index b99e05c9959..9e20c39b051 100644 --- a/Core/GameEngine/Source/GameClient/MapUtil.cpp +++ b/Core/GameEngine/Source/GameClient/MapUtil.cpp @@ -761,7 +761,7 @@ Bool WouldMapTransfer( const AsciiString& mapName ) } //------------------------------------------------------------------------------------------------- -typedef std::set > MapNameList; +typedef std::set/**/> MapNameList; typedef std::map MapDisplayToFileNameList; static void buildMapListForNumPlayers(MapNameList &outMapNames, MapDisplayToFileNameList &outFileNames, Int numPlayers) diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp similarity index 99% rename from Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp index f8111dd0bd2..bb2c3ef8207 100644 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals(tm) +** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify @@ -3902,9 +3902,11 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage if( TheGlobalData->m_useAlternateMouse && TheGlobalData->m_doubleClickAttackMove ) { // create the message and append arguments for a guard location - GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); + if( !TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ) ) + break; + + GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); newMsg->appendLocationArgument(pos); newMsg->appendIntegerArgument(GUARDMODE_NORMAL); @@ -3922,8 +3924,6 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage if (TheGlobalData->m_useAlternateMouse && TheMouse->isClick(&m_mouseRightDragAnchor, &m_mouseRightDragLift, m_mouseRightDown, m_mouseRightUp)) { - Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); - // NOTE: RIGHT_CLICK is not transmitted if AREA_SELECTION or DRAWABLE_PICKED occurs. // If we see this msg, no object was clicked on, therefore clicked on ground. // Issue move command to all currently selected objects. @@ -3934,9 +3934,11 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage // translate from screen coordinates to terrain coords Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); + if( !TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ) ) + break; const CommandButton *command = TheInGameUI->getGUICommand(); + Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); Bool controllable = TheInGameUI->areSelectedObjectsControllable() || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT); if (isPoint && controllable) @@ -3973,9 +3975,11 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage if( !TheGlobalData->m_useAlternateMouse && TheGlobalData->m_doubleClickAttackMove ) { // create the message and append arguments for a guard location - GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); + if( !TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ) ) + break; + + GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); newMsg->appendLocationArgument(pos); newMsg->appendIntegerArgument(GUARDMODE_NORMAL); @@ -3989,8 +3993,6 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage } case GameMessage::MSG_MOUSE_LEFT_CLICK: { - Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); - // NOTE: LEFT_CLICK is not transmitted if AREA_SELECTION or DRAWABLE_PICKED occurs. // If we see this msg, no object was clicked on, therefore clicked on ground. // Issue move command to all currently selected objects. @@ -4001,7 +4003,8 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage // translate from screen coordinates to terrain coords Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); + if( !TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ) ) + break; const CommandButton *command = TheInGameUI->getGUICommand(); // maintain this as the list of GUI button initiated commands that fire with left click in alt mouse mode @@ -4016,6 +4019,7 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage if ((TheGlobalData->m_useAlternateMouse) && (! isFiringGUICommand)) break; + Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); Bool controllable = TheInGameUI->areSelectedObjectsControllable() || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT); if (isPoint && controllable) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp b/Core/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp similarity index 95% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp index d37d7f51dec..76a6054ed9d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp @@ -141,7 +141,8 @@ static CommandStatus doFireWeaponCommand( const CommandButton *command, const IC Coord3D world; // translate the mouse location into world coords - TheTacticalView->screenToTerrain( mouse, &world ); + if( !TheTacticalView->screenToTerrain( mouse, &world ) ) + return COMMAND_COMPLETE; // create the message and append arguments msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_WEAPON_AT_LOCATION ); @@ -153,8 +154,6 @@ static CommandStatus doFireWeaponCommand( const CommandButton *command, const IC Object *target = validUnderCursor( mouse, command, PICK_TYPE_SELECTABLE ); ObjectID targetID = target ? target->getID() : INVALID_ID; msg->appendObjectIDArgument( targetID ); - - } else if( BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) { @@ -233,7 +232,8 @@ static CommandStatus doGuardCommand( const CommandButton *command, GuardMode gua if (BitIsSet( command->getOptions(), NEED_TARGET_POS )) { // translate the mouse location into world coords - TheTacticalView->screenToTerrain( mouse, &world ); + if( !TheTacticalView->screenToTerrain( mouse, &world ) ) + return COMMAND_COMPLETE; } else { @@ -277,7 +277,8 @@ static CommandStatus doAttackMoveCommand( const CommandButton *command, const IC // convert mouse point to world coords Coord3D world; - TheTacticalView->screenToTerrain( mouse, &world ); + if( !TheTacticalView->screenToTerrain( mouse, &world ) ) + return COMMAND_COMPLETE; // send the message to set the rally point GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_ATTACKMOVETO ); @@ -316,7 +317,8 @@ static CommandStatus doSetRallyPointCommand( const CommandButton *command, const // convert mouse point to world coords Coord3D world; - TheTacticalView->screenToTerrain( mouse, &world ); + if( !TheTacticalView->screenToTerrain( mouse, &world ) ) + return COMMAND_COMPLETE; // send the message to set the rally point GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_SET_RALLY_POINT ); @@ -339,7 +341,8 @@ static CommandStatus doPlaceBeacon( const CommandButton *command, const ICoord2D // convert mouse point to world coords Coord3D world; - TheTacticalView->screenToTerrain( mouse, &world ); + if( !TheTacticalView->screenToTerrain( mouse, &world ) ) + return COMMAND_COMPLETE; // send the message to set the rally point GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_PLACE_BEACON ); @@ -414,12 +417,13 @@ GameMessageDisposition GUICommandTranslator::translateGameMessage(const GameMess if (BitIsSet(command->getOptions(), NEED_TARGET_POS)) { Coord3D worldPos; - TheTacticalView->screenToTerrain(&mouse, &worldPos); - - GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_EVACUATE); - msg->appendLocationArgument(worldPos); + if( TheTacticalView->screenToTerrain(&mouse, &worldPos) ) + { + GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_EVACUATE); + msg->appendLocationArgument(worldPos); - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_EVACUATE ); + pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_EVACUATE ); + } commandStatus = COMMAND_COMPLETE; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp b/Core/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp similarity index 99% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp index 615a1aa94c4..29094f59a69 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp @@ -78,7 +78,9 @@ GameMessageDisposition HintSpyTranslator::translateGameMessage(const GameMessage case GameMessage::MSG_RESUME_CONSTRUCTION_HINT: case GameMessage::MSG_ENTER_HINT: case GameMessage::MSG_HIJACK_HINT: +#ifdef RTS_ZEROHOUR case GameMessage::MSG_SABOTAGE_HINT: +#endif case GameMessage::MSG_CONVERT_TO_CARBOMB_HINT: #ifdef ALLOW_SURRENDER case GameMessage::MSG_PICK_UP_PRISONER_HINT: diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp b/Core/GameEngine/Source/GameClient/MessageStream/HotKey.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/HotKey.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp b/Core/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp similarity index 99% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp index e920d40a8e6..28f0fa8a247 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp @@ -182,7 +182,9 @@ static const LookupListRec GameMessageMetaTypeNames[] = { "BEGIN_CAMERA_ZOOM_OUT", GameMessage::MSG_META_BEGIN_CAMERA_ZOOM_OUT }, { "END_CAMERA_ZOOM_OUT", GameMessage::MSG_META_END_CAMERA_ZOOM_OUT }, { "CAMERA_RESET", GameMessage::MSG_META_CAMERA_RESET }, +#ifdef RTS_ZEROHOUR { "TOGGLE_CAMERA_TRACKING_DRAWABLE", GameMessage::MSG_META_TOGGLE_CAMERA_TRACKING_DRAWABLE }, +#endif { "TOGGLE_FAST_FORWARD_REPLAY", GameMessage::MSG_META_TOGGLE_FAST_FORWARD_REPLAY }, { "TOGGLE_PAUSE", GameMessage::MSG_META_TOGGLE_PAUSE }, { "TOGGLE_PAUSE_ALT", GameMessage::MSG_META_TOGGLE_PAUSE_ALT }, diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp b/Core/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp similarity index 95% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp index 0d6999bbd98..e8ba80411eb 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp @@ -80,7 +80,11 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess Coord3D world; // translate mouse position to world position - TheTacticalView->screenToTerrain( &mouse, &world ); + if( !TheTacticalView->screenToTerrain( &mouse, &world ) ) + { + TheInGameUI->placeBuildAvailable( nullptr, nullptr ); + break; + } // // placing things causes a dozer to go over and build it ... get the dozer in question @@ -163,8 +167,7 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess if (build && TheInGameUI->isPlacementAnchored()) { GameMessage *placeMsg; -// Player *player = ThePlayerList->getLocalPlayer(); - Coord3D world; + Coord3D worldStart, worldEnd; Real angle; ICoord2D anchorStart, anchorEnd; Bool isLineBuild = TheBuildAssistant->isLineBuildTemplate( build ); @@ -176,7 +179,11 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess TheInGameUI->getPlacementPoints( &anchorStart, &anchorEnd ); // translate the screen position of start to world target location - TheTacticalView->screenToTerrain( &anchorStart, &world ); + if( !TheTacticalView->screenToTerrain( &anchorStart, &worldStart ) ) + break; + + if( isLineBuild && !TheTacticalView->screenToTerrain( &anchorEnd, &worldEnd ) ) + break; Object *builderObj = TheGameLogic->findObjectByID( TheInGameUI->getPendingPlaceSourceObjectID() ); @@ -217,7 +224,7 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess // check to see if this is a legal location to build something at LegalBuildCode lbc; - lbc = TheBuildAssistant->isLocationLegalToBuild( &world, + lbc = TheBuildAssistant->isLocationLegalToBuild( &worldStart, build, angle, BuildAssistant::USE_QUICK_PATHFIND | @@ -244,7 +251,7 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess //dozer/worker. placeMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_SPECIAL_POWER_AT_LOCATION ); placeMsg->appendIntegerArgument( commandButton->getSpecialPowerTemplate()->getID() ); //The ID of the special power template. - placeMsg->appendLocationArgument( world ); //Position of special to be fired. + placeMsg->appendLocationArgument( worldStart ); //Position of special to be fired. placeMsg->appendRealArgument( angle ); //Angle of special to be fired. placeMsg->appendObjectIDArgument( INVALID_ID ); //There is no object in the way. placeMsg->appendIntegerArgument( commandButton->getOptions() ); //Command button options. @@ -268,15 +275,11 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess placeMsg = TheMessageStream->appendMessage( GameMessage::MSG_DOZER_CONSTRUCT ); placeMsg->appendIntegerArgument(build->getTemplateID()); - placeMsg->appendLocationArgument(world); + placeMsg->appendLocationArgument(worldStart); placeMsg->appendRealArgument(angle); if( isLineBuild ) { - Coord3D worldEnd; - - TheTacticalView->screenToTerrain( &anchorEnd, &worldEnd ); placeMsg->appendLocationArgument( worldEnd ); - } pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), placeMsg->getType() ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp similarity index 99% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp index caca08f832a..7bacb8d956a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp @@ -450,9 +450,11 @@ GameMessageDisposition SelectionTranslator::translateGameMessage(const GameMessa { Coord3D position; - TheTacticalView->screenToTerrain( &pixel, &position ); - mouseoverMessage = TheMessageStream->appendMessage( GameMessage::MSG_MOUSEOVER_LOCATION_HINT ); - mouseoverMessage->appendLocationArgument( position ); + if( TheTacticalView->screenToTerrain( &pixel, &position ) ) + { + mouseoverMessage = TheMessageStream->appendMessage( GameMessage::MSG_MOUSEOVER_LOCATION_HINT ); + mouseoverMessage->appendLocationArgument( position ); + } } } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp diff --git a/Core/GameEngine/Source/GameClient/View.cpp b/Core/GameEngine/Source/GameClient/View.cpp index f4067dc7e97..bc639da6b2e 100644 --- a/Core/GameEngine/Source/GameClient/View.cpp +++ b/Core/GameEngine/Source/GameClient/View.cpp @@ -248,13 +248,12 @@ Bool View::isUserControlLocked() const /** project the 4 corners of this view into the world and return each point as a parameter, the world points are at the requested Z */ //------------------------------------------------------------------------------------------------- -void View::getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, +PlaneClass::IntersectionResType View::getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, Coord3D *bottomRight, Coord3D *bottomLeft, - Real z ) + Real z, ViewportClass viewPort ) { - // sanity if( topLeft == nullptr || topRight == nullptr || bottomRight == nullptr || bottomLeft == nullptr) - return; + return PlaneClass::NO_INTERSECTION; ICoord2D screenTopLeft; ICoord2D screenTopRight; @@ -267,20 +266,36 @@ void View::getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, // setup the screen coords for the 4 corners of the viewable display getOrigin( &origin.x, &origin.y ); - screenTopLeft.x = origin.x; - screenTopLeft.y = origin.y; - screenTopRight.x = origin.x + viewWidth; - screenTopRight.y = origin.y; - screenBottomRight.x = origin.x + viewWidth; - screenBottomRight.y = origin.y + viewHeight; - screenBottomLeft.x = origin.x; - screenBottomLeft.y = origin.y + viewHeight; - - // project - screenToWorldAtZ( &screenTopLeft, topLeft, z ); - screenToWorldAtZ( &screenTopRight, topRight, z ); - screenToWorldAtZ( &screenBottomRight, bottomRight, z ); - screenToWorldAtZ( &screenBottomLeft, bottomLeft, z ); + screenTopLeft.x = origin.x + viewWidth * viewPort.Min.X; + screenTopLeft.y = origin.y + viewHeight * viewPort.Min.Y; + screenTopRight.x = origin.x + viewWidth * viewPort.Max.X; + screenTopRight.y = origin.y + viewHeight * viewPort.Min.Y; + screenBottomRight.x = origin.x + viewWidth * viewPort.Max.X; + screenBottomRight.y = origin.y + viewHeight * viewPort.Max.Y; + screenBottomLeft.x = origin.x + viewWidth * viewPort.Min.X; + screenBottomLeft.y = origin.y + viewHeight * viewPort.Max.Y; + + PlaneClass::IntersectionResType combinedResult = PlaneClass::INSIDE_SEGMENT; + PlaneClass::IntersectionResType individualResults[4]; + individualResults[0] = screenToWorldAtZ( &screenTopLeft, topLeft, z ); + individualResults[1] = screenToWorldAtZ( &screenTopRight, topRight, z ); + individualResults[2] = screenToWorldAtZ( &screenBottomRight, bottomRight, z ); + individualResults[3] = screenToWorldAtZ( &screenBottomLeft, bottomLeft, z ); + + for( Int i = 0; i < 4; ++i ) + { + if( individualResults[i] == PlaneClass::NO_INTERSECTION ) + { + combinedResult = PlaneClass::NO_INTERSECTION; + break; + } + if( individualResults[i] == PlaneClass::OUTSIDE_LINE ) + { + combinedResult = PlaneClass::OUTSIDE_LINE; + } + } + + return combinedResult; } // ------------------------------------------------------------------------------------------------ diff --git a/Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h b/Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h index 2ba3483d23f..32ea80a3498 100644 --- a/Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h +++ b/Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h @@ -103,7 +103,7 @@ struct OpenAudioFile const AudioEventInfo *m_eventInfo; // Not mutable, unlike the one on AudioEventRTS. }; -typedef std::hash_map< AsciiString, OpenAudioFile, rts::hash, rts::equal_to > OpenFilesHash; +typedef std::hash_map< AsciiString, OpenAudioFile, rts::hash, rts::equal_to/**/> OpenFilesHash; typedef OpenFilesHash::iterator OpenFilesHashIt; class AudioFileCache @@ -195,6 +195,8 @@ class MilesAudioManager : public AudioManager virtual UnsignedInt getNum2DSamples() const override; virtual UnsignedInt getNum3DSamples() const override; virtual UnsignedInt getNumStreams() const override; + virtual UnsignedInt getNumAvailable2DSamples() const override; + virtual UnsignedInt getNumAvailable3DSamples() const override; virtual Bool doesViolateLimit( AudioEventRTS *event ) const override; virtual Bool isPlayingLowerPriority( AudioEventRTS *event ) const override; @@ -272,8 +274,8 @@ class MilesAudioManager : public AudioManager void stopAllAudioImmediately(); void freeAllMilesHandles(); - HSAMPLE getFirst2DSample( AudioEventRTS *event ); - H3DSAMPLE getFirst3DSample( AudioEventRTS *event ); + HSAMPLE getAvailable2DSample( AudioEventRTS *event ); + H3DSAMPLE getAvailable3DSample( AudioEventRTS *event ); void adjustPlayingVolume( PlayingAudio *audio ); @@ -301,8 +303,8 @@ class MilesAudioManager : public AudioManager // Available handles for play. Note that there aren't handles open in advance for // streaming things, only 2-D and 3-D sounds. - std::list m_availableSamples; - std::list m_available3DSamples; + std::vector m_availableSamples; + std::vector m_available3DSamples; // Currently Playing audio. Useful if we have to preempt it. // This should rarely if ever happen, as we mirror this in Sounds, and attempt to @@ -368,6 +370,8 @@ class MilesAudioManagerDummy : public MilesAudioManager virtual UnsignedInt getNum2DSamples() const override { return 0; } virtual UnsignedInt getNum3DSamples() const override { return 0; } virtual UnsignedInt getNumStreams() const override { return 0; } + virtual UnsignedInt getNumAvailable2DSamples() const override { return 0; } + virtual UnsignedInt getNumAvailable3DSamples() const override { return 0; } virtual Bool doesViolateLimit(AudioEventRTS* event) const override { return false; } virtual Bool isPlayingLowerPriority(AudioEventRTS* event) const override { return false; } virtual Bool isPlayingAlready(AudioEventRTS* event) const override { return false; } diff --git a/Core/GameEngineDevice/Include/MiniAudioDevice/MiniAudioManager.h b/Core/GameEngineDevice/Include/MiniAudioDevice/MiniAudioManager.h index 931c55401c9..9b9e0fcf6e7 100644 --- a/Core/GameEngineDevice/Include/MiniAudioDevice/MiniAudioManager.h +++ b/Core/GameEngineDevice/Include/MiniAudioDevice/MiniAudioManager.h @@ -122,6 +122,8 @@ class MiniAudioManager : public AudioManager virtual UnsignedInt getNum2DSamples(void) const; virtual UnsignedInt getNum3DSamples(void) const; virtual UnsignedInt getNumStreams(void) const; + virtual UnsignedInt getNumAvailable2DSamples() const; + virtual UnsignedInt getNumAvailable3DSamples() const; virtual Bool doesViolateLimit(AudioEventRTS *event) const; virtual Bool isPlayingLowerPriority(AudioEventRTS *event) const; diff --git a/Core/GameEngineDevice/Include/OpenALAudioDevice/OpenALAudioManager.h b/Core/GameEngineDevice/Include/OpenALAudioDevice/OpenALAudioManager.h index 95c543ecf96..eedb1adaf38 100644 --- a/Core/GameEngineDevice/Include/OpenALAudioDevice/OpenALAudioManager.h +++ b/Core/GameEngineDevice/Include/OpenALAudioDevice/OpenALAudioManager.h @@ -121,6 +121,8 @@ friend class OpenALAudioFileCache; virtual UnsignedInt getNum2DSamples(void) const; virtual UnsignedInt getNum3DSamples(void) const; virtual UnsignedInt getNumStreams(void) const; + virtual UnsignedInt getNumAvailable2DSamples() const; + virtual UnsignedInt getNumAvailable3DSamples() const; virtual Bool doesViolateLimit(AudioEventRTS *event) const; virtual Bool isPlayingLowerPriority(AudioEventRTS *event) const; diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h index e2f590b67fa..9defb85d715 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DModelDraw.h @@ -135,7 +135,7 @@ struct PristineBoneInfo Int boneIndex; }; //typedef std::hash_map< NameKeyType, PristineBoneInfo, rts::hash, rts::equal_to > PristineBoneInfoMap; -typedef std::map< NameKeyType, PristineBoneInfo, std::less > PristineBoneInfoMap; +typedef std::map< NameKeyType, PristineBoneInfo, std::less/**/> PristineBoneInfoMap; //------------------------------------------------------------------------------------------------- @@ -268,7 +268,7 @@ typedef std::vector ModelConditionVector; //------------------------------------------------------------------------------------------------- //typedef std::hash_map< TransitionSig, ModelConditionInfo, std::hash, std::equal_to > TransitionMap; -typedef std::map< TransitionSig, ModelConditionInfo, std::less > TransitionMap; +typedef std::map< TransitionSig, ModelConditionInfo, std::less/**/> TransitionMap; //------------------------------------------------------------------------------------------------- // this is more efficient and also helps solve a projectile-launch-offset problem for double-upgraded diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h index da99cad16a9..df899b086f4 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h @@ -219,8 +219,8 @@ class W3DView : public View, public SubsystemInterface virtual void setFieldOfView( Real angle ) override; ///< Set the horizontal field of view angle virtual WorldToScreenReturn worldToScreenTriReturn( const Coord3D *w, ICoord2D *s ) override; ///< Transform world coordinate "w" into screen coordinate "s" - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) override; ///< transform screen coord to a point on the 3D terrain - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override; ///< transform screen point to world point at the specified world Z value + virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) override; + virtual PlaneClass::IntersectionResType screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) override; CameraClass *get3DCamera() const { return m_3DCamera; } diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h index a0ba2d832a9..5cfdcf6cc22 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/WorldHeightMap.h @@ -247,6 +247,8 @@ class WorldHeightMap : public RefCountClass, Int getXExtent() {return m_width;} ///printf("Speech: %s ", (isOn(AudioAffect_Speech) ? "Yes" : "No")); dd->printf("Music: %s\n", (isOn(AudioAffect_Music) ? "Yes" : "No")); dd->printf("Channels Available: "); - dd->printf("%d Sounds ", m_sound->getAvailableSamples()); - - dd->printf("%d(%d) 3D Sounds\n", m_sound->getAvailable3DSamples(), m_available3DSamples.size() ); + dd->printf("%u Sounds ", getNumAvailable2DSamples()); + dd->printf("%u 3D Sounds\n", getNumAvailable3DSamples()); dd->printf("Volume: "); dd->printf("Sound: %d ", REAL_TO_INT(m_soundVolume * 100.0f)); dd->printf("3DSound: %d ", REAL_TO_INT(m_sound3DVolume * 100.0f)); @@ -200,8 +199,8 @@ void MilesAudioManager::audioDebugDisplay(DebugDisplayInterface *dd, void *, FIL fprintf( fp, "Speech: %s ", (isOn(AudioAffect_Speech) ? "Yes" : "No") ); fprintf( fp, "Music: %s\n", (isOn(AudioAffect_Music) ? "Yes" : "No") ); fprintf( fp, "Channels Available: " ); - fprintf( fp, "%d Sounds ", m_sound->getAvailableSamples() ); - fprintf( fp, "%d 3D Sounds\n", m_sound->getAvailable3DSamples() ); + fprintf( fp, "%u Sounds ", getNumAvailable2DSamples() ); + fprintf( fp, "%u 3D Sounds\n", getNumAvailable3DSamples() ); fprintf( fp, "Volume: "); fprintf( fp, "Sound: %d ", REAL_TO_INT(m_soundVolume * 100.0f) ); fprintf( fp, "3DSound: %d ", REAL_TO_INT(m_sound3DVolume * 100.0f) ); @@ -715,7 +714,7 @@ void MilesAudioManager::playAudioEvent( AudioEventRTS *event ) H3DSAMPLE sample3D; if( !handleToKill || foundSoundToReplace ) { - sample3D = getFirst3DSample( event ); + sample3D = getAvailable3DSample( event ); if( !sample3D ) { //If we don't have an available sample, kill the lowest priority assuming we have one that is lower @@ -724,7 +723,7 @@ void MilesAudioManager::playAudioEvent( AudioEventRTS *event ) //in which case we need to attempt to find another sound to kill. if( killLowestPrioritySoundImmediately( event ) ) { - sample3D = getFirst3DSample( event ); + sample3D = getAvailable3DSample( event ); } } } @@ -740,7 +739,6 @@ void MilesAudioManager::playAudioEvent( AudioEventRTS *event ) if (sample3D) { audio->m_file = playSample3D(event, sample3D); - m_sound->notifyOf3DSampleStart(); } if( !audio->m_file ) @@ -781,7 +779,7 @@ void MilesAudioManager::playAudioEvent( AudioEventRTS *event ) HSAMPLE sample; if( !handleToKill || foundSoundToReplace ) { - sample = getFirst2DSample(event); + sample = getAvailable2DSample(event); if( !sample ) { //If we don't have an available sample, kill the lowest priority assuming we have one that is lower @@ -790,7 +788,7 @@ void MilesAudioManager::playAudioEvent( AudioEventRTS *event ) //in which case we need to attempt to find another sound to kill. if( killLowestPrioritySoundImmediately( event ) ) { - sample = getFirst2DSample( event ); + sample = getAvailable2DSample( event ); } } } @@ -807,7 +805,6 @@ void MilesAudioManager::playAudioEvent( AudioEventRTS *event ) if (sample) { audio->m_file = playSample(event, sample); - m_sound->notifyOf2DSampleStart(); } if (!audio->m_file) { @@ -1042,17 +1039,6 @@ void MilesAudioManager::stopPlayingAudio( PlayingAudio *release ) if (prevStatus != PS_Stopping) { return; } - if (release->m_audioEventRTS->getAudioEventInfo()->m_soundType == AT_SoundEffect) { - if (release->m_type == PAT_Sample) { - if (release->m_sample) { - m_sound->notifyOf2DSampleCompletion(); - } - } else { - if (release->m_3DSample) { - m_sound->notifyOf3DSampleCompletion(); - } - } - } releaseMilesHandles(release); } @@ -1175,48 +1161,47 @@ void MilesAudioManager::freeAllMilesHandles() stopAllAudioImmediately(); // Walks through the available 2-D and 3-D handles and releases them - std::list::iterator it; - for ( it = m_availableSamples.begin(); it != m_availableSamples.end(); ) { - HSAMPLE sample = *it; - AIL_release_sample_handle(sample); - it = m_availableSamples.erase(it); + std::vector::iterator it; + for ( it = m_availableSamples.begin(); it != m_availableSamples.end(); ++it ) { + AIL_release_sample_handle(*it); } + + m_availableSamples.clear(); m_num2DSamples = 0; - std::list::iterator it3D; - for ( it3D = m_available3DSamples.begin(); it3D != m_available3DSamples.end(); ) { - H3DSAMPLE sample3D = *it3D; - AIL_release_3D_sample_handle(sample3D); - it3D = m_available3DSamples.erase(it3D); + std::vector::iterator it3D; + for ( it3D = m_available3DSamples.begin(); it3D != m_available3DSamples.end(); ++it3D ) { + AIL_release_3D_sample_handle(*it3D); } + + m_available3DSamples.clear(); m_num3DSamples = 0; m_numStreams = 0; } //------------------------------------------------------------------------------------------------- -HSAMPLE MilesAudioManager::getFirst2DSample( AudioEventRTS *event ) +HSAMPLE MilesAudioManager::getAvailable2DSample( AudioEventRTS *event ) { - if (m_availableSamples.begin() != m_availableSamples.end()) { - HSAMPLE retSample = *m_availableSamples.begin(); - m_availableSamples.erase(m_availableSamples.begin()); - return (retSample); + if (!m_availableSamples.empty()) { + HSAMPLE retSample = m_availableSamples.back(); + m_availableSamples.pop_back(); + return retSample; } - // Find the first sample of lower priority than my augmented priority that is interruptable and take its handle - + // Find the first sample of lower priority than my augmented priority that is interruptible and take its handle return nullptr; } //------------------------------------------------------------------------------------------------- -H3DSAMPLE MilesAudioManager::getFirst3DSample( AudioEventRTS *event ) +H3DSAMPLE MilesAudioManager::getAvailable3DSample( AudioEventRTS *event ) { - if (m_available3DSamples.begin() != m_available3DSamples.end()) { - H3DSAMPLE retSample = *m_available3DSamples.begin(); - m_available3DSamples.erase(m_available3DSamples.begin()); - return (retSample); + if (!m_available3DSamples.empty()) { + H3DSAMPLE retSample = m_available3DSamples.back(); + m_available3DSamples.pop_back(); + return retSample; } - // Find the first sample of lower priority than my augmented priority that is interruptable and take its handle + // Find the first sample of lower priority than my augmented priority that is interruptible and take its handle return nullptr; } @@ -1755,6 +1740,18 @@ UnsignedInt MilesAudioManager::getNumStreams() const return m_numStreams; } +//------------------------------------------------------------------------------------------------- +UnsignedInt MilesAudioManager::getNumAvailable2DSamples() const +{ + return (UnsignedInt)m_availableSamples.size(); +} + +//------------------------------------------------------------------------------------------------- +UnsignedInt MilesAudioManager::getNumAvailable3DSamples() const +{ + return (UnsignedInt)m_available3DSamples.size(); +} + //------------------------------------------------------------------------------------------------- Bool MilesAudioManager::doesViolateLimit( AudioEventRTS *event ) const { @@ -2769,6 +2766,9 @@ void MilesAudioManager::initSamplePools() return; } + m_availableSamples.reserve(getAudioSettings()->m_sampleCount2D); + m_available3DSamples.reserve(getAudioSettings()->m_sampleCount3D); + int i = 0; for (i = 0; i < getAudioSettings()->m_sampleCount2D; ++i) { HSAMPLE sample = AIL_allocate_sample_handle(m_digitalHandle); @@ -2825,7 +2825,7 @@ void *MilesAudioManager::getHandleForBink() PlayingAudio *aud = allocatePlayingAudio(); aud->m_audioEventRTS = NEW AudioEventRTS("BinkHandle"); // poolify getInfoForAudioEvent(aud->m_audioEventRTS); - aud->m_sample = getFirst2DSample(aud->m_audioEventRTS); + aud->m_sample = getAvailable2DSample(aud->m_audioEventRTS); aud->m_type = PAT_Sample; if (!aud->m_sample) { @@ -2884,7 +2884,7 @@ void MilesAudioManager::friend_forcePlayAudioEventRTS(const AudioEventRTS* event event.generateFilename(); event.generatePlayInfo(); - std::list >::iterator it; + std::list/**/>::iterator it; for (it = m_adjustedVolumes.begin(); it != m_adjustedVolumes.end(); ++it) { if (it->first == event.getEventName()) { event.setVolume(it->second); diff --git a/Core/GameEngineDevice/Source/MiniAudioDevice/MiniAudioManager.cpp b/Core/GameEngineDevice/Source/MiniAudioDevice/MiniAudioManager.cpp index 01ce398e6ab..d886ccf56fc 100644 --- a/Core/GameEngineDevice/Source/MiniAudioDevice/MiniAudioManager.cpp +++ b/Core/GameEngineDevice/Source/MiniAudioDevice/MiniAudioManager.cpp @@ -455,11 +455,11 @@ void MiniAudioManager::playAudioEvent(AudioEventRTS *event) if (pos) { ma_sound_set_position(sound, pos->x, pos->y, pos->z); } - m_sound->notifyOf3DSampleStart(); + } else { audio->m_type = PAT_Sample; - m_sound->notifyOf2DSampleStart(); + } break; } @@ -583,10 +583,10 @@ void MiniAudioManager::releasePlayingAudio(PlayingAudio *release) if (releaseInfo && releaseInfo->m_soundType == AT_SoundEffect && release->m_sound) { if (release->m_type == PAT_Sample) { - m_sound->notifyOf2DSampleCompletion(); + } else if (release->m_type == PAT_3DSample) { - m_sound->notifyOf3DSampleCompletion(); + } // PAT_Stream and PAT_INVALID don't notify } @@ -1567,3 +1567,21 @@ static ma_result vfsFileSeek(ma_vfs *pVFS, ma_vfs_file file, ma_int64 offset, ma handle->file->seek((Int)offset, seekType); return MA_SUCCESS; } + +//------------------------------------------------------------------------------------------------- +UnsignedInt MiniAudioManager::getNumAvailable2DSamples() const +{ + // GeneralsX @bugfix Mr. Meeseeks 27/06/2026 Fix available samples calculation to prevent voicelines culling + UnsignedInt max2D = getAudioSettings()->m_sampleCount2D; + UnsignedInt playing = (UnsignedInt)m_playingSounds.size(); + return (max2D > playing) ? (max2D - playing) : 0; +} + +//------------------------------------------------------------------------------------------------- +UnsignedInt MiniAudioManager::getNumAvailable3DSamples() const +{ + // GeneralsX @bugfix Mr. Meeseeks 27/06/2026 Fix available samples calculation to prevent voicelines culling + UnsignedInt max3D = getAudioSettings()->m_sampleCount3D; + UnsignedInt playing = (UnsignedInt)m_playingSounds.size(); + return (max3D > playing) ? (max3D - playing) : 0; +} diff --git a/Core/GameEngineDevice/Source/OpenALAudioDevice/OpenALAudioManager.cpp b/Core/GameEngineDevice/Source/OpenALAudioDevice/OpenALAudioManager.cpp index fad99e6acc1..aa7f91cc600 100644 --- a/Core/GameEngineDevice/Source/OpenALAudioDevice/OpenALAudioManager.cpp +++ b/Core/GameEngineDevice/Source/OpenALAudioDevice/OpenALAudioManager.cpp @@ -900,7 +900,7 @@ void OpenALAudioManager::playAudioEvent(AudioEventRTS* event) if (source) { audio->m_bufferHandle = playSample3D(event, audio); - m_sound->notifyOf3DSampleStart(); + } if (!audio->m_bufferHandle) @@ -960,7 +960,7 @@ void OpenALAudioManager::playAudioEvent(AudioEventRTS* event) if (source) { audio->m_bufferHandle = playSample(event, audio); - m_sound->notifyOf2DSampleStart(); + } if (!audio->m_bufferHandle) { @@ -1193,12 +1193,12 @@ void OpenALAudioManager::releasePlayingAudio(PlayingAudio* release) if (releaseInfo && releaseInfo->m_soundType == AT_SoundEffect) { if (release->m_type == PAT_Sample) { if (release->m_source) { - m_sound->notifyOf2DSampleCompletion(); + } } else { if (release->m_source) { - m_sound->notifyOf3DSampleCompletion(); + } } } @@ -3211,3 +3211,19 @@ void OpenALAudioManager::dumpAllAssetsUsed() logfile = NULL; } #endif + +//------------------------------------------------------------------------------------------------- +UnsignedInt OpenALAudioManager::getNumAvailable2DSamples() const +{ + // GeneralsX @bugfix Mr. Meeseeks 27/06/2026 Fix available samples calculation to prevent voicelines culling + UnsignedInt playing = (UnsignedInt)m_playingSounds.size(); + return (m_num2DSamples > playing) ? (m_num2DSamples - playing) : 0; +} + +//------------------------------------------------------------------------------------------------- +UnsignedInt OpenALAudioManager::getNumAvailable3DSamples() const +{ + // GeneralsX @bugfix Mr. Meeseeks 27/06/2026 Fix available samples calculation to prevent voicelines culling + UnsignedInt playing = (UnsignedInt)m_playing3DSounds.size(); + return (m_num3DSamples > playing) ? (m_num3DSamples - playing) : 0; +} diff --git a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp index b1517fa0766..6bea0317d30 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp @@ -186,19 +186,19 @@ void W3DRadar::deleteResources() //------------------------------------------------------------------------------------------------- void W3DRadar::reconstructViewBox() { + m_reconstructViewBox = FALSE; + Coord3D world[ 4 ]; ICoord2D radar[ 4 ]; Int i; - // get the 4 points of the view corners in the 3D world at the average Z height in the map + // Get the 4 points of the view corners in the 3D world at the average Z height in the map + // // 1-------2 // \ / // 4---3 - TheTacticalView->getScreenCornerWorldPointsAtZ( &world[ 0 ], - &world[ 1 ], - &world[ 2 ], - &world[ 3 ], - getTerrainAverageZ() ); + if( TheTacticalView->getScreenCornerWorldPointsAtZ(&world[0], &world[1], &world[2], &world[3], getTerrainAverageZ()) == PlaneClass::NO_INTERSECTION ) + return; // convert each of the 4 points in the world to radar cell positions for( i = 0; i < 4; i++ ) @@ -229,8 +229,6 @@ void W3DRadar::reconstructViewBox() } - m_reconstructViewBox = FALSE; - } //------------------------------------------------------------------------------------------------- @@ -290,8 +288,8 @@ void W3DRadar::drawViewBox( Int pixelX, Int pixelY, Int width, Int height ) ICoord2D ulScreen; ICoord2D ulRadar; Coord3D ulWorld; - ICoord2D ulStart = { 0, 0 }; - ICoord2D start, end; + ICoord2D ulPixel; + ICoord2D pixelStart, pixelEnd; ICoord2D clipStart, clipEnd; Real lineWidth = 1.0f; Color topColor = GameMakeColor( 225, 225, 0, 255 ); @@ -312,7 +310,8 @@ void W3DRadar::drawViewBox( Int pixelX, Int pixelY, Int width, Int height ) // convert top left of screen into world position TheTacticalView->getOrigin( &ulScreen.x, &ulScreen.y ); - TheTacticalView->screenToWorldAtZ( &ulScreen, &ulWorld, getTerrainAverageZ() ); + if( TheTacticalView->screenToWorldAtZ( &ulScreen, &ulWorld, getTerrainAverageZ() ) == PlaneClass::NO_INTERSECTION ) + return; // convert world to radar coords ulRadar.x = ulWorld.x / (m_mapExtent.width() / static_cast(RADAR_CELL_WIDTH)); @@ -323,7 +322,7 @@ void W3DRadar::drawViewBox( Int pixelX, Int pixelY, Int width, Int height ) // into position on the radar for where the radar is drawn and the size of the // area that the radar is drawn in // - radarToPixel( &ulRadar, &ulStart, pixelX, pixelY, width, height ); + radarToPixel( &ulRadar, &ulPixel, pixelX, pixelY, width, height ); // // using our view box offset array, convert each of those radar cell offset points @@ -335,36 +334,36 @@ void W3DRadar::drawViewBox( Int pixelX, Int pixelY, Int width, Int height ) ICoord2D radar; // top line - start = ulStart; + pixelStart = ulPixel; radar.x = ulRadar.x + m_viewBox[ 1 ].x; radar.y = ulRadar.y + m_viewBox[ 1 ].y; - radarToPixel( &radar, &end, pixelX, pixelY, width, height ); - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) + radarToPixel( &radar, &pixelEnd, pixelX, pixelY, width, height ); + if( ClipLine2D( &pixelStart, &pixelEnd, &clipStart, &clipEnd, &clipRegion ) ) TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, lineWidth, topColor ); // right line - start = end; + pixelStart = pixelEnd; radar.x += m_viewBox[ 2 ].x; radar.y += m_viewBox[ 2 ].y; - radarToPixel( &radar, &end, pixelX, pixelY, width, height ); - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) + radarToPixel( &radar, &pixelEnd, pixelX, pixelY, width, height ); + if( ClipLine2D( &pixelStart, &pixelEnd, &clipStart, &clipEnd, &clipRegion ) ) TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, lineWidth, topColor, bottomColor ); // bottom line - start = end; + pixelStart = pixelEnd; radar.x += m_viewBox[ 3 ].x; radar.y += m_viewBox[ 3 ].y; - radarToPixel( &radar, &end, pixelX, pixelY, width, height ); - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) + radarToPixel( &radar, &pixelEnd, pixelX, pixelY, width, height ); + if( ClipLine2D( &pixelStart, &pixelEnd, &clipStart, &clipEnd, &clipRegion ) ) TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, lineWidth, bottomColor ); // left line - start = end; - end = ulStart; - if( ClipLine2D( &start, &end, &clipStart, &clipEnd, &clipRegion ) ) + pixelStart = pixelEnd; + pixelEnd = ulPixel; + if( ClipLine2D( &pixelStart, &pixelEnd, &clipStart, &clipEnd, &clipRegion ) ) TheDisplay->drawLine( clipStart.x, clipStart.y, clipEnd.x, clipEnd.y, lineWidth, bottomColor, topColor ); @@ -878,10 +877,7 @@ W3DRadar::W3DRadar() for( Int i = 0; i < 4; i++ ) { - - m_viewBox[ i ].x = 0; - m_viewBox[ i ].y = 0; - + m_viewBox[ i ].zero(); } } diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp index 2323bcf4e8d..45fc59780a6 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/BaseHeightMap.cpp @@ -1383,7 +1383,7 @@ Bool BaseHeightMapRenderObjClass::getMaximumVisibleBox(const FrustumClass &frust ClippedCorners[0]=frustum.Corners[0]; for (Int i=0; i<4; i++) { ClippedCorners[i]=frustum.Corners[i]; - if (groundPlane.Compute_Intersection(frustum.Corners[i],frustum.Corners[i+4],&clipFraction)) + if (groundPlane.Compute_Intersection(frustum.Corners[i],frustum.Corners[i+4],&clipFraction) == PlaneClass::INSIDE_SEGMENT) { //edge intersects the terrain ClippedCorners[i+4]=frustum.Corners[i]+(frustum.Corners[i+4]-frustum.Corners[i])*clipFraction; } diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp index 7fb22b5dd78..6d3568c35ec 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp @@ -1431,6 +1431,7 @@ Int MaskTextureShader::set(Int pass) D3DXMATRIX scale,offset,offsetTextureCenter; Coord3D centerPos; + centerPos.zero(); //Find center of projection (this should be returned from some other filter, etc. but //for now assume terrain location at center of screen. diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index a81f36c3224..e659ea8f6e7 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -92,8 +92,6 @@ #include "WW3D2/dx8renderer.h" #include "WW3D2/light.h" -#include "WW3D2/camera.h" -#include "WW3D2/coltype.h" #include "WW3D2/predlod.h" #include "WW3D2/ww3d.h" @@ -659,7 +657,7 @@ void W3DView::getPickRay(const ICoord2D *screen, Vector3 *rayStart, Vector3 *ray m_3DCamera->Un_Project(*rayEnd,Vector2(logX,logY)); //get world space point *rayEnd -= *rayStart; //vector camera to world space point rayEnd->Normalize(); //make unit vector - *rayEnd *= m_3DCamera->Get_Depth(); //adjust length to reach far clip plane + *rayEnd *= sqr(m_3DCamera->Get_Depth()); //adjust length to reach far clip plane and beyond *rayEnd += *rayStart; //get point on far clip plane along ray from camera. } @@ -779,28 +777,18 @@ void W3DView::updateCameraClipPlanes(const Matrix3D &transform) const Vector3 camPos = transform.Get_Translation(); const Vector3 camDir = -transform.Get_Z_Vector(); - const Int loX = heightMap->getDrawOrgX() - heightMap->getBorderSize(); - const Int loY = heightMap->getDrawOrgY() - heightMap->getBorderSize(); - const Int hiX = loX + heightMap->getDrawWidth(); - const Int hiY = loY + heightMap->getDrawHeight(); - - // Convert to world coordinates - const Real minX = loX * MAP_XY_FACTOR; - const Real minY = loY * MAP_XY_FACTOR; - const Real maxX = hiX * MAP_XY_FACTOR; - const Real maxY = hiY * MAP_XY_FACTOR; - + const Region2D region = heightMap->getDrawRegion2D(); const Real minZ = TheTerrainRenderObject->getMinHeight(); // Bounding sphere Vector3 center; - center.X = (minX + maxX) * 0.5f; - center.Y = (minY + maxY) * 0.5f; + center.X = (region.lo.x + region.hi.x) * 0.5f; + center.Y = (region.lo.y + region.hi.y) * 0.5f; center.Z = minZ - 1.0f; // -1 to avoid Z clipping when looking straight down // Half extents - const Real dx = (maxX - minX) * 0.5f; - const Real dy = (maxY - minY) * 0.5f; + const Real dx = (region.hi.x - region.lo.x) * 0.5f; + const Real dy = (region.hi.y - region.lo.y) * 0.5f; // Project center const Vector3 v = center - camPos; @@ -1710,9 +1698,14 @@ void W3DView::update() //------------------------------------------------------------------------------------------------- /** Find region which contains all drawables in 3D space. */ +// TheSuperHackers @fix Now gives back a proper region on low camera pitch by falling back to +// the drawn terrain area or map extents. //------------------------------------------------------------------------------------------------- void W3DView::getAxisAlignedViewRegion(Region3D &axisAlignedRegion) { + Region3D mapExtent; + TheTerrainLogic->getExtent( &mapExtent ); + // // get the 4 points in 3D space of the 4 corners of the view, we will use a z = 0.0f // value so that we can get everything ... even stuff below the terrain @@ -1721,18 +1714,29 @@ void W3DView::getAxisAlignedViewRegion(Region3D &axisAlignedRegion) // \ / // 4---3 Coord3D box[ 4 ]; - getScreenCornerWorldPointsAtZ( &box[ 0 ], &box[ 1 ], &box[ 2 ], &box[ 3 ], 0.0f ); - - // - // take those 4 corners projected into the world and create an axis aligned bounding - // box, we will use this box to iterate the drawables in 3D space - // - axisAlignedRegion.setFromPointsNoZ(box, ARRAY_SIZE(box)); + if( getScreenCornerWorldPointsAtZ( &box[ 0 ], &box[ 1 ], &box[ 2 ], &box[ 3 ], 0.0f ) == PlaneClass::INSIDE_SEGMENT ) + { + // + // take those 4 corners projected into the world and create an axis aligned bounding + // box, we will use this box to iterate the drawables in 3D space + // + axisAlignedRegion.setXYFromPoints(box, ARRAY_SIZE(box)); + } + else + { + if( WorldHeightMap *heightMap = TheTerrainRenderObject->getMap() ) + { + const Region2D region = heightMap->getDrawRegion2D(); + axisAlignedRegion.setXY(region); + } + else + { + axisAlignedRegion = mapExtent; + } + } // low and high regions will be based of the extent of the map - Region3D mapExtent; - Real safeValue = 999999; - TheTerrainLogic->getExtent( &mapExtent ); + constexpr const Real safeValue = 999999; axisAlignedRegion.lo.z = mapExtent.lo.z - safeValue; axisAlignedRegion.hi.z = mapExtent.hi.z + safeValue; @@ -2562,12 +2566,13 @@ Drawable *W3DView::pickDrawable( const ICoord2D *screen, Bool forceAttack, PickT //------------------------------------------------------------------------------------------------- /** convert a pixel (x,y) to a location in the world on the terrain. Screen coordinates assumed in absolute values relative to full display resolution. */ +// TheSuperHackers @fix Now returns whether a terrain intersection exists to let callers handle the +// failure condition. //------------------------------------------------------------------------------------------------- -void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) +Bool W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) { - // sanity if( screen == nullptr || world == nullptr || TheTerrainRenderObject == nullptr ) - return; + return false; if (m_cameraHasMovedSinceRequest) { m_locationRequests.clear(); @@ -2578,13 +2583,12 @@ void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) m_locationRequests.erase(m_locationRequests.begin(), m_locationRequests.begin() + 10); } - - // We insert them at the end for speed (no copies needed), but using the princ of locality, we should + // We insert them at the end for speed (no copies needed), but using the principle of locality, we should // start searching where we most recently inserted for (int i = m_locationRequests.size() - 1; i >= 0; --i) { if (m_locationRequests[i].first.x == screen->x && m_locationRequests[i].first.y == screen->y) { (*world) = m_locationRequests[i].second; - return; + return true; } } @@ -2592,6 +2596,7 @@ void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) LineSegClass lineseg; CastResultStruct result; Vector3 intersection(0,0,0); + Bool hasIntersection = false; getPickRay(screen,&rayStart,&rayEnd); @@ -2599,11 +2604,11 @@ void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) RayCollisionTestClass raytest(lineseg,&result); + // Get the point of intersection according to W3D if( TheTerrainRenderObject->Cast_Ray(raytest) ) { - // get the point of intersection according to W3D intersection = result.ContactPoint; - + hasIntersection = true; } // Pick bridges. @@ -2611,8 +2616,12 @@ void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) Drawable *bridge = TheTerrainLogic->pickBridge(rayStart, rayEnd, &bridgePt); if (bridge && bridgePt.Z > intersection.Z) { intersection = bridgePt; + hasIntersection = true; } + if (!hasIntersection) + return false; + world->x = intersection.X; world->y = intersection.Y; world->z = intersection.Z; @@ -2622,6 +2631,7 @@ void W3DView::screenToTerrain( const ICoord2D *screen, Coord3D *world ) req.second = (*world); m_locationRequests.push_back(req); // Insert this request at the end, requires no extra copies + return true; } //------------------------------------------------------------------------------------------------- @@ -2647,7 +2657,7 @@ void W3DView::lookAt( const Coord3D *o ) m_3DCamera->Un_Project(rayEnd,Vector2(0.0f,0.0f)); //get world space point rayEnd -= rayStart; //vector camera to world space point rayEnd.Normalize(); //make unit vector - rayEnd *= m_3DCamera->Get_Depth(); //adjust length to reach far clip plane + rayEnd *= sqr(m_3DCamera->Get_Depth()); //adjust length to reach far clip plane and beyond rayStart.Set(pos.x, pos.y, pos.z); rayEnd += rayStart; //get point on far clip plane along ray from camera. lineseg.Set(rayStart,rayEnd); @@ -3673,16 +3683,31 @@ void W3DView::shake( const Coord3D *epicenter, CameraShakeType shakeType ) //------------------------------------------------------------------------------------------------- /** Transform the screen pixel coord passed in, to a world coordinate at the specified z value */ +// TheSuperHackers @fix Now returns whether a Z plane intersection exists to let callers handle the +// failure condition. //------------------------------------------------------------------------------------------------- -void W3DView::screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) +PlaneClass::IntersectionResType W3DView::screenToWorldAtZ( const ICoord2D *screen, Coord3D *world, Real z ) { Vector3 rayStart, rayEnd; - getPickRay( s, &rayStart, &rayEnd ); - w->x = Vector3::Find_X_At_Z( z, rayStart, rayEnd ); - w->y = Vector3::Find_Y_At_Z( z, rayStart, rayEnd ); - w->z = z; + getPickRay( screen, &rayStart, &rayEnd ); + + PlaneClass plane; + plane.N = Vector3(0, 0, 1); + plane.D = z; + float t; + PlaneClass::IntersectionResType intersectionType = plane.Compute_Intersection(rayStart, rayEnd, &t); + + if (intersectionType != PlaneClass::NO_INTERSECTION) + { + Vector3 intersectPos; + intersectPos = rayStart + (rayEnd-rayStart) * t; + world->x = intersectPos.X; + world->y = intersectPos.Y; + world->z = z; + } + return intersectionType; } void W3DView::cameraEnableSlaveMode(const AsciiString & objectName, const AsciiString & boneName) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp index 83d7ed8a6d2..c8838bb59b0 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp @@ -1169,49 +1169,53 @@ void TestWaterUpdate() { if (!haveStart) { mouseAnchor=screenPoint; - TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointStart); - haveStart=1; - UnicodeString string; - string.format(L"Added Start"); - TheInGameUI->message(string); + if (TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointStart)) + { + haveStart=1; + UnicodeString string; + string.format(L"Added Start"); + TheInGameUI->message(string); + } } else { endPoint=screenPoint; - TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointEnd); - haveEnd=1; - //Have enough info to add a wave now - track=TheWaterTracksRenderSystem->bindTrack(currentWaveType); - if (track) - {// track->init(1.5f*MAP_XY_FACTOR,Vector2(terrainPointStart.x,terrainPointStart.y),Vector2(terrainPointEnd.x,terrainPointEnd.y),"wave256.tga"); - //Generate valid input for the 2 points - Vector2 startPoint(terrainPointStart.x,terrainPointStart.y); - Vector2 endPoint(terrainPointEnd.x,terrainPointEnd.y); - Vector2 midPoint = endPoint - startPoint; - Vector2 m_perpDir = midPoint; - m_perpDir.Rotate(1.57079632679f); //get vector perpendicular to wave motion. - m_perpDir.Normalize(); - midPoint = startPoint + (midPoint)*0.5f; - Vector2 dirMidPoint = midPoint + m_perpDir; - - track->init(waveTypeInfo[currentWaveType].m_finalHeight,waveTypeInfo[currentWaveType].m_finalWidth,Vector2(midPoint.X,midPoint.Y),Vector2(dirMidPoint.X,dirMidPoint.Y),waveTypeInfo[currentWaveType].m_textureName,0); - - if (waveTypeInfo[currentWaveType].m_secondWaveTimeOffset) - { - //Add a second track slightly behind this one - track2=TheWaterTracksRenderSystem->bindTrack(currentWaveType); - if (track2) + if (TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointEnd)) + { + haveEnd=1; + //Have enough info to add a wave now + track=TheWaterTracksRenderSystem->bindTrack(currentWaveType); + if (track) + {// track->init(1.5f*MAP_XY_FACTOR,Vector2(terrainPointStart.x,terrainPointStart.y),Vector2(terrainPointEnd.x,terrainPointEnd.y),"wave256.tga"); + //Generate valid input for the 2 points + Vector2 startPoint(terrainPointStart.x,terrainPointStart.y); + Vector2 endPoint(terrainPointEnd.x,terrainPointEnd.y); + Vector2 midPoint = endPoint - startPoint; + Vector2 m_perpDir = midPoint; + m_perpDir.Rotate(1.57079632679f); //get vector perpendicular to wave motion. + m_perpDir.Normalize(); + midPoint = startPoint + (midPoint)*0.5f; + Vector2 dirMidPoint = midPoint + m_perpDir; + + track->init(waveTypeInfo[currentWaveType].m_finalHeight,waveTypeInfo[currentWaveType].m_finalWidth,Vector2(midPoint.X,midPoint.Y),Vector2(dirMidPoint.X,dirMidPoint.Y),waveTypeInfo[currentWaveType].m_textureName,0); + + if (waveTypeInfo[currentWaveType].m_secondWaveTimeOffset) { - track2->init(waveTypeInfo[currentWaveType].m_finalHeight,waveTypeInfo[currentWaveType].m_finalWidth,Vector2(midPoint.X,midPoint.Y),Vector2(dirMidPoint.X,dirMidPoint.Y),waveTypeInfo[currentWaveType].m_textureName,waveTypeInfo[currentWaveType].m_secondWaveTimeOffset); + //Add a second track slightly behind this one + track2=TheWaterTracksRenderSystem->bindTrack(currentWaveType); + if (track2) + { + track2->init(waveTypeInfo[currentWaveType].m_finalHeight,waveTypeInfo[currentWaveType].m_finalWidth,Vector2(midPoint.X,midPoint.Y),Vector2(dirMidPoint.X,dirMidPoint.Y),waveTypeInfo[currentWaveType].m_textureName,waveTypeInfo[currentWaveType].m_secondWaveTimeOffset); + } } - } - UnicodeString string; - string.format(L"Added End"); - TheInGameUI->message(string); + UnicodeString string; + string.format(L"Added End"); + TheInGameUI->message(string); + } + haveStart=0; //reset for next segment + haveEnd=0; } - haveStart=0; //reset for next segment - haveEnd=0; } addPointReset=0; } @@ -1292,21 +1296,23 @@ void TestWaterUpdate() // View *tacticalView = TheDisplay->getFirstView(); // tacticalView->worldToScreen( &m_moveHint[i].pos, &pos ); - TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointEnd); - //Check if point is within correct distance of start - Real xdiff=terrainPointEnd.x - terrainPointStart.x; - Real ydiff=terrainPointEnd.y - terrainPointStart.y; - if (sqrt (xdiff * xdiff + ydiff * ydiff) <= waveTypeInfo[currentWaveType].m_finalWidth) - { TheDisplay->drawLine(mouseAnchor.x, mouseAnchor.y, screenPoint.x, screenPoint.y,1,0xffccccff); - DX8Wrapper::Invalidate_Cached_Render_States(); - ShaderClass::Invalidate(); - } - - pauseWaves=TRUE; + if (TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointEnd)) + { + //Check if point is within correct distance of start + Real xdiff=terrainPointEnd.x - terrainPointStart.x; + Real ydiff=terrainPointEnd.y - terrainPointStart.y; + if (sqrt (xdiff * xdiff + ydiff * ydiff) <= waveTypeInfo[currentWaveType].m_finalWidth) + { TheDisplay->drawLine(mouseAnchor.x, mouseAnchor.y, screenPoint.x, screenPoint.y,1,0xffccccff); + DX8Wrapper::Invalidate_Cached_Render_States(); + ShaderClass::Invalidate(); + } // char buffer[64]; // sprintf(buffer,"\n%d,%d,%d,%d",mouseAnchor.x, mouseAnchor.y, screenPoint.x, screenPoint.y); // OutputDebugString (buffer); + } + + pauseWaves=TRUE; } } } diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp index 5deb1994be3..cff40a8d32c 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp @@ -2200,6 +2200,23 @@ TerrainTextureClass *WorldHeightMap::getFlatTexture(Int xCell, Int yCell, Int ce return newTexture; } +Region2D WorldHeightMap::getDrawRegion2D() +{ + // Get region in heightmap space + const Int loX = getDrawOrgX() - getBorderSize(); + const Int loY = getDrawOrgY() - getBorderSize(); + const Int hiX = loX + getDrawWidth(); + const Int hiY = loY + getDrawHeight(); + + // Convert to world space + Region2D region; + region.lo.x = loX * MAP_XY_FACTOR; + region.lo.y = loY * MAP_XY_FACTOR; + region.hi.x = hiX * MAP_XY_FACTOR; + region.hi.y = hiY * MAP_XY_FACTOR; + + return region; +} WorldHeightMap::DrawArea WorldHeightMap::createDrawArea(Int xOrg, Int yOrg) { diff --git a/Core/Libraries/Include/Lib/BaseType.h b/Core/Libraries/Include/Lib/BaseType.h index 70a43592989..62bcc5ec115 100644 --- a/Core/Libraries/Include/Lib/BaseType.h +++ b/Core/Libraries/Include/Lib/BaseType.h @@ -544,7 +544,17 @@ struct Region3D return lo.is(value) && hi.is(value); } - void setFromPointsNoZ(const Coord3D* points, Int count) + // Set XY from a 2D region and leave Z unchanged. + void setXY(const Region2D ®ion) + { + lo.x = region.lo.x; + lo.y = region.lo.y; + hi.x = region.hi.x; + hi.y = region.hi.y; + } + + // Set XY from any amount of points and leave Z unchanged. + void setXYFromPoints(const Coord3D* points, Int count) { lo.x = points[0].x; lo.y = points[0].y; diff --git a/Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp b/Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp index c2c89a07bdf..51aa8a7f141 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp @@ -49,6 +49,7 @@ #include "statistics.h" #include #include +#include bool SortingRendererClass::_EnableTriangleDraw=true; @@ -150,7 +151,7 @@ void Sort(TempIndexStruct *begin, TempIndexStruct *end) // ---------------------------------------------------------------------------- -class SortingNodeStruct : public DLNodeClass +class SortingNodeStruct { W3DMPO_CODE(SortingNodeStruct) @@ -166,20 +167,19 @@ class SortingNodeStruct : public DLNodeClass unsigned short vertex_count; // Number of vertices used in vb }; -static DLListClass sorted_list; -static DLListClass clean_list; +typedef std::list SortingNodeStructList; +static SortingNodeStructList sorted_list; +static SortingNodeStructList clean_list; static unsigned total_sorting_vertices; static SortingNodeStruct* Get_Sorting_Struct() { - - SortingNodeStruct* state=clean_list.Head(); - if (state) { - state->Remove(); + if (!clean_list.empty()) { + SortingNodeStruct* state = clean_list.front(); + clean_list.pop_front(); return state; } - state=W3DNEW SortingNodeStruct(); - return state; + return W3DNEW SortingNodeStruct(); } // ---------------------------------------------------------------------------- @@ -242,10 +242,6 @@ void SortingRendererClass::Insert_Triangles( state->min_vertex_index=min_vertex_index; state->vertex_count=vertex_count; - SortingVertexBufferClass* vertex_buffer=static_cast(state->sorting_state.vertex_buffers[0]); - WWASSERT(vertex_buffer); - WWASSERT(state->vertex_count<=vertex_buffer->Get_Vertex_Count()); - D3DXMATRIX mtx=(D3DXMATRIX&)state->sorting_state.world*(D3DXMATRIX&)state->sorting_state.view; D3DXVECTOR3 vec=(D3DXVECTOR3&)state->bounding_sphere.Center; D3DXVECTOR4 transformed_vec; @@ -255,23 +251,13 @@ void SortingRendererClass::Insert_Triangles( &mtx); state->transformed_center=Vector3(transformed_vec[0],transformed_vec[1],transformed_vec[2]); - - /// @todo lorenzen sez use a bucket sort here... and stop copying so much data so many times - - SortingNodeStruct* node=sorted_list.Head(); - while (node) { - if (state->transformed_center.Z>node->transformed_center.Z) { - if (sorted_list.Head()==sorted_list.Tail()) - sorted_list.Add_Head(state); - else - state->Insert_Before(node); - break; - } - node=node->Succ(); - } - if (!node) sorted_list.Add_Tail(state); + Insert_To_Sorted_List(state); #ifdef WWDEBUG + SortingVertexBufferClass* vertex_buffer=static_cast(state->sorting_state.vertex_buffers[0]); + WWASSERT(vertex_buffer); + WWASSERT(state->vertex_count<=vertex_buffer->Get_Vertex_Count()); + unsigned short* indices=nullptr; SortingIndexBufferClass* index_buffer=static_cast(state->sorting_state.index_buffer); WWASSERT(index_buffer); @@ -335,6 +321,23 @@ static SortingNodeStruct* overlapping_nodes[MAX_OVERLAPPING_NODES]; // ---------------------------------------------------------------------------- +void SortingRendererClass::Insert_To_Sorted_List(SortingNodeStruct *state) +{ + /// @todo lorenzen sez use a bucket sort here... and stop copying so much data so many times + + for (SortingNodeStructList::iterator node = sorted_list.begin(); node != sorted_list.end(); ++node) + { + if (state->transformed_center.Z > (*node)->transformed_center.Z) { + sorted_list.insert(node, state); + return; + } + } + + sorted_list.push_back(state); +} + +// ---------------------------------------------------------------------------- + void SortingRendererClass::Insert_To_Sorting_Pool(SortingNodeStruct* state) { if (overlapping_node_count>=MAX_OVERLAPPING_NODES) { @@ -577,7 +580,7 @@ void SortingRendererClass::Flush_Sorting_Pool() for (unsigned node_id=0;node_idRemove(); + while (!sorted_list.empty()) { + SortingNodeStruct* state = sorted_list.front(); + sorted_list.pop_front(); if ((state->sorting_state.index_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) && (state->sorting_state.vertex_buffer_types[0]==BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_types[0]==BUFFER_TYPE_DYNAMIC_SORTING)) { @@ -609,7 +613,7 @@ void SortingRendererClass::Flush() DX8Wrapper::Draw_Triangles(state->start_index,state->polygon_count,state->min_vertex_index,state->vertex_count); DX8Wrapper::Release_Render_State(); Release_Refs(state); - clean_list.Add_Head(state); + clean_list.push_front(state); } } @@ -635,98 +639,23 @@ void SortingRendererClass::Flush() void SortingRendererClass::Deinit() { - SortingNodeStruct *head = nullptr; - // // Flush the sorted list // - while ((head = sorted_list.Head ()) != nullptr) { - sorted_list.Remove_Head (); - delete head; + while (!sorted_list.empty()) { + delete sorted_list.front(); + sorted_list.pop_front(); } // // Flush the clean list // - while ((head = clean_list.Head ()) != nullptr) { - clean_list.Remove_Head (); - delete head; + while (!clean_list.empty()) { + delete clean_list.front(); + clean_list.pop_front(); } delete[] temp_index_array; temp_index_array=nullptr; temp_index_array_count=0; } - - -// ---------------------------------------------------------------------------- -// -// Insert a VolumeParticle triangle into the sorting system. -// -// ---------------------------------------------------------------------------- - -void SortingRendererClass::Insert_VolumeParticle( - const SphereClass& bounding_sphere, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count, - unsigned short layerCount) -{ - if (!WW3D::Is_Sorting_Enabled()) { - DX8Wrapper::Draw_Triangles(start_index,polygon_count,min_vertex_index,vertex_count); - return; - } - - //FOR VOLUME_PARTICLE LOGIC: - // WE MUST MULTIPLY THE VERTCOUNT AND POLYCOUNT BY THE VOLUME_PARTICLE DEPTH - DX8_RECORD_SORTING_RENDER( polygon_count * layerCount,vertex_count * layerCount);//THIS IS VOLUME_PARTICLE SPECIFIC - - SortingNodeStruct* state=Get_Sorting_Struct(); - DX8Wrapper::Get_Render_State(state->sorting_state); - - WWASSERT( - ((state->sorting_state.index_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) && - (state->sorting_state.vertex_buffer_types[0]==BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_types[0]==BUFFER_TYPE_DYNAMIC_SORTING))); - - state->bounding_sphere=bounding_sphere; - state->start_index=start_index; - state->min_vertex_index=min_vertex_index; - state->polygon_count=polygon_count * layerCount;//THIS IS VOLUME_PARTICLE SPECIFIC - state->vertex_count=vertex_count * layerCount;//THIS IS VOLUME_PARTICLE SPECIFIC - - SortingVertexBufferClass* vertex_buffer=static_cast(state->sorting_state.vertex_buffers[0]); - WWASSERT(vertex_buffer); - WWASSERT(state->vertex_count<=vertex_buffer->Get_Vertex_Count()); - - // Transform the center point to view space for sorting - - D3DXMATRIX mtx=(D3DXMATRIX&)state->sorting_state.world*(D3DXMATRIX&)state->sorting_state.view; - D3DXVECTOR3 vec=(D3DXVECTOR3&)state->bounding_sphere.Center; - D3DXVECTOR4 transformed_vec; - D3DXVec3Transform( - &transformed_vec, - &vec, - &mtx); - state->transformed_center=Vector3(transformed_vec[0],transformed_vec[1],transformed_vec[2]); - - - // BUT WHAT IS THE DEAL WITH THE VERTCOUNT AND POLYCOUNT BEING N BUT TRANSFORMED CENTER COUNT == 1 - - //THE TRANSFORMED CENTER[2] IS THE ZBUFFER DEPTH - - /// @todo lorenzen sez use a bucket sort here... and stop copying so much data so many times - - SortingNodeStruct* node=sorted_list.Head(); - while (node) { - if (state->transformed_center.Z>node->transformed_center.Z) { - if (sorted_list.Head()==sorted_list.Tail()) - sorted_list.Add_Head(state); - else - state->Insert_Before(node); - break; - } - node=node->Succ(); - } - if (!node) sorted_list.Add_Tail(state); -} diff --git a/Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.h b/Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.h index 06f0b5e826c..6e304f0da7d 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.h @@ -28,6 +28,7 @@ class SortingRendererClass static bool _EnableTriangleDraw; static void Flush_Sorting_Pool(); + static void Insert_To_Sorted_List(SortingNodeStruct* state); static void Insert_To_Sorting_Pool(SortingNodeStruct* state); public: @@ -44,14 +45,6 @@ class SortingRendererClass unsigned short min_vertex_index, unsigned short vertex_count); - static void Insert_VolumeParticle( - const SphereClass& bounding_sphere, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count, - unsigned short layerCount); - static void Flush(); static void Deinit(); diff --git a/Core/Libraries/Source/WWVegas/WWAudio/AudioEvents.h b/Core/Libraries/Source/WWVegas/WWAudio/AudioEvents.h index 391917269fd..4f45017c96f 100644 --- a/Core/Libraries/Source/WWVegas/WWAudio/AudioEvents.h +++ b/Core/Libraries/Source/WWVegas/WWAudio/AudioEvents.h @@ -141,12 +141,12 @@ struct AUDIO_CALLBACK_STRUCT // Protected structures ///////////////////////////////////////////////////////////////////////////////// template -class AudioCallbackListClass : public SimpleDynVecClass< AUDIO_CALLBACK_STRUCT > +class AudioCallbackListClass : public SimpleDynVecClass< AUDIO_CALLBACK_STRUCT/**/> { - using SimpleDynVecClass< AUDIO_CALLBACK_STRUCT >::Vector; - using SimpleDynVecClass< AUDIO_CALLBACK_STRUCT >::ActiveCount; - using SimpleDynVecClass< AUDIO_CALLBACK_STRUCT >::Delete; - using SimpleDynVecClass< AUDIO_CALLBACK_STRUCT >::Add; + using SimpleDynVecClass< AUDIO_CALLBACK_STRUCT/**/>::Vector; + using SimpleDynVecClass< AUDIO_CALLBACK_STRUCT/**/>::ActiveCount; + using SimpleDynVecClass< AUDIO_CALLBACK_STRUCT/**/>::Delete; + using SimpleDynVecClass< AUDIO_CALLBACK_STRUCT/**/>::Add; public: diff --git a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h index fcee4763e0e..c96d4b6c6b3 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h +++ b/Core/Libraries/Source/WWVegas/WWLib/DbgHelpLoader.h @@ -210,7 +210,7 @@ class DbgHelpLoader MiniDumpWriteDump_t m_miniDumpWriteDump; #endif - typedef std::set, stl::system_allocator > Processes; + typedef std::set, stl::system_allocator/**/> Processes; Processes m_initializedProcesses; HMODULE m_dllModule; diff --git a/Core/Libraries/Source/WWVegas/WWLib/STLUtils.h b/Core/Libraries/Source/WWVegas/WWLib/STLUtils.h index bb76c2f507f..5dae677abe8 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/STLUtils.h +++ b/Core/Libraries/Source/WWVegas/WWLib/STLUtils.h @@ -124,21 +124,21 @@ Iter advance_in_range(Iter first, Iter last, ptrdiff_t n) } template -range > get_range(std::multimap& mm, const Key& key, ptrdiff_t n = 0) +range/**/> get_range(std::multimap& mm, const Key& key, ptrdiff_t n = 0) { typedef typename std::multimap::iterator Iter; const std::pair pair = mm.equal_range(key); const Iter it = advance_in_range(pair.first, pair.second, n); - return range >(it, pair.second); + return range/**/>(it, pair.second); } template -const_range > get_range(const std::multimap& mm, const Key& key, ptrdiff_t n = 0) +const_range/**/> get_range(const std::multimap& mm, const Key& key, ptrdiff_t n = 0) { typedef typename std::multimap::const_iterator Iter; const std::pair pair = mm.equal_range(key); const Iter it = advance_in_range(pair.first, pair.second, n); - return const_range >(it, pair.second); + return const_range/**/>(it, pair.second); } } // namespace stl diff --git a/Core/Libraries/Source/WWVegas/WWMath/plane.h b/Core/Libraries/Source/WWVegas/WWMath/plane.h index eb3630595da..f2f6cf3e969 100644 --- a/Core/Libraries/Source/WWVegas/WWMath/plane.h +++ b/Core/Libraries/Source/WWVegas/WWMath/plane.h @@ -59,6 +59,13 @@ class PlaneClass enum { FRONT = 0, BACK, ON }; + enum IntersectionResType + { + NO_INTERSECTION = 0, // No intersection when the line is parallel to the plane + INSIDE_SEGMENT = 1, // The segment INSIDE point A and B intersects the plane + OUTSIDE_LINE = 2, // The infinite line OUTSIDE point A and B intersects the plane + }; + Vector3 N; // Normal of the plane float D; // Distance along the normal from the origin @@ -81,7 +88,7 @@ class PlaneClass inline void Set(const Vector3 & normal,const Vector3 & point); inline void Set(const Vector3 & point1,const Vector3 & point2,const Vector3 & point3); - bool Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const; + PlaneClass::IntersectionResType Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const; bool In_Front(const Vector3 & point) const; bool In_Front(const SphereClass & sphere) const; bool In_Front_Or_Intersecting(const SphereClass & sphere) const; @@ -148,7 +155,7 @@ inline void PlaneClass::Set(const Vector3 & point1, const Vector3 & point2, cons } } -inline bool PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const +inline PlaneClass::IntersectionResType PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const { float num,den; den = Vector3::Dot_Product(N,p1-p0); @@ -157,7 +164,7 @@ inline bool PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & ** If the denominator is zero, the ray is parallel to the plane */ if (den == 0.0f) { - return false; + return PlaneClass::NO_INTERSECTION; } num = -(Vector3::Dot_Product(N,p0) - D); @@ -169,10 +176,10 @@ inline bool PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & ** the plane but the segment does not */ if ((*set_t < 0.0f) || (*set_t > 1.0f)) { - return false; + return PlaneClass::OUTSIDE_LINE; } - return true; + return PlaneClass::INSIDE_SEGMENT; } inline bool PlaneClass::In_Front(const Vector3 & point) const diff --git a/Core/Libraries/Source/WWVegas/WWMath/wwmath.h b/Core/Libraries/Source/WWVegas/WWMath/wwmath.h index 2202f52a5c9..8c8e2f1b263 100644 --- a/Core/Libraries/Source/WWVegas/WWMath/wwmath.h +++ b/Core/Libraries/Source/WWVegas/WWMath/wwmath.h @@ -445,8 +445,10 @@ WWINLINE long WWMath::Float_To_Long(double f) { #if defined(_MSC_VER) && defined(_M_IX86) long retval; - __asm fld qword ptr [f] - __asm fistp dword ptr [retval] + __asm { + fld qword ptr [f] + fistp dword ptr [retval] + } return retval; #else return (long) f; diff --git a/Core/Libraries/Source/profile/internal.h b/Core/Libraries/Source/profile/internal.h index 06184d65a9e..95bbcc0175b 100644 --- a/Core/Libraries/Source/profile/internal.h +++ b/Core/Libraries/Source/profile/internal.h @@ -64,20 +64,24 @@ class ProfileFastCS #define ts_lock _emit 0xF0 DASSERT(((unsigned)&nFlag % 4) == 0); - __asm mov ebx, [nFlag] - __asm ts_lock - __asm bts dword ptr [ebx], 0 - __asm jc The_Bit_Was_Previously_Set_So_Try_Again + __asm { + mov ebx, [nFlag] + ts_lock + bts dword ptr [ebx], 0 + jc The_Bit_Was_Previously_Set_So_Try_Again + } return; The_Bit_Was_Previously_Set_So_Try_Again: // can't use SwitchToThread() here because Win9X doesn't have it! if (testEvent) ::WaitForSingleObject(testEvent,1); - __asm mov ebx, [nFlag] - __asm ts_lock - __asm bts dword ptr [ebx], 0 - __asm jc The_Bit_Was_Previously_Set_So_Try_Again + __asm { + mov ebx, [nFlag] + ts_lock + bts dword ptr [ebx], 0 + jc The_Bit_Was_Previously_Set_So_Try_Again + } } void ThreadSafeClearFlag() diff --git a/Core/Tools/matchbot/wlib/ustring.h b/Core/Tools/matchbot/wlib/ustring.h index c06e0d06744..bee3ac0ba4b 100644 --- a/Core/Tools/matchbot/wlib/ustring.h +++ b/Core/Tools/matchbot/wlib/ustring.h @@ -32,7 +32,7 @@ #define MAX_BYTES_PER_CHAR 1 template -class UstringT : public basic_string > +class UstringT : public basic_string/**/> { public: explicit UstringT(int max_charlength) { @@ -46,8 +46,8 @@ class UstringT : public basic_string > bool operator==(const UstringT &other) { - const basic_string > *other_basic=&other; - const basic_string > *this_basic=this; + const basic_string/**/> *other_basic=&other; + const basic_string/**/> *this_basic=this; return((*other_basic)==(*this_basic)); } diff --git a/Generals/Code/GameEngine/CMakeLists.txt b/Generals/Code/GameEngine/CMakeLists.txt index 4566723acd7..75f34df278f 100644 --- a/Generals/Code/GameEngine/CMakeLists.txt +++ b/Generals/Code/GameEngine/CMakeLists.txt @@ -135,7 +135,7 @@ set(GAMEENGINE_SRC # Include/GameClient/ClientInstance.h # Include/GameClient/ClientRandomValue.h # Include/GameClient/Color.h - Include/GameClient/CommandXlat.h +# Include/GameClient/CommandXlat.h Include/GameClient/ControlBar.h Include/GameClient/ControlBarResizer.h Include/GameClient/ControlBarScheme.h @@ -177,10 +177,10 @@ set(GAMEENGINE_SRC # Include/GameClient/GlobalLanguage.h # Include/GameClient/GraphDraw.h Include/GameClient/GUICallbacks.h - Include/GameClient/GUICommandTranslator.h +# Include/GameClient/GUICommandTranslator.h # Include/GameClient/HeaderTemplate.h - Include/GameClient/HintSpy.h - Include/GameClient/HotKey.h +# Include/GameClient/HintSpy.h +# Include/GameClient/HotKey.h # Include/GameClient/Image.h # Include/GameClient/IMEManager.h Include/GameClient/InGameUI.h @@ -189,21 +189,21 @@ set(GAMEENGINE_SRC # Include/GameClient/LanguageFilter.h # Include/GameClient/Line2D.h # Include/GameClient/LoadScreen.h - Include/GameClient/LookAtXlat.h +# Include/GameClient/LookAtXlat.h # Include/GameClient/MapUtil.h Include/GameClient/MessageBox.h - Include/GameClient/MetaEvent.h +# Include/GameClient/MetaEvent.h # Include/GameClient/Module/AnimatedParticleSysBoneClientUpdate.h # Include/GameClient/Module/BeaconClientUpdate.h # Include/GameClient/Module/SwayClientUpdate.h # Include/GameClient/Mouse.h # Include/GameClient/ParticleSys.h - Include/GameClient/PlaceEventTranslator.h +# Include/GameClient/PlaceEventTranslator.h # Include/GameClient/ProcessAnimateWindow.h # Include/GameClient/RadiusDecal.h # Include/GameClient/RayEffect.h # Include/GameClient/SelectionInfo.h - Include/GameClient/SelectionXlat.h +# Include/GameClient/SelectionXlat.h Include/GameClient/Shadow.h Include/GameClient/Shell.h Include/GameClient/ShellHooks.h @@ -216,7 +216,7 @@ set(GAMEENGINE_SRC # Include/GameClient/Water.h # Include/GameClient/WindowLayout.h # Include/GameClient/WindowVideoManager.h - Include/GameClient/WindowXlat.h +# Include/GameClient/WindowXlat.h # Include/GameClient/WinInstanceData.h Include/GameLogic/AI.h Include/GameLogic/AIDock.h @@ -649,7 +649,7 @@ set(GAMEENGINE_SRC Source/GameClient/Eva.cpp # Source/GameClient/FXList.cpp Source/GameClient/GameClient.cpp - Source/GameClient/GameClientDispatch.cpp +# Source/GameClient/GameClientDispatch.cpp # Source/GameClient/GameText.cpp # Source/GameClient/GlobalLanguage.cpp # Source/GameClient/GraphDraw.cpp @@ -752,15 +752,15 @@ set(GAMEENGINE_SRC # Source/GameClient/LanguageFilter.cpp # Source/GameClient/Line2D.cpp # Source/GameClient/MapUtil.cpp - Source/GameClient/MessageStream/CommandXlat.cpp - Source/GameClient/MessageStream/GUICommandTranslator.cpp - Source/GameClient/MessageStream/HintSpy.cpp - Source/GameClient/MessageStream/HotKey.cpp - Source/GameClient/MessageStream/LookAtXlat.cpp - Source/GameClient/MessageStream/MetaEvent.cpp - Source/GameClient/MessageStream/PlaceEventTranslator.cpp - Source/GameClient/MessageStream/SelectionXlat.cpp - Source/GameClient/MessageStream/WindowXlat.cpp +# Source/GameClient/MessageStream/CommandXlat.cpp +# Source/GameClient/MessageStream/GUICommandTranslator.cpp +# Source/GameClient/MessageStream/HintSpy.cpp +# Source/GameClient/MessageStream/HotKey.cpp +# Source/GameClient/MessageStream/LookAtXlat.cpp +# Source/GameClient/MessageStream/MetaEvent.cpp +# Source/GameClient/MessageStream/PlaceEventTranslator.cpp +# Source/GameClient/MessageStream/SelectionXlat.cpp +# Source/GameClient/MessageStream/WindowXlat.cpp # Source/GameClient/RadiusDecal.cpp # Source/GameClient/SelectionInfo.cpp # Source/GameClient/Statistics.cpp diff --git a/Generals/Code/GameEngine/Include/Common/DamageFX.h b/Generals/Code/GameEngine/Include/Common/DamageFX.h index 4a1ed99b8d7..2802db854bd 100644 --- a/Generals/Code/GameEngine/Include/Common/DamageFX.h +++ b/Generals/Code/GameEngine/Include/Common/DamageFX.h @@ -156,7 +156,7 @@ class DamageFXStore : public SubsystemInterface private: - typedef std::hash_map< NameKeyType, DamageFX, rts::hash, rts::equal_to > DamageFXMap; + typedef std::hash_map< NameKeyType, DamageFX, rts::hash, rts::equal_to/**/> DamageFXMap; DamageFXMap m_dfxmap; }; diff --git a/Generals/Code/GameEngine/Include/Common/ModuleFactory.h b/Generals/Code/GameEngine/Include/Common/ModuleFactory.h index 4a16d318cda..cf6b9447229 100644 --- a/Generals/Code/GameEngine/Include/Common/ModuleFactory.h +++ b/Generals/Code/GameEngine/Include/Common/ModuleFactory.h @@ -113,7 +113,7 @@ class ModuleFactory : public SubsystemInterface, public Snapshot static NameKeyType makeDecoratedNameKey(const AsciiString& name, ModuleType type); - typedef std::map< NameKeyType, ModuleTemplate, std::less > ModuleTemplateMap; + typedef std::map< NameKeyType, ModuleTemplate, std::less/**/> ModuleTemplateMap; typedef std::vector ModuleDataList; ModuleTemplateMap m_moduleTemplateMap; diff --git a/Generals/Code/GameEngine/Include/Common/Player.h b/Generals/Code/GameEngine/Include/Common/Player.h index 369e8cce8e1..6df5cebc64a 100644 --- a/Generals/Code/GameEngine/Include/Common/Player.h +++ b/Generals/Code/GameEngine/Include/Common/Player.h @@ -148,7 +148,7 @@ struct SpecialPowerReadyTimerType // ------------------------------------------------------------------------------------------------ -typedef std::hash_map< PlayerIndex, Relationship, std::hash, std::equal_to > PlayerRelationMapType; +typedef std::hash_map< PlayerIndex, Relationship, std::hash, std::equal_to/**/> PlayerRelationMapType; class PlayerRelationMap : public MemoryPoolObject, public Snapshot { diff --git a/Generals/Code/GameEngine/Include/Common/Team.h b/Generals/Code/GameEngine/Include/Common/Team.h index 655979d48d8..65c8160b73b 100644 --- a/Generals/Code/GameEngine/Include/Common/Team.h +++ b/Generals/Code/GameEngine/Include/Common/Team.h @@ -42,7 +42,7 @@ typedef UnsignedInt TeamPrototypeID; #define TEAM_PROTOTYPE_ID_INVALID 0 // ------------------------------------------------------------------------------------------------ -typedef std::hash_map< TeamID, Relationship, std::hash, std::equal_to > TeamRelationMapType; +typedef std::hash_map< TeamID, Relationship, std::hash, std::equal_to/**/> TeamRelationMapType; class TeamRelationMap : public MemoryPoolObject, public Snapshot { @@ -733,7 +733,7 @@ class TeamFactory : public SubsystemInterface, private: - typedef std::map< NameKeyType, TeamPrototype*, std::less > TeamPrototypeMap; + typedef std::map< NameKeyType, TeamPrototype*, std::less/**/> TeamPrototypeMap; TeamPrototypeMap m_prototypes; TeamPrototypeID m_uniqueTeamPrototypeID; ///< used to assign unique ids to each team prototype diff --git a/Generals/Code/GameEngine/Include/Common/ThingFactory.h b/Generals/Code/GameEngine/Include/Common/ThingFactory.h index b65e08460ad..fa4dad52db0 100644 --- a/Generals/Code/GameEngine/Include/Common/ThingFactory.h +++ b/Generals/Code/GameEngine/Include/Common/ThingFactory.h @@ -44,7 +44,7 @@ class Object; class Drawable; class INI; -typedef std::hash_map, rts::equal_to > ThingTemplateHashMap; +typedef std::hash_map, rts::equal_to/**/> ThingTemplateHashMap; typedef ThingTemplateHashMap::iterator ThingTemplateHashMapIt; //------------------------------------------------------------------------------------------------- /** Implementation of the thing manager interface singleton */ diff --git a/Generals/Code/GameEngine/Include/GameClient/CommandXlat.h b/Generals/Code/GameEngine/Include/GameClient/CommandXlat.h deleted file mode 100644 index 2dcc4c8d3cd..00000000000 --- a/Generals/Code/GameEngine/Include/GameClient/CommandXlat.h +++ /dev/null @@ -1,124 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: CommandXlat.h /////////////////////////////////////////////////////////// -// Author: Steven Johnson, Dec 2001 - -#pragma once - -#include "GameClient/InGameUI.h" - -enum GUICommandType CPP_11(: Int); - -//----------------------------------------------------------------------------- -class CommandTranslator : public GameMessageTranslator -{ -public: - - CommandTranslator(); - virtual ~CommandTranslator() override; - - enum CommandEvaluateType { DO_COMMAND, DO_HINT, EVALUATE_ONLY }; - - - GameMessage::Type evaluateForceAttack( Drawable *draw, const Coord3D *pos, CommandEvaluateType type ); - GameMessage::Type evaluateContextCommand( Drawable *draw, const Coord3D *pos, CommandEvaluateType type ); - -private: - - Int m_objective; - Bool m_teamExists; ///< is there a currently selected "team"? - - // these are for determining if a drag occurred or it was just a sloppy click - ICoord2D m_mouseRightDragAnchor; // the location of a possible mouse drag start - ICoord2D m_mouseRightDragLift; // the location of a possible mouse drag end - UnsignedInt m_mouseRightDown; // when the mouse down happened - UnsignedInt m_mouseRightUp; // when the mouse up happened - - GameMessage::Type createMoveToLocationMessage( Drawable *draw, const Coord3D *dest, CommandEvaluateType commandType ); - GameMessage::Type createAttackMessage( Drawable *draw, Drawable *other, CommandEvaluateType commandType ); - GameMessage::Type createEnterMessage( Drawable *enter, CommandEvaluateType commandType ); - GameMessage::Type issueMoveToLocationCommand( const Coord3D *pos, Drawable *drawableInWay, CommandEvaluateType commandType ); - GameMessage::Type issueAttackCommand( Drawable *target, CommandEvaluateType commandType, GUICommandType command = (GUICommandType)0 ); - GameMessage::Type issueSpecialPowerCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos, Object* ignoreSelObj ); - GameMessage::Type issueFireWeaponCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos ); - GameMessage::Type issueCombatDropCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos ); - - virtual GameMessageDisposition translateGameMessage(const GameMessage *msg) override; -}; - - -enum FilterTypes CPP_11(: Int) -{ - FT_NULL_FILTER=0, - // The following are screen filter shaders, that modify the rendered viewport after it is drawn. - FT_VIEW_BW_FILTER, //filter to apply a black & white filter to the screen. - FT_VIEW_MOTION_BLUR_FILTER, //filter to apply motion blur filter to screen. - FT_VIEW_CROSSFADE, ///. -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GUICommandTranslator.h /////////////////////////////////////////////////////////////////// -// Author: Colin Day, March 2002 -// Desc: Translator for commands activated from the selection GUI, such as special unit -// actions, that require additional clicks in the world like selecting a target -// object or location -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -// USER INCLUDES ////////////////////////////////////////////////////////////////////////////////// -#include "GameClient/InGameUI.h" - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -class GUICommandTranslator : public GameMessageTranslator -{ - -public: - - GUICommandTranslator(); - virtual ~GUICommandTranslator() override; - - virtual GameMessageDisposition translateGameMessage( const GameMessage *msg ) override; -}; diff --git a/Generals/Code/GameEngine/Include/GameClient/GameClient.h b/Generals/Code/GameEngine/Include/GameClient/GameClient.h index 7d42104edb4..ec059aa6afb 100644 --- a/Generals/Code/GameEngine/Include/GameClient/GameClient.h +++ b/Generals/Code/GameEngine/Include/GameClient/GameClient.h @@ -54,7 +54,7 @@ struct RayEffectData; /// Function pointers for use by GameClient callback functions. typedef void (*GameClientFuncPtr)( Drawable *draw, void *userData ); -typedef std::hash_map, rts::equal_to > DrawablePtrHash; +typedef std::hash_map, rts::equal_to/**/> DrawablePtrHash; typedef DrawablePtrHash::iterator DrawablePtrHashIt; //----------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Include/GameClient/HintSpy.h b/Generals/Code/GameEngine/Include/GameClient/HintSpy.h deleted file mode 100644 index 32cf775deda..00000000000 --- a/Generals/Code/GameEngine/Include/GameClient/HintSpy.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: HintSpy.h /////////////////////////////////////////////////////////// -// Author: Steven Johnson, Dec 2001 - -#pragma once - -#include "GameClient/InGameUI.h" - -//----------------------------------------------------------------------------- -class HintSpyTranslator : public GameMessageTranslator -{ -public: - virtual GameMessageDisposition translateGameMessage(const GameMessage *msg) override; - virtual ~HintSpyTranslator() override { } -}; diff --git a/Generals/Code/GameEngine/Include/GameClient/HotKey.h b/Generals/Code/GameEngine/Include/GameClient/HotKey.h deleted file mode 100644 index 3c9cade4eef..00000000000 --- a/Generals/Code/GameEngine/Include/GameClient/HotKey.h +++ /dev/null @@ -1,112 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - - -// FILE: HotKey.h ///////////////////////////////////////////////// -//----------------------------------------------------------------------------- -// -// Electronic Arts Pacific. -// -// Confidential Information -// Copyright (C) 2002 - All Rights Reserved -// -//----------------------------------------------------------------------------- -// -// created: Sep 2002 -// -// Filename: HotKey.h -// -// author: Chris Huybregts -// -// purpose: -// -//----------------------------------------------------------------------------- -/////////////////////////////////////////////////////////////////////////////// - -#pragma once - -//----------------------------------------------------------------------------- -// SYSTEM INCLUDES //////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// USER INCLUDES ////////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- -#include "Common/SubsystemInterface.h" -#include "Common/MessageStream.h" -//----------------------------------------------------------------------------- -// FORWARD REFERENCES ///////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- -class AsciiString; -class GameWindow; -//----------------------------------------------------------------------------- -// TYPE DEFINES /////////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- -class HotKeyTranslator : public GameMessageTranslator -{ -public: - virtual GameMessageDisposition translateGameMessage(const GameMessage *msg) override; - virtual ~HotKeyTranslator() override { } -}; - -//----------------------------------------------------------------------------- -class HotKey -{ -public: - HotKey(); - GameWindow *m_win; - AsciiString m_key; - // we may need a checkmark system. -}; - -//----------------------------------------------------------------------------- -class HotKeyManager : public SubsystemInterface -{ -public: - HotKeyManager(); - virtual ~HotKeyManager() override; - // Inherited from subsystem interface ----------------------------------------------------------- - virtual void init() override; ///< Initialize the Hotkey system - virtual void update() override {} ///< A No-op for us - virtual void reset() override; ///< Reset - //----------------------------------------------------------------------------------------------- - - void addHotKey( GameWindow *win, const AsciiString& key); - Bool executeHotKey( const AsciiString& key); // called fromt eh HotKeyTranslator - - AsciiString searchHotKey( const AsciiString& label); - AsciiString searchHotKey( const UnicodeString& uStr ); - -private: - typedef std::map HotKeyMap; - HotKeyMap m_hotKeyMap; -}; -extern HotKeyManager *TheHotKeyManager; -//----------------------------------------------------------------------------- -// INLINING /////////////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// EXTERNALS ////////////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Include/GameClient/LookAtXlat.h b/Generals/Code/GameEngine/Include/GameClient/LookAtXlat.h deleted file mode 100644 index c47573b5b07..00000000000 --- a/Generals/Code/GameEngine/Include/GameClient/LookAtXlat.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: LookAtXlat.h /////////////////////////////////////////////////////////// -// Author: Steven Johnson, Dec 2001 - -#pragma once - -#include "GameClient/InGameUI.h" - -//----------------------------------------------------------------------------- -// TheSuperHackers @feature The Screen Edge Scrolling can now be enabled or -// disabled depending on the App being Windowed or Fullscreen. -typedef UnsignedInt ScreenEdgeScrollMode; -enum ScreenEdgeScrollMode_ CPP_11(: ScreenEdgeScrollMode) -{ - ScreenEdgeScrollMode_EnabledInWindowedApp = 1<<0, // Scroll when touching the edge while the app is windowed - ScreenEdgeScrollMode_EnabledInFullscreenApp = 1<<1, // Scroll when touching the edge while the app is fullscreen - - ScreenEdgeScrollMode_Default = ScreenEdgeScrollMode_EnabledInFullscreenApp, // Default based on original game behavior -}; - -//----------------------------------------------------------------------------- -class LookAtTranslator : public GameMessageTranslator -{ -public: - LookAtTranslator(); - virtual ~LookAtTranslator() override; - - virtual GameMessageDisposition translateGameMessage(const GameMessage *msg) override; - virtual const ICoord2D* getRMBScrollAnchor(); // get m_anchor ICoord2D if we're RMB scrolling - Bool hasMouseMovedRecently(); - void setCurrentPos( const ICoord2D& pos ); - void setScreenEdgeScrollMode(ScreenEdgeScrollMode mode); - - void resetModes(); //Used when disabling input, so when we reenable it we aren't stuck in a mode. - -private: - enum - { - MAX_VIEW_LOCS = 8 - }; - enum ScrollType - { - SCROLL_NONE = 0, - SCROLL_RMB, - SCROLL_KEY, - SCROLL_SCREENEDGE - }; - ICoord2D m_anchor; - ICoord2D m_originalAnchor; - ICoord2D m_currentPos; - Real m_anchorAngle; - Bool m_isScrolling; // set to true if we are in the act of RMB scrolling - Bool m_isRotating; // set to true if we are in the act of MMB rotating - Bool m_isPitching; // set to true if we are in the act of pitch rotation - Bool m_isPitchingToDefault; // set to true if we are in the act of default pitch rotation - Bool m_isChangingFOV; // set to true if we are in the act of changing the field of view - UnsignedInt m_middleButtonDownTimeMsec; // real-time in milliseconds when middle button goes down - DrawableID m_lastPlaneID; - ViewLocation m_viewLocation[ MAX_VIEW_LOCS ]; - ScrollType m_scrollType; - ScreenEdgeScrollMode m_screenEdgeScrollMode; - UnsignedInt m_lastMouseMoveTimeMsec; // real-time in milliseconds when mouse last moved - - void setScrolling( ScrollType scrollType ); - void stopScrolling(); - Bool canScrollAtScreenEdge() const; -}; - -extern LookAtTranslator *TheLookAtTranslator; diff --git a/Generals/Code/GameEngine/Include/GameClient/MetaEvent.h b/Generals/Code/GameEngine/Include/GameClient/MetaEvent.h deleted file mode 100644 index 9bda58f2b07..00000000000 --- a/Generals/Code/GameEngine/Include/GameClient/MetaEvent.h +++ /dev/null @@ -1,407 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: MetaEvent.h /////////////////////////////////////////////////////////// -// Author: Steven Johnson, Dec 2001 - -#pragma once - -#include "Common/SubsystemInterface.h" -#include "GameClient/InGameUI.h" - - -enum MappableKeyCategories CPP_11(: Int) -{ - CATEGORY_CONTROL = 0, - CATEGORY_INFORMATION, - CATEGORY_INTERFACE, - CATEGORY_SELECTION, - CATEGORY_TAUNT, - CATEGORY_TEAM, - CATEGORY_MISC, - CATEGORY_DEBUG, - - CATEGORY_NUM_CATEGORIES -}; - -static const LookupListRec CategoryListName[] = -{ - {"CONTROL", CATEGORY_CONTROL}, - {"INFORMATION", CATEGORY_INFORMATION}, - {"INTERFACE", CATEGORY_INTERFACE}, - {"SELECTION", CATEGORY_SELECTION}, - {"TAUNT", CATEGORY_TAUNT}, - {"TEAM", CATEGORY_TEAM}, - {"MISC", CATEGORY_MISC}, - {"DEBUG", CATEGORY_DEBUG}, - { nullptr, 0} -}; - - -// ------------------------------------------------------------------------------- -// the keys we allow to be mapped to Meta-events. -// note that this is a subset of all the keys available; -// in particular, "modifier" keys and keypad keys aren't -// available. Note that MappableKeyType is a SUBSET of -// KeyDefType; this is extremely important to maintain! -enum MappableKeyType CPP_11(: Int) -{ - // keypad keys ---------------------------------------------------------------- - MK_KP0 = KEY_KP0, - MK_KP1 = KEY_KP1, - MK_KP2 = KEY_KP2, - MK_KP3 = KEY_KP3, - MK_KP4 = KEY_KP4, - MK_KP5 = KEY_KP5, - MK_KP6 = KEY_KP6, - MK_KP7 = KEY_KP7, - MK_KP8 = KEY_KP8, - MK_KP9 = KEY_KP9, - MK_KPDEL = KEY_KPDEL, - MK_KPSTAR = KEY_KPSTAR, - MK_KPMINUS = KEY_KPMINUS, - MK_KPPLUS = KEY_KPPLUS, - MK_KPENTER = KEY_KPENTER, - MK_KPSLASH = KEY_KPSLASH, - - MK_ESC = KEY_ESC, - MK_BACKSPACE = KEY_BACKSPACE, - MK_ENTER = KEY_ENTER, - MK_SPACE = KEY_SPACE, - MK_TAB = KEY_TAB, - MK_F1 = KEY_F1, - MK_F2 = KEY_F2, - MK_F3 = KEY_F3, - MK_F4 = KEY_F4, - MK_F5 = KEY_F5, - MK_F6 = KEY_F6, - MK_F7 = KEY_F7, - MK_F8 = KEY_F8, - MK_F9 = KEY_F9, - MK_F10 = KEY_F10, - MK_F11 = KEY_F11, - MK_F12 = KEY_F12, - MK_A = KEY_A, - MK_B = KEY_B, - MK_C = KEY_C, - MK_D = KEY_D, - MK_E = KEY_E, - MK_F = KEY_F, - MK_G = KEY_G, - MK_H = KEY_H, - MK_I = KEY_I, - MK_J = KEY_J, - MK_K = KEY_K, - MK_L = KEY_L, - MK_M = KEY_M, - MK_N = KEY_N, - MK_O = KEY_O, - MK_P = KEY_P, - MK_Q = KEY_Q, - MK_R = KEY_R, - MK_S = KEY_S, - MK_T = KEY_T, - MK_U = KEY_U, - MK_V = KEY_V, - MK_W = KEY_W, - MK_X = KEY_X, - MK_Y = KEY_Y, - MK_Z = KEY_Z, - MK_1 = KEY_1, - MK_2 = KEY_2, - MK_3 = KEY_3, - MK_4 = KEY_4, - MK_5 = KEY_5, - MK_6 = KEY_6, - MK_7 = KEY_7, - MK_8 = KEY_8, - MK_9 = KEY_9, - MK_0 = KEY_0, - MK_MINUS = KEY_MINUS, - MK_EQUAL = KEY_EQUAL, - MK_LBRACKET = KEY_LBRACKET, - MK_RBRACKET = KEY_RBRACKET, - MK_SEMICOLON = KEY_SEMICOLON, - MK_APOSTROPHE = KEY_APOSTROPHE, - MK_TICK = KEY_TICK, - MK_BACKSLASH = KEY_BACKSLASH, - MK_COMMA = KEY_COMMA, - MK_PERIOD = KEY_PERIOD, - MK_SLASH = KEY_SLASH, - MK_UP = KEY_UP, - MK_DOWN = KEY_DOWN, - MK_LEFT = KEY_LEFT, - MK_RIGHT = KEY_RIGHT, - MK_HOME = KEY_HOME, - MK_END = KEY_END, - MK_PGUP = KEY_PGUP, - MK_PGDN = KEY_PGDN, - MK_INS = KEY_INS, - MK_DEL = KEY_DEL, - MK_NONE = KEY_NONE - -}; - -static const LookupListRec KeyNames[] = -{ - // keypad keys ---------------------------------------------------------------- - { "KEY_KP0", MK_KP0 }, - { "KEY_KP1", MK_KP1 }, - { "KEY_KP2", MK_KP2 }, - { "KEY_KP3", MK_KP3 }, - { "KEY_KP4", MK_KP4 }, - { "KEY_KP5", MK_KP5 }, - { "KEY_KP6", MK_KP6 }, - { "KEY_KP7", MK_KP7 }, - { "KEY_KP8", MK_KP8 }, - { "KEY_KP9", MK_KP9 }, - { "KEY_KPDEL", MK_KPDEL }, - { "KEY_KPSTAR", MK_KPSTAR }, - { "KEY_KPMINUS", MK_KPMINUS }, - { "KEY_KPPLUS", MK_KPPLUS }, - { "KEY_KPENTER", MK_KPENTER }, - { "KEY_KPSLASH", MK_KPSLASH }, - - { "KEY_ESC", MK_ESC }, - { "KEY_BACKSPACE", MK_BACKSPACE }, - { "KEY_ENTER", MK_ENTER }, - { "KEY_SPACE", MK_SPACE }, - { "KEY_TAB", MK_TAB }, - { "KEY_F1", MK_F1 }, - { "KEY_F2", MK_F2 }, - { "KEY_F3", MK_F3 }, - { "KEY_F4", MK_F4 }, - { "KEY_F5", MK_F5 }, - { "KEY_F6", MK_F6 }, - { "KEY_F7", MK_F7 }, - { "KEY_F8", MK_F8 }, - { "KEY_F9", MK_F9 }, - { "KEY_F10", MK_F10 }, - { "KEY_F11", MK_F11 }, - { "KEY_F12", MK_F12 }, - { "KEY_A", MK_A }, - { "KEY_B", MK_B }, - { "KEY_C", MK_C }, - { "KEY_D", MK_D }, - { "KEY_E", MK_E }, - { "KEY_F", MK_F }, - { "KEY_G", MK_G }, - { "KEY_H", MK_H }, - { "KEY_I", MK_I }, - { "KEY_J", MK_J }, - { "KEY_K", MK_K }, - { "KEY_L", MK_L }, - { "KEY_M", MK_M }, - { "KEY_N", MK_N }, - { "KEY_O", MK_O }, - { "KEY_P", MK_P }, - { "KEY_Q", MK_Q }, - { "KEY_R", MK_R }, - { "KEY_S", MK_S }, - { "KEY_T", MK_T }, - { "KEY_U", MK_U }, - { "KEY_V", MK_V }, - { "KEY_W", MK_W }, - { "KEY_X", MK_X }, - { "KEY_Y", MK_Y }, - { "KEY_Z", MK_Z }, - { "KEY_1", MK_1 }, - { "KEY_2", MK_2 }, - { "KEY_3", MK_3 }, - { "KEY_4", MK_4 }, - { "KEY_5", MK_5 }, - { "KEY_6", MK_6 }, - { "KEY_7", MK_7 }, - { "KEY_8", MK_8 }, - { "KEY_9", MK_9 }, - { "KEY_0", MK_0 }, - { "KEY_MINUS", MK_MINUS }, - { "KEY_EQUAL", MK_EQUAL }, - { "KEY_LBRACKET", MK_LBRACKET }, - { "KEY_RBRACKET", MK_RBRACKET }, - { "KEY_SEMICOLON", MK_SEMICOLON }, - { "KEY_APOSTROPHE", MK_APOSTROPHE }, - { "KEY_TICK", MK_TICK }, - { "KEY_BACKSLASH", MK_BACKSLASH }, - { "KEY_COMMA", MK_COMMA }, - { "KEY_PERIOD", MK_PERIOD }, - { "KEY_SLASH", MK_SLASH }, - { "KEY_UP", MK_UP }, - { "KEY_DOWN", MK_DOWN }, - { "KEY_LEFT", MK_LEFT }, - { "KEY_RIGHT", MK_RIGHT }, - { "KEY_HOME", MK_HOME }, - { "KEY_END", MK_END }, - { "KEY_PGUP", MK_PGUP }, - { "KEY_PGDN", MK_PGDN }, - { "KEY_INS", MK_INS }, - { "KEY_DEL", MK_DEL }, - { "KEY_NONE", MK_NONE }, - { nullptr, 0 } -}; - -// ------------------------------------------------------------------------------- -enum MappableKeyTransition CPP_11(: Int) -{ - DOWN, - UP, - DOUBLEDOWN, // if a key transition is repeated immediately, we generate this. - - MAPPABLE_KEY_TRANSITION_COUNT -}; - -static const LookupListRec TransitionNames[] = -{ - { "DOWN", DOWN }, - { "UP", UP }, - { "DOUBLEDOWN", DOUBLEDOWN }, - { nullptr, 0 } -}; -static_assert(ARRAY_SIZE(TransitionNames) == MAPPABLE_KEY_TRANSITION_COUNT + 1, "Incorrect array size"); - -// ------------------------------------------------------------------------------- -// an easier-to-type subset of the KEY_STATE stuff. -enum MappableKeyModState CPP_11(: Int) -{ - NONE = 0, - CTRL = KEY_STATE_LCONTROL, - ALT = KEY_STATE_LALT, - SHIFT = KEY_STATE_LSHIFT, - CTRL_ALT = CTRL|ALT, - SHIFT_CTRL = SHIFT|CTRL, - SHIFT_ALT = SHIFT|ALT, - SHIFT_ALT_CTRL = SHIFT|ALT|CTRL -}; - -static const LookupListRec ModifierNames[] = -{ - { "NONE", NONE }, - { "CTRL", CTRL }, - { "ALT", ALT }, - { "SHIFT", SHIFT }, - { "CTRL_ALT", CTRL_ALT }, - { "SHIFT_CTRL", SHIFT_CTRL }, - { "SHIFT_ALT", SHIFT_ALT }, - { "SHIFT_ALT_CTRL" , SHIFT_ALT_CTRL }, - { nullptr, 0 } -}; - - - -// ------------------------------------------------------------------------------- -// CommandUsableInType sets in what state the commands are allowed. -enum CommandUsableInType CPP_11(: Int) -{ - COMMANDUSABLE_NONE = 0, - - COMMANDUSABLE_SHELL = (1 << 0), // Command is usable when in Shell (Menus) - COMMANDUSABLE_GAME = (1 << 1), // Command is usable when not in Shell - COMMANDUSABLE_OBSERVER = (1 << 2), // TheSuperHackers @feature Command is usable when observing - - COMMANDUSABLE_EVERYWHERE = ~0, -}; - -static const char* const TheCommandUsableInNames[] = -{ - "SHELL", - "GAME", - "OBSERVER", - - nullptr -}; - -// ------------------------------------------------------------------------------- -class MetaMapRec : public MemoryPoolObject -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(MetaMapRec, "MetaMapRec") -public: - MetaMapRec* m_next; - GameMessage::Type m_meta; ///< the meta-event to emit - MappableKeyType m_key; ///< the key we want - MappableKeyTransition m_transition; ///< the state of the key - MappableKeyModState m_modState; ///< the required state of the ctrl-alt-shift keys - CommandUsableInType m_usableIn; ///< the allowed place the command can be used in - // Next fields are added for Key mapping Dialog - MappableKeyCategories m_category; ///< This is the category the key falls under - UnicodeString m_description; ///< The description string for the keys - UnicodeString m_displayName; ///< The display name of our command -}; -EMPTY_DTOR(MetaMapRec) - - -//----------------------------------------------------------------------------- -class MetaEventTranslator : public GameMessageTranslator -{ -private: - - Int m_lastKeyDown; // really a MappableKeyType - Int m_lastModState; // really a MappableKeyModState - - enum { NUM_MOUSE_BUTTONS = 3 }; - ICoord2D m_mouseDownPosition[NUM_MOUSE_BUTTONS]; - Bool m_nextUpShouldCreateDoubleClick[NUM_MOUSE_BUTTONS]; - -public: - MetaEventTranslator(); - virtual ~MetaEventTranslator() override; - virtual GameMessageDisposition translateGameMessage(const GameMessage *msg) override; - -private: - void onMouseEvent(const GameMessage *msg); - void onKeyEvent(const GameMessage *msg, GameMessageDisposition &disp); -}; - -//----------------------------------------------------------------------------- -class MetaMap : public SubsystemInterface -{ - friend class MetaEventTranslator; - -private: - MetaMapRec *m_metaMaps; - -protected: - GameMessage::Type findGameMessageMetaType(const char* name); - MetaMapRec *getMetaMapRec(GameMessage::Type t); - -public: - - MetaMap(); - virtual ~MetaMap() override; - - virtual void init() override { } - virtual void reset() override { } - virtual void update() override { } - - static void parseMetaMap(INI* ini); - - // TheSuperHackers @feature Function to generate default key mappings - // for actions that were not found in a CommandMap.ini - void generateMetaMap(); - - void verifyMetaMap(); - - const MetaMapRec *getFirstMetaMapRec() const { return m_metaMaps; } -}; - -extern MetaMap *TheMetaMap; diff --git a/Generals/Code/GameEngine/Include/GameClient/PlaceEventTranslator.h b/Generals/Code/GameEngine/Include/GameClient/PlaceEventTranslator.h deleted file mode 100644 index 409c3fa8a45..00000000000 --- a/Generals/Code/GameEngine/Include/GameClient/PlaceEventTranslator.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PlaceEventTranslator.h /////////////////////////////////////////////////////////// -// Author: Steven Johnson, Dec 2001 - -#pragma once - -#include "GameClient/InGameUI.h" - -//----------------------------------------------------------------------------- -class PlaceEventTranslator : public GameMessageTranslator -{ -private: - UnsignedInt m_frameOfUpButton; - -public: - PlaceEventTranslator(); - virtual ~PlaceEventTranslator() override; - virtual GameMessageDisposition translateGameMessage(const GameMessage *msg) override; -}; diff --git a/Generals/Code/GameEngine/Include/GameClient/SelectionXlat.h b/Generals/Code/GameEngine/Include/GameClient/SelectionXlat.h deleted file mode 100644 index 1f154c03fe2..00000000000 --- a/Generals/Code/GameEngine/Include/GameClient/SelectionXlat.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: SelectionXlat.h /////////////////////////////////////////////////////////// -// Author: Steven Johnson, Dec 2001 - -#pragma once - -#include "GameClient/InGameUI.h" - -class ThingTemplate; - -typedef std::map SelectCountMap; -typedef SelectCountMap::iterator SelectCountMapIt; - -//----------------------------------------------------------------------------- -class SelectionTranslator : public GameMessageTranslator -{ - // this is an evil friend wrapper due to the current limitations of Drawable iterators. - friend Bool selectFriendsWrapper( Drawable *draw, void *userData ); - friend Bool killThemKillThemAllWrapper( Drawable *draw, void *userData ); -private: - - Bool m_leftMouseButtonIsDown; - Bool m_dragSelecting; - UnsignedInt m_lastGroupSelTime; - Int m_lastGroupSelGroup; - ICoord2D m_selectFeedbackAnchor; // Note: Used for drawing feedback only. - ICoord2D m_deselectFeedbackAnchor; // Note: Used for drawing feedback only. - Bool m_displayedMaxWarning; // did we already display a warning about selecting too many units? - UnsignedInt m_lastClick; ///< timer used for checking double click for type selection - - SelectCountMap m_selectCountMap; - - Coord3D m_deselectDownCameraPosition; - - Bool selectFriends( Drawable *draw, GameMessage *createTeamMsg, Bool dragSelecting ); - Bool killThemKillThemAll( Drawable *draw, GameMessage *killThemAllMsg ); - -public: - SelectionTranslator(); - virtual ~SelectionTranslator() override; - virtual GameMessageDisposition translateGameMessage(const GameMessage *msg) override; - //added for fix to the drag selection when entering control bar - //changes the mode of drag selecting to it's opposite - void setDragSelecting(Bool dragSelect); - void setLeftMouseButton(Bool state); - -#if defined(RTS_DEBUG) || defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE) - Bool m_HandOfGodSelectionMode; - Bool isHandOfGodSelectionMode() { return m_HandOfGodSelectionMode; }; -#endif - -}; - -Bool CanSelectDrawable( const Drawable *draw, Bool dragSelecting ); -extern SelectionTranslator *TheSelectionTranslator; diff --git a/Generals/Code/GameEngine/Include/GameClient/WindowXlat.h b/Generals/Code/GameEngine/Include/GameClient/WindowXlat.h deleted file mode 100644 index 52d384c532f..00000000000 --- a/Generals/Code/GameEngine/Include/GameClient/WindowXlat.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: WindowXlat.h /////////////////////////////////////////////////////////// -// Author: Steven Johnson, Dec 2001 - -#pragma once - -#include "GameClient/InGameUI.h" - -//----------------------------------------------------------------------------- -class WindowTranslator : public GameMessageTranslator -{ -private: - // nothing -public: - WindowTranslator(); - virtual ~WindowTranslator() override; - virtual GameMessageDisposition translateGameMessage(const GameMessage *msg) override; -}; diff --git a/Generals/Code/GameEngine/Include/GameLogic/Armor.h b/Generals/Code/GameEngine/Include/GameLogic/Armor.h index ffa97d84b2c..121e12f6864 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Armor.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Armor.h @@ -121,7 +121,7 @@ class ArmorStore : public SubsystemInterface private: - typedef std::hash_map< NameKeyType, ArmorTemplate, rts::hash, rts::equal_to > ArmorTemplateMap; + typedef std::hash_map< NameKeyType, ArmorTemplate, rts::hash, rts::equal_to/**/> ArmorTemplateMap; ArmorTemplateMap m_armorTemplates; }; diff --git a/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h b/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h index f8c1388e32b..c47c61eb7dc 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h +++ b/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h @@ -89,7 +89,7 @@ enum /// Function pointers for use by GameLogic callback functions. typedef void (*GameLogicFuncPtr)( Object *obj, void *userData ); -typedef std::hash_map, rts::equal_to > ObjectPtrHash; +typedef std::hash_map, rts::equal_to/**/> ObjectPtrHash; typedef ObjectPtrHash::const_iterator ObjectPtrIter; typedef std::vector ObjectPtrVector; @@ -369,13 +369,13 @@ class GameLogic : public SubsystemInterface, public Snapshot overrides to thing template buildable status. doesn't really belong here, but has to go somewhere. (srj) */ - typedef std::hash_map< AsciiString, BuildableStatus, rts::hash, rts::equal_to > BuildableMap; + typedef std::hash_map< AsciiString, BuildableStatus, rts::hash, rts::equal_to/**/> BuildableMap; BuildableMap m_thingTemplateBuildableOverrides; /** overrides to control bars. doesn't really belong here, but has to go somewhere. (srj) */ - typedef std::hash_map< AsciiString, ConstCommandButtonPtr, rts::hash, rts::equal_to > ControlBarOverrideMap; + typedef std::hash_map< AsciiString, ConstCommandButtonPtr, rts::hash, rts::equal_to/**/> ControlBarOverrideMap; ControlBarOverrideMap m_controlBarOverrides; Real m_width, m_height; ///< Dimensions of the world diff --git a/Generals/Code/GameEngine/Include/GameLogic/Locomotor.h b/Generals/Code/GameEngine/Include/GameLogic/Locomotor.h index 22ab24b7e6e..7787ba89436 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Locomotor.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Locomotor.h @@ -484,7 +484,7 @@ class LocomotorStore : public SubsystemInterface private: - typedef std::map< NameKeyType, LocomotorTemplate*, std::less > LocomotorTemplateMap; + typedef std::map< NameKeyType, LocomotorTemplate*, std::less/**/> LocomotorTemplateMap; LocomotorTemplateMap m_locomotorTemplates; diff --git a/Generals/Code/GameEngine/Include/GameLogic/Module/AIUpdate.h b/Generals/Code/GameEngine/Include/GameLogic/Module/AIUpdate.h index 66fd996b7d3..8050b13518a 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Module/AIUpdate.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Module/AIUpdate.h @@ -184,7 +184,7 @@ enum MoodActionAdjustment CPP_11(: Int) //------------------------------------------------------------------------------------------------- typedef std::vector< const LocomotorTemplate* > LocomotorTemplateVector; -typedef std::map< LocomotorSetType, LocomotorTemplateVector, std::less > LocomotorTemplateMap; +typedef std::map< LocomotorSetType, LocomotorTemplateVector, std::less/**/> LocomotorTemplateMap; //------------------------------------------------------------------------------------------------- class AIUpdateModuleData : public UpdateModuleData diff --git a/Generals/Code/GameEngine/Include/GameLogic/Module/AssistedTargetingUpdate.h b/Generals/Code/GameEngine/Include/GameLogic/Module/AssistedTargetingUpdate.h index 04284c0f18a..0ec053b0993 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Module/AssistedTargetingUpdate.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Module/AssistedTargetingUpdate.h @@ -38,15 +38,14 @@ class AssistedTargetingUpdateModuleData : public UpdateModuleData public: Int m_clipSize; WeaponSlotType m_weaponSlot; - ThingTemplate *m_laserFromAssisted; - ThingTemplate *m_laserToTarget; + + AsciiString m_laserFromAssistedName; + AsciiString m_laserToTargetName; AssistedTargetingUpdateModuleData() { m_clipSize = 1; m_weaponSlot = PRIMARY_WEAPON; - m_laserFromAssisted = nullptr; - m_laserToTarget = nullptr; } static void buildFieldParse(MultiIniFieldParse& p); @@ -72,4 +71,7 @@ class AssistedTargetingUpdate : public UpdateModule private: void makeFeedbackLaser( const ThingTemplate *laserTemplate, const Object *from, const Object *to ); + + const ThingTemplate *m_laserFromAssisted; + const ThingTemplate *m_laserToTarget; }; diff --git a/Generals/Code/GameEngine/Include/GameLogic/Module/OpenContain.h b/Generals/Code/GameEngine/Include/GameLogic/Module/OpenContain.h index f4194c95816..cf145317cd1 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Module/OpenContain.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Module/OpenContain.h @@ -239,7 +239,7 @@ class OpenContain : public UpdateModule, UnsignedInt m_containListSize; ///< size of contained list private: - typedef std::map< ObjectID, ObjectEnterExitType, std::less > ObjectEnterExitMap; + typedef std::map< ObjectID, ObjectEnterExitType, std::less/**/> ObjectEnterExitMap; ObjectEnterExitMap m_objectEnterExitInfo; UnsignedInt m_stealthUnitsContained; ///< number of stealth units that can't be seen by enemy players. diff --git a/Generals/Code/GameEngine/Include/GameLogic/ObjectCreationList.h b/Generals/Code/GameEngine/Include/GameLogic/ObjectCreationList.h index b403756bd17..11913483e7c 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/ObjectCreationList.h +++ b/Generals/Code/GameEngine/Include/GameLogic/ObjectCreationList.h @@ -205,7 +205,7 @@ class ObjectCreationListStore : public SubsystemInterface private: - typedef std::map< NameKeyType, ObjectCreationList, std::less > ObjectCreationListMap; + typedef std::map< NameKeyType, ObjectCreationList, std::less/**/> ObjectCreationListMap; ObjectCreationListMap m_ocls; // note, this list doesn't own the nuggets; all nuggets are owned by the Store. diff --git a/Generals/Code/GameEngine/Include/GameLogic/ScriptEngine.h b/Generals/Code/GameEngine/Include/GameLogic/ScriptEngine.h index ef943a40cc5..73dc8796c71 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/ScriptEngine.h +++ b/Generals/Code/GameEngine/Include/GameLogic/ScriptEngine.h @@ -99,7 +99,7 @@ typedef std::pair PairAsciiStringUINT; typedef std::list ListAsciiStringUINT; typedef ListAsciiStringUINT::iterator ListAsciiStringUINTIt; -typedef std::map< const ThingTemplate *, Int, std::less > AttackPriorityMap; +typedef std::map< const ThingTemplate *, Int, std::less/**/> AttackPriorityMap; typedef std::pair AsciiStringObjectIDPair; typedef std::list ListAsciiStringObjectID; typedef std::list::iterator ListAsciiStringObjectIDIt; diff --git a/Generals/Code/GameEngine/Include/GameLogic/Weapon.h b/Generals/Code/GameEngine/Include/GameLogic/Weapon.h index c0408a1c25d..6f5f44336c4 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/Weapon.h +++ b/Generals/Code/GameEngine/Include/GameLogic/Weapon.h @@ -864,7 +864,7 @@ class WeaponStore : public SubsystemInterface std::vector m_weaponTemplateVector; // TheSuperHackers @performance IamInnocent 01/01/2026 - Now additionally stores the same weapon templates in a hash map to optimize lookups by name key - typedef std::hash_map, rts::equal_to > WeaponTemplateMap; + typedef std::hash_map, rts::equal_to/**/> WeaponTemplateMap; WeaponTemplateMap m_weaponTemplateHashMap; std::list m_weaponDDI; diff --git a/Generals/Code/GameEngine/Source/Common/PerfTimer.cpp b/Generals/Code/GameEngine/Source/Common/PerfTimer.cpp index f55f08e7104..27d96b22531 100644 --- a/Generals/Code/GameEngine/Source/Common/PerfTimer.cpp +++ b/Generals/Code/GameEngine/Source/Common/PerfTimer.cpp @@ -214,7 +214,7 @@ void InitPrecisionTimer() /*static*/ Bool AutoPerfGatherIgnore::s_ignoring = false; //------------------------------------------------------------------------------------------------- -typedef std::vector< std::pair< AsciiString, AsciiString > > StringPairVec; +typedef std::vector< std::pair< AsciiString, AsciiString >/**/> StringPairVec; //------------------------------------------------------------------------------------------------- // PerfMetrics class. Basically, request a handle with your name and it will return. We use a vector diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClientDispatch.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClientDispatch.cpp deleted file mode 100644 index fb657816171..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/GameClientDispatch.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: .cpp ///////////////////////////////////////////////////////////////////////////////////// -// Author: Colin Day -// Description: Game Client message dispatcher -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/MessageStream.h" -#include "GameClient/GameClient.h" - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -/** The Client message dispatcher, this is the last "translator" on the message - * stream before the messages go to the network for processing. It gives - * the client itself the opportunity to respond to any messages on the stream - * or create new ones to pass along to the network and logic */ -GameMessageDisposition GameClientMessageDispatcher::translateGameMessage(const GameMessage *msg) -{ - if (msg->getType() >= GameMessage::MSG_BEGIN_NETWORK_MESSAGES && msg->getType() <= GameMessage::MSG_END_NETWORK_MESSAGES) - return KEEP_MESSAGE; - if (msg->getType() == GameMessage::MSG_NEW_GAME || msg->getType() == GameMessage::MSG_CLEAR_GAME_DATA) - return KEEP_MESSAGE; - - if (msg->getType() == GameMessage::MSG_FRAME_TICK) - return KEEP_MESSAGE; - - //DEBUG_LOG(("GameClientMessageDispatcher::translateGameMessage() - eating a %s on frame %d", - //((GameMessage *)msg)->getCommandAsString(), TheGameClient->getFrame())); - - return DESTROY_MESSAGE; -} diff --git a/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp b/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp index 3b62554ba46..5618f45aa60 100644 --- a/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -1477,19 +1477,6 @@ void InGameUI::handleRadiusCursor() { if (!m_curRadiusCursor.isEmpty()) { - const MouseIO* mouseIO = TheMouse->getMouseStatus(); - Coord3D pos; - - // - // if the mouse is in the radar window, the position in the world is that which is - // represented by the radar, otherwise we use the mouse position itself transformed - // from screen to world - // But only if the radar is on. - // - if( !rts::localPlayerHasRadar() || (TheRadar->screenPixelToWorld( &mouseIO->pos, &pos ) == FALSE) )// if radar off, or point not on radar - TheTacticalView->screenToTerrain( &mouseIO->pos, &pos ); - - if ( TheGlobalData->m_doubleClickAttackMove && m_duringDoubleClickAttackMoveGuardHintTimer > 0 ) { m_curRadiusCursor.setOpacity( m_duringDoubleClickAttackMoveGuardHintTimer * 0.1f ); @@ -1498,8 +1485,31 @@ void InGameUI::handleRadiusCursor() } else { - m_curRadiusCursor.setPosition(pos); //world space position of center of decal - m_curRadiusCursor.update(); + const MouseIO* mouseIO = TheMouse->getMouseStatus(); + Coord3D pos; + Bool hasPos = false; + + // + // if the mouse is in the radar window, the position in the world is that which is + // represented by the radar, otherwise we use the mouse position itself transformed + // from screen to world, but only if the radar is on. + // + if( rts::localPlayerHasRadar() ) + { + hasPos = TheRadar->screenPixelToWorld( &mouseIO->pos, &pos ); + } + + if( !hasPos ) + { + // if radar off, or point not on radar + hasPos = TheTacticalView->screenToTerrain( &mouseIO->pos, &pos ); + } + + if( hasPos ) + { + m_curRadiusCursor.setPosition(pos); //world space position of center of decal + m_curRadiusCursor.update(); + } } } @@ -1508,9 +1518,11 @@ void InGameUI::handleRadiusCursor() void InGameUI::triggerDoubleClickAttackMoveGuardHint() { - m_duringDoubleClickAttackMoveGuardHintTimer = 11; const MouseIO* mouseIO = TheMouse->getMouseStatus(); - TheTacticalView->screenToTerrain( &mouseIO->pos, &m_duringDoubleClickAttackMoveGuardHintStashedPosition ); + if( TheTacticalView->screenToTerrain( &mouseIO->pos, &m_duringDoubleClickAttackMoveGuardHintStashedPosition ) ) + { + m_duringDoubleClickAttackMoveGuardHintTimer = 11; + } } @@ -1603,20 +1615,21 @@ void InGameUI::handleBuildPlacements() Coord3D worldStart, worldEnd; // project the start and the end points of the line anchor into the 3D world - TheTacticalView->screenToTerrain( &start, &worldStart ); - TheTacticalView->screenToTerrain( &end, &worldEnd ); - - Coord2D v; - v.x = worldEnd.x - worldStart.x; - v.y = worldEnd.y - worldStart.y; - angle = v.toAngle(); - - // TheSuperHackers @tweak Stubbjax 04/08/2025 Snap angle to nearest 45 degrees - // while using force attack mode for convenience. - if (isInForceAttackMode()) + if( TheTacticalView->screenToTerrain( &start, &worldStart ) && + TheTacticalView->screenToTerrain( &end, &worldEnd ) ) { - const Real snapRadians = DEG_TO_RADF(45); - angle = WWMath::Round(angle / snapRadians) * snapRadians; + Coord2D v; + v.x = worldEnd.x - worldStart.x; + v.y = worldEnd.y - worldStart.y; + angle = v.toAngle(); + + // TheSuperHackers @tweak Stubbjax 04/08/2025 Snap angle to nearest 45 degrees + // while using force attack mode for convenience. + if (isInForceAttackMode()) + { + const Real snapRadians = DEG_TO_RADF(45); + angle = WWMath::Round(angle / snapRadians) * snapRadians; + } } } @@ -1633,56 +1646,52 @@ void InGameUI::handleBuildPlacements() // set the location and angle of the place icon /**@todo this whole orientation vector thing is LAME! Must replace, all I want to to do is set a simple angle and have it automatically change, ug! */ - TheTacticalView->screenToTerrain( &loc, &world ); - m_placeIcon[ 0 ]->setPosition( &world ); - m_placeIcon[ 0 ]->setOrientation( angle ); - - - // - // check to see if this is a legal location to build something at and tint or "un-tint" - // the cursor icons as appropriate. This involves a pathfind which could be - // expensive so we don't want to do it on every frame (although that would be ideal) - // If we discover there are cases that this is just too slow we should increase the - // delay time between checks or we need to come up with a way of recording what is - // valid and what isn't or "fudge" the results to feel "ok" - // - if( TheGameClient->getFrame() & 0x1 ) + if( TheTacticalView->screenToTerrain( &loc, &world ) ) { - TheTerrainVisual->removeAllBibs(); - - Object *builderObject = TheGameLogic->findObjectByID( getPendingPlaceSourceObjectID() ); - - LegalBuildCode lbc; - lbc = TheBuildAssistant->isLocationLegalToBuild( &world, - m_pendingPlaceType, - angle, - BuildAssistant::USE_QUICK_PATHFIND | - BuildAssistant::TERRAIN_RESTRICTIONS | - BuildAssistant::CLEAR_PATH | - BuildAssistant::NO_OBJECT_OVERLAP | - BuildAssistant::SHROUD_REVEALED, - builderObject, - nullptr ); - - if( lbc != LBC_OK ) - m_placeIcon[ 0 ]->colorTint( &IllegalBuildColor ); - else - m_placeIcon[ 0 ]->colorTint( nullptr ); - + m_placeIcon[ 0 ]->setPosition( &world ); + m_placeIcon[ 0 ]->setOrientation( angle ); - - - // Add the bibs around the structure. - if (lbc != LBC_OK) + // + // check to see if this is a legal location to build something at and tint or "un-tint" + // the cursor icons as appropriate. This involves a pathfind which could be + // expensive so we don't want to do it on every frame (although that would be ideal) + // If we discover there are cases that this is just too slow we should increase the + // delay time between checks or we need to come up with a way of recording what is + // valid and what isn't or "fudge" the results to feel "ok" + // + if( TheGameClient->getFrame() & 0x1 ) { - TheTerrainVisual->addFactionBibDrawable(m_placeIcon[0], lbc != LBC_OK); - } else { - TheTerrainVisual->removeFactionBibDrawable(m_placeIcon[0]); + TheTerrainVisual->removeAllBibs(); + + Object *builderObject = TheGameLogic->findObjectByID( getPendingPlaceSourceObjectID() ); + + LegalBuildCode lbc; + lbc = TheBuildAssistant->isLocationLegalToBuild( &world, + m_pendingPlaceType, + angle, + BuildAssistant::USE_QUICK_PATHFIND | + BuildAssistant::TERRAIN_RESTRICTIONS | + BuildAssistant::CLEAR_PATH | + BuildAssistant::NO_OBJECT_OVERLAP | + BuildAssistant::SHROUD_REVEALED, + builderObject, + nullptr ); + + if( lbc != LBC_OK ) + m_placeIcon[ 0 ]->colorTint( &IllegalBuildColor ); + else + m_placeIcon[ 0 ]->colorTint( nullptr ); + + // Add the bibs around the structure. + if (lbc != LBC_OK) + { + TheTerrainVisual->addFactionBibDrawable(m_placeIcon[0], lbc != LBC_OK); + } else { + TheTerrainVisual->removeFactionBibDrawable(m_placeIcon[0]); + } } } - - // // we have additional place icons when we're placing down a line of walls or other // similarly placed object ... for those we will have them be oriented the same way @@ -1690,77 +1699,78 @@ void InGameUI::handleBuildPlacements() // if( isPlacementAnchored() && TheBuildAssistant->isLineBuildTemplate( m_pendingPlaceType ) ) { - Int i; - // get our line placement points ICoord2D screenStart, screenEnd; getPlacementPoints( &screenStart, &screenEnd ); // project the start and the end points of the line anchor into the 3D world Coord3D worldStart, worldEnd; - TheTacticalView->screenToTerrain( &screenStart, &worldStart ); - TheTacticalView->screenToTerrain( &screenEnd, &worldEnd ); - - // how big are each of our objects - Real objectSize = m_pendingPlaceType->getTemplateGeometryInfo().getMajorRadius() * 2.0f; - - // what is our max tiling length we can make - Int maxObjects = TheGlobalData->m_maxLineBuildObjects; - - // get the builder object that will be constructing things - Object *builderObject = TheGameLogic->findObjectByID( getPendingPlaceSourceObjectID() ); - - // - // given the start/end points in the world and the the angle of the wall, fill - // out an array of positions that "tile" this wall across the landscape - // - BuildAssistant::TileBuildInfo *tileBuildInfo; - tileBuildInfo = TheBuildAssistant->buildTiledLocations( m_pendingPlaceType, angle, - &worldStart, &worldEnd, - objectSize, maxObjects, - builderObject ); - - // create any necessary drawables we need to "fill out" the line - for( i = 0; i < tileBuildInfo->tilesUsed; i++ ) + if( TheTacticalView->screenToTerrain( &screenStart, &worldStart ) && + TheTacticalView->screenToTerrain( &screenEnd, &worldEnd ) ) { - - if( m_placeIcon[ i ] == nullptr ) + // how big are each of our objects + Real objectSize = m_pendingPlaceType->getTemplateGeometryInfo().getMajorRadius() * 2.0f; + + // what is our max tiling length we can make + Int maxObjects = TheGlobalData->m_maxLineBuildObjects; + + // get the builder object that will be constructing things + Object *builderObject = TheGameLogic->findObjectByID( getPendingPlaceSourceObjectID() ); + + // + // given the start/end points in the world and the the angle of the wall, fill + // out an array of positions that "tile" this wall across the landscape + // + BuildAssistant::TileBuildInfo *tileBuildInfo; + tileBuildInfo = TheBuildAssistant->buildTiledLocations( m_pendingPlaceType, angle, + &worldStart, &worldEnd, + objectSize, maxObjects, + builderObject ); + + // create any necessary drawables we need to "fill out" the line + Int i; + for( i = 0; i < tileBuildInfo->tilesUsed; i++ ) { - UnsignedInt drawableStatus = DRAWABLE_STATUS_NO_STATE_PARTICLES; - drawableStatus |= TheGlobalData->m_objectPlacementShadows ? DRAWABLE_STATUS_SHADOWS : 0; - m_placeIcon[ i ] = TheThingFactory->newDrawable( m_pendingPlaceType, drawableStatus ); + + if( m_placeIcon[ i ] == nullptr ) + { + UnsignedInt drawableStatus = DRAWABLE_STATUS_NO_STATE_PARTICLES; + drawableStatus |= TheGlobalData->m_objectPlacementShadows ? DRAWABLE_STATUS_SHADOWS : 0; + m_placeIcon[ i ] = TheThingFactory->newDrawable( m_pendingPlaceType, drawableStatus ); + } + } - } + // + // destroy any drawables that we're not using anymore because a previous + // line length was longer + // + for( i = tileBuildInfo->tilesUsed; i < maxObjects; i++ ) + { - // - // destroy any drawables that we're not using anymore because a previous - // line length was longer - // - for( i = tileBuildInfo->tilesUsed; i < maxObjects; i++ ) - { + if( m_placeIcon[ i ] != nullptr ) + TheGameClient->destroyDrawable( m_placeIcon[ i ] ); + m_placeIcon[ i ] = nullptr; - if( m_placeIcon[ i ] != nullptr ) - TheGameClient->destroyDrawable( m_placeIcon[ i ] ); - m_placeIcon[ i ] = nullptr; + } - } + // + // march down each drawable and set the position based on its position in the + // line and set their angles all the same + // + for( i = 0; i < tileBuildInfo->tilesUsed; i++ ) + { - // - // march down each drawable and set the position based on its position in the - // line and set their angles all the same - // - for( i = 0; i < tileBuildInfo->tilesUsed; i++ ) - { + // set the drawable position + m_placeIcon[ i ]->setPosition( &tileBuildInfo->positions[ i ] ); - // set the drawable position - m_placeIcon[ i ]->setPosition( &tileBuildInfo->positions[ i ] ); + // set opacity for the drawable + m_placeIcon[ i ]->setDrawableOpacity( TheGlobalData->m_objectPlacementOpacity ); - // set opacity for the drawable - m_placeIcon[ i ]->setDrawableOpacity( TheGlobalData->m_objectPlacementOpacity ); + // set the drawable angle + m_placeIcon[ i ]->setOrientation( angle ); - // set the drawable angle - m_placeIcon[ i ]->setOrientation( angle ); + } } diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp deleted file mode 100644 index 3ae17884275..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp +++ /dev/null @@ -1,512 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: GUICommandTranslator.cpp ///////////////////////////////////////////////////////////////// -// Author: Colin Day, March 2002 -// Desc: Translator for commands activated from the selection GUI, such as special unit -// actions, that require additional clicks in the world like selecting a target -// object or location -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// USER INCLUDES ////////////////////////////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/ActionManager.h" -#include "Common/GameCommon.h" -#include "Common/GameAudio.h" -#include "Common/NameKeyGenerator.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/SpecialPower.h" -#include "Common/ThingTemplate.h" -#include "GameClient/ControlBar.h" -#include "GameClient/Drawable.h" -#include "GameClient/GameText.h" -#include "Common/Geometry.h" -#include "GameClient/GUICommandTranslator.h" -#include "GameClient/CommandXlat.h" - - -// PRIVATE //////////////////////////////////////////////////////////////////////////////////////// -enum CommandStatus -{ - COMMAND_INCOMPLETE = 0, - COMMAND_COMPLETE -}; - -// PUBLIC ///////////////////////////////////////////////////////////////////////////////////////// - -PickAndPlayInfo::PickAndPlayInfo() -{ - m_air = FALSE; - m_drawTarget = nullptr; - m_weaponSlot = nullptr; - m_specialPowerType = SPECIAL_INVALID; -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -GUICommandTranslator::GUICommandTranslator() -{ - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -GUICommandTranslator::~GUICommandTranslator() -{ - -} - -//------------------------------------------------------------------------------------------------- -/** Is the object under the mouse position a valid target for the command */ -//------------------------------------------------------------------------------------------------- -static Object *validUnderCursor( const ICoord2D *mouse, const CommandButton *command, PickType pickType ) -{ - Object *pickObj = nullptr; - - // pick a drawable at the mouse location - Drawable *pick = TheTacticalView->pickDrawable( mouse, FALSE, pickType ); - - // only continue if there is something there - if( pick && pick->getObject() ) - { - Player *player = ThePlayerList->getLocalPlayer(); - - // get object we picked - pickObj = pick->getObject(); - - if (!command->isValidObjectTarget(player, pickObj)) - pickObj = nullptr; - - } - - - return pickObj; - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -static CommandStatus doFireWeaponCommand( const CommandButton *command, const ICoord2D *mouse ) -{ - - // sanity - if( command == nullptr || mouse == nullptr ) - return COMMAND_COMPLETE; - - // - // for single object selections get the source ID and sanity check for illegal object and - // bail along the way - // - ObjectID sourceID = INVALID_ID; - if( TheInGameUI->getSelectCount() == 1 ) - { - Drawable *draw = TheInGameUI->getFirstSelectedDrawable(); - - // sanity - if( draw == nullptr || draw->getObject() == nullptr ) - return COMMAND_COMPLETE; - - // get object id - sourceID = draw->getObject()->getID(); - - } - - // create message and send to the logic - GameMessage *msg; - if( BitIsSet( command->getOptions(), NEED_TARGET_POS ) ) - { - Coord3D world; - - // translate the mouse location into world coords - TheTacticalView->screenToTerrain( mouse, &world ); - - // create the message and append arguments - msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_WEAPON_AT_LOCATION ); - msg->appendIntegerArgument( command->getWeaponSlot() ); - msg->appendLocationArgument( world ); - msg->appendIntegerArgument( command->getMaxShotsToFire() ); - - //Also append the object ID (incase weapon doesn't like obstacles on land). - Object *target = validUnderCursor( mouse, command, PICK_TYPE_SELECTABLE ); - ObjectID targetID = target ? target->getID() : INVALID_ID; - msg->appendObjectIDArgument( targetID ); - - - } - else if( BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) - { - - // setup the pick type ... some commands allow us to target shrubbery - PickType pickType = PICK_TYPE_SELECTABLE; - - if( BitIsSet( command->getOptions(), ALLOW_SHRUBBERY_TARGET ) == TRUE ) - pickType = (PickType)((Int)pickType | (Int)PICK_TYPE_SHRUBBERY); - - if( BitIsSet( command->getOptions(), ALLOW_MINE_TARGET ) == TRUE ) - pickType = (PickType)((Int)pickType | (Int)PICK_TYPE_MINES); - - // get the target object under the cursor - Object *target = validUnderCursor( mouse, command, pickType ); - - // only continue if the object meets all the command criteria - if( target ) - { - - msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_WEAPON_AT_OBJECT ); - msg->appendIntegerArgument( command->getWeaponSlot() ); - msg->appendObjectIDArgument( target->getID() ); - msg->appendIntegerArgument( command->getMaxShotsToFire() ); - - } - - } - else - { - msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_WEAPON ); - msg->appendIntegerArgument( command->getWeaponSlot() ); - msg->appendIntegerArgument( command->getMaxShotsToFire() ); - - //This could be legit now -- think of firing a self destruct weapon - //----------------------------------------------------------------- - //DEBUG_CRASH( ("doFireWeaponCommand: Command options say it doesn't need additional user input '%s'", - // command->m_name.str()) ); - //return COMMAND_COMPLETE; - - } - - return COMMAND_COMPLETE; - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -static CommandStatus doGuardCommand( const CommandButton *command, GuardMode guardMode, const ICoord2D *mouse ) -{ - // sanity - if( command == nullptr || mouse == nullptr ) - return COMMAND_COMPLETE; - - if( TheInGameUI->getSelectCount() == 0 ) - return COMMAND_COMPLETE; - - GameMessage *msg = nullptr; - - if ( msg == nullptr && BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) - { - // get the target object under the cursor - Object* target = validUnderCursor( mouse, command, PICK_TYPE_SELECTABLE ); - if( target ) - { - msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_OBJECT ); - msg->appendObjectIDArgument( target->getID() ); - msg->appendIntegerArgument(guardMode); - pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_GUARD_OBJECT); - } - } - - if( msg == nullptr ) - { - Coord3D world; - if (BitIsSet( command->getOptions(), NEED_TARGET_POS )) - { - // translate the mouse location into world coords - TheTacticalView->screenToTerrain( mouse, &world ); - } - else - { - Drawable *draw = TheInGameUI->getFirstSelectedDrawable(); - if( draw == nullptr || draw->getObject() == nullptr ) - return COMMAND_COMPLETE; - world = *draw->getObject()->getPosition(); - } - - // create the message and append arguments - msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); - msg->appendLocationArgument(world); - msg->appendIntegerArgument(guardMode); - pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_GUARD_POSITION); - } - - return COMMAND_COMPLETE; - -} - -//------------------------------------------------------------------------------------------------- -/** Do the set rally point command */ -//------------------------------------------------------------------------------------------------- -static CommandStatus doAttackMoveCommand( const CommandButton *command, const ICoord2D *mouse ) -{ - - // sanity - if( command == nullptr || mouse == nullptr ) - return COMMAND_COMPLETE; - - // - // we can only set rally points for structures ... and we never multiple select structures - // so we must be sure there is only one thing selected (that thing we will set the point on) - // - Drawable *draw = TheInGameUI->getFirstSelectedDrawable(); - DEBUG_ASSERTCRASH( draw, ("doAttackMoveCommand: No selected object(s)") ); - - // sanity - if( draw == nullptr || draw->getObject() == nullptr ) - return COMMAND_COMPLETE; - - // convert mouse point to world coords - Coord3D world; - TheTacticalView->screenToTerrain( mouse, &world ); - - // send the message to set the rally point - GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_ATTACKMOVETO ); - msg->appendLocationArgument( world ); - - // Play the unit voice response - pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_ATTACKMOVETO); - - return COMMAND_COMPLETE; - -} - - -//------------------------------------------------------------------------------------------------- -/** Do the set rally point command */ -//------------------------------------------------------------------------------------------------- -static CommandStatus doSetRallyPointCommand( const CommandButton *command, const ICoord2D *mouse ) -{ - - // sanity - if( command == nullptr || mouse == nullptr ) - return COMMAND_COMPLETE; - - // - // we can only set rally points for structures ... and we never multiple select structures - // so we must be sure there is only one thing selected (that thing we will set the point on) - // - DEBUG_ASSERTCRASH( TheInGameUI->getSelectCount() == 1, - ("doSetRallyPointCommand: The selected count is not 1, we can only set a rally point on a *SINGLE* building\n") ); - Drawable *draw = TheInGameUI->getFirstSelectedDrawable(); - DEBUG_ASSERTCRASH( draw, ("doSetRallyPointCommand: No selected object") ); - - // sanity - if( draw == nullptr || draw->getObject() == nullptr ) - return COMMAND_COMPLETE; - - // convert mouse point to world coords - Coord3D world; - TheTacticalView->screenToTerrain( mouse, &world ); - - // send the message to set the rally point - GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_SET_RALLY_POINT ); - msg->appendObjectIDArgument( draw->getObject()->getID() ); - msg->appendLocationArgument( world ); - - return COMMAND_COMPLETE; - -} - -//------------------------------------------------------------------------------------------------- -/** Do the beacon placement command */ -//------------------------------------------------------------------------------------------------- -static CommandStatus doPlaceBeacon( const CommandButton *command, const ICoord2D *mouse ) -{ - - // sanity - if( command == nullptr || mouse == nullptr ) - return COMMAND_COMPLETE; - - // convert mouse point to world coords - Coord3D world; - TheTacticalView->screenToTerrain( mouse, &world ); - - // send the message to set the rally point - GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_PLACE_BEACON ); - msg->appendLocationArgument( world ); - - return COMMAND_COMPLETE; - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -GameMessageDisposition GUICommandTranslator::translateGameMessage(const GameMessage *msg) -{ - GameMessageDisposition disp = KEEP_MESSAGE; - - // only pay attention to clicks in this translator if there is a pending GUI command - const CommandButton *command = TheInGameUI->getGUICommand(); - if( command == nullptr ) - return disp; - - switch( msg->getType() ) - { - - //--------------------------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_DOWN: - { - - // - // - // it is necessary to use this input when there is a pending gui command, we don't wan't - // it to fall through to the rest of the system when we're in pending gui command "mode" - // because things like selection rectangles will start when we want to stay totally - // within the gui command "mode" here - // - disp = DESTROY_MESSAGE; - - break; - - } - - //--------------------------------------------------------------------------------------------- - case GameMessage::MSG_MOUSE_LEFT_DOUBLE_CLICK: - case GameMessage::MSG_MOUSE_LEFT_CLICK: - { - CommandStatus commandStatus = COMMAND_COMPLETE; - ICoord2D mouse = msg->getArgument(0)->pixelRegion.hi; - - // do the command action - if( command && !command->isContextCommand() ) - { - switch( command->getCommandType() ) - { - - //--------------------------------------------------------------------------------------- - case GUI_COMMAND_FIRE_WEAPON: - { - commandStatus = doFireWeaponCommand( command, &mouse ); - - PickAndPlayInfo info; - WeaponSlotType slot = command->getWeaponSlot(); - info.m_weaponSlot = &slot; - - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_WEAPON_AT_LOCATION, &info ); - break; - - } - - - //--------------------------------------------------------------------------------------- - case GUI_COMMAND_EVACUATE: - { - if (BitIsSet(command->getOptions(), NEED_TARGET_POS)) { - Coord3D worldPos; - - TheTacticalView->screenToTerrain(&mouse, &worldPos); - - GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_EVACUATE); - msg->appendLocationArgument(worldPos); - - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_EVACUATE ); - - commandStatus = COMMAND_COMPLETE; - } - - break; - } - - //--------------------------------------------------------------------------------------- - case GUI_COMMAND_GUARD: - { - commandStatus = doGuardCommand( command, GUARDMODE_NORMAL, &mouse ); - break; - } - - //--------------------------------------------------------------------------------------- - case GUI_COMMAND_GUARD_WITHOUT_PURSUIT: - { - commandStatus = doGuardCommand( command, GUARDMODE_GUARD_WITHOUT_PURSUIT, &mouse ); - break; - } - - //--------------------------------------------------------------------------------------- - case GUI_COMMAND_GUARD_FLYING_UNITS_ONLY: - { - commandStatus = doGuardCommand( command, GUARDMODE_GUARD_FLYING_UNITS_ONLY, &mouse ); - break; - } - - //Special weapons are now always context commands... - //--------------------------------------------------------------------------------------- - case GUI_COMMAND_SPECIAL_POWER: - case GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT: - { - return KEEP_MESSAGE; - break; - - } - - case GUI_COMMAND_ATTACK_MOVE: - { - commandStatus = doAttackMoveCommand( command, &mouse ); - break; - } - - //--------------------------------------------------------------------------------------- - case GUI_COMMAND_SET_RALLY_POINT: - { - commandStatus = doSetRallyPointCommand( command, &mouse ); - break; - - } - - //--------------------------------------------------------------------------------------- - case GUICOMMANDMODE_PLACE_BEACON: - { - commandStatus = doPlaceBeacon( command, &mouse ); - break; - - } - - } - - // used the input - disp = DESTROY_MESSAGE; - - // get out of GUI command mode if we completed the command one way or another - if( commandStatus == COMMAND_COMPLETE ) - { - TheInGameUI->setPreventLeftClickDeselectionInAlternateMouseModeForOneClick( TRUE ); - TheInGameUI->setGUICommand( nullptr ); - } - } - - break; - - } - - } - - // If we're destroying the message, it means we used it. Therefore, destroy the current - // attack move instruction as well. - if (disp == DESTROY_MESSAGE) - TheInGameUI->clearAttackMoveToMode(); - - - return disp; - -} - - diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp deleted file mode 100644 index 37174941ebb..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// HintSpy.cpp -// The HintSpy sits on the message stream and watches for certain messages, -// for which it then generates visual "hints". -// Author: Michael S. Booth, March 2001 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/MessageStream.h" -#include "GameClient/HintSpy.h" -#include "GameClient/GameWindowManager.h" -#include "GameClient/GameWindow.h" -#include "GameClient/GameClient.h" -#include "GameClient/Drawable.h" -/** - * This message handler displays UI "hints" (ie: a rectangle for drag selection) based - * upon the messages that pass through it. - */ -GameMessageDisposition HintSpyTranslator::translateGameMessage(const GameMessage *msg) -{ - GameMessageDisposition disp = KEEP_MESSAGE; - - /// @todo Create an automated way to associate method callbacks with messages - switch( msg->getType() ) - { - //----------------------------------------------------------------------------- - case GameMessage::MSG_MOUSEOVER_DRAWABLE_HINT: - { - TheInGameUI->createMouseoverHint( msg ); - - disp = DESTROY_MESSAGE; //hint no longer needed by anyone. Eat it. - } - break; - case GameMessage::MSG_MOUSEOVER_LOCATION_HINT: - { - TheInGameUI->createMouseoverHint( msg ); - - disp = DESTROY_MESSAGE; //hint no longer needed by anyone. Eat it. - } - break; - - //----------------------------------------------------------------------------- - case GameMessage::MSG_DEFECTOR_HINT: - case GameMessage::MSG_DO_MOVETO_HINT: - case GameMessage::MSG_DO_ATTACKMOVETO_HINT: - case GameMessage::MSG_DO_ATTACK_OBJECT_HINT: - case GameMessage::MSG_DO_ATTACK_OBJECT_AFTER_MOVING_HINT: - case GameMessage::MSG_DO_FORCE_ATTACK_OBJECT_HINT: - case GameMessage::MSG_DO_FORCE_ATTACK_GROUND_HINT: - case GameMessage::MSG_ADD_WAYPOINT_HINT: - case GameMessage::MSG_GET_REPAIRED_HINT: - case GameMessage::MSG_DOCK_HINT: - case GameMessage::MSG_GET_HEALED_HINT: - case GameMessage::MSG_DO_REPAIR_HINT: - case GameMessage::MSG_RESUME_CONSTRUCTION_HINT: - case GameMessage::MSG_ENTER_HINT: - case GameMessage::MSG_HIJACK_HINT: - case GameMessage::MSG_CONVERT_TO_CARBOMB_HINT: -#ifdef ALLOW_SURRENDER - case GameMessage::MSG_PICK_UP_PRISONER_HINT: -#endif - case GameMessage::MSG_VALID_GUICOMMAND_HINT: - case GameMessage::MSG_INVALID_GUICOMMAND_HINT: - case GameMessage::MSG_CAPTUREBUILDING_HINT: - case GameMessage::MSG_HACK_HINT: - case GameMessage::MSG_SET_RALLY_POINT_HINT: - case GameMessage::MSG_IMPOSSIBLE_ATTACK_HINT: - case GameMessage::MSG_DO_SPECIAL_POWER_OVERRIDE_DESTINATION_HINT: - case GameMessage::MSG_DO_SALVAGE_HINT: - case GameMessage::MSG_DO_INVALID_HINT: - TheInGameUI->createCommandHint( msg ); - disp = DESTROY_MESSAGE; //hint no longer needed by anyone. Eat it. - break; - - //----------------------------------------------------------------------------- - case GameMessage::MSG_BEGIN_AREA_SELECTION_HINT: - TheInGameUI->beginAreaSelectHint( msg ); - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------- - // A BEGIN_AREA_SELECTION_HINT is always followed by an END_AREA_SELECTION_HINT, so - // watch for it to stop hinting. - case GameMessage::MSG_END_AREA_SELECTION_HINT: - TheInGameUI->endAreaSelectHint( msg ); - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------- - case GameMessage::MSG_DO_MOVETO: - case GameMessage::MSG_DO_ATTACKMOVETO: - case GameMessage::MSG_DO_FORCEMOVETO: - case GameMessage::MSG_ADD_WAYPOINT: - TheInGameUI->createMoveHint( msg ); - break; - - //----------------------------------------------------------------------------- - case GameMessage::MSG_DO_ATTACK_OBJECT: - TheInGameUI->createAttackHint( msg ); - break; - - //----------------------------------------------------------------------------- - case GameMessage::MSG_DO_FORCE_ATTACK_GROUND: - case GameMessage::MSG_DO_FORCE_ATTACK_OBJECT: - TheInGameUI->createForceAttackHint( msg ); - break; - - //----------------------------------------------------------------------------- - case GameMessage::MSG_ENTER: - TheInGameUI->createGarrisonHint( msg ); - break; - - } - return disp; -} diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp deleted file mode 100644 index 63af29ea6fd..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: HotKey.cpp ///////////////////////////////////////////////// -//----------------------------------------------------------------------------- -// -// Electronic Arts Pacific. -// -// Confidential Information -// Copyright (C) 2002 - All Rights Reserved -// -//----------------------------------------------------------------------------- -// -// created: Sep 2002 -// -// Filename: HotKey.cpp -// -// author: Chris Huybregts -// -// purpose: -// -//----------------------------------------------------------------------------- -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -// SYSTEM INCLUDES //////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine -//----------------------------------------------------------------------------- -// USER INCLUDES ////////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- -#include "GameClient/HotKey.h" -#include "GameClient/KeyDefs.h" -#include "GameClient/MetaEvent.h" -#include "GameClient/GameWindow.h" -#include "GameClient/GameWindowManager.h" -#include "GameClient/Keyboard.h" -#include "GameClient/GameText.h" -#include "Common/AudioEventRTS.h" -//----------------------------------------------------------------------------- -// DEFINES //////////////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// PUBLIC FUNCTIONS /////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -GameMessageDisposition HotKeyTranslator::translateGameMessage(const GameMessage *msg) -{ - GameMessageDisposition disp = KEEP_MESSAGE; - GameMessage::Type t = msg->getType(); - - if ( t == GameMessage::MSG_RAW_KEY_UP) - { - - //char key = msg->getArgument(0)->integer; - Int keyState = msg->getArgument(1)->integer; - - // for our purposes here, we don't care to distinguish between right and left keys, - // so just fudge a little to simplify things. - Int newModState = 0; - - if( keyState & KEY_STATE_CONTROL ) - { - newModState |= CTRL; - } - - if( keyState & KEY_STATE_SHIFT ) - { - newModState |= SHIFT; - } - - if( keyState & KEY_STATE_ALT ) - { - newModState |= ALT; - } - if(newModState != 0) - return disp; - WideChar key = TheKeyboard->getPrintableKey((KeyDefType)msg->getArgument(0)->integer, 0); - UnicodeString uKey; - uKey.concat(key); - AsciiString aKey; - aKey.translate(uKey); - if(TheHotKeyManager && TheHotKeyManager->executeHotKey(aKey)) - disp = DESTROY_MESSAGE; - } - return disp; -} - -//----------------------------------------------------------------------------- -HotKey::HotKey() -{ - m_win = nullptr; - m_key.clear(); -} - -//----------------------------------------------------------------------------- -HotKeyManager::HotKeyManager() -{ - -} - -//----------------------------------------------------------------------------- -HotKeyManager::~HotKeyManager() -{ - m_hotKeyMap.clear(); -} - -//----------------------------------------------------------------------------- -void HotKeyManager::init() -{ - m_hotKeyMap.clear(); -} - -//----------------------------------------------------------------------------- -void HotKeyManager::reset() -{ - m_hotKeyMap.clear(); -} - -//----------------------------------------------------------------------------- -void HotKeyManager::addHotKey( GameWindow *win, const AsciiString& keyIn) -{ - AsciiString key = keyIn; - key.toLower(); - HotKeyMap::iterator it = m_hotKeyMap.find(key); - if( it != m_hotKeyMap.end() ) - { - DEBUG_CRASH(("Hotkey %s is already mapped to window %s, current window is %s", key.str(), it->second.m_win->winGetInstanceData()->m_decoratedNameString.str(), win->winGetInstanceData()->m_decoratedNameString.str())); - return; - } - HotKey newHK; - newHK.m_key.set(key); - newHK.m_win = win; - m_hotKeyMap[key] = newHK; -} - -//----------------------------------------------------------------------------- -Bool HotKeyManager::executeHotKey( const AsciiString& keyIn ) -{ - AsciiString key = keyIn; - key.toLower(); - HotKeyMap::iterator it = m_hotKeyMap.find(key); - if( it == m_hotKeyMap.end() ) - return FALSE; - GameWindow *win = it->second.m_win; - if( !win ) - return FALSE; - if( !BitIsSet( win->winGetStatus(), WIN_STATUS_HIDDEN ) ) - { - if( BitIsSet( win->winGetStatus(), WIN_STATUS_ENABLED ) ) - { - TheWindowManager->winSendSystemMsg( win->winGetParent(), GBM_SELECTED, (WindowMsgData)win, win->winGetWindowId() ); - - // here we make the same click sound that the GUI uses when you click a button - AudioEventRTS buttonClick("GUIClick"); - - if( TheAudio ) - { - TheAudio->addAudioEvent( &buttonClick ); - } - return TRUE; - } - - AudioEventRTS disabledClick( "GUIClickDisabled" ); - if( TheAudio ) - { - TheAudio->addAudioEvent( &disabledClick ); - } - } - return FALSE; -} - -//----------------------------------------------------------------------------- -AsciiString HotKeyManager::searchHotKey( const AsciiString& label) -{ - return searchHotKey(TheGameText->fetch(label)); -} - -//----------------------------------------------------------------------------- -AsciiString HotKeyManager::searchHotKey( const UnicodeString& uStr ) -{ - if(uStr.isEmpty()) - return AsciiString::TheEmptyString; - - const WideChar *marker = (const WideChar *)uStr.str(); - while (marker && *marker) - { - if (*marker == L'&') - { - // found a '&' - now look for the next char - UnicodeString tmp = UnicodeString::TheEmptyString; - tmp.concat(*(marker+1)); - AsciiString retStr; - retStr.translate(tmp); - return retStr; - } - marker++; - } - return AsciiString::TheEmptyString; -} - -//----------------------------------------------------------------------------- -HotKeyManager *TheHotKeyManager = nullptr; - -//----------------------------------------------------------------------------- -// PRIVATE FUNCTIONS ////////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- - diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp deleted file mode 100644 index 9a9c2dc232f..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ /dev/null @@ -1,781 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// LookAtXlat.cpp -// Translate raw input events into camera movement commands -// Author: Michael S. Booth, April 2001 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/FramePacer.h" -#include "Common/GameType.h" -#include "Common/GameEngine.h" -#include "Common/MessageStream.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/Recorder.h" -#include "Common/StatsCollector.h" -#include "Common/OptionPreferences.h" -#include "GameLogic/Object.h" -#include "GameLogic/PartitionManager.h" -#include "GameClient/Display.h" -#include "GameClient/GameText.h" -#include "GameClient/Mouse.h" -#include "GameClient/Shell.h" -#include "GameClient/GameClient.h" -#include "GameClient/KeyDefs.h" -#include "GameClient/View.h" -#include "GameClient/Drawable.h" -#include "GameClient/LookAtXlat.h" -#include "GameLogic/Module/UpdateModule.h" -#include "GameLogic/GameLogic.h" - -#include "Common/GlobalData.h" // for camera pitch angle only - -LookAtTranslator *TheLookAtTranslator = nullptr; - -enum -{ - DIR_UP = 0, - DIR_DOWN, - DIR_LEFT, - DIR_RIGHT -}; - -static Bool scrollDir[4] = { false, false, false, false }; - -// TheSuperHackers @tweak Introduces the SCROLL_MULTIPLIER for all scrolling to -// -// 1. bring the RMB scroll speed back to how it was at 30 FPS in the retail game version -// 2. increase the upper limit of the Scroll Factor when set from the Options Menu (0.20 to 2.90 instead of 0.10 to 1.45) -// 3. increase the scroll speed for Edge/Key scrolling to better fit the high speeds of RMB scrolling -// -// The multiplier of 2 was logically chosen because originally the Scroll Factor did practically not affect the RMB scroll speed -// and because the default Scroll Factor is/was 0.5, it needs to be doubled to get to a neutral 1x multiplier. - -constexpr const Real SCROLL_MULTIPLIER = 2.0f; -constexpr const Real SCROLL_AMT = 100.0f * SCROLL_MULTIPLIER; - -static const Int edgeScrollSize = 3; - -static Mouse::MouseCursor prevCursor = Mouse::ARROW; - -//----------------------------------------------------------------------------- -void LookAtTranslator::setScrolling(ScrollType scrollType) -{ - if (!TheInGameUI->getInputEnabled()) - return; - - prevCursor = TheMouse->getMouseCursor(); - m_isScrolling = true; - TheInGameUI->setScrolling( TRUE ); - TheTacticalView->setMouseLock( TRUE ); - m_scrollType = scrollType; - if(TheStatsCollector) - TheStatsCollector->startScrollTime(); -} - -//----------------------------------------------------------------------------- -void LookAtTranslator::stopScrolling() -{ - m_isScrolling = false; - TheInGameUI->setScrolling( FALSE ); - TheTacticalView->setMouseLock( FALSE ); - TheMouse->setCursor(prevCursor); - m_scrollType = SCROLL_NONE; - - // increment the stats if we have a stats collector - if(TheStatsCollector) - TheStatsCollector->endScrollTime(); - -} - -//----------------------------------------------------------------------------- -Bool LookAtTranslator::canScrollAtScreenEdge() const -{ - if (!TheMouse->isCursorCaptured()) - return false; - -#ifdef _WIN32 - if (TheDisplay->getWindowed()) - { - if ((m_screenEdgeScrollMode & ScreenEdgeScrollMode_EnabledInWindowedApp) == 0) - return false; - } - else - { - if ((m_screenEdgeScrollMode & ScreenEdgeScrollMode_EnabledInFullscreenApp) == 0) - return false; - } -#endif - - return true; -} - -//----------------------------------------------------------------------------- -LookAtTranslator::LookAtTranslator() : - m_isScrolling(false), - m_isRotating(false), - m_isPitching(false), - m_isPitchingToDefault(false), - m_isChangingFOV(false), - m_middleButtonDownTimeMsec(0), - m_lastPlaneID(INVALID_DRAWABLE_ID), - m_lastMouseMoveTimeMsec(0), - m_scrollType(SCROLL_NONE) -{ - m_anchor.x = m_anchor.y = 0; - m_currentPos.x = m_currentPos.y = 0; - m_originalAnchor.x = m_originalAnchor.y = 0; - - OptionPreferences prefs; - m_screenEdgeScrollMode = prefs.getScreenEdgeScrollMode(); - - DEBUG_ASSERTCRASH(!TheLookAtTranslator, ("Already have a LookAtTranslator - why do you need two?")); - TheLookAtTranslator = this; -} - -//----------------------------------------------------------------------------- -LookAtTranslator::~LookAtTranslator() -{ - if (TheLookAtTranslator == this) - TheLookAtTranslator = nullptr; -} - -const ICoord2D* LookAtTranslator::getRMBScrollAnchor() -{ - if (m_isScrolling && m_scrollType == SCROLL_RMB) - { - return &m_anchor; - } - return nullptr; -} - -Bool LookAtTranslator::hasMouseMovedRecently() -{ - const UnsignedInt now = timeGetTime(); - const UnsignedInt lastMove = m_lastMouseMoveTimeMsec; - - const UnsignedInt elapsedMsec = now - lastMove; - - return elapsedMsec <= MSEC_PER_SECOND; -} - -void LookAtTranslator::setCurrentPos( const ICoord2D& pos ) -{ - m_currentPos = pos; -} - -void LookAtTranslator::setScreenEdgeScrollMode(ScreenEdgeScrollMode mode) -{ - m_screenEdgeScrollMode = mode; -} - -//----------------------------------------------------------------------------- -/** - * The LookAt Translator is responsible for camera movements. It is directly responsible for - * right mouse button scrolling, and CTRL- bookmarking. It also responds to certain - * LOOKAT message on the message stream. - */ -GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage *msg) -{ - GameMessageDisposition disp = KEEP_MESSAGE; - - GameMessage::Type t = msg->getType(); - switch (t) - { - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_KEY_DOWN: - case GameMessage::MSG_RAW_KEY_UP: - { - // get key and state from args - UnsignedByte key = msg->getArgument( 0 )->integer; - UnsignedByte state = msg->getArgument( 1 )->integer; - Bool isPressed = !(BitIsSet( state, KEY_STATE_UP )); - - if (TheShell && TheShell->isShellActive()) - break; - - switch (key) - { - case KEY_UP: - scrollDir[DIR_UP] = isPressed; - break; - case KEY_DOWN: - scrollDir[DIR_DOWN] = isPressed; - break; - case KEY_LEFT: - scrollDir[DIR_LEFT] = isPressed; - break; - case KEY_RIGHT: - scrollDir[DIR_RIGHT] = isPressed; - break; - } - - if (TheInGameUI->isSelecting() || (m_isScrolling && m_scrollType != SCROLL_KEY)) - break; - - // see if we need to start/stop scrolling - Int numDirs = 0; - for (Int i=0; i<4; ++i) - { - if (scrollDir[i]) - numDirs++; - } - - if (numDirs && !m_isScrolling) - { - setScrolling( SCROLL_KEY ); - } - else if (!numDirs && m_isScrolling) - { - stopScrolling(); - } - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN: - { - m_lastMouseMoveTimeMsec = timeGetTime(); - - m_anchor = msg->getArgument( 0 )->pixel; - m_currentPos = msg->getArgument( 0 )->pixel; - - const Bool userWantsRMBScroll = !TheGlobalData->m_useAlternateMouse || TheGlobalData->m_useRightMouseScrollWithAlternateMouse; - - if (userWantsRMBScroll && !TheInGameUI->isSelecting() && !m_isScrolling) - { - setScrolling(SCROLL_RMB); - } - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: - { - m_lastMouseMoveTimeMsec = timeGetTime(); - - if (m_scrollType == SCROLL_RMB) - { - stopScrolling(); - } - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_DOWN: - { - const UnsignedInt now = timeGetTime(); - m_lastMouseMoveTimeMsec = now; - m_middleButtonDownTimeMsec = now; - - m_isRotating = true; - m_anchor = msg->getArgument( 0 )->pixel; - m_anchorAngle = TheTacticalView->getAngle(); - m_originalAnchor = msg->getArgument( 0 )->pixel; - m_currentPos = msg->getArgument( 0 )->pixel; - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_UP: - { - const UnsignedInt now = timeGetTime(); - m_lastMouseMoveTimeMsec = now; - - const UnsignedInt CLICK_DURATION_MSEC = 167; - const UnsignedInt PIXEL_OFFSET = 5; - - m_isRotating = false; - Int dx = m_currentPos.x-m_originalAnchor.x; - if (dx<0) dx = -dx; - Int dy = m_currentPos.y-m_originalAnchor.y; - Bool didMove = dx>PIXEL_OFFSET || dy>PIXEL_OFFSET; - - const UnsignedInt elapsedMsec = now - m_middleButtonDownTimeMsec; - - // if middle button is "clicked", reset to "home" orientation - if (!didMove && elapsedMsec < CLICK_DURATION_MSEC) - { - TheTacticalView->userResetPivotToGround(); - TheTacticalView->userSetAngleToDefault(); - TheTacticalView->userSetPitchToDefault(); - TheTacticalView->userSetZoomToDefault(); - } - - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_POSITION: - { - if (m_currentPos.x != msg->getArgument( 0 )->pixel.x || m_currentPos.y != msg->getArgument( 0 )->pixel.y) - m_lastMouseMoveTimeMsec = timeGetTime(); - - m_currentPos = msg->getArgument( 0 )->pixel; - - UnsignedInt height = TheDisplay->getHeight(); - UnsignedInt width = TheDisplay->getWidth(); - - if (TheInGameUI->getInputEnabled() == FALSE) { - // We don't care how we're scrolling, just stop. - if (m_isScrolling) - stopScrolling(); - break; - } - - if (canScrollAtScreenEdge()) - { - if (m_isScrolling) - { - if ( m_scrollType == SCROLL_SCREENEDGE && (m_currentPos.x >= edgeScrollSize && m_currentPos.y >= edgeScrollSize && m_currentPos.y < height-edgeScrollSize && m_currentPos.x < width-edgeScrollSize) ) - { - stopScrolling(); - } - } - else - { - if ( m_currentPos.x < edgeScrollSize || m_currentPos.y < edgeScrollSize || m_currentPos.y >= height-edgeScrollSize || m_currentPos.x >= width-edgeScrollSize ) - { - setScrolling(SCROLL_SCREENEDGE); - } - } - } - - // rotate the view - if (m_isRotating) - { - const Real FACTOR = 0.01f; - const Real angle = FACTOR * (m_currentPos.x - m_originalAnchor.x); - Real targetAngle = m_anchorAngle + angle; - - // TheSuperHackers @tweak Stubbjax 13/11/2025 Snap angle to nearest 45 degrees - // while using force attack mode for convenience. - if (TheInGameUI->isInForceAttackMode()) - { - const Real snapRadians = DEG_TO_RADF(45); - targetAngle = WWMath::Round(targetAngle / snapRadians) * snapRadians; - } - - TheTacticalView->userSetAngle(targetAngle); - m_anchor = msg->getArgument( 0 )->pixel; - } - - // rotate the view up/down - if (m_isPitching) - { - constexpr const Real Scale = 0.01f; - const Real angle = Scale * (m_currentPos.y - m_anchor.y); - TheTacticalView->userSetPitch( TheTacticalView->getPitch() - angle ); - m_anchor = msg->getArgument( 0 )->pixel; - } - -#if defined(RTS_DEBUG) - if (m_isPitchingToDefault) - { - constexpr const Real Scale = 0.01f; - const Real angle = Scale * (m_currentPos.y - m_anchor.y); - TheTacticalView->userSetDefaultPitch( TheTacticalView->getDefaultPitch() - angle ); - TheTacticalView->userSetPitchToDefault(); - m_anchor = msg->getArgument( 0 )->pixel; - } - - // adjust the field of view - if (m_isChangingFOV) - { - constexpr const Real Scale = 0.01f; - const Real angle = Scale * (m_currentPos.y - m_anchor.y); - TheTacticalView->userSetFieldOfView( TheTacticalView->getFieldOfView() + angle ); - m_anchor = msg->getArgument( 0 )->pixel; - } -#endif - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_WHEEL: - { - m_lastMouseMoveTimeMsec = timeGetTime(); - - const Real spin = msg->getArgument( 1 )->real; - const Real zoom = -spin * View::ZoomHeightPerSecond; - TheTacticalView->userZoom(zoom); - - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_META_OPTIONS: - { - // stop the scrolling - stopScrolling(); - // let the message drop through, cause we need to process this message for - // selection as well. - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_FRAME_TICK: - { - Coord2D offset = {0, 0}; - - if (m_isScrolling && !TheInGameUI->isScrolling()) - { - // If we've been forced to stop scrolling (script action?) - TheInGameUI->setScrollAmount(offset); - TheTacticalView->scrollBy(&offset); - stopScrolling(); - } - else if (m_isScrolling) - { - // Scroll the view - // TheSuperHackers @bugfix Mauller 07/06/2025 The camera scrolling is now decoupled from the render update. - const Real fpsRatio = TheFramePacer->getBaseOverUpdateFpsRatio(); - - switch (m_scrollType) - { - case SCROLL_RMB: - { - if (TheInGameUI->shouldMoveRMBScrollAnchor()) - { - Int maxX = TheDisplay->getWidth()/2; - Int maxY = TheDisplay->getHeight()/2; - - if (m_currentPos.x + maxX < m_anchor.x) - m_anchor.x = m_currentPos.x + maxX; - else if (m_currentPos.x - maxX > m_anchor.x) - m_anchor.x = m_currentPos.x - maxX; - - if (m_currentPos.y + maxY < m_anchor.y) - m_anchor.y = m_currentPos.y + maxY; - else if (m_currentPos.y - maxY > m_anchor.y) - m_anchor.y = m_currentPos.y - maxY; - } - - // TheSuperHackers @fix Mauller 16/06/2025 fix RMB scrolling to allow it to scale with the user adjusted scroll factor - Coord2D vec; - vec.x = (m_currentPos.x - m_anchor.x); - vec.y = (m_currentPos.y - m_anchor.y); - // TheSuperHackers @info calculate the length of the vector to obtain the movement speed before the vector is normalized - float vecLength = vec.length(); - vec.normalize(); - offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * fpsRatio * vecLength * vec.x * SCROLL_MULTIPLIER * TheGlobalData->m_keyboardScrollFactor; - offset.y = TheGlobalData->m_verticalScrollSpeedFactor * fpsRatio * vecLength * vec.y * SCROLL_MULTIPLIER * TheGlobalData->m_keyboardScrollFactor; - } - break; - case SCROLL_KEY: - { - if (scrollDir[DIR_UP]) - { - offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * fpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; - } - if (scrollDir[DIR_DOWN]) - { - offset.y += TheGlobalData->m_verticalScrollSpeedFactor * fpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; - } - if (scrollDir[DIR_LEFT]) - { - offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * fpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; - } - if (scrollDir[DIR_RIGHT]) - { - offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * fpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; - } - } - break; - case SCROLL_SCREENEDGE: - { - UnsignedInt height = TheDisplay->getHeight(); - UnsignedInt width = TheDisplay->getWidth(); - if (m_currentPos.y < edgeScrollSize) - { - offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * fpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; - } - if (m_currentPos.y >= height-edgeScrollSize) - { - offset.y += TheGlobalData->m_verticalScrollSpeedFactor * fpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; - } - if (m_currentPos.x < edgeScrollSize) - { - offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * fpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; - } - if (m_currentPos.x >= width-edgeScrollSize) - { - offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * fpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; - } - } - break; - } - - TheInGameUI->setScrollAmount(offset); - TheTacticalView->userScrollBy( &offset ); - } - else - { - //not scrolling so reset amount - TheInGameUI->setScrollAmount(offset); - TheTacticalView->scrollBy(&offset); - } - - //if (TheGlobalData->m_saveCameraInReplay /*&& TheRecorder->getMode() != RECORDERMODETYPE_PLAYBACK *//**/&& (TheGameLogic->isInSinglePlayerGame() || TheGameLogic->isInSkirmishGame())/**/) - //if (TheGlobalData->m_saveCameraInReplay && (TheGameLogic->isInMultiplayerGame() || TheGameLogic->isInSinglePlayerGame() || TheGameLogic->isInSkirmishGame())) - if (TheGlobalData->m_saveCameraInReplay && (TheGameLogic->isInSinglePlayerGame() || TheGameLogic->isInSkirmishGame())) - { - ViewLocation currentView; - TheTacticalView->getLocation(¤tView); - GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_SET_REPLAY_CAMERA ); - msg->appendLocationArgument( currentView.getPosition() ); - msg->appendRealArgument( currentView.getAngle() ); - msg->appendRealArgument( currentView.getPitch() ); - msg->appendRealArgument( currentView.getZoom() ); - msg->appendIntegerArgument( (Int)TheMouse->getMouseCursor() ); - msg->appendPixelArgument( m_currentPos ); - // TheSuperHackers @tweak Save 3D camera position and direction to recover optimal playback precision - msg->appendLocationArgument( TheTacticalView->get3DCameraPosition() ); - msg->appendLocationArgument( TheTacticalView->get3DCameraDirection() ); - } - break; - } - - // ------------------------------------------------------------------------ -#if defined(RTS_DEBUG) - case GameMessage::MSG_META_DEMO_BEGIN_ADJUST_PITCH: - { - DEBUG_ASSERTCRASH(!m_isPitching, ("hmm, mismatched m_isPitching")); - m_isPitching = true; - m_anchor = m_currentPos; - disp = DESTROY_MESSAGE; - break; - } -#endif // #if defined(RTS_DEBUG) - - // ------------------------------------------------------------------------ -#if defined(RTS_DEBUG) - case GameMessage::MSG_META_DEMO_END_ADJUST_PITCH: - { - DEBUG_ASSERTCRASH(m_isPitching, ("hmm, mismatched m_isPitching")); - m_isPitching = false; - disp = DESTROY_MESSAGE; - break; - } -#endif // #if defined(RTS_DEBUG) - - // ------------------------------------------------------------------------ -#if defined(RTS_DEBUG) - case GameMessage::MSG_META_DEMO_BEGIN_ADJUST_DEFAULTPITCH: - { - DEBUG_ASSERTCRASH(!m_isPitchingToDefault, ("hmm, mismatched m_isPitchingToDefault")); - m_isPitchingToDefault = true; - m_anchor = m_currentPos; - disp = DESTROY_MESSAGE; - break; - } -#endif // #if defined(RTS_DEBUG) - - // ------------------------------------------------------------------------ -#if defined(RTS_DEBUG) - case GameMessage::MSG_META_DEMO_END_ADJUST_DEFAULTPITCH: - { - DEBUG_ASSERTCRASH(m_isPitchingToDefault, ("hmm, mismatched m_isPitchingToDefault")); - m_isPitchingToDefault = false; - disp = DESTROY_MESSAGE; - break; - } -#endif // #if defined(RTS_DEBUG) - - // ------------------------------------------------------------------------ -#if defined(RTS_DEBUG) - case GameMessage::MSG_META_DEMO_DESHROUD: - { - ThePartitionManager->revealMapForPlayerPermanently( ThePlayerList->getLocalPlayer()->getPlayerIndex() ); - break; - } -#endif // #if defined(RTS_DEBUG) - - // ------------------------------------------------------------------------ -#if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE) - case GameMessage::MSG_CHEAT_DESHROUD: - { - if (!TheGameLogic->isInMultiplayerGame()) - { - ThePartitionManager->revealMapForPlayerPermanently( ThePlayerList->getLocalPlayer()->getPlayerIndex() ); - } - break; - } -#endif // #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE) - - // ------------------------------------------------------------------------ -#if defined(RTS_DEBUG) - case GameMessage::MSG_META_DEMO_ENSHROUD: - { - // Need to first undo the permanent Look laid down by DEMO_DESHROUD, then blast a shroud dollop. - ThePartitionManager->undoRevealMapForPlayerPermanently( ThePlayerList->getLocalPlayer()->getPlayerIndex() ); - ThePartitionManager->shroudMapForPlayer( ThePlayerList->getLocalPlayer()->getPlayerIndex() ); - break; - } -#endif // #if defined(RTS_DEBUG) - - // ------------------------------------------------------------------------ -#if defined(RTS_DEBUG) - case GameMessage::MSG_META_DEMO_BEGIN_ADJUST_FOV: - { - //DEBUG_ASSERTCRASH(!m_isChangingFOV, ("hmm, mismatched m_isChangingFOV")); - m_isChangingFOV = true; - m_anchor = m_currentPos; - disp = DESTROY_MESSAGE; - break; - } -#endif // #if defined(RTS_DEBUG) - - // ------------------------------------------------------------------------ -#if defined(RTS_DEBUG) - case GameMessage::MSG_META_DEMO_END_ADJUST_FOV: - { - // DEBUG_ASSERTCRASH(m_isChangingFOV, ("hmm, mismatched m_isChangingFOV")); - m_isChangingFOV = false; - disp = DESTROY_MESSAGE; - break; - } -#endif // #if defined(RTS_DEBUG) - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_SAVE_VIEW1: - case GameMessage::MSG_META_SAVE_VIEW2: - case GameMessage::MSG_META_SAVE_VIEW3: - case GameMessage::MSG_META_SAVE_VIEW4: - case GameMessage::MSG_META_SAVE_VIEW5: - case GameMessage::MSG_META_SAVE_VIEW6: - case GameMessage::MSG_META_SAVE_VIEW7: - case GameMessage::MSG_META_SAVE_VIEW8: - { - Int slot = t - GameMessage::MSG_META_SAVE_VIEW1 + 1; - if ( slot > 0 && slot <= MAX_VIEW_LOCS ) - { - TheTacticalView->getLocation( &m_viewLocation[slot-1] ); - UnicodeString msg; - msg.format( TheGameText->fetch( "GUI:BookmarkXSet" ), slot ); - TheInGameUI->message( msg ); - } - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_VIEW_VIEW1: - case GameMessage::MSG_META_VIEW_VIEW2: - case GameMessage::MSG_META_VIEW_VIEW3: - case GameMessage::MSG_META_VIEW_VIEW4: - case GameMessage::MSG_META_VIEW_VIEW5: - case GameMessage::MSG_META_VIEW_VIEW6: - case GameMessage::MSG_META_VIEW_VIEW7: - case GameMessage::MSG_META_VIEW_VIEW8: - { - Int slot = t - GameMessage::MSG_META_VIEW_VIEW1 + 1; - if ( slot > 0 && slot <= MAX_VIEW_LOCS ) - { - TheTacticalView->userSetLocation( &m_viewLocation[slot-1] ); - } - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------- -#if defined(RTS_DEBUG) - case GameMessage::MSG_META_DEMO_LOCK_CAMERA_TO_PLANES: - { - Drawable *first = nullptr; - - if (m_lastPlaneID) - first = TheGameClient->findDrawableByID( m_lastPlaneID ); - - if (first == nullptr) - first = TheGameClient->firstDrawable(); - - if (first) - { - Drawable *d = first; - Bool done = false; - - while(!done) - { - // get next Drawable, wrapping around to head of list if necessary - d = d->getNextDrawable(); - if (d == nullptr) - d = TheGameClient->firstDrawable(); - - // if we've found an airborne object, lock onto it -// "isAboveTerrain" only indicates that we are currently in the air, but that -// could be the case if we are a buggy jumping a hill, or a unit being paradropped. -// the right thing would be to look at the locomotors. -// so this isn't really right, but will suffice for demo purposes. - if (d->getObject() && d->getObject()->isAboveTerrain() ) - { - Bool doLock = true; - - // but don't lock onto projectiles - ProjectileUpdateInterface* pui = nullptr; - for (BehaviorModule** u = d->getObject()->getBehaviorModules(); *u; ++u) - { - if ((pui = (*u)->getProjectileUpdateInterface()) != nullptr) - { - doLock = false; - break; - } - } - - if (doLock) - { - TheTacticalView->userSetCameraLock( d->getObject()->getID() ); - m_lastPlaneID = d->getID(); - done = true; - break; - } - } - - // if we're back to the first, quit - if (d == first) - break; - } - } - - disp = DESTROY_MESSAGE; - break; - } -#endif // #if defined(RTS_DEBUG) - - } - - return disp; - -} - -void LookAtTranslator::resetModes() -{ - m_isScrolling = FALSE; - m_isRotating = FALSE; - m_isPitching = FALSE; - m_isPitchingToDefault = FALSE; - m_isChangingFOV = FALSE; -} diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp deleted file mode 100644 index 7631ccc883d..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp +++ /dev/null @@ -1,903 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: MetaEvent.cpp //////////////////////////////////////////////////////////////////////////// -// Created: Colin Day, September 2001 -// Desc: Translating keystrokes into event command messages -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/GameUtility.h" -#include "Common/INI.h" -#include "Common/MessageStream.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/Team.h" -#include "Common/ThingTemplate.h" - -#include "GameClient/Drawable.h" -#include "GameClient/Mouse.h" -#include "GameClient/GameClient.h" -#include "GameClient/InGameUI.h" -#include "GameClient/KeyDefs.h" -#include "GameClient/ParticleSys.h" // for ParticleSystemDebugDisplay -#include "GameClient/Shell.h" -#include "GameClient/WindowLayout.h" -#include "GameClient/GUICallbacks.h" -#include "GameClient/DebugDisplay.h" // for AudioDebugDisplay -#include "GameClient/GameText.h" -#include "GameClient/MetaEvent.h" - -#include "GameLogic/GameLogic.h" // for TheGameLogic->getFrame() - -MetaMap *TheMetaMap = nullptr; - - - -// DEFINES //////////////////////////////////////////////////////////////////// - -// PRIVATE TYPES ////////////////////////////////////////////////////////////////////////////////// - -// PRIVATE DATA /////////////////////////////////////////////////////////////////////////////////// - -static const LookupListRec GameMessageMetaTypeNames[] = -{ - { "SAVE_VIEW1", GameMessage::MSG_META_SAVE_VIEW1 }, - { "SAVE_VIEW2", GameMessage::MSG_META_SAVE_VIEW2 }, - { "SAVE_VIEW3", GameMessage::MSG_META_SAVE_VIEW3 }, - { "SAVE_VIEW4", GameMessage::MSG_META_SAVE_VIEW4 }, - { "SAVE_VIEW5", GameMessage::MSG_META_SAVE_VIEW5 }, - { "SAVE_VIEW6", GameMessage::MSG_META_SAVE_VIEW6 }, - { "SAVE_VIEW7", GameMessage::MSG_META_SAVE_VIEW7 }, - { "SAVE_VIEW8", GameMessage::MSG_META_SAVE_VIEW8 }, - { "VIEW_VIEW1", GameMessage::MSG_META_VIEW_VIEW1 }, - { "VIEW_VIEW2", GameMessage::MSG_META_VIEW_VIEW2 }, - { "VIEW_VIEW3", GameMessage::MSG_META_VIEW_VIEW3 }, - { "VIEW_VIEW4", GameMessage::MSG_META_VIEW_VIEW4 }, - { "VIEW_VIEW5", GameMessage::MSG_META_VIEW_VIEW5 }, - { "VIEW_VIEW6", GameMessage::MSG_META_VIEW_VIEW6 }, - { "VIEW_VIEW7", GameMessage::MSG_META_VIEW_VIEW7 }, - { "VIEW_VIEW8", GameMessage::MSG_META_VIEW_VIEW8 }, - { "CREATE_TEAM0", GameMessage::MSG_META_CREATE_TEAM0 }, - { "CREATE_TEAM1", GameMessage::MSG_META_CREATE_TEAM1 }, - { "CREATE_TEAM2", GameMessage::MSG_META_CREATE_TEAM2 }, - { "CREATE_TEAM3", GameMessage::MSG_META_CREATE_TEAM3 }, - { "CREATE_TEAM4", GameMessage::MSG_META_CREATE_TEAM4 }, - { "CREATE_TEAM5", GameMessage::MSG_META_CREATE_TEAM5 }, - { "CREATE_TEAM6", GameMessage::MSG_META_CREATE_TEAM6 }, - { "CREATE_TEAM7", GameMessage::MSG_META_CREATE_TEAM7 }, - { "CREATE_TEAM8", GameMessage::MSG_META_CREATE_TEAM8 }, - { "CREATE_TEAM9", GameMessage::MSG_META_CREATE_TEAM9 }, - { "SELECT_TEAM0", GameMessage::MSG_META_SELECT_TEAM0 }, - { "SELECT_TEAM1", GameMessage::MSG_META_SELECT_TEAM1 }, - { "SELECT_TEAM2", GameMessage::MSG_META_SELECT_TEAM2 }, - { "SELECT_TEAM3", GameMessage::MSG_META_SELECT_TEAM3 }, - { "SELECT_TEAM4", GameMessage::MSG_META_SELECT_TEAM4 }, - { "SELECT_TEAM5", GameMessage::MSG_META_SELECT_TEAM5 }, - { "SELECT_TEAM6", GameMessage::MSG_META_SELECT_TEAM6 }, - { "SELECT_TEAM7", GameMessage::MSG_META_SELECT_TEAM7 }, - { "SELECT_TEAM8", GameMessage::MSG_META_SELECT_TEAM8 }, - { "SELECT_TEAM9", GameMessage::MSG_META_SELECT_TEAM9 }, - { "ADD_TEAM0", GameMessage::MSG_META_ADD_TEAM0 }, - { "ADD_TEAM1", GameMessage::MSG_META_ADD_TEAM1 }, - { "ADD_TEAM2", GameMessage::MSG_META_ADD_TEAM2 }, - { "ADD_TEAM3", GameMessage::MSG_META_ADD_TEAM3 }, - { "ADD_TEAM4", GameMessage::MSG_META_ADD_TEAM4 }, - { "ADD_TEAM5", GameMessage::MSG_META_ADD_TEAM5 }, - { "ADD_TEAM6", GameMessage::MSG_META_ADD_TEAM6 }, - { "ADD_TEAM7", GameMessage::MSG_META_ADD_TEAM7 }, - { "ADD_TEAM8", GameMessage::MSG_META_ADD_TEAM8 }, - { "ADD_TEAM9", GameMessage::MSG_META_ADD_TEAM9 }, - { "VIEW_TEAM0", GameMessage::MSG_META_VIEW_TEAM0 }, - { "VIEW_TEAM1", GameMessage::MSG_META_VIEW_TEAM1 }, - { "VIEW_TEAM2", GameMessage::MSG_META_VIEW_TEAM2 }, - { "VIEW_TEAM3", GameMessage::MSG_META_VIEW_TEAM3 }, - { "VIEW_TEAM4", GameMessage::MSG_META_VIEW_TEAM4 }, - { "VIEW_TEAM5", GameMessage::MSG_META_VIEW_TEAM5 }, - { "VIEW_TEAM6", GameMessage::MSG_META_VIEW_TEAM6 }, - { "VIEW_TEAM7", GameMessage::MSG_META_VIEW_TEAM7 }, - { "VIEW_TEAM8", GameMessage::MSG_META_VIEW_TEAM8 }, - { "VIEW_TEAM9", GameMessage::MSG_META_VIEW_TEAM9 }, - { "SELECT_MATCHING_UNITS", GameMessage::MSG_META_SELECT_MATCHING_UNITS }, - { "SELECT_NEXT_UNIT", GameMessage::MSG_META_SELECT_NEXT_UNIT }, - { "SELECT_PREV_UNIT", GameMessage::MSG_META_SELECT_PREV_UNIT }, - { "SELECT_NEXT_WORKER", GameMessage::MSG_META_SELECT_NEXT_WORKER }, - { "SELECT_PREV_WORKER", GameMessage::MSG_META_SELECT_PREV_WORKER }, - { "SELECT_NEXT_IDLE_WORKER", GameMessage::MSG_META_SELECT_NEXT_IDLE_WORKER }, - { "SELECT_HERO", GameMessage::MSG_META_SELECT_HERO }, - { "SELECT_ALL", GameMessage::MSG_META_SELECT_ALL }, - { "SELECT_ALL_AIRCRAFT", GameMessage::MSG_META_SELECT_ALL_AIRCRAFT }, - { "VIEW_COMMAND_CENTER", GameMessage::MSG_META_VIEW_COMMAND_CENTER }, - { "VIEW_LAST_RADAR_EVENT", GameMessage::MSG_META_VIEW_LAST_RADAR_EVENT }, - { "SCATTER", GameMessage::MSG_META_SCATTER }, - { "STOP", GameMessage::MSG_META_STOP }, - { "DEPLOY", GameMessage::MSG_META_DEPLOY }, - { "CREATE_FORMATION", GameMessage::MSG_META_CREATE_FORMATION }, - { "FOLLOW", GameMessage::MSG_META_FOLLOW }, - { "CHAT_PLAYERS", GameMessage::MSG_META_CHAT_PLAYERS }, - { "CHAT_ALLIES", GameMessage::MSG_META_CHAT_ALLIES }, - { "CHAT_EVERYONE", GameMessage::MSG_META_CHAT_EVERYONE }, - { "DIPLOMACY", GameMessage::MSG_META_DIPLOMACY }, - { "PLACE_BEACON", GameMessage::MSG_META_PLACE_BEACON }, - { "DELETE_BEACON", GameMessage::MSG_META_REMOVE_BEACON }, - { "OPTIONS", GameMessage::MSG_META_OPTIONS }, - { "INCREASE_MAX_RENDER_FPS", GameMessage::MSG_META_INCREASE_MAX_RENDER_FPS }, - { "DECREASE_MAX_RENDER_FPS", GameMessage::MSG_META_DECREASE_MAX_RENDER_FPS }, - { "INCREASE_LOGIC_TIME_SCALE", GameMessage::MSG_META_INCREASE_LOGIC_TIME_SCALE }, - { "DECREASE_LOGIC_TIME_SCALE", GameMessage::MSG_META_DECREASE_LOGIC_TIME_SCALE }, - { "TOGGLE_LOWER_DETAILS", GameMessage::MSG_META_TOGGLE_LOWER_DETAILS }, - { "TOGGLE_CONTROL_BAR", GameMessage::MSG_META_TOGGLE_CONTROL_BAR }, - { "TOGGLE_PLAYER_OBSERVER", GameMessage::MSG_META_TOGGLE_PLAYER_OBSERVER }, - { "BEGIN_PATH_BUILD", GameMessage::MSG_META_BEGIN_PATH_BUILD }, - { "END_PATH_BUILD", GameMessage::MSG_META_END_PATH_BUILD }, - { "BEGIN_FORCEATTACK", GameMessage::MSG_META_BEGIN_FORCEATTACK }, - { "END_FORCEATTACK", GameMessage::MSG_META_END_FORCEATTACK }, - { "BEGIN_FORCEMOVE", GameMessage::MSG_META_BEGIN_FORCEMOVE }, - { "END_FORCEMOVE", GameMessage::MSG_META_END_FORCEMOVE }, - { "BEGIN_WAYPOINTS", GameMessage::MSG_META_BEGIN_WAYPOINTS }, - { "END_WAYPOINTS", GameMessage::MSG_META_END_WAYPOINTS }, - { "BEGIN_PREFER_SELECTION", GameMessage::MSG_META_BEGIN_PREFER_SELECTION }, - { "END_PREFER_SELECTION", GameMessage::MSG_META_END_PREFER_SELECTION }, - - { "TAKE_SCREENSHOT", GameMessage::MSG_META_TAKE_SCREENSHOT }, - { "ALL_CHEER", GameMessage::MSG_META_ALL_CHEER }, - - { "BEGIN_CAMERA_ROTATE_LEFT", GameMessage::MSG_META_BEGIN_CAMERA_ROTATE_LEFT }, - { "END_CAMERA_ROTATE_LEFT", GameMessage::MSG_META_END_CAMERA_ROTATE_LEFT }, - { "BEGIN_CAMERA_ROTATE_RIGHT", GameMessage::MSG_META_BEGIN_CAMERA_ROTATE_RIGHT }, - { "END_CAMERA_ROTATE_RIGHT", GameMessage::MSG_META_END_CAMERA_ROTATE_RIGHT }, - { "BEGIN_CAMERA_ZOOM_IN", GameMessage::MSG_META_BEGIN_CAMERA_ZOOM_IN }, - { "END_CAMERA_ZOOM_IN", GameMessage::MSG_META_END_CAMERA_ZOOM_IN }, - { "BEGIN_CAMERA_ZOOM_OUT", GameMessage::MSG_META_BEGIN_CAMERA_ZOOM_OUT }, - { "END_CAMERA_ZOOM_OUT", GameMessage::MSG_META_END_CAMERA_ZOOM_OUT }, - { "CAMERA_RESET", GameMessage::MSG_META_CAMERA_RESET }, - { "TOGGLE_FAST_FORWARD_REPLAY", GameMessage::MSG_META_TOGGLE_FAST_FORWARD_REPLAY }, - { "TOGGLE_PAUSE", GameMessage::MSG_META_TOGGLE_PAUSE }, - { "TOGGLE_PAUSE_ALT", GameMessage::MSG_META_TOGGLE_PAUSE_ALT }, - { "STEP_FRAME", GameMessage::MSG_META_STEP_FRAME }, - { "STEP_FRAME_ALT", GameMessage::MSG_META_STEP_FRAME_ALT }, - { "DEMO_INSTANT_QUIT", GameMessage::MSG_META_DEMO_INSTANT_QUIT }, - -#if defined(RTS_DEBUG) - { "HELP", GameMessage::MSG_META_HELP }, - { "DEMO_TOGGLE_BEHIND_BUILDINGS", GameMessage::MSG_META_DEMO_TOGGLE_BEHIND_BUILDINGS }, - { "DEMO_LOD_DECREASE", GameMessage::MSG_META_DEMO_LOD_DECREASE }, - { "DEMO_LOD_INCREASE", GameMessage::MSG_META_DEMO_LOD_INCREASE }, - { "DEMO_TOGGLE_LETTERBOX", GameMessage::MSG_META_DEMO_TOGGLE_LETTERBOX }, - { "DEMO_TOGGLE_MESSAGE_TEXT", GameMessage::MSG_META_DEMO_TOGGLE_MESSAGE_TEXT }, - - { "DEMO_GIVE_ALL_SCIENCES", GameMessage::MSG_META_DEMO_GIVE_ALL_SCIENCES }, - { "DEMO_GIVE_RANKLEVEL", GameMessage::MSG_META_DEMO_GIVE_RANKLEVEL }, - { "DEMO_TAKE_RANKLEVEL", GameMessage::MSG_META_DEMO_TAKE_RANKLEVEL }, - { "DEMO_GIVE_SCIENCEPURCHASEPOINTS", GameMessage::MSG_META_DEMO_GIVE_SCIENCEPURCHASEPOINTS }, - { "DEMO_SWITCH_TEAMS", GameMessage::MSG_META_DEMO_SWITCH_TEAMS }, - { "DEMO_SWITCH_TEAMS_CHINA_USA", GameMessage::MSG_META_DEMO_SWITCH_TEAMS_BETWEEN_CHINA_USA }, - { "DEMO_TOGGLE_CASHMAPDEBUG", GameMessage::MSG_META_DEMO_TOGGLE_CASHMAPDEBUG }, - { "DEMO_TOGGLE_GRAPHICALFRAMERATEBAR", GameMessage::MSG_META_DEMO_TOGGLE_GRAPHICALFRAMERATEBAR }, - { "DEMO_TOGGLE_PARTICLEDEBUG", GameMessage::MSG_META_DEMO_TOGGLE_PARTICLEDEBUG }, - { "DEMO_TOGGLE_THREATDEBUG", GameMessage::MSG_META_DEMO_TOGGLE_THREATDEBUG }, - { "DEMO_TOGGLE_VISIONDEBUG", GameMessage::MSG_META_DEMO_TOGGLE_VISIONDEBUG }, - { "DEMO_TOGGLE_PROJECTILEDEBUG", GameMessage::MSG_META_DEMO_TOGGLE_PROJECTILEDEBUG }, - { "DEMO_LOD_DECREASE", GameMessage::MSG_META_DEMO_LOD_DECREASE }, - { "DEMO_LOD_INCREASE", GameMessage::MSG_META_DEMO_LOD_INCREASE }, - { "DEMO_TOGGLE_SHADOW_VOLUMES", GameMessage::MSG_META_DEMO_TOGGLE_SHADOW_VOLUMES }, - { "DEMO_TOGGLE_FOGOFWAR", GameMessage::MSG_META_DEMO_TOGGLE_FOGOFWAR }, - { "DEMO_KILL_ALL_ENEMIES", GameMessage::MSG_META_DEMO_KILL_ALL_ENEMIES }, - { "DEMO_KILL_SELECTION", GameMessage::MSG_META_DEMO_KILL_SELECTION }, - { "DEMO_TOGGLE_HURT_ME_MODE", GameMessage::MSG_META_DEMO_TOGGLE_HURT_ME_MODE }, - { "DEMO_TOGGLE_HAND_OF_GOD_MODE", GameMessage::MSG_META_DEMO_TOGGLE_HAND_OF_GOD_MODE }, - { "DEMO_DEBUG_SELECTION", GameMessage::MSG_META_DEMO_DEBUG_SELECTION }, - { "DEMO_LOCK_CAMERA_TO_SELECTION", GameMessage::MSG_META_DEMO_LOCK_CAMERA_TO_SELECTION }, - { "DEMO_TOGGLE_SOUND", GameMessage::MSG_META_DEMO_TOGGLE_SOUND }, - { "DEMO_TOGGLE_TRACKMARKS", GameMessage::MSG_META_DEMO_TOGGLE_TRACKMARKS }, - { "DEMO_TOGGLE_WATERPLANE", GameMessage::MSG_META_DEMO_TOGGLE_WATERPLANE }, - { "DEMO_TIME_OF_DAY", GameMessage::MSG_META_DEMO_TIME_OF_DAY }, - { "DEMO_TOGGLE_MILITARY_SUBTITLES", GameMessage::MSG_META_DEMO_TOGGLE_MILITARY_SUBTITLES }, - { "DEMO_TOGGLE_MUSIC", GameMessage::MSG_META_DEMO_TOGGLE_MUSIC }, - { "DEMO_MUSIC_NEXT_TRACK", GameMessage::MSG_META_DEMO_MUSIC_NEXT_TRACK }, - { "DEMO_MUSIC_PREV_TRACK", GameMessage::MSG_META_DEMO_MUSIC_PREV_TRACK }, - { "DEMO_NEXT_OBJECTIVE_MOVIE", GameMessage::MSG_META_DEMO_NEXT_OBJECTIVE_MOVIE }, - { "DEMO_PLAY_OBJECTIVE_MOVIE1", GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE1 }, - { "DEMO_PLAY_OBJECTIVE_MOVIE2", GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE2 }, - { "DEMO_PLAY_OBJECTIVE_MOVIE3", GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE3 }, - { "DEMO_PLAY_OBJECTIVE_MOVIE4", GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE4 }, - { "DEMO_PLAY_OBJECTIVE_MOVIE5", GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE5 }, - { "DEMO_PLAY_OBJECTIVE_MOVIE6", GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE6 }, - { "DEMO_BEGIN_ADJUST_PITCH", GameMessage::MSG_META_DEMO_BEGIN_ADJUST_PITCH }, - { "DEMO_END_ADJUST_PITCH", GameMessage::MSG_META_DEMO_END_ADJUST_PITCH }, - { "DEMO_BEGIN_ADJUST_DEFAULTPITCH", GameMessage::MSG_META_DEMO_BEGIN_ADJUST_DEFAULTPITCH }, - { "DEMO_END_ADJUST_DEFAULTPITCH", GameMessage::MSG_META_DEMO_END_ADJUST_DEFAULTPITCH }, - { "DEMO_BEGIN_ADJUST_FOV", GameMessage::MSG_META_DEMO_BEGIN_ADJUST_FOV }, - { "DEMO_END_ADJUST_FOV", GameMessage::MSG_META_DEMO_END_ADJUST_FOV }, - { "DEMO_LOCK_CAMERA_TO_PLANES", GameMessage::MSG_META_DEMO_LOCK_CAMERA_TO_PLANES }, - { "DEMO_REMOVE_PREREQ", GameMessage::MSG_META_DEMO_REMOVE_PREREQ }, - { "DEMO_RUNSCRIPT1", GameMessage::MSG_META_DEMO_RUNSCRIPT1 }, - { "DEMO_RUNSCRIPT2", GameMessage::MSG_META_DEMO_RUNSCRIPT2 }, - { "DEMO_RUNSCRIPT3", GameMessage::MSG_META_DEMO_RUNSCRIPT3 }, - { "DEMO_RUNSCRIPT4", GameMessage::MSG_META_DEMO_RUNSCRIPT4 }, - { "DEMO_RUNSCRIPT5", GameMessage::MSG_META_DEMO_RUNSCRIPT5 }, - { "DEMO_RUNSCRIPT6", GameMessage::MSG_META_DEMO_RUNSCRIPT6 }, - { "DEMO_RUNSCRIPT7", GameMessage::MSG_META_DEMO_RUNSCRIPT7 }, - { "DEMO_RUNSCRIPT8", GameMessage::MSG_META_DEMO_RUNSCRIPT8 }, - { "DEMO_RUNSCRIPT9", GameMessage::MSG_META_DEMO_RUNSCRIPT9 }, - { "DEMO_ADDCASH", GameMessage::MSG_META_DEMO_ADD_CASH }, - { "DEMO_TOGGLE_RENDER", GameMessage::MSG_META_DEMO_TOGGLE_RENDER }, - { "DEMO_TOGGLE_BW_VIEW", GameMessage::MSG_META_DEMO_TOGGLE_BW_VIEW }, - { "DEMO_TOGGLE_RED_VIEW", GameMessage::MSG_META_DEMO_TOGGLE_RED_VIEW }, - { "DEMO_TOGGLE_GREEN_VIEW", GameMessage::MSG_META_DEMO_TOGGLE_GREEN_VIEW }, - { "DEMO_TOGGLE_MOTION_BLUR_ZOOM", GameMessage::MSG_META_DEMO_TOGGLE_MOTION_BLUR_ZOOM }, - { "DEMO_SHOW_EXTENTS", GameMessage::MSG_META_DEBUG_SHOW_EXTENTS }, - { "DEMO_SHOW_HEALTH", GameMessage::MSG_META_DEBUG_SHOW_HEALTH }, - { "DEMO_GIVE_VETERANCY", GameMessage::MSG_META_DEBUG_GIVE_VETERANCY }, - { "DEMO_TAKE_VETERANCY", GameMessage::MSG_META_DEBUG_TAKE_VETERANCY }, - { "DEMO_BATTLE_CRY", GameMessage::MSG_META_DEMO_BATTLE_CRY }, -#ifdef ALLOW_SURRENDER - { "DEMO_TEST_SURRENDER", GameMessage::MSG_META_DEMO_TEST_SURRENDER }, -#endif - { "DEMO_TOGGLE_AVI", GameMessage::MSG_META_DEMO_TOGGLE_AVI }, - { "DEMO_PLAY_CAMEO_MOVIE", GameMessage::MSG_META_DEMO_PLAY_CAMEO_MOVIE }, - { "DEMO_TOGGLE_ZOOM_LOCK", GameMessage::MSG_META_DEMO_TOGGLE_ZOOM_LOCK }, - { "DEMO_TOGGLE_SPECIAL_POWER_DELAYS", GameMessage::MSG_META_DEMO_TOGGLE_SPECIAL_POWER_DELAYS }, - - { "DEMO_TOGGLE_METRICS", GameMessage::MSG_META_DEMO_TOGGLE_METRICS}, - { "DEMO_DESHROUD", GameMessage::MSG_META_DEMO_DESHROUD }, - { "DEMO_ENSHROUD", GameMessage::MSG_META_DEMO_ENSHROUD }, - { "DEMO_TOGGLE_AI_DEBUG", GameMessage::MSG_META_DEMO_TOGGLE_AI_DEBUG }, - { "DEMO_TOGGLE_NO_DRAW", GameMessage::MSG_NO_DRAW }, - { "DEMO_CYCLE_LOD_LEVEL", GameMessage::MSG_META_DEMO_CYCLE_LOD_LEVEL }, - { "DEMO_DUMP_ASSETS", GameMessage::MSG_META_DEBUG_DUMP_ASSETS}, - - { "DEMO_INSTANT_BUILD", GameMessage::MSG_META_DEMO_INSTANT_BUILD }, - { "DEMO_TOGGLE_CAMERA_DEBUG", GameMessage::MSG_META_DEMO_TOGGLE_CAMERA_DEBUG }, - - /// Begin VTUNE - { "DEMO_VTUNE_ON", GameMessage::MSG_META_DEBUG_VTUNE_ON }, - { "DEMO_VTUNE_OFF", GameMessage::MSG_META_DEBUG_VTUNE_OFF }, - /// End VTUNE - - - //lorenzen's feather water - { "DEMO_TOGGLE_FEATHER_WATER", GameMessage::MSG_META_DEBUG_TOGGLE_FEATHER_WATER }, - - { "DEMO_INCR_ANIM_SKATE_SPEED", GameMessage::MSG_META_DEBUG_INCR_ANIM_SKATE_SPEED }, - { "DEMO_DECR_ANIM_SKATE_SPEED", GameMessage::MSG_META_DEBUG_DECR_ANIM_SKATE_SPEED }, - { "DEMO_CYCLE_EXTENT_TYPE", GameMessage::MSG_META_DEBUG_CYCLE_EXTENT_TYPE }, - { "DEMO_INCR_EXTENT_MAJOR", GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MAJOR }, - { "DEMO_DECR_EXTENT_MAJOR", GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MAJOR }, - { "DEMO_INCR_EXTENT_MAJOR_LARGE", GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MAJOR_BIG }, - { "DEMO_DECR_EXTENT_MAJOR_LARGE", GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MAJOR_BIG }, - { "DEMO_INCR_EXTENT_MINOR", GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MINOR }, - { "DEMO_DECR_EXTENT_MINOR", GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MINOR }, - { "DEMO_INCR_EXTENT_MINOR_LARGE", GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MINOR_BIG }, - { "DEMO_DECR_EXTENT_MINOR_LARGE", GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MINOR_BIG }, - { "DEMO_INCR_EXTENT_HEIGHT", GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_HEIGHT }, - { "DEMO_DECR_EXTENT_HEIGHT", GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_HEIGHT }, - { "DEMO_INCR_EXTENT_HEIGHT_LARGE", GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_HEIGHT_BIG }, - { "DEMO_DECR_EXTENT_HEIGHT_LARGE", GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_HEIGHT_BIG }, - { "DEMO_TOGGLE_NETWORK", GameMessage::MSG_META_DEBUG_TOGGLE_NETWORK }, - { "DEBUG_DUMP_PLAYER_OBJECTS", GameMessage::MSG_META_DEBUG_DUMP_PLAYER_OBJECTS }, - { "DEBUG_DUMP_ALL_PLAYER_OBJECTS", GameMessage::MSG_META_DEBUG_DUMP_ALL_PLAYER_OBJECTS }, - { "DEMO_WIN", GameMessage::MSG_META_DEBUG_WIN }, - { "DEMO_TOGGLE_DEBUG_STATS", GameMessage::MSG_META_DEMO_TOGGLE_DEBUG_STATS }, -#endif // defined(RTS_DEBUG) - - -#if defined(RTS_DEBUG) - { "DEMO_TOGGLE_AUDIODEBUG", GameMessage::MSG_META_DEMO_TOGGLE_AUDIODEBUG }, -#endif//defined(RTS_DEBUG) -#ifdef DUMP_PERF_STATS - { "DEMO_PERFORM_STATISTICAL_DUMP", GameMessage::MSG_META_DEMO_PERFORM_STATISTICAL_DUMP }, -#endif//DUMP_PERF_STATS - - - { nullptr, 0 } -}; - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// PRIVATE DATA /////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////// -static const FieldParse TheMetaMapFieldParseTable[] = -{ - - { "Key", INI::parseLookupList, KeyNames, offsetof( MetaMapRec, m_key ) }, - { "Transition", INI::parseLookupList, TransitionNames, offsetof( MetaMapRec, m_transition ) }, - { "Modifiers", INI::parseLookupList, ModifierNames, offsetof( MetaMapRec, m_modState ) }, - { "UseableIn", INI::parseBitString32, TheCommandUsableInNames, offsetof( MetaMapRec, m_usableIn ) }, - { "Category", INI::parseLookupList, CategoryListName, offsetof( MetaMapRec, m_category ) }, - { "Description", INI::parseAndTranslateLabel, nullptr, offsetof( MetaMapRec, m_description ) }, - { "DisplayName", INI::parseAndTranslateLabel, nullptr, offsetof( MetaMapRec, m_displayName ) }, - - { nullptr, nullptr, nullptr, 0 } - -}; - -// PRIVATE FUNCTIONS ////////////////////////////////////////////////////////////////////////////// - -// PUBLIC FUNCTIONS /////////////////////////////////////////////////////////////////////////////// - -//------------------------------------------------------------------------------------------------- -MetaEventTranslator::MetaEventTranslator() : - m_lastKeyDown(MK_NONE), - m_lastModState(0) -{ - for (Int i = 0; i < NUM_MOUSE_BUTTONS; ++i) { - m_nextUpShouldCreateDoubleClick[i] = FALSE; - } - - -} - -//------------------------------------------------------------------------------------------------- -MetaEventTranslator::~MetaEventTranslator() -{ -} - -//------------------------------------------------------------------------------------------------- -static const char * findGameMessageNameByType(GameMessage::Type type) -{ - for (const LookupListRec* metaNames = GameMessageMetaTypeNames; metaNames->name; metaNames++) - if (metaNames->value == (Int)type) - return metaNames->name; - - DEBUG_CRASH(("MetaTypeName %d not found -- did you remember to add it to GameMessageMetaTypeNames[] ?", (Int)type)); - return "???"; -} - -//------------------------------------------------------------------------------------------------- -static Bool isMessageUsable(CommandUsableInType usableIn) -{ - // We will ignore all commands if the game client has not yet incremented to frame 1. - // It prevents the user from doing commands during a map load, which throws the input - // system into whack because there isn't a client frame for the input event, and in - // the case of a command that pauses the game, like the quit menu, the client frame - // will never get beyond 0 and we lose the ability to process any input. - if (TheGameClient->getFrame() == 0) - return false; - - const Bool usableInShell = (usableIn & COMMANDUSABLE_SHELL); - const Bool usableInGame = (usableIn & COMMANDUSABLE_GAME); - const Bool usableAsObserver = (usableIn & COMMANDUSABLE_OBSERVER); - const Bool isShellActive = TheShell && TheShell->isShellActive(); - const Bool isObserving = !ThePlayerList->getLocalPlayer()->isPlayerActive(); - - if (usableInShell && isShellActive) - return true; - - if (usableInGame && !isShellActive) - return true; - - if (usableAsObserver && isObserving) - return true; - - return false; -} - -//------------------------------------------------------------------------------------------------- -GameMessageDisposition MetaEventTranslator::translateGameMessage(const GameMessage *msg) -{ - GameMessageDisposition disp = KEEP_MESSAGE; - const GameMessage::Type t = msg->getType(); - - if (t == GameMessage::MSG_RAW_KEY_DOWN || t == GameMessage::MSG_RAW_KEY_UP) - { - onKeyEvent(msg, disp); - } - else if (t > GameMessage::MSG_RAW_MOUSE_BEGIN && t < GameMessage::MSG_RAW_MOUSE_END ) - { - onMouseEvent(msg); - } - - return disp; -} - -//------------------------------------------------------------------------------------------------- -void MetaEventTranslator::onMouseEvent(const GameMessage *msg) -{ - Int index = 3; - switch (msg->getType()) - { - case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_DOWN: - --index; - FALLTHROUGH; - case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_DOWN: - --index; - FALLTHROUGH; - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN: - { - --index; - m_mouseDownPosition[index] = msg->getArgument(0)->pixel; - m_nextUpShouldCreateDoubleClick[index] = FALSE; - break; - } - - case GameMessage::MSG_RAW_MOUSE_LEFT_DOUBLE_CLICK: - --index; - FALLTHROUGH; - case GameMessage::MSG_RAW_MOUSE_MIDDLE_DOUBLE_CLICK: - --index; - FALLTHROUGH; - case GameMessage::MSG_RAW_MOUSE_RIGHT_DOUBLE_CLICK: - { - --index; - m_nextUpShouldCreateDoubleClick[index] = TRUE; - break; - } - - case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_UP: - --index; - FALLTHROUGH; - case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_UP: - --index; - FALLTHROUGH; - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: - { - --index; - - constexpr const GameMessage::Type SingleClickMessages[3] = - { - GameMessage::MSG_MOUSE_LEFT_CLICK, - GameMessage::MSG_MOUSE_MIDDLE_CLICK, - GameMessage::MSG_MOUSE_RIGHT_CLICK, - }; - constexpr const GameMessage::Type DoubleClickMessages[3] = - { - GameMessage::MSG_MOUSE_LEFT_DOUBLE_CLICK, - GameMessage::MSG_MOUSE_MIDDLE_DOUBLE_CLICK, - GameMessage::MSG_MOUSE_RIGHT_DOUBLE_CLICK, - }; - - const ICoord2D location = msg->getArgument(0)->pixel; - const GameMessage::Type messageType = m_nextUpShouldCreateDoubleClick[index] ? DoubleClickMessages[index] : SingleClickMessages[index]; - GameMessage *newMessage = TheMessageStream->insertMessage(messageType, const_cast(msg)); - - IRegion2D pixelRegion; - buildRegion( &m_mouseDownPosition[index], &location, &pixelRegion ); - if (abs(pixelRegion.hi.x - pixelRegion.lo.x) < TheMouse->m_dragTolerance && - abs(pixelRegion.hi.y - pixelRegion.lo.y) < TheMouse->m_dragTolerance) - { - pixelRegion.hi.x = pixelRegion.lo.x; - pixelRegion.hi.y = pixelRegion.lo.y; - } - - newMessage->appendPixelRegionArgument( pixelRegion ); - - // append the modifier keys to the message. - newMessage->appendIntegerArgument( msg->getArgument(1)->integer ); - - // append the time to the message. - //newMessage->appendIntegerArgument( msg->getArgument(2)->integer ); - break; - } - } -} - -//------------------------------------------------------------------------------------------------- -// GeneralsX @refactor fbraz3 06/05/2026 — adopt upstream's structural split (#2758) -// into a single onKeyEvent() helper while keeping GeneralsX's pre-existing -// input semantics: a "mods-only-changed" branch using m_lastModState and a -// m_lastKeyDown-tracking normal key-transition branch. We do not adopt -// upstream's m_keyDownInfos / KeyDownInfo bit-array (introduced for the -// "ignore order of modifier release" fix in #2577) because that fix is not -// part of GeneralsX's behavior, and the bit-array member is not declared -// in MetaEvent.h. -void MetaEventTranslator::onKeyEvent(const GameMessage *msg, GameMessageDisposition &disp) -{ - const Int systemKey = msg->getArgument(0)->integer; - const Int systemKeyState = msg->getArgument(1)->integer; - - const MappableKeyType key = (MappableKeyType)systemKey; - - // for our purposes here, we don't care to distinguish between right and left keys, - // so just fudge a little to simplify things. - Int newModState = 0; - - if (systemKeyState & KEY_STATE_CONTROL) - { - newModState |= CTRL; - } - - if (systemKeyState & KEY_STATE_SHIFT) - { - newModState |= SHIFT; - } - - if (systemKeyState & KEY_STATE_ALT) - { - newModState |= ALT; - } - - for (const MetaMapRec *map = TheMetaMap->getFirstMetaMapRec(); map; map = map->m_next) - { - if (!isMessageUsable(map->m_usableIn)) - continue; - - // check for the special case of mods-only-changed. - if ( - map->m_key == MK_NONE && - newModState != m_lastModState && - ( - (map->m_transition == UP && map->m_modState == m_lastModState) || - (map->m_transition == DOWN && map->m_modState == newModState) - ) - ) - { - //DEBUG_LOG(("Frame %d: MetaEventTranslator::translateGameMessage() Mods-only change: %s", TheGameLogic->getFrame(), findGameMessageNameByType(map->m_meta))); - /*GameMessage *metaMsg =*/ TheMessageStream->appendMessage(map->m_meta); - disp = DESTROY_MESSAGE; - break; - } - - // ok, now check for "normal" key transitions. - if ( - map->m_key == key && - map->m_modState == newModState && - ( - (map->m_transition == UP && (systemKeyState & KEY_STATE_UP)) || - (map->m_transition == DOWN && (systemKeyState & KEY_STATE_DOWN)) //|| - //(map->m_transition == DOUBLEDOWN && (systemKeyState & KEY_STATE_DOWN) && m_lastKeyDown == key) - ) - ) - { - - if (systemKeyState & KEY_STATE_AUTOREPEAT) - { - // if it's an autorepeat of a "known" key, don't generate the meta-event, - // but DO eat the keystroke so no one else can mess with it - //DEBUG_LOG(("Frame %d: MetaEventTranslator::translateGameMessage() auto-repeat: %s", TheGameLogic->getFrame(), findGameMessageNameByType(map->m_meta))); - } - else - { - - // THIS IS A GREASY HACK... MESSAGE SHOULD BE HANDLED IN A TRANSLATOR, BUT DURING CINEMATICS THE TRANSLATOR IS DISABLED - if (map->m_meta == GameMessage::MSG_META_TOGGLE_FAST_FORWARD_REPLAY) - { - #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)//may be defined in GameCommon.h - if (TheGlobalData) - #else - if (TheGlobalData && TheGameLogic->isInReplayGame()) - #endif - { - if (TheWritableGlobalData) - TheWritableGlobalData->m_TiVOFastMode = 1 - TheGlobalData->m_TiVOFastMode; - - if (TheInGameUI) - TheInGameUI->messageNoFormat( TheGlobalData->m_TiVOFastMode - ? TheGameText->FETCH_OR_SUBSTITUTE("GUI:FF_ON", L"Fast Forward is on") - : TheGameText->FETCH_OR_SUBSTITUTE("GUI:FF_OFF", L"Fast Forward is off") - ); - } - disp = KEEP_MESSAGE; // cause for goodness sake, this key gets used a lot by non-replay hotkeys - break; - } - - - /*GameMessage *metaMsg =*/ TheMessageStream->appendMessage(map->m_meta); - //DEBUG_LOG(("Frame %d: MetaEventTranslator::translateGameMessage() normal: %s", TheGameLogic->getFrame(), findGameMessageNameByType(map->m_meta))); - } - disp = DESTROY_MESSAGE; - break; - } - } - - if (msg->getType() == GameMessage::MSG_RAW_KEY_DOWN) - { - m_lastKeyDown = key; - } - - m_lastModState = newModState; -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- - -//------------------------------------------------------------------------------------------------- -MetaMap::MetaMap() : - m_metaMaps(nullptr) -{ -} - -//------------------------------------------------------------------------------------------------- -MetaMap::~MetaMap() -{ - while (m_metaMaps) - { - MetaMapRec *next = m_metaMaps->m_next; - deleteInstance(m_metaMaps); - m_metaMaps = next; - } -} - -//------------------------------------------------------------------------------------------------- -GameMessage::Type MetaMap::findGameMessageMetaType(const char* name) -{ - for (const LookupListRec* metaNames = GameMessageMetaTypeNames; metaNames->name; metaNames++) - if (stricmp(metaNames->name, name) == 0) - return (GameMessage::Type)metaNames->value; - - DEBUG_CRASH(("MetaTypeName %s not found -- did you remember to add it to GameMessageMetaTypeNames[] ?", name)); - return GameMessage::MSG_INVALID; -} - -//------------------------------------------------------------------------------------------------- -MetaMapRec *MetaMap::getMetaMapRec(GameMessage::Type t) -{ - for (MetaMapRec *map = m_metaMaps; map; map = map->m_next) - { - if (map->m_meta == t) - return map; - } - - // not found.. create a new one. - MetaMapRec *m = newInstance(MetaMapRec); - m->m_meta = t; - m->m_key = MK_NONE; - m->m_transition = DOWN; - m->m_modState = NONE; - m->m_usableIn = COMMANDUSABLE_NONE; - m->m_category = CATEGORY_MISC; - m->m_description.clear(); - m->m_displayName.clear(); - m->m_next = m_metaMaps; - m_metaMaps = m; - - return m; -} - -//------------------------------------------------------------------------------------------------- -/*static */ void MetaMap::parseMetaMap(INI* ini) -{ - // read and ignore the meta-map name - const char *c = ini->getNextToken(); - - GameMessage::Type t = TheMetaMap->findGameMessageMetaType(c); - if (t == GameMessage::MSG_INVALID) - throw INI_INVALID_DATA; - - MetaMapRec *map = TheMetaMap->getMetaMapRec(t); - if (map == nullptr) - throw INI_INVALID_DATA; - - ini->initFromINI(map, TheMetaMapFieldParseTable); -} - -//------------------------------------------------------------------------------------------------- -void MetaMap::generateMetaMap() -{ - // TheSuperHackers @info A default mapping for MSG_META_SELECT_ALL_AIRCRAFT would be useful for Generals - // but is not recommended, because it will cause key mapping conflicts with original game languages. - - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_INCREASE_MAX_RENDER_FPS); - if (map->m_key == MK_NONE) - { - map->m_key = MK_KPPLUS; - map->m_transition = DOWN; - map->m_modState = CTRL; - map->m_usableIn = COMMANDUSABLE_EVERYWHERE; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_DECREASE_MAX_RENDER_FPS); - if (map->m_key == MK_NONE) - { - map->m_key = MK_KPMINUS; - map->m_transition = DOWN; - map->m_modState = CTRL; - map->m_usableIn = COMMANDUSABLE_EVERYWHERE; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_INCREASE_LOGIC_TIME_SCALE); - if (map->m_key == MK_NONE) - { - map->m_key = MK_KPPLUS; - map->m_transition = DOWN; - map->m_modState = SHIFT_CTRL; - map->m_usableIn = COMMANDUSABLE_EVERYWHERE; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_DECREASE_LOGIC_TIME_SCALE); - if (map->m_key == MK_NONE) - { - map->m_key = MK_KPMINUS; - map->m_transition = DOWN; - map->m_modState = SHIFT_CTRL; - map->m_usableIn = COMMANDUSABLE_EVERYWHERE; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_TOGGLE_PLAYER_OBSERVER); - if (map->m_key == MK_NONE) - { - map->m_key = MK_M; - map->m_transition = DOWN; - map->m_modState = NONE; - map->m_usableIn = COMMANDUSABLE_OBSERVER; - } - } - { - // Is mostly useful for Generals. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_TOGGLE_FAST_FORWARD_REPLAY); - if (map->m_key == MK_NONE) - { - map->m_key = MK_F; - map->m_transition = DOWN; - map->m_modState = NONE; - map->m_usableIn = COMMANDUSABLE_GAME; // @todo COMMANDUSABLE_OBSERVER - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_TOGGLE_PAUSE); - if (map->m_key == MK_NONE) - { - map->m_key = MK_P; - map->m_transition = DOWN; - map->m_modState = NONE; - map->m_usableIn = COMMANDUSABLE_OBSERVER; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_TOGGLE_PAUSE_ALT); - if (map->m_key == MK_NONE) - { - map->m_key = MK_P; - map->m_transition = DOWN; - map->m_modState = SHIFT; // Requires modifier to avoid key conflicts as a player. - map->m_usableIn = COMMANDUSABLE_EVERYWHERE; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_STEP_FRAME); - if (map->m_key == MK_NONE) - { - map->m_key = MK_O; - map->m_transition = DOWN; - map->m_modState = NONE; - map->m_usableIn = COMMANDUSABLE_OBSERVER; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_STEP_FRAME_ALT); - if (map->m_key == MK_NONE) - { - map->m_key = MK_O; - map->m_transition = DOWN; - map->m_modState = SHIFT; // Requires modifier to avoid key conflicts as a player. - map->m_usableIn = COMMANDUSABLE_EVERYWHERE; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_SELECT_NEXT_IDLE_WORKER); - if (map->m_key == MK_NONE) { - map->m_key = MK_I; - map->m_transition = DOWN; - map->m_modState = CTRL; - map->m_usableIn = COMMANDUSABLE_GAME; - map->m_category = CATEGORY_SELECTION; - map->m_description = TheGameText->FETCH_OR_SUBSTITUTE("GUI:SelectNextIdleWorkerDescription", L"Select the next idle worker"); - map->m_displayName = TheGameText->FETCH_OR_SUBSTITUTE("GUI:SelectNextIdleWorker", L"Next Idle Worker"); - } - } - { - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_ALT_CAMERA_ROTATE_LEFT); - if (map->m_key == MK_NONE) { - map->m_key = MK_KP4; - map->m_transition = DOWN; - map->m_modState = CTRL; - map->m_usableIn = COMMANDUSABLE_GAME; - } - } - { - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_ALT_CAMERA_ROTATE_RIGHT); - if (map->m_key == MK_NONE) { - map->m_key = MK_KP6; - map->m_transition = DOWN; - map->m_modState = CTRL; - map->m_usableIn = COMMANDUSABLE_GAME; - } - } - -#if defined(RTS_DEBUG) - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_DEMO_REMOVE_PREREQ); - if (map->m_key == MK_NONE) - { - map->m_key = MK_P; - map->m_transition = DOWN; - map->m_modState = ALT; - map->m_usableIn = COMMANDUSABLE_GAME; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = getMetaMapRec(GameMessage::MSG_META_DEMO_FREE_BUILD); - if (map->m_key == MK_NONE) - { - map->m_key = MK_B; - map->m_transition = DOWN; - map->m_modState = ALT; - map->m_usableIn = COMMANDUSABLE_GAME; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = TheMetaMap->getMetaMapRec(GameMessage::MSG_META_DEMO_BEGIN_ADJUST_DEFAULTPITCH); - if (map->m_key == MK_NONE) - { - map->m_key = MK_COMMA; - map->m_transition = DOWN; - map->m_modState = CTRL; - map->m_usableIn = COMMANDUSABLE_GAME; - } - } - { - // Is useful for Generals and Zero Hour. - MetaMapRec *map = TheMetaMap->getMetaMapRec(GameMessage::MSG_META_DEMO_END_ADJUST_DEFAULTPITCH); - if (map->m_key == MK_NONE) - { - map->m_key = MK_COMMA; - map->m_transition = UP; - map->m_modState = CTRL; - map->m_usableIn = COMMANDUSABLE_GAME; - } - } -#endif // defined(RTS_DEBUG) -} - -//------------------------------------------------------------------------------------------------- -void MetaMap::verifyMetaMap() -{ -#ifdef DEBUG_CRASHING - for (const MetaMapRec *map = getFirstMetaMapRec(); map; map = map->m_next) - { - DEBUG_ASSERTCRASH( - map->m_meta > GameMessage::MSG_BEGIN_META_MESSAGES && - map->m_meta < GameMessage::MSG_END_META_MESSAGES, - ("hmm, expected only meta-msgs here")); - } -#endif -} - -//------------------------------------------------------------------------------------------------- -/*static*/ void INI::parseMetaMapDefinition( INI* ini ) -{ - MetaMap::parseMetaMap(ini); -} - diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp deleted file mode 100644 index 142af157c40..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp +++ /dev/null @@ -1,355 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: PlaceEventTranslator.cpp /////////////////////////////////////////////////////////// -// Author: Steven Johnson, Dec 2001 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/BuildAssistant.h" -#include "Common/GameAudio.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/SpecialPower.h" -#include "Common/ThingTemplate.h" - -#include "GameClient/CommandXlat.h" -#include "GameClient/ControlBar.h" -#include "GameClient/Drawable.h" -#include "GameClient/Eva.h" -#include "GameClient/PlaceEventTranslator.h" - -#include "GameLogic/GameLogic.h" -#include "GameLogic/Object.h" - -#include "GameLogic/Module/ProductionUpdate.h" - - - -//------------------------------------------------------------------------------------------------- -PlaceEventTranslator::PlaceEventTranslator() : m_frameOfUpButton(-1) -{ -} - -//------------------------------------------------------------------------------------------------- -PlaceEventTranslator::~PlaceEventTranslator() -{ -} - -//------------------------------------------------------------------------------------------------- -/** Translator to process raw input messages into the "place something" message(s) */ -//------------------------------------------------------------------------------------------------- -GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMessage *msg) -{ - GameMessageDisposition disp = KEEP_MESSAGE; - - switch(msg->getType()) - { - - //--------------------------------------------------------------------------------------------- - // TheSuperHackers @bugfix Prevent double-clicks from falling through to other translators during building placement - case GameMessage::MSG_RAW_MOUSE_LEFT_DOUBLE_CLICK: - case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_DOWN: - { - // if we're in a building placement mode, do the place and send to all players - const ThingTemplate *build = TheInGameUI->getPendingPlaceType(); - if( build && TheInGameUI->isPlacementAnchored() == FALSE ) - { - ICoord2D mouse = msg->getArgument(0)->pixel; - Coord3D world; - - // translate mouse position to world position - TheTacticalView->screenToTerrain( &mouse, &world ); - - // - // placing things causes a dozer to go over and build it ... get the dozer in question - // from the in game UI - // - Object *builderObject = TheGameLogic->findObjectByID( TheInGameUI->getPendingPlaceSourceObjectID() ); - - // if our source object is gone cancel this whole placement process - if( builderObject == nullptr ) - { - - TheInGameUI->placeBuildAvailable( nullptr, nullptr ); - break; - - } - - // set this location as the placement anchor - TheInGameUI->setPlacementStart( &mouse ); - -/* -// -// This block of code checks for valid placement on a down mouse click, but since we can -// rotate a building into a valid location, this check prevents us from placing things -// down in some legal locations -// - // get the type of thing we want to build - const ThingTemplate *whatToBuild = TheInGameUI->getPendingPlaceType(); - - // - // if the spot at which they choose to place this thing is illegal we won't start - // the placement anchor, instead we play a "can't do that" sound - // - LegalBuildCode lbc; - lbc = TheBuildAssistant->isLocationLegalToBuild( &world, - whatToBuild, - TheInGameUI->getPlacementAngle(), - BuildAssistant::USE_QUICK_PATHFIND | - BuildAssistant::TERRAIN_RESTRICTIONS | - BuildAssistant::CLEAR_PATH | - BuildAssistant::NO_OBJECT_OVERLAP, - builderObject ); - if( lbc != LBC_OK ) - { - static const Sound *noCanDoSound = TheAudio->Sounds->getSound( "NoCanDoSound" ); - - // play a can't do that sound - TheAudio->Sounds->playSound( noCanDoSound ); - - // display a message to the user as to why you can't build there - TheInGameUI->displayCantBuildMessage( lbc ); - - } - else - { - - // start placement anchor - TheInGameUI->setPlacementStart(&mouse); - - } -*/ - - // used the input - disp = DESTROY_MESSAGE; - - } - break; - } - - //--------------------------------------------------------------------------------------------- - case GameMessage::MSG_MOUSE_LEFT_DOUBLE_CLICK: - case GameMessage::MSG_MOUSE_LEFT_CLICK: - { - // if we're in a building placement mode, do the place and send to all players - const ThingTemplate *build = TheInGameUI->getPendingPlaceType(); - - // ... and also remove any radius cursor that is active. - // (srj sez: not sure if this is always necessary... more of a failsafe to make it go away.) - TheInGameUI->setRadiusCursorNone(); - - if (build && TheInGameUI->isPlacementAnchored()) - { - GameMessage *placeMsg; -// Player *player = ThePlayerList->getLocalPlayer(); - Coord3D world; - Real angle; - ICoord2D anchorStart, anchorEnd; - Bool isLineBuild = TheBuildAssistant->isLineBuildTemplate( build ); - - // get the angle of the drawable at the cursor to use as the initial angle - angle = TheInGameUI->getPlacementAngle(); - - // get start point from the anchor arrow used to place and select angles - TheInGameUI->getPlacementPoints( &anchorStart, &anchorEnd ); - - // translate the screen position of start to world target location - TheTacticalView->screenToTerrain( &anchorStart, &world ); - - Object *builderObj = TheGameLogic->findObjectByID( TheInGameUI->getPendingPlaceSourceObjectID() ); - - //Kris: September 27, 2002 - //Make sure we have enough CASH to build it! It's possible that between the - //time we initiated it and the time we confirm it, a hacker has stolen some of - //our cash! - CanMakeType cmt = TheBuildAssistant->canMakeUnit( builderObj, build ); - if( cmt != CANMAKE_OK ) - { - if (cmt == CANMAKE_NO_MONEY) - { - TheEva->setShouldPlay(EVA_InsufficientFunds); - TheInGameUI->message( "GUI:NotEnoughMoneyToBuild" ); - break; - } - else if (cmt == CANMAKE_QUEUE_FULL) - { - TheInGameUI->message( "GUI:ProductionQueueFull" ); - break; - } - else if (cmt == CANMAKE_PARKING_PLACES_FULL) - { - TheInGameUI->message( "GUI:ParkingPlacesFull" ); - break; - } - else if( cmt == CANMAKE_MAXED_OUT_FOR_PLAYER ) - { - TheInGameUI->message( "GUI:UnitMaxedOut" ); - break; - } - // get out of pending placement mode, this will also clear the arrow anchor status - TheInGameUI->placeBuildAvailable( nullptr, nullptr ); - break; - } - - DEBUG_ASSERTCRASH(builderObj != nullptr, ("builderObj is null")); - - // check to see if this is a legal location to build something at - LegalBuildCode lbc; - lbc = TheBuildAssistant->isLocationLegalToBuild( &world, - build, - angle, - BuildAssistant::USE_QUICK_PATHFIND | - BuildAssistant::TERRAIN_RESTRICTIONS | - BuildAssistant::CLEAR_PATH | - BuildAssistant::NO_OBJECT_OVERLAP | - BuildAssistant::SHROUD_REVEALED | - BuildAssistant::IGNORE_STEALTHED | - BuildAssistant::FAIL_STEALTHED_WITHOUT_FEEDBACK, - builderObj, nullptr ); - if( lbc == LBC_OK ) - { - //Are we building this structure via the special power system? (special case for sneak attack) - if( builderObj ) - { - ProductionUpdateInterface *puInterface = builderObj->getProductionUpdateInterface(); - if( puInterface ) - { - const CommandButton *commandButton = puInterface->getSpecialPowerConstructionCommandButton(); - if( commandButton ) - { - //If we get this far, then we aren't going to really build the object using the production update - //interface. Instead, we're going to trigger the special power to create it magically without a - //dozer/worker. - placeMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_SPECIAL_POWER_AT_LOCATION ); - placeMsg->appendIntegerArgument( commandButton->getSpecialPowerTemplate()->getID() ); //The ID of the special power template. - placeMsg->appendLocationArgument( world ); //Position of special to be fired. - placeMsg->appendRealArgument( angle ); //Angle of special to be fired. - placeMsg->appendObjectIDArgument( INVALID_ID ); //There is no object in the way. - placeMsg->appendIntegerArgument( commandButton->getOptions() ); //Command button options. - placeMsg->appendObjectIDArgument( builderObj->getID() ); //The source object responsible for firing the special. - - // get out of pending placement mode, this will also clear the arrow anchor status - TheInGameUI->placeBuildAvailable( nullptr, nullptr ); - - // used the input - disp = DESTROY_MESSAGE; - m_frameOfUpButton = TheGameLogic->getFrame(); - break; - } - } - } - - // create the right kind of message - if( isLineBuild ) - placeMsg = TheMessageStream->appendMessage( GameMessage::MSG_DOZER_CONSTRUCT_LINE ); - else - placeMsg = TheMessageStream->appendMessage( GameMessage::MSG_DOZER_CONSTRUCT ); - - placeMsg->appendIntegerArgument(build->getTemplateID()); - placeMsg->appendLocationArgument(world); - placeMsg->appendRealArgument(angle); - if( isLineBuild ) - { - Coord3D worldEnd; - - TheTacticalView->screenToTerrain( &anchorEnd, &worldEnd ); - placeMsg->appendLocationArgument( worldEnd ); - - } - - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), placeMsg->getType() ); - - // get out of pending placement mode, this will also clear the arrow anchor status - TheInGameUI->placeBuildAvailable( nullptr, nullptr ); - - } - else - { - // can't place, display why - TheInGameUI->displayCantBuildMessage( lbc ); - - //Cannot build here -- play the voice sound from the dozer - AudioEventRTS sound = *builderObj->getTemplate()->getPerUnitSound( "VoiceNoBuild" ); - sound.setObjectID( builderObj->getID() ); - TheAudio->addAudioEvent( &sound ); - - // play a can't do that sound (UI beep type sound) - static AudioEventRTS noCanDoSound( "NoCanDoSound" ); - TheAudio->addAudioEvent( &noCanDoSound ); - - // unhook the anchor so they can try again - TheInGameUI->setPlacementStart( nullptr ); - - } - - // used the input - disp = DESTROY_MESSAGE; - m_frameOfUpButton = TheGameLogic->getFrame(); - - } - - if (disp == DESTROY_MESSAGE) - TheInGameUI->clearAttackMoveToMode(); - - break; - - } - - //--------------------------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_POSITION: - { - // if a building placement is in progress update the destination position - if (TheInGameUI->isPlacementAnchored()) - { - const Int PLACEMENT_DRAG_THRESHOLD_DIST = 5; // in pixels away from anchor point - ICoord2D mouse = msg->getArgument(0)->pixel; - - // - // we will only process placement end point sets (clicking, and dragging to set angles) - // if we have moved far enough away from the start point - // - ICoord2D start; - TheInGameUI->getPlacementPoints( &start, nullptr ); - - Int x, y; - x = mouse.x - start.x; - y = mouse.y - start.y; - if( sqrt( (x * x) + (y * y) ) >= PLACEMENT_DRAG_THRESHOLD_DIST ) - { - - TheInGameUI->setPlacementEnd(&mouse); - disp = DESTROY_MESSAGE; - - } - - } - break; - } - } - - return disp; -} - - diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp deleted file mode 100644 index 363f11e3356..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp +++ /dev/null @@ -1,1323 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// SelectionXlat.cpp -// Message stream translator -// Author: Michael S. Booth, January 2001 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "Common/ActionManager.h" -#include "Common/GameAudio.h" -#include "Common/GameEngine.h" -#include "Common/MessageStream.h" -#include "Common/MiscAudio.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/ThingTemplate.h" - -#include "GameLogic/Damage.h" -#include "GameLogic/GameLogic.h" -#include "GameLogic/Object.h" -#include "GameLogic/Squad.h" -#include "GameLogic/Module/BodyModule.h" -#include "GameLogic/Module/ContainModule.h" -#include "GameLogic/Module/UpdateModule.h" - -#include "GameClient/ControlBar.h" -#include "GameClient/Display.h" -#include "GameClient/Drawable.h" -#include "GameClient/GameClient.h" -#include "GameClient/GameText.h" -#include "GameClient/GameWindowManager.h" -#include "GameClient/Keyboard.h" -#include "GameClient/SelectionInfo.h" -#include "GameClient/SelectionXlat.h" -#include "GameClient/TerrainVisual.h" - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -#if defined(RTS_DEBUG) -static Bool TheHurtSelectionMode = false; -static Bool TheDebugSelectionMode = false; -#endif - -//----------------------------------------------------------------------------- -static Bool currentlyLookingForSelection( ) -{ - // This needs to check if we are currently targeting for special weapons fire. - return TheInGameUI->getGUICommand() == nullptr; -} - -//----------------------------------------------------------------------------- -static Bool areAllSelected( const DrawableList& listToCheck ) -{ - DrawableListCIt it; - for ( it = listToCheck.begin(); it != listToCheck.end(); ++it ) { - if (!*it) - continue; - - if (!(*it)->isSelected()) - return FALSE; - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -struct SFWRec -{ - SelectionTranslator *translator; - GameMessage *createTeamMsg; - Bool dragSelecting; -}; - -//----------------------------------------------------------------------------- -/*friend*/ Bool selectFriendsWrapper( Drawable *draw, void *userData ) -{ - SFWRec *info = (SFWRec *)userData; - return info->translator->selectFriends(draw, info->createTeamMsg, info->dragSelecting) != 0; -} - -/*friend*/ Bool killThemKillThemAllWrapper( Drawable *draw, void *userData ) -{ - SFWRec *info = (SFWRec *)userData; - info->translator->killThemKillThemAll( draw, info->createTeamMsg ); - return true; -} - -//----------------------------------------------------------------------------- -/** - * Returns true if the drawable can be selected under the current rules - * of the system - */ -Bool CanSelectDrawable( const Drawable *draw, Bool dragSelecting ) -{ - - if(!draw || !draw->getObject()) - { - return FALSE; // can't select - } - const Object *obj = draw->getObject(); - - if( obj->isEffectivelyDead() && !obj->isKindOf(KINDOF_ALWAYS_SELECTABLE)) - { - //Don't select dead/dying units. - return FALSE; - } - - //Added this to support attacking cargo planes without being able to select them. - //I added the KINDOF_FORCEATTACKABLE to them, but unsure if it's possible to select - //something without the KINDOF_SELECTABLE -- so doing a LATE code change. My gut - //says we should simply have the KINDOF_SELECTABLE check only... but best to be safe. - if( !obj->isKindOf( KINDOF_SELECTABLE ) && obj->isKindOf( KINDOF_FORCEATTACKABLE ) ) - { - return FALSE; - } - - // hidden objects cannot be selected - if( draw->isDrawableEffectivelyHidden() ) - { - return FALSE; // can't select - } - - // ignore objects obscured by the GUI - GameWindow *window = nullptr; - if (TheWindowManager) - { - const Coord3D *c = draw->getPosition(); - ICoord2D c2; - TheTacticalView->worldToScreen(c, &c2); - window = TheWindowManager->getWindowUnderCursor(c2.x, c2.y); - } - - while (window) - { - // check to see if it or any of its parents are opaque. If so, we can't select anything. - if (!BitIsSet( window->winGetStatus(), WIN_STATUS_SEE_THRU )) - { - return FALSE; - } - - window = window->winGetParent(); - } - - // - // structures cannot be selected by a drag select, you must individually pick them - // NOTE that this is really a convenience for the multi select context sensitive UI, - // later we might want to allow you to drag select buildings if only one building is - // actually in the selection area, but don't forget complications like holding down - // a key to "add" to an already existing selection list - // - // not allowing you to have multiple buildings selected drastically simplifies the - // user interface ... including all those context sensitive commands that we - // can just assume are for a single building selected. - // - if( dragSelecting && draw->isKindOf( KINDOF_STRUCTURE ) ) - { - return FALSE; - } - - // You cannot select something that has a logic override of unselectability or masked - if( obj->getStatusBits().testForAny( MAKE_OBJECT_STATUS_MASK2( OBJECT_STATUS_UNSELECTABLE, OBJECT_STATUS_MASKED ) ) ) - { - return FALSE; - } - - if (!obj->isSelectable()) - { - return false; - } - //Now allowing the selection of everything including enemies... but only if not drag selecting. - //In fact the only way you can drag select is if the unit is on your team. - if( dragSelecting && !obj->isLocallyControlled() ) - { - return FALSE; - } - - //Now we can select anything that is selectable. - return TRUE; - -} - -//----------------------------------------------------------------------------- -static Bool canSelectWrapper( Drawable *draw, void *userData ) -{ - Bool dragSelecting = *((Bool *)userData); - return CanSelectDrawable( draw, dragSelecting ); -} - -//----------------------------------------------------------------------------- -/** - * Deselect all drawables, and emit a "TEAM_DESTROY" message, since - * the "team" was the group of currently selected units. - */ -static void deselectAll() -{ - - // deselect it all - TheInGameUI->deselectAllDrawables(); -} - -//----------------------------------------------------------------------------- -/** - * Select the given drawable, without playing its sound. - * Returns true. - */ -static Bool selectSingleDrawableWithoutSound( Drawable *draw ) -{ - - // since we are single selecting a drawable, unselect everything else - deselectAll(); - - // do the drawable selection - TheInGameUI->selectDrawable( draw ); - - Object *obj = draw->getObject(); - if (obj != nullptr) { - GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_CREATE_SELECTED_GROUP_NO_SOUND); - msg->appendBooleanArgument(TRUE); - msg->appendObjectIDArgument(obj->getID()); - } - - return true; - -} - -SelectionTranslator *TheSelectionTranslator = nullptr; -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -SelectionTranslator::SelectionTranslator() -{ - m_leftMouseButtonIsDown = FALSE; - m_dragSelecting = FALSE; - m_lastGroupSelTime = 0; - m_lastGroupSelGroup = -1; - m_selectFeedbackAnchor.x = 0; - m_selectFeedbackAnchor.y = 0; - m_deselectFeedbackAnchor.x = 0; - m_deselectFeedbackAnchor.y = 0; - m_lastClick = 0; - m_deselectDownCameraPosition.zero(); - m_displayedMaxWarning = FALSE; - m_selectCountMap.clear(); - - TheSelectionTranslator = this; - -#if defined(RTS_DEBUG) || defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE) - m_HandOfGodSelectionMode = FALSE; -#endif -} - -//----------------------------------------------------------------------------- -SelectionTranslator::~SelectionTranslator() -{ -} - -//----------------------------------------------------------------------------- -/** - * If this drawable is a 'friend' of mine, select it. - */ -Bool SelectionTranslator::selectFriends( Drawable *draw, GameMessage *createTeamMsg, - Bool dragSelecting ) -{ - if (CanSelectDrawable( draw, dragSelecting )) - { - // enforce an optional selection size limit - if (TheInGameUI->getMaxSelectCount() > 0 && TheInGameUI->getSelectCount() >= TheInGameUI->getMaxSelectCount()) - { - if (!m_displayedMaxWarning) - { - m_displayedMaxWarning = TRUE; - UnicodeString msg; - msg.format(TheGameText->fetch("GUI:MaxSelectionSize").str(), TheInGameUI->getMaxSelectCount()); - TheInGameUI->message(msg); - } - return false; - } - - TheInGameUI->selectDrawable( draw ); - - m_selectCountMap[draw->getTemplate()]++; - - // add to message's argument list if an object is present - if( draw->getObject() && createTeamMsg ) - createTeamMsg->appendObjectIDArgument( draw->getObject()->getID() ); - - return true; // selected - - } - - return false; // not selected - -} - - -//----------------------------------------------------------------------------- -Bool SelectionTranslator::killThemKillThemAll( Drawable *draw, GameMessage *killThemAllMsg ) -{ - if( draw ) - { - Object *obj = draw->getObject(); - if( obj ) - { - // enforce an optional selection size limit - if (TheInGameUI->getMaxSelectCount() > 0 && TheInGameUI->getSelectCount() >= TheInGameUI->getMaxSelectCount()) - { - if (!m_displayedMaxWarning) - { - m_displayedMaxWarning = TRUE; - UnicodeString msg; - msg.format(TheGameText->fetch("GUI:MaxSelectionSize").str(), TheInGameUI->getMaxSelectCount()); - TheInGameUI->message(msg); - } - return false; - } - - // add to message's argument list if an object is present - if( killThemAllMsg ) - { - killThemAllMsg->appendObjectIDArgument( draw->getObject()->getID() ); - } - - return true; // selected - } - } - return false; -} - -//----------------------------------------------------------------------------- -/** - * The SelectionTranslator is responsible for all selection semantics, - * including click selection, area drag selection, right-click de-selection, - * and CTRL-key group selection. - * NOTE: This handler changes the event semantics for mouse buttons from - * LEFT_DOWN -> LEFT_UP to LEFT_DOWN -> { LEFT_UP, AREA_SELECTION, or DRAWABLE_PICKED } - */ -GameMessageDisposition SelectionTranslator::translateGameMessage(const GameMessage *msg) -{ - GameMessageDisposition disp = KEEP_MESSAGE; - - if( !TheInGameUI->getInputEnabled() ) - { - //Keep the message so the other translators (WindowXlat) can handle. - if( m_dragSelecting ) - { - //Turn off drag select - m_dragSelecting = FALSE; - TheInGameUI->setSelecting( FALSE ); - TheInGameUI->endAreaSelectHint(nullptr); - TheTacticalView->setMouseLock( FALSE ); - } - return KEEP_MESSAGE; - } - - GameMessage::Type t = msg->getType(); - switch (t) - { - case GameMessage::MSG_META_BEGIN_FORCEATTACK: - TheInGameUI->setForceAttackMode( true ); - break; - - case GameMessage::MSG_META_END_FORCEATTACK: - TheInGameUI->setForceAttackMode( false ); - break; - - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_POSITION: - { - ICoord2D pixel; - pixel = msg->getArgument( 0 )->pixel; - - - // modifier appears to be unused, and the argument doesn't exist. jba. - //Int modifier = msg->getArgument( 1 )->integer; - - if (m_leftMouseButtonIsDown) - { - ICoord2D delta; - - delta.x = abs(pixel.x - m_selectFeedbackAnchor.x); - delta.y = abs(pixel.y - m_selectFeedbackAnchor.y); - - // if mouse has moved while left button is down, begin drag selection - if (delta.x > TheMouse->m_dragTolerance || delta.y > TheMouse->m_dragTolerance) - { - if (m_dragSelecting == false) - { - m_dragSelecting = true; - TheTacticalView->setMouseLock( TRUE ); - TheInGameUI->setSelecting( TRUE ); - } - } - - // create "hint" messages defining selection region under construction - if (m_dragSelecting) - { - // insert area selection "hint" message into stream - GameMessage *hintMsg = TheMessageStream->appendMessage( GameMessage::MSG_BEGIN_AREA_SELECTION_HINT ); - - // build rectangular region defined by the drag selection - IRegion2D pixelRegion; - buildRegion( &m_selectFeedbackAnchor, &pixel, &pixelRegion ); - hintMsg->appendPixelRegionArgument( pixelRegion ); - } - } - else //left button is not down (not drag select) - { - // insert Mouseover hint into stream for CommandTranslator and HintSpy to see. - GameMessage *mouseoverMessage; - - //Kris: We want to show information such as the popup text on objects that are forceattackable even - // when we're not in force attackable mode! - UnsignedInt pickType = getPickTypesForContext( true /*TheInGameUI->isInForceAttackMode()*/ ); - - Drawable *underCursor = TheTacticalView->pickDrawable( &pixel, TheInGameUI->isInForceAttackMode(), (PickType) pickType ); - Object *objUnderCursor = underCursor ? underCursor->getObject() : nullptr; - - if( objUnderCursor && (!objUnderCursor->isEffectivelyDead() || objUnderCursor->isKindOf( KINDOF_ALWAYS_SELECTABLE )) ) - { - mouseoverMessage = TheMessageStream->appendMessage( GameMessage::MSG_MOUSEOVER_DRAWABLE_HINT ); - mouseoverMessage->appendDrawableIDArgument( underCursor->getID() ); - } - else// else this is a mouseover terrain - { - Coord3D position; - - TheTacticalView->screenToTerrain( &pixel, &position ); - mouseoverMessage = TheMessageStream->appendMessage( GameMessage::MSG_MOUSEOVER_LOCATION_HINT ); - mouseoverMessage->appendLocationArgument( position ); - } - } - - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_MOUSE_LEFT_DOUBLE_CLICK: - { - Int modifiers = msg->getArgument(1)->integer; - - // Pressing ctrl is disallowed for double clicking - if (TheInGameUI->isInForceAttackMode()) - break; - - const IRegion2D& region = msg->getArgument(0)->pixelRegion; - - // Single point. If there's a unit in there, double click will select all of them. - if (region.height() == 0 && region.width() == 0) - { - Bool selectAcrossMap = (BitIsSet(modifiers, KEY_STATE_ALT) ? TRUE : FALSE); - - // only allow things that are selectable. Also, we aren't allowed to - Drawable *picked = TheTacticalView->pickDrawable( ®ion.lo, FALSE, PICK_TYPE_SELECTABLE); - - // If there wasn't anyone to pick, then we want to propagate this double click. - if (picked == nullptr) - break; - - if (!picked->isMassSelectable()) - break; - - Object *pickedObj = picked->getObject(); - - // We have to have an object in order to be able to do interesting double click stuff on - // him. Also, if it is a structure, it is already selected, so don't select all the units - // like him. - if (pickedObj == nullptr || !pickedObj->isLocallyControlled()) - break; - - // Ok. The logic is a little bit weird here. What we need to do is deselect everything - // except for this one picked thing. Store off the old selection, pick the single clicked thing. - // Then if - DrawableList listOfSelectedDrawables; - if (TheInGameUI->isInPreferSelectionMode()) { - listOfSelectedDrawables = *TheInGameUI->getAllSelectedDrawables(); - } - - // Pick just that one guy. - selectSingleDrawableWithoutSound(picked); - - // Yay. Either select across the screen or the world depending on selectAcrossMap - if (selectAcrossMap) - TheInGameUI->selectMatchingAcrossMap(); - else - TheInGameUI->selectMatchingAcrossScreen(); - - // emit "picked" message - GameMessage *pickMsg = TheMessageStream->appendMessage( GameMessage::MSG_END_AREA_SELECTION_HINT ); - pickMsg->appendDrawableIDArgument( picked->getID() ); /// note we are putting in a drawable id - - if (TheInGameUI->isInPreferSelectionMode() && !listOfSelectedDrawables.empty()) { - GameMessage *selectMore = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP_NO_SOUND ); - selectMore->appendBooleanArgument(FALSE); - for (DrawableListIt it = listOfSelectedDrawables.begin(); it != listOfSelectedDrawables.end(); ++it) { - Drawable *draw = *it; - if (draw && draw->isSelectable()) { - TheInGameUI->selectDrawable(draw); - selectMore->appendObjectIDArgument(draw->getObject()->getID()); - } - } - } - - disp = DESTROY_MESSAGE; - } - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_MOUSEOVER_DRAWABLE_HINT: - { - if (TheInGameUI->isScrolling()) { - // dont show this now. - break; - } - - DrawableID id = msg->getArgument(0)->drawableID; - Drawable *draw = TheGameClient->findDrawableByID(id); - if (!draw) { - break; - } - - GameMessage::Type msgType = TheGameClient->evaluateContextCommand(draw, draw->getPosition(), CommandTranslator::EVALUATE_ONLY); - if( msgType == GameMessage::MSG_INVALID ) - { - TheInGameUI->createMouseoverHint(msg); // this sets the cursor - disp = DESTROY_MESSAGE; - const CommandButton *command = TheInGameUI->getGUICommand(); - - Bool ignoreCommand = FALSE; - if( command ) - { - if( command->getCommandType() == GUI_COMMAND_ATTACK_MOVE || - command->getCommandType() == GUI_COMMAND_GUARD || - command->getCommandType() == GUI_COMMAND_GUARD_WITHOUT_PURSUIT || - command->getCommandType() == GUI_COMMAND_GUARD_FLYING_UNITS_ONLY ) - { - //These GUI commands can take care of themselves -- don't let - //the selection translator meddle. - ignoreCommand = TRUE; - } - } - if( !ignoreCommand && !draw->getTemplate()->isKindOf( KINDOF_SHRUBBERY ) ) - { - if( CanSelectDrawable( draw, FALSE ) ) - { - TheMouse->setCursor(Mouse::SELECTING); - } - else - { - TheMouse->setCursor( Mouse::ARROW ); - } - } - } - - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_MOUSE_LEFT_CLICK: - { - // If the quit menu is visible, we need to not process left clicks through the selection translator. - if (TheInGameUI->isQuitMenuVisible()) - { - disp = DESTROY_MESSAGE; - break; - } - - // Basically, we need to first determine if there are any drawables in the region of interest. - // If there aren't then this click should move forward. - IRegion2D selectionRegion = msg->getArgument(0)->pixelRegion; - Bool isPoint = (selectionRegion.height() == 0 && selectionRegion.width() == 0); - - DrawableList drawablesThatWillSelect; - PickDrawableStruct pds; - pds.drawableListToFill = &drawablesThatWillSelect; - pds.isPointSelection = isPoint; - TheTacticalView->iterateDrawablesInRegion(&selectionRegion, addDrawableToList, &pds); - - if (drawablesThatWillSelect.empty()) - { - break; - } - - // if there were drawables in the region, then we should determine if there is a context - // sensitive command that should take place. If there is, then this isn't a selection thing - const DrawableList *currentList = TheInGameUI->getAllSelectedDrawables(); - if (!currentlyLookingForSelection()) - { - break; - } - - SelectionInfo si; - if (contextCommandForNewSelection(currentList, &drawablesThatWillSelect, &si, isPoint)) - { - break; - } - - // There isn't a context command, so this is a selection thing. Now, based on the keys, - // determine whether or not we should create a new group, or append these guys to our existing - // group. - - Bool addToGroup = TheInGameUI->isInPreferSelectionMode(); - - if (si.currentCountEnemies > 0 || - si.currentCountCivilians > 0 || - si.currentCountFriends > 0 || - si.currentCountMineBuildings > 0) - { - // force a new group creation - addToGroup = FALSE; - } - - // If there are any of my units, then select those. - if (si.newCountMine > 0) - { - si.selectMine = TRUE; - - // EXACTLY ONE CLICKED OR DRAGGED BUILDING - if ( si.newCountMineBuildings == 1 && si.newCountMine == 1 ) - { - addToGroup = FALSE; - si.selectMineBuildings = TRUE; - } - else if ( si.newCountMineBuildings > 0 )////////////// SO SORRY, I KNOW THIS IS MICKEY MOUSE /////////////////// - { // What we are after here is to allow the drag select to get the building, - // if the other things in the list are going to be ignored anyway - // so we find out whether the other things are not selectible - // this came up with the new AmericaBuildingFireBase, which shows its contained - // but does not let you select them. The selection is propagated to the container - // in new code in SelectionInfo.cpp, in the static addDrawableToList(); - // -Mark Lorenzen, 6/12/03 - Bool onlyTheOneBuildingIsSelectableAnyway = TRUE; - DrawableID buildingID = INVALID_DRAWABLE_ID; - for (DrawableListIt it = drawablesThatWillSelect.begin(); it != drawablesThatWillSelect.end(); ++it) - { - const Drawable *d = *it; - if ( d->isKindOf( KINDOF_STRUCTURE ) ) - {// make sure there is really only the one building in the list, as it may be multiply listed - - if ( buildingID == INVALID_DRAWABLE_ID ) // this is the first building - buildingID = d->getID(); - else if ( buildingID != d->getID() )//oops, more than one building! - onlyTheOneBuildingIsSelectableAnyway = FALSE; - } - else if ( d->isSelectable() ) - onlyTheOneBuildingIsSelectableAnyway = FALSE; - - if ( ! onlyTheOneBuildingIsSelectableAnyway ) - break; - } - if ( onlyTheOneBuildingIsSelectableAnyway ) - { - addToGroup = FALSE; - si.selectMineBuildings = TRUE; - } - } - - } - else if (si.newCountEnemies > 0 && si.newCountCivilians > 0 && si.newCountFriends > 0) - { - // No go here - break; - } - else if (si.newCountEnemies == 1) - { - addToGroup = FALSE; - si.selectEnemies = TRUE; - } - else if (si.newCountCivilians == 1) - { - addToGroup = FALSE; - si.selectCivilians = TRUE; - } - else if (si.newCountFriends == 1) - { - addToGroup = FALSE; - si.selectFriends = TRUE; - } - - // If we're not going to select anything, just bail now. - if (!(si.selectMine || si.selectEnemies || si.selectCivilians || si.selectFriends)) - { - break; - } - - // If we've made it here, its time to do some selecting. - disp = DESTROY_MESSAGE; - - // Whenever we manually select something, reset the last selected group. - m_lastGroupSelGroup = -1; - - if (TheInGameUI->isInPreferSelectionMode() && isPoint && areAllSelected(drawablesThatWillSelect)) - { - // If this was a point, shift was pressed and we already have that unit selected, then we - // need to deselect those units. - GameMessage *newMsg = TheMessageStream->appendMessage(GameMessage::MSG_REMOVE_FROM_SELECTED_GROUP); - Drawable *draw = nullptr; - DrawableListIt it; - for (it = drawablesThatWillSelect.begin(); it != drawablesThatWillSelect.end(); ++it) - { - draw = *it; - if (!draw) - { - continue; - } - - Object *objToDeselect = draw->getObject(); - if (!objToDeselect) - { - continue; - } - - newMsg->appendObjectIDArgument(objToDeselect->getID()); - TheInGameUI->deselectDrawable(draw); - } - } - else - { - if (!addToGroup) - { - deselectAll(); - } - - GameMessage *newMsg = TheMessageStream->appendMessage(GameMessage::MSG_CREATE_SELECTED_GROUP); - newMsg->appendBooleanArgument(!addToGroup); - - Player *localPlayer = ThePlayerList->getLocalPlayer(); - - Int newDrawablesSelected = 0; - Drawable *draw = nullptr; - DrawableListIt it; - for (it = drawablesThatWillSelect.begin(); it != drawablesThatWillSelect.end(); ++it) - { - draw = *it; - if (!draw) - { - continue; - } - - Object *obj = draw->getObject(); - if (!obj) - { - continue; - } - - if (obj && obj->getContainedBy() != nullptr) - { - // we're contained, and so we shouldn't be selectable. - continue; - } - - Drawable *drawToSelect = nullptr; - ObjectID objToAppend = INVALID_ID; - if (si.selectMine && obj->isLocallyControlled()) - { - if (!obj->isKindOf(KINDOF_STRUCTURE) || si.selectMineBuildings) - { - drawToSelect = draw; - objToAppend = obj->getID(); - } - } - else - { - Relationship rel = localPlayer->getRelationship(obj->getTeam()); - if (si.selectEnemies && rel == ENEMIES) - { - drawToSelect = draw; - objToAppend = obj->getID(); - } - else if (si.selectCivilians && rel == NEUTRAL) - { - drawToSelect = draw; - objToAppend = obj->getID(); - } - else if (si.selectFriends && rel == ALLIES) - { - drawToSelect = draw; - objToAppend = obj->getID(); - } - } - - if (drawToSelect && objToAppend != INVALID_ID) - { - newMsg->appendObjectIDArgument(objToAppend); - TheInGameUI->selectDrawable(drawToSelect); - ++newDrawablesSelected; - } - } - - if( newDrawablesSelected > 1 ) - { - localPlayer->getAcademyStats()->recordDragSelection(); - } - - if (newDrawablesSelected == 1 && draw) - { -#if defined(RTS_DEBUG) || defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE) - if (m_HandOfGodSelectionMode && draw) - { - Object* obj = draw->getObject(); - if (obj) - { - TheAudio->addAudioEvent(&TheAudio->getMiscAudio()->m_noCanDoSound); - GameMessage* msg = TheMessageStream->appendMessage( GameMessage::MSG_DEBUG_KILL_OBJECT ); - msg->appendObjectIDArgument(obj->getID()); - } - disp = DESTROY_MESSAGE; - break; - } -#endif - -#if defined(RTS_DEBUG) - if (TheHurtSelectionMode && draw) - { - Object* obj = draw->getObject(); - if (obj) - { - TheAudio->addAudioEvent(&TheAudio->getMiscAudio()->m_noCanDoSound); - GameMessage* msg = TheMessageStream->appendMessage( GameMessage::MSG_DEBUG_HURT_OBJECT ); - msg->appendObjectIDArgument(obj->getID()); - } - disp = DESTROY_MESSAGE; - break; - } - -#ifdef DEBUG_OBJECT_ID_EXISTS - if (TheDebugSelectionMode && draw && draw->getObject()) - { - if (TheObjectIDToDebug == 0) - { - TheObjectIDToDebug = draw->getObject()->getID(); - AsciiString msg; - msg.format("Item %s %08x selected for debugging",draw->getTemplate()->getName().str(),TheObjectIDToDebug); - UnicodeString msgu; - msgu.translate(msg); - TheInGameUI->message(msgu); - disp = DESTROY_MESSAGE; - break; - } - } -#endif // DEBUG_OBJECT_ID_EXISTS -#endif // RTS_DEBUG - } - } - - if (disp == DESTROY_MESSAGE) - TheInGameUI->clearAttackMoveToMode(); - - break; - } - - //----------------------------------------------------------------------------- - // Note that the raw left messages are only used to draw feedback now when - // appropriate. All actual selection code takes place in - // MSG_MOUSE_LEFT_CLICK & MSG_MOUSE_LEFT_DOUBLE_CLICK - case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_DOWN: - { - // cannot actually start area selection yet - have to wait for cursor to move a bit - m_leftMouseButtonIsDown = true; - m_selectFeedbackAnchor = msg->getArgument( 0 )->pixel; - break; - } - - //----------------------------------------------------------------------------- - // Note that the raw left messages are only used to draw feedback now when - // appropriate. All actual selection code takes place in - // MSG_MOUSE_LEFT_CLICK & MSG_MOUSE_LEFT_DOUBLE_CLICK - case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_UP: - { - m_leftMouseButtonIsDown = FALSE; - - if (m_dragSelecting) { - // Stop drag selecting now, thanks. - m_dragSelecting = FALSE; - - TheTacticalView->setMouseLock( FALSE ); - TheInGameUI->setSelecting( FALSE ); - TheInGameUI->endAreaSelectHint(nullptr); - - // insert area selection message into stream - GameMessage *dragMsg = TheMessageStream->appendMessage( GameMessage::MSG_END_AREA_SELECTION_HINT ); - - IRegion2D selectionRegion; - buildRegion( &m_selectFeedbackAnchor, &msg->getArgument(0)->pixel, &selectionRegion ); - dragMsg->appendPixelRegionArgument( selectionRegion ); - } - else - { - // left click behavior (not right drag) - - //Added support to cancel the GUI command without deselecting the unit(s) involved - //when you right click. - if( !TheInGameUI->getGUICommand() && !TheKeyboard->isShift() && !TheKeyboard->isCtrl() && !TheKeyboard->isAlt() ) - { - //No GUI command mode, so deselect everyone if we're in alternate mouse mode. - if( TheGlobalData->m_useAlternateMouse && TheInGameUI->getPendingPlaceSourceObjectID() == INVALID_ID ) - { - if( !TheInGameUI->getPreventLeftClickDeselectionInAlternateMouseModeForOneClick() ) - { - deselectAll(); - m_lastGroupSelGroup = -1; - } - else - { - //Prevent deselection of unit if it just issued some type of UI order such as attack move, guard, - //initiating construction of a new structure. - TheInGameUI->setPreventLeftClickDeselectionInAlternateMouseModeForOneClick( FALSE ); - } - } - } - } - - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN: - { - // There are three ways in which we can ignore this as a deselect: - // 1) 2-D position on screen - // 2) Time has exceeded the time which we allow for this to be a click. - // 3) 3-D camera position has changed - m_deselectFeedbackAnchor = msg->getArgument( 0 )->pixel; - m_lastClick = (UnsignedInt) msg->getArgument( 2 )->integer; - m_deselectDownCameraPosition = TheTacticalView->getPosition(); - - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: - { - Coord3D cameraPos = TheTacticalView->getPosition(); - cameraPos.sub(&m_deselectDownCameraPosition); - - ICoord2D pixel = msg->getArgument( 0 )->pixel; - UnsignedInt currentTime = (UnsignedInt) msg->getArgument( 2 )->integer; - - // right click behavior (not right drag) - if (TheMouse->isClick(&m_deselectFeedbackAnchor, &pixel, m_lastClick, currentTime)) - { - //Added support to cancel the GUI command without deselecting the unit(s) involved - //when you right click. - if( TheInGameUI->getGUICommand() ) - { - //Cancel GUI command mode... don't deselect units. - TheInGameUI->setGUICommand( nullptr ); - - //With a GUI command cancel, we want no other behavior. - disp = DESTROY_MESSAGE; - TheInGameUI->setScrolling( FALSE ); - } - else - { - //In alternate mouse mode, right click still cancels building placement. - // TheSuperHackers @tweak Stubbjax 08/08/2025 Canceling building placement no longer deselects the builder. - if (TheInGameUI->getPendingPlaceSourceObjectID() != INVALID_ID) - { - TheInGameUI->placeBuildAvailable(nullptr, nullptr); - TheInGameUI->setPreventLeftClickDeselectionInAlternateMouseModeForOneClick(FALSE); - disp = DESTROY_MESSAGE; - TheInGameUI->setScrolling(FALSE); - } - else if (!TheGlobalData->m_useAlternateMouse) - { - //No GUI command mode, so deselect everyone if we're in regular mouse mode. - deselectAll(); - } - } - } - - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_META_CREATE_TEAM0: - case GameMessage::MSG_META_CREATE_TEAM1: - case GameMessage::MSG_META_CREATE_TEAM2: - case GameMessage::MSG_META_CREATE_TEAM3: - case GameMessage::MSG_META_CREATE_TEAM4: - case GameMessage::MSG_META_CREATE_TEAM5: - case GameMessage::MSG_META_CREATE_TEAM6: - case GameMessage::MSG_META_CREATE_TEAM7: - case GameMessage::MSG_META_CREATE_TEAM8: - case GameMessage::MSG_META_CREATE_TEAM9: - { - Int group = t - GameMessage::MSG_META_CREATE_TEAM0; - if ( group >= 0 && group < 10 ) - { - DEBUG_LOG(("META: create team %d",group)); - // Assign selected items to a group - GameMessage *newmsg = TheMessageStream->appendMessage((GameMessage::Type)(GameMessage::MSG_CREATE_TEAM0 + group)); - Drawable *drawable = TheGameClient->getDrawableList(); - while (drawable != nullptr) - { - if (drawable->isSelected() && drawable->getObject() && drawable->getObject()->isLocallyControlled()) - { - newmsg->appendObjectIDArgument(drawable->getObject()->getID()); - } - drawable = drawable->getNextDrawable(); - } - } - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_META_SELECT_TEAM0: - case GameMessage::MSG_META_SELECT_TEAM1: - case GameMessage::MSG_META_SELECT_TEAM2: - case GameMessage::MSG_META_SELECT_TEAM3: - case GameMessage::MSG_META_SELECT_TEAM4: - case GameMessage::MSG_META_SELECT_TEAM5: - case GameMessage::MSG_META_SELECT_TEAM6: - case GameMessage::MSG_META_SELECT_TEAM7: - case GameMessage::MSG_META_SELECT_TEAM8: - case GameMessage::MSG_META_SELECT_TEAM9: - { - Int group = t - GameMessage::MSG_META_SELECT_TEAM0; - if ( group >= 0 && group < 10 ) - { - DEBUG_LOG(("META: select team %d",group)); - - UnsignedInt now = timeGetTime(); - if ( m_lastGroupSelTime == 0 ) - { - m_lastGroupSelTime = now; - } - - Bool performSelection = TRUE; - - // check for double-press to jump view - if ( now - m_lastGroupSelTime < TheGlobalData->m_doubleClickTimeMS && group == m_lastGroupSelGroup ) - { - DEBUG_LOG(("META: DOUBLETAP select team %d",group)); - // TheSuperHackers @bugfix Stubbjax 26/05/2025 Perform selection on double-press - // if the group or part of it is somehow deselected between presses. - performSelection = FALSE; - Player *player = ThePlayerList->getLocalPlayer(); - if (player) - { - Squad *selectedSquad = player->getHotkeySquad(group); - if (selectedSquad != nullptr) - { - VecObjectPtr objlist = selectedSquad->getLiveObjects(); - Int numObjs = objlist.size(); - if (numObjs > 0) - { - // if there's someone in the group, center the camera on them. - Drawable* drawable = objlist[numObjs - 1]->getDrawable(); - TheTacticalView->userLookAt( drawable->getPosition() ); - performSelection = !TheInGameUI->areAllObjectsSelected( objlist ); - } - } - } - } - - if ( performSelection ) - { - TheInGameUI->deselectAllDrawables( false ); //No need to post message because we're just creating a new group! - - // no need to send two messages for selecting the same group. - TheMessageStream->appendMessage((GameMessage::Type)(GameMessage::MSG_SELECT_TEAM0 + group)); - Player *player = ThePlayerList->getLocalPlayer(); - if (player) - { - Squad *selectedSquad = player->getHotkeySquad(group); - if (selectedSquad != nullptr) - { - VecObjectPtr objlist = selectedSquad->getLiveObjects(); - Int numObjs = objlist.size(); - for (Int i = 0; i < numObjs; ++i) - { - if( objlist[i]->getControllingPlayer() == player ) - { - TheInGameUI->selectDrawable(objlist[i]->getDrawable()); - } - } - } - } - } - m_lastGroupSelTime = now; - m_lastGroupSelGroup = group; - } - disp = DESTROY_MESSAGE; - break; - } - - case GameMessage::MSG_META_ADD_TEAM0: - case GameMessage::MSG_META_ADD_TEAM1: - case GameMessage::MSG_META_ADD_TEAM2: - case GameMessage::MSG_META_ADD_TEAM3: - case GameMessage::MSG_META_ADD_TEAM4: - case GameMessage::MSG_META_ADD_TEAM5: - case GameMessage::MSG_META_ADD_TEAM6: - case GameMessage::MSG_META_ADD_TEAM7: - case GameMessage::MSG_META_ADD_TEAM8: - case GameMessage::MSG_META_ADD_TEAM9: - { - Int group = t - GameMessage::MSG_META_ADD_TEAM0; - if ( group >= 0 && group < 10 ) - { - DEBUG_LOG(("META: select team %d",group)); - - UnsignedInt now = timeGetTime(); - if ( m_lastGroupSelTime == 0 ) - { - m_lastGroupSelTime = now; - } - - // check for double-press to jump view - - if ( now - m_lastGroupSelTime < TheGlobalData->m_doubleClickTimeMS && group == m_lastGroupSelGroup ) - { - DEBUG_LOG(("META: DOUBLETAP select team %d",group)); - Player *player = ThePlayerList->getLocalPlayer(); - if (player) - { - Squad *selectedSquad = player->getHotkeySquad(group); - if (selectedSquad != nullptr) - { - VecObjectPtr objlist = selectedSquad->getLiveObjects(); - Int numObjs = objlist.size(); - if (numObjs > 0) - { - // if there's someone in the group, center the camera on them. - TheTacticalView->userLookAt( objlist[numObjs-1]->getDrawable()->getPosition() ); - } - } - } - - } - else - { - - Drawable *draw = TheInGameUI->getFirstSelectedDrawable(); - if( draw && draw->isKindOf( KINDOF_STRUCTURE ) ) - { - //Kris: Jan 12, 2005 - //Can't select other units if you have a structure selected. So deselect the structure to prevent - //group force attack exploit. - TheInGameUI->deselectAllDrawables(); - } - - // no need to send two messages for selecting the same group. - TheMessageStream->appendMessage((GameMessage::Type)(GameMessage::MSG_ADD_TEAM0 + group)); - Player *player = ThePlayerList->getLocalPlayer(); - if (player) - { - Squad *selectedSquad = player->getHotkeySquad(group); - if (selectedSquad != nullptr) - { - VecObjectPtr objlist = selectedSquad->getLiveObjects(); - Int numObjs = objlist.size(); - - // TheSuperHackers @bugfix skyaero 22/07/2025 Can't select other units if you have a structure selected. So deselect the structure to prevent group force attack exploit. - if (numObjs > 0 && objlist[0]->getDrawable()->isKindOf(KINDOF_STRUCTURE)) - { - TheInGameUI->deselectAllDrawables(); - } - - for (Int i = 0; i < numObjs; ++i) - { - TheInGameUI->selectDrawable(objlist[i]->getDrawable()); - } - } - } - } - m_lastGroupSelTime = now; - m_lastGroupSelGroup = group; - } - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_META_VIEW_TEAM0: - case GameMessage::MSG_META_VIEW_TEAM1: - case GameMessage::MSG_META_VIEW_TEAM2: - case GameMessage::MSG_META_VIEW_TEAM3: - case GameMessage::MSG_META_VIEW_TEAM4: - case GameMessage::MSG_META_VIEW_TEAM5: - case GameMessage::MSG_META_VIEW_TEAM6: - case GameMessage::MSG_META_VIEW_TEAM7: - case GameMessage::MSG_META_VIEW_TEAM8: - case GameMessage::MSG_META_VIEW_TEAM9: - { - Int group = t - GameMessage::MSG_META_VIEW_TEAM0; - if ( group >= 1 && group <= 10 ) - { - DEBUG_LOG(("META: view team %d",group)); - Player *player = ThePlayerList->getLocalPlayer(); - if (player) - { - Squad *selectedSquad = player->getHotkeySquad(group); - if (selectedSquad != nullptr) - { - VecObjectPtr objlist = selectedSquad->getLiveObjects(); - Int numObjs = objlist.size(); - if (numObjs > 0) - { - // if there's someone in the group, center the camera on them. - TheTacticalView->userLookAt( objlist[ numObjs-1 ]->getDrawable()->getPosition() ); - } - } - } - } - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_OPTIONS: - { - // stop drawing selection feedback, as we're going to ignore the selection. - m_leftMouseButtonIsDown = FALSE; - // let this message drop through, the commandXLat will show the options screen itself. - break; - } - - -#if defined(RTS_DEBUG) - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_HAND_OF_GOD_MODE: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - m_HandOfGodSelectionMode = !m_HandOfGodSelectionMode; - TheInGameUI->message( L"Meta Hand-Of-God Mode is %s", m_HandOfGodSelectionMode ? L"ON" : L"OFF" ); - disp = DESTROY_MESSAGE; - } - break; - } -#endif - -#if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE) - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_CHEAT_TOGGLE_HAND_OF_GOD_MODE://NOTICE THE DIFFERENT NAME!!!!!!!!!!!!!!!!!!!!!!!!!!ML - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - m_HandOfGodSelectionMode = !m_HandOfGodSelectionMode; - TheInGameUI->message( L"Hand-Of-God Mode is %s", m_HandOfGodSelectionMode ? L"ON" : L"OFF" ); - disp = DESTROY_MESSAGE; - } - break; - } -#endif - -#if defined(RTS_DEBUG) - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_HURT_ME_MODE: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - TheHurtSelectionMode = !TheHurtSelectionMode; - TheInGameUI->message( L"Hurt-Me Mode is %s", TheHurtSelectionMode ? L"ON" : L"OFF" ); - disp = DESTROY_MESSAGE; - } - break; - } -#endif - -#if defined(RTS_DEBUG) - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_DEBUG_SELECTION: - { - TheDebugSelectionMode = !TheDebugSelectionMode; - TheInGameUI->message( L"Debug-Selected-Item Mode is %s", TheDebugSelectionMode ? L"ON" : L"OFF" ); - #ifdef DEBUG_OBJECT_ID_EXISTS - TheObjectIDToDebug = INVALID_ID; - #endif - disp = DESTROY_MESSAGE; - break; - } -#endif - } - - return disp; -} - - -//setDragSelecting(Bool dragSelect) -//Added to fix the drag selection problem in control bar -//////////////////////////////////////////////////////////////////////// -void SelectionTranslator::setDragSelecting(Bool dragSelect) -{ - m_dragSelecting = dragSelect; -} - -//setLeftMouseButton(Bool state) -//Added to turn of Left button down when left button goes up -//////////////////////////////////////////////////////////////////////// -void SelectionTranslator::setLeftMouseButton(Bool state) -{ - m_leftMouseButtonIsDown = state; -} diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp deleted file mode 100644 index 9c790c3ab79..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/* -** Command & Conquer Generals(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: WindowXlat.cpp /////////////////////////////////////////////////////// -//----------------------------------------------------------------------------- -// -// Westwood Studios Pacific. -// -// Confidential Information -// Copyright (C) 2001 - All Rights Reserved -// -//----------------------------------------------------------------------------- -// -// Project: RTS3 -// -// File name: WindowXlat.cpp -// -// Created: Colin Day, September 2001 -// -// Desc: Window system translator that monitors raw input messages -// on the stream from the input devices and acts on anything -// relevant to the windowing system. -// -//----------------------------------------------------------------------------- -/////////////////////////////////////////////////////////////////////////////// - -// SYSTEM INCLUDES //////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -// USER INCLUDES ////////////////////////////////////////////////////////////// -#include "Common/MessageStream.h" -#include "GameClient/GameWindowManager.h" -#include "GameClient/WindowXlat.h" -#include "GameClient/Shell.h" -#include "GameClient/Display.h" - - -// DEFINES //////////////////////////////////////////////////////////////////// - -// PRIVATE TYPES ////////////////////////////////////////////////////////////// - -// PRIVATE DATA /////////////////////////////////////////////////////////////// - -// PUBLIC DATA //////////////////////////////////////////////////////////////// - -// PRIVATE PROTOTYPES ///////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// PRIVATE FUNCTIONS ////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -#if defined(RTS_DEBUG) //debug hack to view object under mouse stats -extern ICoord2D TheMousePos; -#endif - -// rawMouseToWindowMessage ==================================================== -/** Translate a raw mouse input event to a game window specific message - * for the window system */ -//============================================================================= -static GameWindowMessage rawMouseToWindowMessage( const GameMessage *msg ) -{ - GameWindowMessage gwm = GWM_NONE; - - switch( msg->getType() ) - { - // ------------------------------------------------------------------------ - case GameMessage::MSG_RAW_MOUSE_POSITION: - gwm = GWM_MOUSE_POS; - break; - - // ------------------------------------------------------------------------ - // Strange, but true. The window stuff really doesn't care about double clicks, so just - // treat it as a down click.. Kinda like a second click. - case GameMessage::MSG_RAW_MOUSE_LEFT_DOUBLE_CLICK: - case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_DOWN: - gwm = GWM_LEFT_DOWN; - break; - - case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_UP: - gwm = GWM_LEFT_UP; - break; - - case GameMessage::MSG_RAW_MOUSE_LEFT_DRAG: - gwm = GWM_LEFT_DRAG; - break; - - // ------------------------------------------------------------------------ - case GameMessage::MSG_RAW_MOUSE_MIDDLE_DOUBLE_CLICK: - case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_DOWN: - gwm = GWM_MIDDLE_DOWN; - break; - - case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_UP: - gwm = GWM_MIDDLE_UP; - break; - - case GameMessage::MSG_RAW_MOUSE_MIDDLE_DRAG: - gwm = GWM_MIDDLE_DRAG; - break; - - // ------------------------------------------------------------------------ - case GameMessage::MSG_RAW_MOUSE_RIGHT_DOUBLE_CLICK: - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN: - gwm = GWM_RIGHT_DOWN; - break; - - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: - gwm = GWM_RIGHT_UP; - break; - - case GameMessage::MSG_RAW_MOUSE_RIGHT_DRAG: - gwm = GWM_RIGHT_DRAG; - break; - - // ------------------------------------------------------------------------ - case GameMessage::MSG_RAW_MOUSE_WHEEL: - if( msg->getArgument( 1 )->real > 0 ) - gwm = GWM_WHEEL_UP; - else - gwm = GWM_WHEEL_DOWN; - break; - - } - - return gwm; - -} - -/////////////////////////////////////////////////////////////////////////////// -// PUBLIC FUNCTIONS /////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -//============================================================================= -WindowTranslator::WindowTranslator() -{ -} - -//============================================================================= -WindowTranslator::~WindowTranslator() -{ -} - -// WindowTranslator =========================================================== -/** Window translator that monitors raw input messages on the stream and - * acts on anything relevant to the windowing system */ -//============================================================================= -GameMessageDisposition WindowTranslator::translateGameMessage(const GameMessage *msg) -{ - GameMessageDisposition disp = KEEP_MESSAGE; - Bool forceKeepMessage = FALSE; - WinInputReturnCode returnCode = WIN_INPUT_NOT_USED; - - if (TheTacticalView && TheTacticalView->isMouseLocked()) - { - //Kris: Aug 15, 2003 - //Added the scrolling check that will not return KEEP_MESSAGE if we happen - //to in scrolling mode (via keyboard or mouse) and left click in the controlbar. - //Without this code, the left click goes through the interface ignoring buttons and blockage - //and ends up issuing orders right through the controlbar! - if( TheInGameUI->isScrolling() ) - { - if( msg->getType() != GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_UP && - msg->getType() != GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_DOWN ) - { - //We're scrolling, but unless we're clicking the left button, get out. - return KEEP_MESSAGE; - } - //Pass through and handle button clicks or getting input blocked! - } - else - { - return KEEP_MESSAGE; - } - } - - switch( msg->getType() ) - { - // ------------------------------------------------------------------------ - case GameMessage::MSG_META_TOGGLE_ATTACKMOVE: - { - // Basically, we're cheating here. The mouse no longer sends us useless spam. - ICoord2D mousePos = TheMouse->getMouseStatus()->pos; - - if( TheWindowManager ) - TheWindowManager->winProcessMouseEvent( GWM_NONE, &mousePos, nullptr ); - - // Force it to keep the message, regardless of what the window thinks it did with the input. - return KEEP_MESSAGE; - } - - // ------------------------------------------------------------------------ - case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_UP: - { - if( TheInGameUI && TheInGameUI->isPlacementAnchored() ) - { - //If we release the button outside - forceKeepMessage = TRUE; - } - FALLTHROUGH; //FALL THROUGH INTENTIONALLY! - } - case GameMessage::MSG_RAW_MOUSE_POSITION: - case GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_DOWN: - case GameMessage::MSG_RAW_MOUSE_LEFT_DOUBLE_CLICK: - case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_DOWN: - case GameMessage::MSG_RAW_MOUSE_MIDDLE_DOUBLE_CLICK: - case GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_UP: - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN: - case GameMessage::MSG_RAW_MOUSE_RIGHT_DOUBLE_CLICK: - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: - { - // all window events have the position of the mouse as arg 0 - ICoord2D mousePos = msg->getArgument( 0 )->pixel; -#if defined(RTS_DEBUG) //debug hack to view object under mouse stats - TheMousePos.x = mousePos.x; - TheMousePos.y = mousePos.y; -#endif - - // process the mouse event position - GameWindowMessage gwm = rawMouseToWindowMessage( msg ); - if( TheWindowManager ) - returnCode = TheWindowManager->winProcessMouseEvent( gwm, &mousePos, nullptr ); - - if( TheShell && TheShell->isShellActive() ) - returnCode = WIN_INPUT_USED; - - if ( TheInGameUI && TheInGameUI->getInputEnabled() == FALSE ) - returnCode = WIN_INPUT_USED; - - break; - - } - - // ------------------------------------------------------------------------ - case GameMessage::MSG_RAW_MOUSE_LEFT_DRAG: - case GameMessage::MSG_RAW_MOUSE_MIDDLE_DRAG: - case GameMessage::MSG_RAW_MOUSE_RIGHT_DRAG: - { - // all window events have the position of the mouse as arg 0 - ICoord2D mousePos = msg->getArgument( 0 )->pixel; - - // get delta for drag - ICoord2D delta = msg->getArgument( 1 )->pixel; - - // process drag event - GameWindowMessage gwm = rawMouseToWindowMessage( msg ); - if( TheWindowManager ) - returnCode = TheWindowManager->winProcessMouseEvent( gwm, &mousePos, &delta ); - - if( TheShell && TheShell->isShellActive() ) - returnCode = WIN_INPUT_USED; - - if ( TheInGameUI && TheInGameUI->getInputEnabled() == FALSE ) - returnCode = WIN_INPUT_USED; - - break; - - } - - // ------------------------------------------------------------------------ - case GameMessage::MSG_RAW_MOUSE_WHEEL: - { - // all window events have the position of the mouse as arg 0 - ICoord2D mousePos = msg->getArgument( 0 )->pixel; - - // get wheel position - Real wheelPos = msg->getArgument( 1 )->real; - - // process wheel event - GameWindowMessage gwm = rawMouseToWindowMessage( msg ); - if( TheWindowManager ) - returnCode = TheWindowManager->winProcessMouseEvent( gwm, &mousePos, - &wheelPos ); - - if( TheShell && TheShell->isShellActive() ) - returnCode = WIN_INPUT_USED; - - if ( TheInGameUI && TheInGameUI->getInputEnabled() == FALSE ) - returnCode = WIN_INPUT_USED; - - break; - - } - - // ------------------------------------------------------------------------ - case GameMessage::MSG_RAW_KEY_DOWN: - case GameMessage::MSG_RAW_KEY_UP: - { - // get key and state from args - UnsignedByte key = msg->getArgument( 0 )->integer; - UnsignedByte state = msg->getArgument( 1 )->integer; - - // process event through window system - if( TheWindowManager ) - returnCode = TheWindowManager->winProcessKey( key, state ); - - - // If we're in a movie, we want to be able to escape out of it - if(returnCode != WIN_INPUT_USED - && (key == KEY_ESC) - && (BitIsSet( state, KEY_STATE_UP )) - && TheDisplay->isMoviePlaying() - && TheGlobalData->m_allowExitOutOfMovies == TRUE ) - { - TheDisplay->stopMovie(); - returnCode = WIN_INPUT_USED; - } - - // TheSuperHackers @bugfix If the input is disabled, then only allow the ESC button to get through. - // Otherwise it would be possible to call user camera actions during scripted camera scenes. - if(returnCode != WIN_INPUT_USED - && (key != KEY_ESC) - && (TheInGameUI && (TheInGameUI->getInputEnabled() == FALSE)) ) - { - returnCode = WIN_INPUT_USED; - } - - break; - - } - - // ------------------------------------------------------------------------ - default: - break; - - } - - // remove event from the stream if the return code specifies to do so - // If TheShell doesn't exist, then well, we're not in RTS, we're in GUIEdit - if( returnCode == WIN_INPUT_USED && !forceKeepMessage )// || (TheShell && TheShell->isShellActive())) - { - disp = DESTROY_MESSAGE; - } - - return disp; - -} diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp index 20f57f56049..5d6aec0dfd8 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp @@ -49,23 +49,24 @@ //------------------------------------------------------------------------------------------------- void AssistedTargetingUpdateModuleData::buildFieldParse(MultiIniFieldParse& p) { - UpdateModuleData::buildFieldParse(p); + UpdateModuleData::buildFieldParse(p); static const FieldParse dataFieldParse[] = { { "AssistingClipSize", INI::parseInt, nullptr, offsetof( AssistedTargetingUpdateModuleData, m_clipSize ) }, { "AssistingWeaponSlot", INI::parseLookupList, TheWeaponSlotTypeNamesLookupList, offsetof( AssistedTargetingUpdateModuleData, m_weaponSlot ) }, - { "LaserFromAssisted", INI::parseThingTemplate, nullptr, offsetof( AssistedTargetingUpdateModuleData, m_laserFromAssisted ) }, - { "LaserToTarget", INI::parseThingTemplate, nullptr, offsetof( AssistedTargetingUpdateModuleData, m_laserToTarget ) }, + { "LaserFromAssisted", INI::parseAsciiString, nullptr, offsetof( AssistedTargetingUpdateModuleData, m_laserFromAssistedName ) }, + { "LaserToTarget", INI::parseAsciiString, nullptr, offsetof( AssistedTargetingUpdateModuleData, m_laserToTargetName ) }, { nullptr, nullptr, nullptr, 0 } }; - p.add(dataFieldParse); + p.add(dataFieldParse); } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- AssistedTargetingUpdate::AssistedTargetingUpdate( Thing *thing, const ModuleData* moduleData ) : UpdateModule( thing, moduleData ) { - setWakeFrame(getObject(), UPDATE_SLEEP_FOREVER); + m_laserFromAssisted = nullptr; + m_laserToTarget = nullptr; } //------------------------------------------------------------------------------------------------- @@ -100,10 +101,10 @@ void AssistedTargetingUpdate::assistAttack( const Object *requestingObject, Obje me->setWeaponLock( md->m_weaponSlot, LOCKED_TEMPORARILY ); me->getAI()->aiAttackObject( victimObject, md->m_clipSize, CMD_FROM_AI ); - if( md->m_laserFromAssisted ) - makeFeedbackLaser( md->m_laserFromAssisted, requestingObject, me ); - if( md->m_laserToTarget ) - makeFeedbackLaser( md->m_laserToTarget, me, victimObject ); + if( m_laserFromAssisted ) + makeFeedbackLaser( m_laserFromAssisted, requestingObject, me ); + if( m_laserToTarget ) + makeFeedbackLaser( m_laserToTarget, me, victimObject ); } //------------------------------------------------------------------------------------------------- @@ -137,6 +138,11 @@ void AssistedTargetingUpdate::makeFeedbackLaser( const ThingTemplate *laserTempl //------------------------------------------------------------------------------------------------- UpdateSleepTime AssistedTargetingUpdate::update() { + const AssistedTargetingUpdateModuleData *d = getAssistedTargetingUpdateModuleData(); + + m_laserFromAssisted = TheThingFactory->findTemplate( d->m_laserFromAssistedName ); + m_laserToTarget = TheThingFactory->findTemplate( d->m_laserToTargetName ); + return UPDATE_SLEEP_FOREVER; } @@ -174,8 +180,11 @@ void AssistedTargetingUpdate::xfer( Xfer *xfer ) // ------------------------------------------------------------------------------------------------ void AssistedTargetingUpdate::loadPostProcess() { + const AssistedTargetingUpdateModuleData *d = getAssistedTargetingUpdateModuleData(); + + m_laserFromAssisted = TheThingFactory->findTemplate( d->m_laserFromAssistedName ); + m_laserToTarget = TheThingFactory->findTemplate( d->m_laserToTargetName ); // extend base class UpdateModule::loadPostProcess(); - } diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 7f33c551b94..9d267331194 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1525,9 +1525,16 @@ void W3DDisplay::gatherDebugStats() //display the x and y mouse coordinates const MouseIO *mouseIO = TheMouse->getMouseStatus(); Coord3D worldPos; - TheTacticalView->screenToTerrain(&mouseIO->pos, &worldPos); - unibuffer.format( L"Mouse position: screen: (%d, %d), world: (%g, %g, %g)", mouseIO->pos.x, mouseIO->pos.y, - worldPos.x, worldPos.y, worldPos.z); + if( TheTacticalView->screenToTerrain(&mouseIO->pos, &worldPos) ) + { + unibuffer.format( L"Mouse position: screen: (%d, %d), world: (%g, %g, %g)", + mouseIO->pos.x, mouseIO->pos.y, worldPos.x, worldPos.y, worldPos.z); + } + else + { + unibuffer.format( L"Mouse position: screen: (%d, %d), world: none", + mouseIO->pos.x, mouseIO->pos.y); + } m_displayStrings[MousePosition]->setText( unibuffer ); //display the number of particles in the world and being displayed on screen diff --git a/Generals/Code/Tools/WorldBuilder/include/GroveOptions.h b/Generals/Code/Tools/WorldBuilder/include/GroveOptions.h index 031efe9c22e..f6775966e7b 100644 --- a/Generals/Code/Tools/WorldBuilder/include/GroveOptions.h +++ b/Generals/Code/Tools/WorldBuilder/include/GroveOptions.h @@ -39,7 +39,7 @@ UnicodeString GetDisplayNameFromPair(const PairNameDisplayName *pNamePair); class GroveOptions : public COptionsPanel { protected: - std::vector > mVecGroup; + std::vector/**/> mVecGroup; VecPairNameDisplayName mVecDisplayNames; Int mNumTrees; diff --git a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp index 8e358bf5951..e606881e037 100644 --- a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -174,11 +174,11 @@ class PlaceholderView : public View Bool (*callback)( Drawable *draw, void *userData ), void *userData ) override {return 0;}; virtual WorldToScreenReturn worldToScreenTriReturn( const Coord3D *w, ICoord2D *s ) override { return WTS_INVALID; }; ///< Transform world coordinate "w" into screen coordinate "s" - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) override {}; ///< transform screen coord to a point on the 3D terrain - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override {}; ///< transform screen point to world point at the specified world Z value - virtual void getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, + virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) override { return false; } + virtual PlaneClass::IntersectionResType screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override { return PlaneClass::NO_INTERSECTION; } + virtual PlaneClass::IntersectionResType getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, Coord3D *bottomRight, Coord3D *bottomLeft, - Real z ) override {}; + Real z, ViewportClass viewPort = ViewportClass() ) override { return PlaneClass::NO_INTERSECTION; } virtual void drawView() override {}; ///< Render the world visible in this view. virtual void updateView() override {}; ///< Render the world visible in this view. diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index 7b7deb4d0ab..f9c7a31bb43 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -141,7 +141,7 @@ set(GAMEENGINE_SRC # Include/GameClient/ClientInstance.h # Include/GameClient/ClientRandomValue.h # Include/GameClient/Color.h - Include/GameClient/CommandXlat.h +# Include/GameClient/CommandXlat.h Include/GameClient/ControlBar.h Include/GameClient/ControlBarResizer.h Include/GameClient/ControlBarScheme.h @@ -183,10 +183,10 @@ set(GAMEENGINE_SRC # Include/GameClient/GlobalLanguage.h # Include/GameClient/GraphDraw.h Include/GameClient/GUICallbacks.h - Include/GameClient/GUICommandTranslator.h +# Include/GameClient/GUICommandTranslator.h # Include/GameClient/HeaderTemplate.h - Include/GameClient/HintSpy.h - Include/GameClient/HotKey.h +# Include/GameClient/HintSpy.h +# Include/GameClient/HotKey.h # Include/GameClient/Image.h # Include/GameClient/IMEManager.h Include/GameClient/InGameUI.h @@ -195,22 +195,22 @@ set(GAMEENGINE_SRC # Include/GameClient/LanguageFilter.h # Include/GameClient/Line2D.h # Include/GameClient/LoadScreen.h - Include/GameClient/LookAtXlat.h +# Include/GameClient/LookAtXlat.h # Include/GameClient/MapUtil.h Include/GameClient/MessageBox.h - Include/GameClient/MetaEvent.h +# Include/GameClient/MetaEvent.h # Include/GameClient/Module/AnimatedParticleSysBoneClientUpdate.h # Include/GameClient/Module/BeaconClientUpdate.h # Include/GameClient/Module/SwayClientUpdate.h # Include/GameClient/Mouse.h # Include/GameClient/ParabolicEase.h # Include/GameClient/ParticleSys.h - Include/GameClient/PlaceEventTranslator.h +# Include/GameClient/PlaceEventTranslator.h # Include/GameClient/ProcessAnimateWindow.h # Include/GameClient/RadiusDecal.h # Include/GameClient/RayEffect.h # Include/GameClient/SelectionInfo.h - Include/GameClient/SelectionXlat.h +# Include/GameClient/SelectionXlat.h Include/GameClient/Shadow.h Include/GameClient/Shell.h Include/GameClient/ShellHooks.h @@ -225,7 +225,7 @@ set(GAMEENGINE_SRC # Include/GameClient/Water.h # Include/GameClient/WindowLayout.h # Include/GameClient/WindowVideoManager.h - Include/GameClient/WindowXlat.h +# Include/GameClient/WindowXlat.h # Include/GameClient/WinInstanceData.h Include/GameLogic/AI.h Include/GameLogic/AIDock.h @@ -690,7 +690,7 @@ set(GAMEENGINE_SRC Source/GameClient/Eva.cpp # Source/GameClient/FXList.cpp Source/GameClient/GameClient.cpp - Source/GameClient/GameClientDispatch.cpp +# Source/GameClient/GameClientDispatch.cpp # Source/GameClient/GameText.cpp # Source/GameClient/GlobalLanguage.cpp # Source/GameClient/GraphDraw.cpp @@ -795,15 +795,15 @@ set(GAMEENGINE_SRC # Source/GameClient/LanguageFilter.cpp # Source/GameClient/Line2D.cpp # Source/GameClient/MapUtil.cpp - Source/GameClient/MessageStream/CommandXlat.cpp - Source/GameClient/MessageStream/GUICommandTranslator.cpp - Source/GameClient/MessageStream/HintSpy.cpp - Source/GameClient/MessageStream/HotKey.cpp - Source/GameClient/MessageStream/LookAtXlat.cpp - Source/GameClient/MessageStream/MetaEvent.cpp - Source/GameClient/MessageStream/PlaceEventTranslator.cpp - Source/GameClient/MessageStream/SelectionXlat.cpp - Source/GameClient/MessageStream/WindowXlat.cpp +# Source/GameClient/MessageStream/CommandXlat.cpp +# Source/GameClient/MessageStream/GUICommandTranslator.cpp +# Source/GameClient/MessageStream/HintSpy.cpp +# Source/GameClient/MessageStream/HotKey.cpp +# Source/GameClient/MessageStream/LookAtXlat.cpp +# Source/GameClient/MessageStream/MetaEvent.cpp +# Source/GameClient/MessageStream/PlaceEventTranslator.cpp +# Source/GameClient/MessageStream/SelectionXlat.cpp +# Source/GameClient/MessageStream/WindowXlat.cpp # Source/GameClient/ParabolicEase.cpp # Source/GameClient/RadiusDecal.cpp # Source/GameClient/SelectionInfo.cpp diff --git a/GeneralsMD/Code/GameEngine/Include/Common/DamageFX.h b/GeneralsMD/Code/GameEngine/Include/Common/DamageFX.h index 9db1cf06fdb..070273db719 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/DamageFX.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/DamageFX.h @@ -156,7 +156,7 @@ class DamageFXStore : public SubsystemInterface private: - typedef std::hash_map< NameKeyType, DamageFX, rts::hash, rts::equal_to > DamageFXMap; + typedef std::hash_map< NameKeyType, DamageFX, rts::hash, rts::equal_to/**/> DamageFXMap; DamageFXMap m_dfxmap; }; diff --git a/GeneralsMD/Code/GameEngine/Include/Common/ModuleFactory.h b/GeneralsMD/Code/GameEngine/Include/Common/ModuleFactory.h index 381964c068c..48426d40d49 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/ModuleFactory.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/ModuleFactory.h @@ -113,7 +113,7 @@ class ModuleFactory : public SubsystemInterface, public Snapshot static NameKeyType makeDecoratedNameKey(const AsciiString& name, ModuleType type); - typedef std::map< NameKeyType, ModuleTemplate, std::less > ModuleTemplateMap; + typedef std::map< NameKeyType, ModuleTemplate, std::less/**/> ModuleTemplateMap; typedef std::vector ModuleDataList; ModuleTemplateMap m_moduleTemplateMap; diff --git a/GeneralsMD/Code/GameEngine/Include/Common/Player.h b/GeneralsMD/Code/GameEngine/Include/Common/Player.h index 7c51d483357..dc66f4e9f5d 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/Player.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/Player.h @@ -148,7 +148,7 @@ struct SpecialPowerReadyTimerType // ------------------------------------------------------------------------------------------------ -typedef std::hash_map< PlayerIndex, Relationship, std::hash, std::equal_to > PlayerRelationMapType; +typedef std::hash_map< PlayerIndex, Relationship, std::hash, std::equal_to/**/> PlayerRelationMapType; class PlayerRelationMap : public MemoryPoolObject, public Snapshot { diff --git a/GeneralsMD/Code/GameEngine/Include/Common/Team.h b/GeneralsMD/Code/GameEngine/Include/Common/Team.h index a9deba8c0d4..64365defa95 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/Team.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/Team.h @@ -42,7 +42,7 @@ typedef UnsignedInt TeamPrototypeID; #define TEAM_PROTOTYPE_ID_INVALID 0 // ------------------------------------------------------------------------------------------------ -typedef std::hash_map< TeamID, Relationship, std::hash, std::equal_to > TeamRelationMapType; +typedef std::hash_map< TeamID, Relationship, std::hash, std::equal_to/**/> TeamRelationMapType; class TeamRelationMap : public MemoryPoolObject, public Snapshot { @@ -733,7 +733,7 @@ class TeamFactory : public SubsystemInterface, private: - typedef std::map< NameKeyType, TeamPrototype*, std::less > TeamPrototypeMap; + typedef std::map< NameKeyType, TeamPrototype*, std::less/**/> TeamPrototypeMap; TeamPrototypeMap m_prototypes; TeamPrototypeID m_uniqueTeamPrototypeID; ///< used to assign unique ids to each team prototype diff --git a/GeneralsMD/Code/GameEngine/Include/Common/ThingFactory.h b/GeneralsMD/Code/GameEngine/Include/Common/ThingFactory.h index e1b29581c64..8fdb75e8937 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/ThingFactory.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/ThingFactory.h @@ -44,7 +44,7 @@ class Object; class Drawable; class INI; -typedef std::hash_map, rts::equal_to > ThingTemplateHashMap; +typedef std::hash_map, rts::equal_to/**/> ThingTemplateHashMap; typedef ThingTemplateHashMap::iterator ThingTemplateHashMapIt; //------------------------------------------------------------------------------------------------- /** Implementation of the thing manager interface singleton */ diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Armor.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Armor.h index 62ade9d5ee1..8dd29c5a677 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Armor.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Armor.h @@ -121,7 +121,7 @@ class ArmorStore : public SubsystemInterface private: - typedef std::hash_map< NameKeyType, ArmorTemplate, rts::hash, rts::equal_to > ArmorTemplateMap; + typedef std::hash_map< NameKeyType, ArmorTemplate, rts::hash, rts::equal_to/**/> ArmorTemplateMap; ArmorTemplateMap m_armorTemplates; }; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h index 60f5fb22e7c..8192d3fbe68 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h @@ -376,13 +376,13 @@ class GameLogic : public SubsystemInterface, public Snapshot overrides to thing template buildable status. doesn't really belong here, but has to go somewhere. (srj) */ - typedef std::hash_map< AsciiString, BuildableStatus, rts::hash, rts::equal_to > BuildableMap; + typedef std::hash_map< AsciiString, BuildableStatus, rts::hash, rts::equal_to/**/> BuildableMap; BuildableMap m_thingTemplateBuildableOverrides; /** overrides to control bars. doesn't really belong here, but has to go somewhere. (srj) */ - typedef std::hash_map< AsciiString, ConstCommandButtonPtr, rts::hash, rts::equal_to > ControlBarOverrideMap; + typedef std::hash_map< AsciiString, ConstCommandButtonPtr, rts::hash, rts::equal_to/**/> ControlBarOverrideMap; ControlBarOverrideMap m_controlBarOverrides; Real m_width, m_height; ///< Dimensions of the world diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Locomotor.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Locomotor.h index 59c4e908f47..2db72c27d7b 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Locomotor.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Locomotor.h @@ -502,7 +502,7 @@ class LocomotorStore : public SubsystemInterface private: - typedef std::map< NameKeyType, LocomotorTemplate*, std::less > LocomotorTemplateMap; + typedef std::map< NameKeyType, LocomotorTemplate*, std::less/**/> LocomotorTemplateMap; LocomotorTemplateMap m_locomotorTemplates; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/AIUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/AIUpdate.h index a475e3d40b1..4aa0483c815 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/AIUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/AIUpdate.h @@ -185,7 +185,7 @@ enum MoodActionAdjustment CPP_11(: Int) //------------------------------------------------------------------------------------------------- typedef std::vector< const LocomotorTemplate* > LocomotorTemplateVector; -typedef std::map< LocomotorSetType, LocomotorTemplateVector, std::less > LocomotorTemplateMap; +typedef std::map< LocomotorSetType, LocomotorTemplateVector, std::less/**/> LocomotorTemplateMap; //------------------------------------------------------------------------------------------------- class AIUpdateModuleData : public UpdateModuleData diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/AssistedTargetingUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/AssistedTargetingUpdate.h index c784a12d450..4362325ca35 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/AssistedTargetingUpdate.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/AssistedTargetingUpdate.h @@ -39,15 +39,13 @@ class AssistedTargetingUpdateModuleData : public UpdateModuleData Int m_clipSize; WeaponSlotType m_weaponSlot; - AsciiString m_laserFromAssistedName; - AsciiString m_laserToTargetName; + AsciiString m_laserFromAssistedName; + AsciiString m_laserToTargetName; AssistedTargetingUpdateModuleData() { m_clipSize = 1; m_weaponSlot = PRIMARY_WEAPON; - m_laserFromAssistedName.clear(); - m_laserToTargetName.clear(); } static void buildFieldParse(MultiIniFieldParse& p); @@ -76,6 +74,4 @@ class AssistedTargetingUpdate : public UpdateModule const ThingTemplate *m_laserFromAssisted; const ThingTemplate *m_laserToTarget; - - }; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/OpenContain.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/OpenContain.h index 0c447408c29..c3c3f1f99bb 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/OpenContain.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/OpenContain.h @@ -259,7 +259,7 @@ class OpenContain : public UpdateModule, UnsignedInt m_containListSize; ///< size of contained list private: - typedef std::map< ObjectID, ObjectEnterExitType, std::less > ObjectEnterExitMap; + typedef std::map< ObjectID, ObjectEnterExitType, std::less/**/> ObjectEnterExitMap; ObjectEnterExitMap m_objectEnterExitInfo; UnsignedInt m_stealthUnitsContained; ///< number of stealth units that can't be seen by enemy players. diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/ObjectCreationList.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/ObjectCreationList.h index b156d47f517..8e164795d0f 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/ObjectCreationList.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/ObjectCreationList.h @@ -205,7 +205,7 @@ class ObjectCreationListStore : public SubsystemInterface private: - typedef std::map< NameKeyType, ObjectCreationList, std::less > ObjectCreationListMap; + typedef std::map< NameKeyType, ObjectCreationList, std::less/**/> ObjectCreationListMap; ObjectCreationListMap m_ocls; // note, this list doesn't own the nuggets; all nuggets are owned by the Store. diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/ScriptEngine.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/ScriptEngine.h index a6ce0c38a7d..3ed3d9fc00c 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/ScriptEngine.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/ScriptEngine.h @@ -99,7 +99,7 @@ typedef std::pair PairAsciiStringUINT; typedef std::list ListAsciiStringUINT; typedef ListAsciiStringUINT::iterator ListAsciiStringUINTIt; -typedef std::map< const ThingTemplate *, Int, std::less > AttackPriorityMap; +typedef std::map< const ThingTemplate *, Int, std::less/**/> AttackPriorityMap; typedef std::pair AsciiStringObjectIDPair; typedef std::list ListAsciiStringObjectID; typedef std::list::iterator ListAsciiStringObjectIDIt; diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Weapon.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Weapon.h index 753015dccea..c5997707ba7 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Weapon.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Weapon.h @@ -889,7 +889,7 @@ class WeaponStore : public SubsystemInterface std::vector m_weaponTemplateVector; // TheSuperHackers @performance IamInnocent 01/01/2026 - Now additionally stores the same weapon templates in a hash map to optimize lookups by name key - typedef std::hash_map, rts::equal_to > WeaponTemplateMap; + typedef std::hash_map, rts::equal_to/**/> WeaponTemplateMap; WeaponTemplateMap m_weaponTemplateHashMap; std::list m_weaponDDI; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/PerfTimer.cpp b/GeneralsMD/Code/GameEngine/Source/Common/PerfTimer.cpp index 1db95bc0a17..1450b416b73 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/PerfTimer.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/PerfTimer.cpp @@ -215,7 +215,7 @@ void InitPrecisionTimer() /*static*/ Bool AutoPerfGatherIgnore::s_ignoring = false; //------------------------------------------------------------------------------------------------- -typedef std::vector< std::pair< AsciiString, AsciiString > > StringPairVec; +typedef std::vector< std::pair< AsciiString, AsciiString >/**/> StringPairVec; //------------------------------------------------------------------------------------------------- // PerfMetrics class. Basically, request a handle with your name and it will return. We use a vector diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp index 8b05ba9d08d..9f2853bfeb5 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -1520,19 +1520,6 @@ void InGameUI::handleRadiusCursor() { if (!m_curRadiusCursor.isEmpty()) { - const MouseIO* mouseIO = TheMouse->getMouseStatus(); - Coord3D pos; - - // - // if the mouse is in the radar window, the position in the world is that which is - // represented by the radar, otherwise we use the mouse position itself transformed - // from screen to world - // But only if the radar is on. - // - if( !rts::localPlayerHasRadar() || (TheRadar->screenPixelToWorld( &mouseIO->pos, &pos ) == FALSE) )// if radar off, or point not on radar - TheTacticalView->screenToTerrain( &mouseIO->pos, &pos ); - - if ( TheGlobalData->m_doubleClickAttackMove && m_duringDoubleClickAttackMoveGuardHintTimer > 0 ) { m_curRadiusCursor.setOpacity( m_duringDoubleClickAttackMoveGuardHintTimer * 0.1f ); @@ -1541,8 +1528,31 @@ void InGameUI::handleRadiusCursor() } else { - m_curRadiusCursor.setPosition(pos); //world space position of center of decal - m_curRadiusCursor.update(); + const MouseIO* mouseIO = TheMouse->getMouseStatus(); + Coord3D pos; + Bool hasPos = false; + + // + // if the mouse is in the radar window, the position in the world is that which is + // represented by the radar, otherwise we use the mouse position itself transformed + // from screen to world, but only if the radar is on. + // + if( rts::localPlayerHasRadar() ) + { + hasPos = TheRadar->screenPixelToWorld( &mouseIO->pos, &pos ); + } + + if( !hasPos ) + { + // if radar off, or point not on radar + hasPos = TheTacticalView->screenToTerrain( &mouseIO->pos, &pos ); + } + + if( hasPos ) + { + m_curRadiusCursor.setPosition(pos); //world space position of center of decal + m_curRadiusCursor.update(); + } } } @@ -1551,9 +1561,11 @@ void InGameUI::handleRadiusCursor() void InGameUI::triggerDoubleClickAttackMoveGuardHint() { - m_duringDoubleClickAttackMoveGuardHintTimer = 11; const MouseIO* mouseIO = TheMouse->getMouseStatus(); - TheTacticalView->screenToTerrain( &mouseIO->pos, &m_duringDoubleClickAttackMoveGuardHintStashedPosition ); + if( TheTacticalView->screenToTerrain( &mouseIO->pos, &m_duringDoubleClickAttackMoveGuardHintStashedPosition ) ) + { + m_duringDoubleClickAttackMoveGuardHintTimer = 11; + } } @@ -1646,20 +1658,21 @@ void InGameUI::handleBuildPlacements() Coord3D worldStart, worldEnd; // project the start and the end points of the line anchor into the 3D world - TheTacticalView->screenToTerrain( &start, &worldStart ); - TheTacticalView->screenToTerrain( &end, &worldEnd ); - - Coord2D v; - v.x = worldEnd.x - worldStart.x; - v.y = worldEnd.y - worldStart.y; - angle = v.toAngle(); - - // TheSuperHackers @tweak Stubbjax 04/08/2025 Snap angle to nearest 45 degrees - // while using force attack mode for convenience. - if (isInForceAttackMode()) + if( TheTacticalView->screenToTerrain( &start, &worldStart ) && + TheTacticalView->screenToTerrain( &end, &worldEnd ) ) { - const Real snapRadians = DEG_TO_RADF(45); - angle = WWMath::Round(angle / snapRadians) * snapRadians; + Coord2D v; + v.x = worldEnd.x - worldStart.x; + v.y = worldEnd.y - worldStart.y; + angle = v.toAngle(); + + // TheSuperHackers @tweak Stubbjax 04/08/2025 Snap angle to nearest 45 degrees + // while using force attack mode for convenience. + if (isInForceAttackMode()) + { + const Real snapRadians = DEG_TO_RADF(45); + angle = WWMath::Round(angle / snapRadians) * snapRadians; + } } } @@ -1676,57 +1689,53 @@ void InGameUI::handleBuildPlacements() // set the location and angle of the place icon /**@todo this whole orientation vector thing is LAME! Must replace, all I want to to do is set a simple angle and have it automatically change, ug! */ - TheTacticalView->screenToTerrain( &loc, &world ); - m_placeIcon[ 0 ]->setPosition( &world ); - m_placeIcon[ 0 ]->setOrientation( angle ); - - - // - // check to see if this is a legal location to build something at and tint or "un-tint" - // the cursor icons as appropriate. This involves a pathfind which could be - // expensive so we don't want to do it on every frame (although that would be ideal) - // If we discover there are cases that this is just too slow we should increase the - // delay time between checks or we need to come up with a way of recording what is - // valid and what isn't or "fudge" the results to feel "ok" - // - if( TheGameClient->getFrame() & 0x1 ) + if( TheTacticalView->screenToTerrain( &loc, &world ) ) { - TheTerrainVisual->removeAllBibs(); - - Object *builderObject = TheGameLogic->findObjectByID( getPendingPlaceSourceObjectID() ); - - LegalBuildCode lbc; - lbc = TheBuildAssistant->isLocationLegalToBuild( &world, - m_pendingPlaceType, - angle, - BuildAssistant::USE_QUICK_PATHFIND | - BuildAssistant::TERRAIN_RESTRICTIONS | - BuildAssistant::CLEAR_PATH | - BuildAssistant::NO_OBJECT_OVERLAP | - BuildAssistant::SHROUD_REVEALED | - BuildAssistant::IGNORE_STEALTHED, - builderObject, - nullptr ); - - if( lbc != LBC_OK ) - m_placeIcon[ 0 ]->colorTint( &IllegalBuildColor ); - else - m_placeIcon[ 0 ]->colorTint( nullptr ); - + m_placeIcon[ 0 ]->setPosition( &world ); + m_placeIcon[ 0 ]->setOrientation( angle ); - - - // Add the bibs around the structure. - if (lbc != LBC_OK) + // + // check to see if this is a legal location to build something at and tint or "un-tint" + // the cursor icons as appropriate. This involves a pathfind which could be + // expensive so we don't want to do it on every frame (although that would be ideal) + // If we discover there are cases that this is just too slow we should increase the + // delay time between checks or we need to come up with a way of recording what is + // valid and what isn't or "fudge" the results to feel "ok" + // + if( TheGameClient->getFrame() & 0x1 ) { - TheTerrainVisual->addFactionBibDrawable(m_placeIcon[0], lbc != LBC_OK); - } else { - TheTerrainVisual->removeFactionBibDrawable(m_placeIcon[0]); + TheTerrainVisual->removeAllBibs(); + + Object *builderObject = TheGameLogic->findObjectByID( getPendingPlaceSourceObjectID() ); + + LegalBuildCode lbc; + lbc = TheBuildAssistant->isLocationLegalToBuild( &world, + m_pendingPlaceType, + angle, + BuildAssistant::USE_QUICK_PATHFIND | + BuildAssistant::TERRAIN_RESTRICTIONS | + BuildAssistant::CLEAR_PATH | + BuildAssistant::NO_OBJECT_OVERLAP | + BuildAssistant::SHROUD_REVEALED | + BuildAssistant::IGNORE_STEALTHED, + builderObject, + nullptr ); + + if( lbc != LBC_OK ) + m_placeIcon[ 0 ]->colorTint( &IllegalBuildColor ); + else + m_placeIcon[ 0 ]->colorTint( nullptr ); + + // Add the bibs around the structure. + if (lbc != LBC_OK) + { + TheTerrainVisual->addFactionBibDrawable(m_placeIcon[0], lbc != LBC_OK); + } else { + TheTerrainVisual->removeFactionBibDrawable(m_placeIcon[0]); + } } } - - // // we have additional place icons when we're placing down a line of walls or other // similarly placed object ... for those we will have them be oriented the same way @@ -1734,77 +1743,78 @@ void InGameUI::handleBuildPlacements() // if( isPlacementAnchored() && TheBuildAssistant->isLineBuildTemplate( m_pendingPlaceType ) ) { - Int i; - // get our line placement points ICoord2D screenStart, screenEnd; getPlacementPoints( &screenStart, &screenEnd ); // project the start and the end points of the line anchor into the 3D world Coord3D worldStart, worldEnd; - TheTacticalView->screenToTerrain( &screenStart, &worldStart ); - TheTacticalView->screenToTerrain( &screenEnd, &worldEnd ); - - // how big are each of our objects - Real objectSize = m_pendingPlaceType->getTemplateGeometryInfo().getMajorRadius() * 2.0f; - - // what is our max tiling length we can make - Int maxObjects = TheGlobalData->m_maxLineBuildObjects; - - // get the builder object that will be constructing things - Object *builderObject = TheGameLogic->findObjectByID( getPendingPlaceSourceObjectID() ); - - // - // given the start/end points in the world and the the angle of the wall, fill - // out an array of positions that "tile" this wall across the landscape - // - BuildAssistant::TileBuildInfo *tileBuildInfo; - tileBuildInfo = TheBuildAssistant->buildTiledLocations( m_pendingPlaceType, angle, - &worldStart, &worldEnd, - objectSize, maxObjects, - builderObject ); - - // create any necessary drawables we need to "fill out" the line - for( i = 0; i < tileBuildInfo->tilesUsed; i++ ) + if( TheTacticalView->screenToTerrain( &screenStart, &worldStart ) && + TheTacticalView->screenToTerrain( &screenEnd, &worldEnd ) ) { - - if( m_placeIcon[ i ] == nullptr ) + // how big are each of our objects + Real objectSize = m_pendingPlaceType->getTemplateGeometryInfo().getMajorRadius() * 2.0f; + + // what is our max tiling length we can make + Int maxObjects = TheGlobalData->m_maxLineBuildObjects; + + // get the builder object that will be constructing things + Object *builderObject = TheGameLogic->findObjectByID( getPendingPlaceSourceObjectID() ); + + // + // given the start/end points in the world and the the angle of the wall, fill + // out an array of positions that "tile" this wall across the landscape + // + BuildAssistant::TileBuildInfo *tileBuildInfo; + tileBuildInfo = TheBuildAssistant->buildTiledLocations( m_pendingPlaceType, angle, + &worldStart, &worldEnd, + objectSize, maxObjects, + builderObject ); + + // create any necessary drawables we need to "fill out" the line + Int i; + for( i = 0; i < tileBuildInfo->tilesUsed; i++ ) { - UnsignedInt drawableStatus = DRAWABLE_STATUS_NO_STATE_PARTICLES; - drawableStatus |= TheGlobalData->m_objectPlacementShadows ? DRAWABLE_STATUS_SHADOWS : 0; - m_placeIcon[ i ] = TheThingFactory->newDrawable( m_pendingPlaceType, drawableStatus ); + + if( m_placeIcon[ i ] == nullptr ) + { + UnsignedInt drawableStatus = DRAWABLE_STATUS_NO_STATE_PARTICLES; + drawableStatus |= TheGlobalData->m_objectPlacementShadows ? DRAWABLE_STATUS_SHADOWS : 0; + m_placeIcon[ i ] = TheThingFactory->newDrawable( m_pendingPlaceType, drawableStatus ); + } + } - } + // + // destroy any drawables that we're not using anymore because a previous + // line length was longer + // + for( i = tileBuildInfo->tilesUsed; i < maxObjects; i++ ) + { - // - // destroy any drawables that we're not using anymore because a previous - // line length was longer - // - for( i = tileBuildInfo->tilesUsed; i < maxObjects; i++ ) - { + if( m_placeIcon[ i ] != nullptr ) + TheGameClient->destroyDrawable( m_placeIcon[ i ] ); + m_placeIcon[ i ] = nullptr; - if( m_placeIcon[ i ] != nullptr ) - TheGameClient->destroyDrawable( m_placeIcon[ i ] ); - m_placeIcon[ i ] = nullptr; + } - } + // + // march down each drawable and set the position based on its position in the + // line and set their angles all the same + // + for( i = 0; i < tileBuildInfo->tilesUsed; i++ ) + { - // - // march down each drawable and set the position based on its position in the - // line and set their angles all the same - // - for( i = 0; i < tileBuildInfo->tilesUsed; i++ ) - { + // set the drawable position + m_placeIcon[ i ]->setPosition( &tileBuildInfo->positions[ i ] ); - // set the drawable position - m_placeIcon[ i ]->setPosition( &tileBuildInfo->positions[ i ] ); + // set opacity for the drawable + m_placeIcon[ i ]->setDrawableOpacity( TheGlobalData->m_objectPlacementOpacity ); - // set opacity for the drawable - m_placeIcon[ i ]->setDrawableOpacity( TheGlobalData->m_objectPlacementOpacity ); + // set the drawable angle + m_placeIcon[ i ]->setOrientation( angle ); - // set the drawable angle - m_placeIcon[ i ]->setOrientation( angle ); + } } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp deleted file mode 100644 index fa0d78a384f..00000000000 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp +++ /dev/null @@ -1,5539 +0,0 @@ -/* -** Command & Conquer Generals Zero Hour(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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// CommandXlat.cpp -// Translate raw input events into tactical commands -// Author: Michael S. Booth, February 2001 - -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "stdlib.h" // VC++ wants this here, or gives compile error... - -#include "Common/AudioAffect.h" -#include "Common/ActionManager.h" -#include "Common/FramePacer.h" -#include "Common/GameAudio.h" -#include "Common/GameEngine.h" -#include "Common/GameType.h" -#include "Common/GameUtility.h" -#include "Common/GlobalData.h" -#include "Common/MessageStream.h" -#include "Common/MiscAudio.h" -#include "Common/MultiplayerSettings.h" -#include "Common/PerfTimer.h" -#include "Common/Player.h" -#include "Common/PlayerList.h" -#include "Common/PlayerTemplate.h" -#include "Common/Radar.h" -#include "Common/Recorder.h" -#include "Common/SpecialPower.h" -#include "Common/StatsCollector.h" -#include "Common/ThingTemplate.h" -#include "Common/GameLOD.h" - -#include "GameClient/InGameUI.h" -#include "GameClient/CommandXlat.h" -#include "GameClient/DebugDisplay.h" -#include "GameClient/Drawable.h" -#include "GameClient/GameClient.h" -#include "GameClient/GameWindowManager.h" -#include "GameClient/GameText.h" -#include "GameClient/ParticleSys.h" -#include "GameClient/GUICallbacks.h" -#include "GameClient/Shell.h" -#include "GameClient/ControlBar.h" -#include "GameClient/SelectionInfo.h" -#include "GameClient/SelectionXlat.h" - -#include "GameLogic/Module/AIUpdate.h" -#include "GameLogic/ExperienceTracker.h" -#include "GameLogic/GameLogic.h" -#include "GameLogic/Module/BodyModule.h" -#include "GameLogic/Module/ProductionUpdate.h" -#include "GameLogic/Object.h" -#include "GameLogic/PartitionManager.h" -#include "GameLogic/ScriptEngine.h" -#include "GameLogic/TerrainLogic.h" -#include "GameLogic/GhostObject.h" -#include "GameLogic/Weapon.h" -#include "GameLogic/Module/SpawnBehavior.h" -#include "GameLogic/Module/SpecialPowerModule.h" - - -#include "Common/ThingFactory.h" -#include "GameLogic/Module/ContainModule.h" - -#include "GameNetwork/NetworkInterface.h" -#include "GameNetwork/GameInfo.h" -#include "GameNetwork/GameSpyOverlay.h" -#include "GameNetwork/GameSpy/BuddyThread.h" - -#include "ww3d.h" - -#if defined(RTS_DEBUG) -/*non-static*/ Real TheSkateDistOverride = 0.0f; - -void countObjects(Object *obj, void *userData) -{ - Int *numObjects = (Int *)userData; - - DEBUG_LOG(("Looking at obj %d (%s) - isEffectivelyDead()==%d, isDestroyed==%d, numObjects==%d", - obj->getID(), obj->getTemplate()->getName().str(), obj->isEffectivelyDead(), obj->isDestroyed(), *numObjects)); - - if (!obj->isEffectivelyDead() && !obj->isDestroyed() && !obj->isKindOf(KINDOF_INERT)) - ++(*numObjects); -} - -void printObjects(Object *obj, void *userData) -{ - Bool isDead = obj->isEffectivelyDead() || obj->isDestroyed(); - Bool isInert = obj->isKindOf(KINDOF_INERT); - AsciiString statusStr = (isDead)?"Dead":(isInert)?"Inert":"Living"; - - AsciiString line; - if (obj->getName().isEmpty()) - line.format(" Obj#%d %s - (%g,%g) %s", obj->getID(), obj->getTemplate()->getName().str(), - obj->getPosition()->x, obj->getPosition()->y, statusStr.str()); - else - line.format(" Obj#%d %s (%s) - (%g,%g) %s", obj->getID(), obj->getTemplate()->getName().str(), - obj->getName().str(), obj->getPosition()->x, obj->getPosition()->y, statusStr.str()); - TheScriptEngine->AppendDebugMessage(line, FALSE); -} - -#endif // defined(RTS_DEBUG) - - -#if defined(RTS_DEBUG) || defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE) - -void giveAllSciences(Player* player) -{ - // cheese festival: do NOT imitate this code. it is for debug purposes only. - std::vector v = TheScienceStore->friend_getScienceNames(); - for (size_t i = 0; i < v.size(); ++i) - { - ScienceType st = TheScienceStore->getScienceFromInternalName(v[i]); - if (st != SCIENCE_INVALID && TheScienceStore->isScienceGrantable(st)) - { - player->grantScience(st); - } - } -} - -void objectUnderConstruction(Object* obj, void *underConstruction) -{ - if (obj->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) - { - *(Bool*)underConstruction = true; - return; - } - - ProductionUpdateInterface *pui = ProductionUpdate::getProductionUpdateInterfaceFromObject(obj); - if(pui != nullptr && pui->getProductionCount() > 0) - { - *(Bool*)underConstruction = true; - return; - } -} - -Bool hasThingsInProduction(Player* player) -{ - Bool hasThingInProduction = false; - player->iterateObjects( objectUnderConstruction, &hasThingInProduction ); - return hasThingInProduction; -} - -Bool hasThingsInProduction(PlayerType playerType) -{ - for (Int n = 0; n < ThePlayerList->getPlayerCount(); ++n) - { - Player* player = ThePlayerList->getNthPlayer(n); - if (player->getPlayerType() == playerType) - { - if (hasThingsInProduction(player)) - return true; - } - } - return false; -} - -#endif // defined(RTS_DEBUG) || defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE) - - -bool changeMaxRenderFps(FpsValueChange change) -{ - UnsignedInt maxRenderFps = TheFramePacer->getFramesPerSecondLimit(); - maxRenderFps = RenderFpsPreset::changeFpsValue(maxRenderFps, change); - - TheFramePacer->setFramesPerSecondLimit(maxRenderFps); - TheWritableGlobalData->m_useFpsLimit = (maxRenderFps != RenderFpsPreset::UncappedFpsValue); - - UnicodeString message; - - if (TheWritableGlobalData->m_useFpsLimit) - { - message = TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:SetMaxRenderFps", L"Max Render FPS is %u", maxRenderFps); - } - else - { - message = TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:SetUncappedRenderFps", L"Max Render FPS is uncapped"); - } - - TheInGameUI->messageNoFormat(message); - - return true; -} - -bool changeLogicTimeScale(FpsValueChange change) -{ - if (TheNetwork != nullptr) - return false; - - const UnsignedInt maxRenderFps = TheFramePacer->getFramesPerSecondLimit(); - UnsignedInt maxRenderRemainder = LogicTimeScaleFpsPreset::StepFpsValue; - maxRenderRemainder -= maxRenderFps % LogicTimeScaleFpsPreset::StepFpsValue; - maxRenderRemainder %= LogicTimeScaleFpsPreset::StepFpsValue; - - UnsignedInt logicTimeScaleFps = TheFramePacer->getLogicTimeScaleFps(); - // Set the value to the max render fps value plus a bit when time scale is - // disabled. This ensures that the time scale does not re-enable with a - // 'surprise' value. - if (!TheFramePacer->isLogicTimeScaleEnabled()) - { - logicTimeScaleFps = maxRenderFps + maxRenderRemainder; - } - // Ceil the value at the max render fps value plus a bit so that the next fps - // value decrease would undercut the max render fps at the correct step value. - // Example: render fps 72 -> logic value ceiled to 75 -> decreased to 70. - logicTimeScaleFps = min(logicTimeScaleFps, maxRenderFps + maxRenderRemainder); - logicTimeScaleFps = LogicTimeScaleFpsPreset::changeFpsValue(logicTimeScaleFps, change); - - // Set value before potentially disabling it. - if (TheFramePacer->isLogicTimeScaleEnabled()) - { - TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps); - } - - TheFramePacer->enableLogicTimeScale(logicTimeScaleFps < maxRenderFps); - - // Set value after potentially enabling it. - if (TheFramePacer->isLogicTimeScaleEnabled()) - { - TheFramePacer->setLogicTimeScaleFps(logicTimeScaleFps); - } - - logicTimeScaleFps = TheFramePacer->getLogicTimeScaleFps(); - const UnsignedInt actualLogicTimeScaleFps = TheFramePacer->getActualLogicTimeScaleFps(); - const Real actualLogicTimeScaleRatio = TheFramePacer->getActualLogicTimeScaleRatio(); - - UnicodeString message; - - if (TheFramePacer->isLogicTimeScaleEnabled()) - { - message = TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:SetLogicTimeScaleFps", L"Logic Time Scale FPS is %u (actual %u, ratio %.02f)", - logicTimeScaleFps, actualLogicTimeScaleFps, actualLogicTimeScaleRatio); - } - else - { - message = TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:SetUncappedLogicTimeScaleFps", L"Logic Time Scale FPS is uncapped (actual %u, ratio %.02f)", - actualLogicTimeScaleFps, actualLogicTimeScaleRatio); - } - - TheInGameUI->messageNoFormat(message); - - return true; -} - - -static Bool isSystemMessage( const GameMessage *msg ); - -enum{ DROPPED_MAX_PARTICLE_COUNT = 1000}; - -static Bool canSelectionSalvage( const Object *targetObj) -{ - if (!targetObj) { - return FALSE; - } - - if (!targetObj->isSalvageCrate()) { - return FALSE; - } - - const DrawableList *drawList = TheInGameUI->getAllSelectedDrawables(); - - for (DrawableListCIt cit = drawList->begin(); cit != drawList->end(); ++cit) - { - Drawable *draw = *cit; - if (!draw) - { - continue; - } - - - Object *obj = draw->getObject(); - if (!obj) - { - continue; - } - - if (obj->isKindOf(KINDOF_SALVAGER)) { - return TRUE; - } - } - - return FALSE; -} - -//------------------------------------------------------------------------------------------------- -static CanAttackResult canObjectForceAttack( Object *obj, const Object *victim, const Coord3D *pos ) -{ - CanAttackResult result; - result = obj->isAbleToAttack() ? ATTACKRESULT_POSSIBLE : ATTACKRESULT_NOT_POSSIBLE; - if( result == ATTACKRESULT_NOT_POSSIBLE ) - { - return ATTACKRESULT_NOT_POSSIBLE; - } - - if (victim) - { - result = obj->getAbleToAttackSpecificObject(ATTACK_NEW_TARGET_FORCED, victim, CMD_FROM_PLAYER ); - - //Special case -- objects with spawn weapons have to do different checks. Stinger site with stinger soldiers is - //the catalyst example. - if ( obj->isKindOf( KINDOF_SPAWNS_ARE_THE_WEAPONS ) ) - { - if( result != ATTACKRESULT_POSSIBLE && result != ATTACKRESULT_POSSIBLE_AFTER_MOVING ) - { - SpawnBehaviorInterface *spawnInterface = obj->getSpawnBehaviorInterface(); - if( spawnInterface ) - { - //We found the spawn interface, now get the closest slave to the target. - Object *slave = spawnInterface->getClosestSlave( victim->getPosition() ); - if( slave ) - { - result = slave->getAbleToAttackSpecificObject( ATTACK_NEW_TARGET_FORCED, victim, CMD_FROM_PLAYER ); - } - } - } - else // oh dear me. The weird case of a garrisoncontainer being a KINDOF_SPAWNS_ARE_THE_WEAPONS... the AmericaBuildingFirebase - { - ContainModuleInterface *contain = obj->getContain(); - if ( contain ) - { - Object *rider = contain->getClosestRider( victim->getPosition() ); - if ( rider ) - { - result = rider->getAbleToAttackSpecificObject( ATTACK_NEW_TARGET_FORCED, victim, CMD_FROM_PLAYER ); - if( result != ATTACKRESULT_NOT_POSSIBLE ) - return result; - } - } - } - - } - - - return result; - } - else - { - //Almost every combat unit can force attack a position. The exceptions include stationary units - //that try to force attack in a location beyond their reach (range, LOS, etc). - if( pos ) - { - Object *testObj = obj; - if( obj->isKindOf( KINDOF_IMMOBILE ) || obj->isKindOf( KINDOF_SPAWNS_ARE_THE_WEAPONS ) ) - { - SpawnBehaviorInterface *spawnInterface = obj->getSpawnBehaviorInterface(); - if( spawnInterface ) - { - //We found the spawn interface, now get the closest slave to the target. - Object *slave = spawnInterface->getClosestSlave( pos ); - if( slave ) - { - testObj = slave; - } - } - else - { - result = obj->getAbleToUseWeaponAgainstTarget( ATTACK_NEW_TARGET, nullptr, pos, CMD_FROM_PLAYER ); - if( result != ATTACKRESULT_POSSIBLE ) // oh dear me. The weird case of a garrisoncontainer being a KINDOF_SPAWNS_ARE_THE_WEAPONS... the AmericaBuildingFirebase - { - ContainModuleInterface *contain = obj->getContain(); - if ( contain ) - { - Object *rider = contain->getClosestRider( pos ); - if ( rider ) - testObj = rider; - } - } - } - } - //Now evaluate the testObj again to see if it is capable of force attacking the pos. - result = testObj->getAbleToUseWeaponAgainstTarget( ATTACK_NEW_TARGET, nullptr, pos, CMD_FROM_PLAYER ); - return result; - } - } - return ATTACKRESULT_NOT_POSSIBLE; -} - -//------------------------------------------------------------------------------------------------- -static CanAttackResult canAnyForceAttack(const DrawableList *allSelected, const Object *victim, const Coord3D *pos ) -{ - // check to make sure that allSelected can attack obj. - for (DrawableListCIt cit = allSelected->begin(); cit != allSelected->end(); ++cit) - { - Drawable *draw = *cit; - if (!draw) - { - continue; - } - - Object *obj = draw->getObject(); - if (!obj) - { - continue; - } - - return canObjectForceAttack( obj, victim, pos ); - } - - return ATTACKRESULT_NOT_POSSIBLE; -} - -//------------------------------------------------------------------------------------------------- -void pickAndPlayUnitVoiceResponse( const DrawableList *list, GameMessage::Type msgType, PickAndPlayInfo *info ) -{ - if (!list) - { - return; - } - - const AudioEventRTS* soundToPlayPtr = nullptr; - - Object *objectWithSound = nullptr; - Bool skip = false; - - Object *target = nullptr; - if( info && info->m_drawTarget ) - { - target = info->m_drawTarget->getObject(); - } - - //Now, loop through all the drawables (even if you find a match on the first. - //The innards are responsible for "upgrading" a sound that is played based on - //priorities. For example, the voice move or voice crush. Voice move gets set - //when we have a null event -- but if any of the units can crush the specified - //target, then it changes to VoiceCrush. - for( DrawableListCIt it = list->begin(); it != list->end(); ++it ) - { - Object *obj = (*it)->getObject(); - - if (obj->isKindOf( KINDOF_IGNORED_IN_GUI )) - continue; - - // Use the object instead of the drawable to get the thing template from. This way, we get the - // sounds even if the thing is disguised as something else. (Ala bomb truck.) - const ThingTemplate *templ = obj->getTemplate(); - if (!templ) - { - return; - } - - switch (msgType) - { - case GameMessage::MSG_DOCK: - soundToPlayPtr = templ->getPerUnitSound("VoiceSupply"); - objectWithSound = obj; - skip = true; - break; - case GameMessage::MSG_SELECT_TEAM0: - case GameMessage::MSG_SELECT_TEAM1: - case GameMessage::MSG_SELECT_TEAM2: - case GameMessage::MSG_SELECT_TEAM3: - case GameMessage::MSG_SELECT_TEAM4: - case GameMessage::MSG_SELECT_TEAM5: - case GameMessage::MSG_SELECT_TEAM6: - case GameMessage::MSG_SELECT_TEAM7: - case GameMessage::MSG_SELECT_TEAM8: - case GameMessage::MSG_SELECT_TEAM9: - case GameMessage::MSG_CREATE_SELECTED_GROUP: - soundToPlayPtr = templ->getVoiceSelect(); - objectWithSound = obj; - skip = true; - break; - case GameMessage::MSG_EVACUATE: - soundToPlayPtr = templ->getPerUnitSound( "VoiceUnload" ); - objectWithSound = obj; - skip = true; - break; - case GameMessage::MSG_DO_REPAIR: - soundToPlayPtr = templ->getPerUnitSound( "VoiceRepair" ); - objectWithSound = obj; - skip = true; - break; -#ifdef ALLOW_SURRENDER - case GameMessage::MSG_PICK_UP_PRISONER: - soundToPlayPtr = templ->getPerUnitSound( "VoicePickup" ); - objectWithSound = obj; - skip = true; - break; -#endif - case GameMessage::MSG_COMBATDROP_AT_LOCATION: - case GameMessage::MSG_COMBATDROP_AT_OBJECT: - soundToPlayPtr = templ->getPerUnitSound( "VoiceCombatDrop" ); - objectWithSound = obj; - skip = true; - break; - case GameMessage::MSG_ENTER: - if( target && target->isKindOf( KINDOF_HEAL_PAD ) ) - { - soundToPlayPtr = templ->getPerUnitSound( "VoiceGetHealed" ); - } - else if( target && target->isKindOf( KINDOF_STRUCTURE ) ) - { - if( obj->getRelationship( target ) == ENEMIES ) - { - //Saboteurs - soundToPlayPtr = templ->getPerUnitSound( "VoiceEnterHostile" ); - } - else - { - soundToPlayPtr = templ->getPerUnitSound( "VoiceGarrison" ); - } - } - // order matters: we want to know if I consider it to be an ally, not vice versa - else if( target && obj->getRelationship(target) != ALLIES ) - { - soundToPlayPtr = templ->getPerUnitSound( "VoiceEnterHostile" ); - } - else - { - soundToPlayPtr = templ->getPerUnitSound( "VoiceEnter" ); - } - objectWithSound = obj; - skip = true; - break; - - case GameMessage::MSG_DO_MOVETO: - case GameMessage::MSG_DO_ATTACKMOVETO: - case GameMessage::MSG_GET_REPAIRED: - case GameMessage::MSG_GET_HEALED: - case GameMessage::MSG_DO_SALVAGE: - { - AIUpdateInterface *ai = obj->getAI(); - if( ai ) - { - //This flag determines if the object has started moving yet... if not - //it's a good initial check. - Bool isEffectivelyMoving = ai->isMoving() || ai->isWaitingForPath(); - - if( TheInGameUI->isInWaypointMode() ) - { - if( isEffectivelyMoving ) - { - //Don't want to play the sound unless he's not moving! - continue; - } - } - - //Default to voice move (it'll be selected if we can't find a crush case as we iterate - //through the rest of the drawables) - if( !soundToPlayPtr ) - { - soundToPlayPtr = templ->getVoiceMove(); - objectWithSound = obj; - } - if( TheInGameUI->isInForceMoveToMode() && target ) - { - if( obj->canCrushOrSquish( target ) ) - { - //Change it to voice crush because we are intentionally trying to crush this! - soundToPlayPtr = templ->getPerUnitSound( "VoiceCrush" ); - objectWithSound = obj; - skip = true; - } - } - if (msgType == GameMessage::MSG_DO_SALVAGE) - { - const AudioEventRTS *tempSound = templ->getPerUnitSound( "VoiceSalvage" ); - if (TheAudio->isValidAudioEvent(tempSound)) - { - soundToPlayPtr = tempSound; - objectWithSound = obj; - skip = true; - } - } - // Special case for GLA worker to use a different set of move voices when he has received the worker shoes upgrade - Player *player = obj->getControllingPlayer(); - static const UpgradeTemplate *workerShoeTemplate = TheUpgradeCenter->findUpgrade( "Upgrade_GLAWorkerShoes" ); - if (player && workerShoeTemplate && player->hasUpgradeComplete(workerShoeTemplate)) - { - if (obj->isKindOf(KINDOF_INFANTRY) && obj->isKindOf(KINDOF_DOZER) && obj->isKindOf(KINDOF_HARVESTER)) // Only Workers fit all 3 - { - soundToPlayPtr = templ->getPerUnitSound( "VoiceMoveUpgraded" ); - objectWithSound = obj; - skip = true; - } - } - } - break; - } - - case GameMessage::MSG_RESUME_CONSTRUCTION: - case GameMessage::MSG_DOZER_CONSTRUCT: - case GameMessage::MSG_DOZER_CONSTRUCT_LINE: - { - soundToPlayPtr = templ->getPerUnitSound( "VoiceBuildResponse" ); - objectWithSound = obj; - skip = true; - - break; - } - - case GameMessage::MSG_SWITCH_WEAPONS: - { - if( info && info->m_weaponSlot ) - { - switch( *info->m_weaponSlot ) - { - case PRIMARY_WEAPON: - soundToPlayPtr = templ->getPerUnitSound( "VoicePrimaryWeaponMode" ); - break; - case SECONDARY_WEAPON: - soundToPlayPtr = templ->getPerUnitSound( "VoiceSecondaryWeaponMode" ); - break; - case TERTIARY_WEAPON: - soundToPlayPtr = templ->getPerUnitSound( "VoiceTertiaryWeaponMode" ); - break; - } - objectWithSound = obj; - skip = true; - } - break; - } - - case GameMessage::MSG_DO_FORCE_ATTACK_GROUND: - { - soundToPlayPtr = templ->getPerUnitSound( "VoiceBombard" ); - objectWithSound = obj; - skip = true; - - if (TheAudio->isValidAudioEvent(soundToPlayPtr)) { - break; - } else { - // clear out the sound to play, and drop into the attack object logic. - soundToPlayPtr = nullptr; - FALLTHROUGH; - } - } - case GameMessage::MSG_DO_FORCE_ATTACK_OBJECT: - case GameMessage::MSG_DO_ATTACK_OBJECT: - case GameMessage::MSG_DO_WEAPON_AT_OBJECT: - { - if( !soundToPlayPtr ) - { - //Low priority sounds -- only do this if uninitialized. - if( info && info->m_air ) - soundToPlayPtr = templ->getVoiceAttackAir(); - else - soundToPlayPtr = templ->getVoiceAttack(); - - objectWithSound = obj; - } - - //Look for a specialty weapon fired via command button! - Bool specialtyWeapon = FALSE; - if( msgType == GameMessage::MSG_DO_WEAPON_AT_OBJECT ) - { - specialtyWeapon = TRUE; - } - - Weapon *weapon = obj->getCurrentWeapon(); - if( info && info->m_weaponSlot ) - { - weapon = obj->getWeaponInWeaponSlot( *info->m_weaponSlot ); - } - if( weapon ) - { - switch( weapon->getDamageType() ) - { -// this stays, even if ALLOW_SURRENDER is not defed, since flashbangs still use 'em - case DAMAGE_SURRENDER: - if( target && target->isKindOf( KINDOF_STRUCTURE ) ) - { - //We are attempting to take over a building with rangers and flashbangs! - soundToPlayPtr = templ->getPerUnitSound( "VoiceClearBuilding" ); - } - else - { - //Special for subdue attacks. - soundToPlayPtr = templ->getPerUnitSound( "VoiceSubdue" ); - } - objectWithSound = obj; - skip = true; - break; - case DAMAGE_DISARM: - //Special for mine clearing attacks. - soundToPlayPtr = templ->getPerUnitSound( "VoiceDisarm" ); - objectWithSound = obj; - skip = true; - break; - case DAMAGE_KILLPILOT: - if( specialtyWeapon ) - { - //Special for sniping vehicle pilots. - soundToPlayPtr = templ->getPerUnitSound( "VoiceSnipePilot" ); - objectWithSound = obj; - skip = true; - } - break; - case DAMAGE_MELEE: - if( specialtyWeapon ) - { - //Special for stabbing - soundToPlayPtr = templ->getPerUnitSound( "VoiceMelee" ); - objectWithSound = obj; - skip = true; - } - break; - } - } - break; - } - - case GameMessage::MSG_DO_WEAPON_AT_LOCATION: - { - - if( !soundToPlayPtr ) - { - //Low priority sounds -- only do this if uninitialized. - if( info && info->m_air ) - soundToPlayPtr = templ->getVoiceAttackAir(); - else - soundToPlayPtr = templ->getVoiceAttack(); - objectWithSound = obj; - } - - //Check for possibility of a higher priority sound! - Weapon *weapon = obj->getCurrentWeapon(); - if( info && info->m_weaponSlot ) - { - weapon = obj->getWeaponInWeaponSlot( *info->m_weaponSlot ); - } - if( weapon ) - { - switch( weapon->getDamageType() ) - { -// this stays, even if ALLOW_SURRENDER is not defed, since flashbangs still use 'em - case DAMAGE_SURRENDER: - break; - case DAMAGE_DISARM: - //Special for mine clearing attacks. - soundToPlayPtr = templ->getPerUnitSound( "VoiceDisarm" ); - objectWithSound = obj; - break; - //these are specific to the guicommand based ground attacks, the toxin sprinkler and the firestorm wall thing - //hence the additional check for it being a non-primary weapon - case DAMAGE_FLAME: - if (weapon->getWeaponSlot() != PRIMARY_WEAPON) - { - soundToPlayPtr = templ->getPerUnitSound( "VoiceFlameLocation" ); - objectWithSound = obj; - } - break; - case DAMAGE_POISON: - if (weapon->getWeaponSlot() != PRIMARY_WEAPON) - { - soundToPlayPtr = templ->getPerUnitSound( "VoicePoisonLocation" ); - objectWithSound = obj; - } - break; - default: - if( !weapon->getName().compare( "ComancheRocketPodWeapon" ) ) - { - //Special case for comanche rocket pods. - soundToPlayPtr = templ->getPerUnitSound( "VoiceFireRocketPods" ); - objectWithSound = obj; - skip = true; - } - } - } - break; - } - case GameMessage::MSG_DO_GUARD_POSITION: - case GameMessage::MSG_DO_GUARD_OBJECT: - soundToPlayPtr = templ->getVoiceGuard(); - objectWithSound = obj; - skip = true; - break; - - case GameMessage::MSG_DO_SPECIAL_POWER: - case GameMessage::MSG_DO_SPECIAL_POWER_AT_LOCATION: - case GameMessage::MSG_DO_SPECIAL_POWER_AT_OBJECT: - { - if( info && info->m_specialPowerType != SPECIAL_INVALID ) - { - SpecialPowerModuleInterface *spmInterface = obj->findSpecialPowerModuleInterface( info->m_specialPowerType ); - if( spmInterface ) - { - objectWithSound = obj; - soundToPlayPtr = &spmInterface->getInitiateSound(); - skip = TRUE; - } - } - break; - } - - case GameMessage::MSG_INTERNET_HACK: - objectWithSound = obj; - soundToPlayPtr = templ->getPerUnitSound( "VoiceHackInternet" ); - skip = TRUE; - break; - - default: - DEBUG_LOG(("Requested to add voice of message type %d, but don't know how - jkmcd", msgType)); - break; - } - if( skip ) - { - //The unit sound doesn't have any sort of priority or special case, so simply play the first one that comes along. - break; - } - - } - - - - - if (!soundToPlayPtr) - return; - - AudioEventRTS soundToPlay = *soundToPlayPtr; - - // to prevent voice stepping. - if( objectWithSound ) - { - soundToPlay.setObjectID( objectWithSound->getID() ); - TheAudio->addAudioEvent(&soundToPlay); - - // This seems really hacky, and MarkL admits that it is. However, we do this so that we - // can "randomly" pick a different sound the next time, if we have 3 or more sounds. - jkmcd - soundToPlayPtr->setPlayingAudioIndex( soundToPlay.getPlayingAudioIndex() ); - - if( objectWithSound->testStatus( OBJECT_STATUS_IS_CARBOMB ) ) - { - //Additional sounds for terrorists in cars. - switch (msgType) - { - case GameMessage::MSG_DO_FORCE_ATTACK_GROUND: - case GameMessage::MSG_DO_FORCE_ATTACK_OBJECT: - case GameMessage::MSG_DO_ATTACK_OBJECT: - soundToPlay = TheAudio->getMiscAudio()->m_terroristInCarAttackVoice; - soundToPlay.setObjectID( objectWithSound->getID() ); - TheAudio->addAudioEvent(&soundToPlay); - break; - - case GameMessage::MSG_DO_MOVETO: - case GameMessage::MSG_DO_ATTACKMOVETO: - case GameMessage::MSG_GET_REPAIRED: - case GameMessage::MSG_GET_HEALED: - case GameMessage::MSG_DO_SALVAGE: - soundToPlay = TheAudio->getMiscAudio()->m_terroristInCarMoveVoice; - soundToPlay.setObjectID( objectWithSound->getID() ); - TheAudio->addAudioEvent(&soundToPlay); - break; - - case GameMessage::MSG_SELECT_TEAM0: - case GameMessage::MSG_SELECT_TEAM1: - case GameMessage::MSG_SELECT_TEAM2: - case GameMessage::MSG_SELECT_TEAM3: - case GameMessage::MSG_SELECT_TEAM4: - case GameMessage::MSG_SELECT_TEAM5: - case GameMessage::MSG_SELECT_TEAM6: - case GameMessage::MSG_SELECT_TEAM7: - case GameMessage::MSG_SELECT_TEAM8: - case GameMessage::MSG_SELECT_TEAM9: - case GameMessage::MSG_CREATE_SELECTED_GROUP: - soundToPlay = TheAudio->getMiscAudio()->m_terroristInCarSelectVoice; - soundToPlay.setObjectID( objectWithSound->getID() ); - TheAudio->addAudioEvent(&soundToPlay); - break; - } - } - } -} - - -//------------------------------------------------------------------------------------ -/** - * Find a suitable command center to view. - */ - -struct CommandCenterLocator -{ - Bool atLeastOne; - Bool isCommandCenter; - Int val; - Coord3D loc; - - CommandCenterLocator() : atLeastOne(false), isCommandCenter(false), val(-1) - { - loc.zero(); - } -}; - -void findCommandCenterOrMostExpensiveBuilding(Object* obj, void* vccl) -{ - CommandCenterLocator *ccl = (CommandCenterLocator*) vccl; - - // here's the deal. We want to get the first Command Center in the list. - // Barring that, we want the most expensive structure we currently own. - if (obj->isKindOf(KINDOF_COMMANDCENTER)) { - ccl->isCommandCenter = true; - ccl->loc = *obj->getPosition(); - } else if (!ccl->isCommandCenter) { - if (!obj->isKindOf(KINDOF_STRUCTURE)) { - return; - } - - Int costToBuild = obj->getTemplate()->calcCostToBuild(obj->getControllingPlayer()); - if (costToBuild > ccl->val) { - ccl->val = costToBuild; - ccl->loc = *obj->getPosition(); - } - } - - ccl->atLeastOne = true; -} - -static void viewCommandCenter() -{ - Player* localPlayer = rts::getObservedOrLocalPlayer(); - if (!localPlayer->isPlayerActive()) - return; - - CommandCenterLocator ccl; - localPlayer->iterateObjects(findCommandCenterOrMostExpensiveBuilding, &ccl); - - if (ccl.atLeastOne) { - TheTacticalView->userLookAt(&ccl.loc); - } else { - // @todo. Find their starting position and look at that instead? - } -} - - - -//----------------- Select and View Hero ----------------------------------- - -struct HeroHolder -{ - Object *hero; -}; - -void amIAHero(Object* obj, void* heroHolder) -{ - if (((HeroHolder*)heroHolder)->hero != nullptr) - { - return; - } - - if (obj->isKindOf( KINDOF_HERO )) - { - ((HeroHolder*)heroHolder)->hero = obj; - } -} - - - -static Object *iNeedAHero() -{ - Player* localPlayer = rts::getObservedOrLocalPlayer(); - if (!localPlayer->isPlayerActive()) - return nullptr; - - HeroHolder heroHolder; - heroHolder.hero = nullptr; - - localPlayer->iterateObjects(amIAHero, (void*)&heroHolder); - - return heroHolder.hero; - -} - -//------------------------------------------------------------------------------------ -/** - * Create DO_MOVE_TO messages for each selected object, instructing it to move to the given location. - */ -GameMessage::Type CommandTranslator::issueMoveToLocationCommand( const Coord3D *pos, Drawable *drawableInWay, - CommandEvaluateType commandType ) -{ - GameMessage::Type msgType = GameMessage::MSG_INVALID; - Object *obj = drawableInWay ? drawableInWay->getObject() : nullptr; - - Bool isForceAttackable = FALSE; - if (obj) { - isForceAttackable = obj->isKindOf(KINDOF_FORCEATTACKABLE); - } - - if (m_teamExists) - { - if( TheInGameUI->isInWaypointMode() ) - { - msgType = GameMessage::MSG_ADD_WAYPOINT; - } - else if( TheInGameUI->isInAttackMoveToMode()) - { - msgType = GameMessage::MSG_DO_ATTACKMOVETO; - } - else if( TheInGameUI->isInForceMoveToMode() ) - { - msgType = GameMessage::MSG_DO_FORCEMOVETO; - } - else if( TheInGameUI->isInForceAttackMode() && isForceAttackable ) - { - msgType = GameMessage::MSG_DO_ATTACK_OBJECT; - } - else - { - msgType = GameMessage::MSG_DO_MOVETO; - } - if( commandType == DO_COMMAND ) - { - GameMessage *movemsg = TheMessageStream->appendMessage( msgType ); - if (msgType == GameMessage::MSG_DO_ATTACK_OBJECT) - movemsg->appendObjectIDArgument( obj->getID() ); - else - movemsg->appendLocationArgument( *pos ); - - } - } - - // only make sounds if we really did the command messages - if( commandType == DO_COMMAND ) - { - PickAndPlayInfo info; - info.m_drawTarget = drawableInWay; - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_MOVETO, &info ); - } - - if(TheStatsCollector) - TheStatsCollector->incrementMoveCount(); - - // return the actual msg type used - return msgType; - -} - -//------------------------------------------------------------------------------------ -/// @todo Play attack command response sound on client-side to hide latency -GameMessage::Type CommandTranslator::createAttackMessage( Drawable *draw, - Drawable *other, - CommandEvaluateType commandType ) -{ - GameMessage::Type msgType = GameMessage::MSG_INVALID; - - // the drawable must have an object to be able to attack - if( draw->getObject() == nullptr ) - return msgType; - - // the target must have an object to be attacked - if( other->getObject() == nullptr ) - return msgType; - - // insert object attack command message into stream - msgType = GameMessage::MSG_DO_ATTACK_OBJECT; - - // only make the message if we are really doing a command - if( commandType == DO_COMMAND ) - { - GameMessage *attackmsg = TheMessageStream->appendMessage( msgType ); - - attackmsg->appendObjectIDArgument( other->getObject()->getID() ); // must pass object IDs to logic - - } - - // return the message type created - return msgType; - -} - -//------------------------------------------------------------------------------------ -/** - * Create DO_ATTACK_GROUND_OBJECT messages for each selected object, instructing it to attack the given enemy. - * Return TRUE if any attacks actually occurred. - */ -GameMessage::Type CommandTranslator::issueAttackCommand( Drawable *target, - CommandEvaluateType commandType, - GUICommandType command ) -{ - GameMessage::Type msgType = GameMessage::MSG_INVALID; - - if (target == nullptr) - return msgType; - - // you cannot attack an enemy that has no object representation - Object *targetObj = target->getObject(); - if( !targetObj ) - return msgType; - - if( m_teamExists ) - { - - //DEBUG_LOG(("issuing team-attack cmd against %s",enemy->getTemplate()->getName().str())); - - // insert team attack command message into stream - switch( command ) - { -#ifdef ALLOW_SURRENDER - case GUICOMMANDMODE_PICK_UP_PRISONER: - msgType = GameMessage::MSG_PICK_UP_PRISONER; - break; -#endif - case GUI_COMMAND_NONE: - msgType = GameMessage::MSG_DO_ATTACK_OBJECT; - break; - default: - DEBUG_CRASH( ("issueAttackCommand was passed in a GUICommandType type that isn't supported yet...") ); - return msgType; - } - - // only create the message if our command type is DO_COMMAND - if( commandType == DO_COMMAND ) - { - GameMessage *attackMsg; - - attackMsg = TheMessageStream->appendMessage( msgType ); - - attackMsg->appendObjectIDArgument( targetObj->getID() ); // must pass target object ID to logic - - // if we have a stats collector, increment the stats - if(TheStatsCollector) - TheStatsCollector->incrementAttackCount(); - } - } - else - { - DEBUG_LOG(("issuing NON-team-attack cmd against %s",target->getTemplate()->getName().str())); - - // send single attack command for selected drawable - const DrawableList *selected = TheInGameUI->getAllSelectedDrawables(); - - // loop through all the selected drawables - Drawable *draw; - for( DrawableListCIt it = selected->begin(); it != selected->end(); ++it ) - { - draw = *it; - msgType = createAttackMessage(draw, target, commandType ); - } - } - - // only make sounds if the command was for real - if( commandType == DO_COMMAND ) - { - PickAndPlayInfo info; - info.m_air = targetObj->isUsingAirborneLocomotor(); - info.m_drawTarget = target; - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), msgType, &info ); - } - - // return the actual message type created - return msgType; - -} - -//------------------------------------------------------------------------------------------------- -GameMessage::Type CommandTranslator::issueSpecialPowerCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos, Object* ignoreSelObj ) -{ - GameMessage::Type msgType = GameMessage::MSG_INVALID; - - if( !command || !command->getSpecialPowerTemplate()) - { - return msgType; - } - - Drawable* sourceDraw = ignoreSelObj ? ignoreSelObj->getDrawable() : TheInGameUI->getFirstSelectedDrawable(); - ObjectID specificSource = ignoreSelObj ? ignoreSelObj->getID() : INVALID_ID; - - if( BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) - { - // OBJECT BASED SPECIAL - if (!command->isValidObjectTarget(sourceDraw, target)) - return msgType; - - msgType = GameMessage::MSG_DO_SPECIAL_POWER_AT_OBJECT; - if( commandType == DO_COMMAND ) - { - GameMessage *msg; - msg = TheMessageStream->appendMessage( msgType ); - msg->appendIntegerArgument( command->getSpecialPowerTemplate()->getID() ); - msg->appendObjectIDArgument( target->getObject()->getID() ); - msg->appendIntegerArgument( command->getOptions() ); - msg->appendObjectIDArgument( specificSource ); - - // say something like " I think I'll put some dynamite on that there tank." - PickAndPlayInfo info; - info.m_drawTarget = target; - info.m_specialPowerType = command->getSpecialPowerTemplate()->getSpecialPowerType(); - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), msgType, &info ); - - } - } - else if( BitIsSet( command->getOptions(), NEED_TARGET_POS ) ) - { - //LOCATION BASED SPECIAL - msgType = GameMessage::MSG_DO_SPECIAL_POWER_AT_LOCATION; - if( commandType == DO_COMMAND ) - { - GameMessage *msg; - msg = TheMessageStream->appendMessage( msgType ); - msg->appendIntegerArgument( command->getSpecialPowerTemplate()->getID() ); - msg->appendLocationArgument( *pos ); -#if !(RTS_GENERALS && RETAIL_COMPATIBLE_NETWORKING) - msg->appendRealArgument( INVALID_ANGLE ); //We don't use the angle (unless we're using a construction special in PlaceEventTranslator). -#endif - //Object in way.... some specials care, others don't - ObjectID targetID = (target && target->getObject()) ? target->getObject()->getID() : INVALID_ID; - msg->appendObjectIDArgument( targetID ); - msg->appendIntegerArgument( command->getOptions() ); - msg->appendObjectIDArgument( specificSource ); - - // say something like " I think I'll put a timed charge on the ground, here." - PickAndPlayInfo info; - info.m_drawTarget = target; - info.m_specialPowerType = command->getSpecialPowerTemplate()->getSpecialPowerType(); - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), msgType, &info ); - - } - } - else - { - //NO TARGET SPECIAL - msgType = GameMessage::MSG_DO_SPECIAL_POWER; - if( commandType == DO_COMMAND ) - { - GameMessage *msg; - msg = TheMessageStream->appendMessage( msgType ); - msg->appendIntegerArgument( command->getSpecialPowerTemplate()->getID() ); - msg->appendIntegerArgument( command->getOptions() ); - msg->appendObjectIDArgument( specificSource ); - - // say something like " I think I'll set down my laptop and hack some cash from a bank in the Cayman Islands." - PickAndPlayInfo info; - info.m_drawTarget = target; - info.m_specialPowerType = command->getSpecialPowerTemplate()->getSpecialPowerType(); - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), msgType, &info ); - - } - } - - if( command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT && commandType == DO_COMMAND ) - { - Object *obj = sourceDraw->getObject(); - SpecialPowerUpdateInterface *spUpdate = obj->findSpecialPowerWithOverridableDestination(); - if( spUpdate ) - { - //Deselect the drawables before posting the selection message. - TheInGameUI->deselectAllDrawables(); - - //Because we just launched a special power via shortcut, and the special power accepts input - //from the player (particle uplink cannon, spectre gunship), simply select the object now. - //-------------------- - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP_NO_SOUND ); - // creating a new team so pass in true - teamMsg->appendBooleanArgument( TRUE ); - teamMsg->appendObjectIDArgument( obj->getID() ); - - TheInGameUI->selectDrawable( obj->getDrawable() ); - } - } - - - - return msgType; -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -GameMessage::Type CommandTranslator::issueCombatDropCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos ) -{ - if( !command ) - { - return GameMessage::MSG_INVALID; - } - - if( target != nullptr && BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) - { - - // OBJECT BASED SPECIAL - if (!command->isValidObjectTarget(TheInGameUI->getFirstSelectedDrawable(), target)) - return GameMessage::MSG_INVALID; - - GameMessage::Type msgType = GameMessage::MSG_COMBATDROP_AT_OBJECT; - if( commandType == DO_COMMAND ) - { - GameMessage *msg = TheMessageStream->appendMessage( msgType ); - ObjectID targetID = (target && target->getObject()) ? target->getObject()->getID() : INVALID_ID; - msg->appendObjectIDArgument( targetID ); - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_COMBATDROP_AT_OBJECT ); - } - return msgType; - } - else if ( BitIsSet( command->getOptions(), NEED_TARGET_POS ) ) - { - GameMessage::Type msgType = GameMessage::MSG_COMBATDROP_AT_LOCATION; - if( commandType == DO_COMMAND ) - { - GameMessage *msg = TheMessageStream->appendMessage( msgType ); - msg->appendLocationArgument( *pos ); - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_COMBATDROP_AT_LOCATION ); - } - return msgType; - } - else - { - return GameMessage::MSG_INVALID; - } -} - -//------------------------------------------------------------------------------------------------- -GameMessage::Type CommandTranslator::issueFireWeaponCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos ) -{ - GameMessage::Type msgType = GameMessage::MSG_INVALID; - - if( !command ) - { - return msgType; - } - - if( BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) - { - //OBJECT BASED FIRE WEAPON - if (!target || !target->getObject()) - return msgType; - - if (!command->isValidObjectTarget(TheInGameUI->getFirstSelectedDrawable(), target)) - return msgType; - - if( BitIsSet( command->getOptions(), ATTACK_OBJECTS_POSITION ) ) - { - //Actually, you know what.... we want to attack the object's location instead. - msgType = GameMessage::MSG_DO_WEAPON_AT_LOCATION; - if( commandType == DO_COMMAND ) - { - GameMessage *msg; - msg = TheMessageStream->appendMessage( msgType ); - msg->appendIntegerArgument( command->getWeaponSlot() ); - msg->appendLocationArgument( *pos ); - msg->appendIntegerArgument( command->getMaxShotsToFire() ); - //Object in way.... some location weapons care, others don't - ObjectID targetID = (target && target->getObject()) ? target->getObject()->getID() : INVALID_ID; - msg->appendObjectIDArgument( targetID ); - } - } - else - { - msgType = GameMessage::MSG_DO_WEAPON_AT_OBJECT; - if( commandType == DO_COMMAND ) - { - GameMessage *msg; - msg = TheMessageStream->appendMessage( msgType ); - msg->appendIntegerArgument( command->getWeaponSlot() ); - ObjectID targetID = (target && target->getObject()) ? target->getObject()->getID() : INVALID_ID; - msg->appendObjectIDArgument( targetID ); - msg->appendIntegerArgument( command->getMaxShotsToFire() ); - - //play a unit specific sound? - PickAndPlayInfo info; - WeaponSlotType slot = command->getWeaponSlot(); - info.m_weaponSlot = &slot; - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_WEAPON_AT_OBJECT, &info ); - } - } - } - else if( BitIsSet( command->getOptions(), NEED_TARGET_POS ) ) - { - //LOCATION BASED FIRE WEAPON - msgType = GameMessage::MSG_DO_WEAPON_AT_LOCATION; - if( commandType == DO_COMMAND ) - { - GameMessage *msg; - msg = TheMessageStream->appendMessage( msgType ); - msg->appendIntegerArgument( command->getWeaponSlot() ); - msg->appendLocationArgument( *pos ); - msg->appendIntegerArgument( command->getMaxShotsToFire() ); - //Object in way.... some location weapons care, others don't - ObjectID targetID = (target && target->getObject()) ? target->getObject()->getID() : INVALID_ID; - msg->appendObjectIDArgument( targetID ); - } - } - else - { - //NO TARGET WEAPON - msgType = GameMessage::MSG_DO_WEAPON; - if( commandType == DO_COMMAND ) - { - GameMessage *msg; - msg = TheMessageStream->appendMessage( msgType ); - DEBUG_ASSERTCRASH( (command->getSpecialPowerTemplate()), ("No Special Power Weapon here to 'do' with! ML")); - msg->appendIntegerArgument( command->getSpecialPowerTemplate()->getID() ); - } - } - - return msgType; -} - -//------------------------------------------------------------------------------------------------- -GameMessage::Type CommandTranslator::createEnterMessage( Drawable *enter, - CommandEvaluateType commandType ) -{ - GameMessage::Type msgType = GameMessage::MSG_ENTER; - - // if we're just evaluating then get out of here without actually doing the action - if( commandType == EVALUATE_ONLY ) - return msgType; - - if (!enter || !enter->getObject()) - return msgType; - - // sanity - DEBUG_ASSERTCRASH( commandType == DO_COMMAND, ("createEnterMessage - commandType is not DO_COMMAND") ); - - if( m_teamExists ) - { - PickAndPlayInfo info; - info.m_drawTarget = enter; - pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), msgType, &info ); - - GameMessage *enterMsg = TheMessageStream->appendMessage( msgType ); - enterMsg->appendObjectIDArgument( INVALID_ID ); // 0 means current "selection team" of this player - enterMsg->appendObjectIDArgument( enter->getObject()->getID() ); - - } - else - { - DEBUG_CRASH(("Shouldn't get here. jkmcd")); - } - - // return the type of the message used - return msgType; - -} - -//==================================================================================== -CommandTranslator::CommandTranslator() : - m_objective(0), - m_teamExists(false), - m_mouseRightDown(0), - m_mouseRightUp(0) -{ - m_mouseRightDragAnchor.x = 0; - m_mouseRightDragAnchor.y = 0; - m_mouseRightDragLift.x = 0; - m_mouseRightDragLift.y = 0; -} - -//==================================================================================== -CommandTranslator::~CommandTranslator() -{ -} - - - -//------------------------------------------------------------------------------------------------- -GameMessage::Type CommandTranslator::evaluateForceAttack( Drawable *draw, const Coord3D *pos, CommandEvaluateType type ) -{ - // evaluateForceAttack is used to determine whether or not we can force attack the - // given target, and if we can, to issue the appropriate command. - - GameMessage::Type retVal = GameMessage::MSG_INVALID; - if( !draw && !pos ) - { - return retVal; - } - - const DrawableList *allSelected = TheInGameUI->getAllSelectedDrawables(); - - if( draw ) - { - Object *obj = draw ? draw->getObject() : nullptr; - if( !obj ) - { - return retVal; - } - - CanAttackResult result = canAnyForceAttack( allSelected, obj, pos ); - - if( result == ATTACKRESULT_POSSIBLE || result == ATTACKRESULT_POSSIBLE_AFTER_MOVING ) - { - retVal = GameMessage::MSG_DO_FORCE_ATTACK_OBJECT; - - if( type == DO_COMMAND ) - { - pickAndPlayUnitVoiceResponse( allSelected, retVal ); - GameMessage *newMsg = TheMessageStream->appendMessage( retVal ); - newMsg->appendObjectIDArgument( obj->getID() ); - - } - else if( type == DO_HINT ) - { - retVal = GameMessage::MSG_DO_FORCE_ATTACK_OBJECT_HINT; - // Don't need the message back, cause there is nothing to append to it. - TheMessageStream->appendMessage( retVal ); - } - } - else if( result == ATTACKRESULT_INVALID_SHOT && type == DO_HINT ) - { - retVal = GameMessage::MSG_IMPOSSIBLE_ATTACK_HINT; - TheMessageStream->appendMessage( retVal ); - } - } - else if( pos ) - { - CanAttackResult result = canAnyForceAttack( allSelected, nullptr, pos ); - - if( result == ATTACKRESULT_POSSIBLE || result == ATTACKRESULT_POSSIBLE_AFTER_MOVING ) - { - retVal = GameMessage::MSG_DO_FORCE_ATTACK_GROUND; - - if( type == DO_COMMAND ) - { - pickAndPlayUnitVoiceResponse( allSelected, retVal ); - GameMessage *newMsg = TheMessageStream->appendMessage( retVal ); - newMsg->appendLocationArgument( *pos ); - } - else if( type == DO_HINT ) - { - retVal = GameMessage::MSG_DO_FORCE_ATTACK_GROUND_HINT; - // Don't need the message back, cause there is nothing to append to it. - TheMessageStream->appendMessage( retVal ); - } - } - else if( result == ATTACKRESULT_INVALID_SHOT && type == DO_HINT ) - { - retVal = GameMessage::MSG_IMPOSSIBLE_ATTACK_HINT; - TheMessageStream->appendMessage( retVal ); - } - } - - return retVal; -} - -// ------------------------------------------------------------------------------------------------ -/** This method and the order of operations in the check here, determine what command would - * actually happen (if type parameter == DO_COMMAND) if the user clicked on the drawable - * 'draw'. If type == DO_HINT, then the user hasn't actually clicked, but has moused over - * the drawable 'draw' and we want to generate a hint message as to what the actual - * command would be if clicked - * NOTE: draw can be null, in which case we give a hint for the location */ -// ------------------------------------------------------------------------------------------------ -GameMessage::Type CommandTranslator::evaluateContextCommand( Drawable *draw, - const Coord3D *pos, - CommandEvaluateType type ) -{ - Object *obj = draw ? draw->getObject() : nullptr; - Drawable *drawableInWay = draw; - - //This piece of code is used to prevent interaction with unselectable objects or masked objects. When we - //call this function, we typically pass in both a position and a drawable (if applicable), so if the - //drawable is invalid... then convert it to a position to be evaluated instead. - //Added: shrubberies are the exception for interactions... - //Removed: GS Took out ObjectStatusUnselectable, since that status only prevents selection, not everything - if( obj == nullptr || - ( obj->getStatusBits().test( OBJECT_STATUS_MASKED ) && - !obj->isKindOf(KINDOF_SHRUBBERY) && !obj->isKindOf(KINDOF_FORCEATTACKABLE) ) ) - { - //Nulling out the draw and obj pointer will force the remainder of this code to evaluate - //a position interaction. - draw = nullptr; - obj = nullptr; - } - - // If the thing is a mine, and is locally controlled, then we should issue a moveto to its location. - if (obj && obj->isLocallyControlled() && obj->isKindOf(KINDOF_MINE)) { - draw = nullptr; - obj = nullptr; - } - - if( TheInGameUI->isInForceMoveToMode() ) - { - //Nulling out the draw and obj pointer will force the remainder of this code to evaluate - //a position interaction. - draw = nullptr; - obj = nullptr; - } else if (TheInGameUI->isInForceAttackMode() ) { - // setting the drawableInWay to draw will allow us to force attack in the issue move command - // if there is a location to which we should attack. - drawableInWay = draw; - } - - GameMessage::Type msgType = GameMessage::MSG_INVALID; - - // Then we should determine if the game currently prefers selection events. If it does, then return - // the invalid message. - if (obj) { - if (obj->isLocallyControlled() && TheInGameUI->isInPreferSelectionMode()) { - return msgType; - } - } - - // Kris: Now that we can select non-controllable units/structures, don't allow any actions to be performed. - const CommandButton *command = TheInGameUI->getGUICommand(); - - if (command && command->getCommandType() == GUICOMMANDMODE_PLACE_BEACON) - { - msgType = GameMessage::MSG_VALID_GUICOMMAND_HINT; - TheMessageStream->appendMessage(msgType); - } - else if( TheInGameUI->areSelectedObjectsControllable() - || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT)) - { - GameMessage *hintMessage; - - if( TheInGameUI->isInWaypointMode() ) - { - //Override any *other* commands with waypoint commands. - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - if( TheTerrainLogic ) - { - msgType = issueMoveToLocationCommand( pos, draw, type ); - } - } - else - { - msgType = GameMessage::MSG_ADD_WAYPOINT_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendLocationArgument( *pos ); - } - return msgType; - } - - CanAttackResult result; - - if(command && - (command->isContextCommand() - || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER - || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT)) - { - if( obj && obj->isKindOf( KINDOF_SHRUBBERY ) && !BitIsSet( command->getOptions(), ALLOW_SHRUBBERY_TARGET ) ) - { - //If our object is a shrubbery, and we don't allow targeting it... then null it out. - //Nulling out the draw and obj pointer will force the remainder of this code to evaluate - //a position interaction. - draw = nullptr; - obj = nullptr; - } - - if( obj && obj->isKindOf( KINDOF_MINE ) && !BitIsSet( command->getOptions(), ALLOW_MINE_TARGET ) ) - { - //If our object is a mine, and we don't allow targeting it... then null it out. - //Nulling out the draw and obj pointer will force the remainder of this code to evaluate - //a position interaction. - draw = nullptr; - obj = nullptr; - } - - //Kris: September 27, 2002 - //Added relationship tests to make sure we're not attempting a context-command on a restricted relationship. - //This case prevents rebels from using tranq darts on allies. - if( obj && BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) - { - Relationship relationship = ThePlayerList->getLocalPlayer()->getRelationship( obj->getTeam() ); - switch( relationship ) - { - case ALLIES: - if( !BitIsSet( command->getOptions(), NEED_TARGET_ALLY_OBJECT ) ) - { - draw = nullptr; - obj = nullptr; - } - break; - case ENEMIES: - if( !BitIsSet( command->getOptions(), NEED_TARGET_ENEMY_OBJECT ) ) - { - draw = nullptr; - obj = nullptr; - } - break; - case NEUTRAL: - if( !BitIsSet( command->getOptions(), NEED_TARGET_NEUTRAL_OBJECT ) ) - { - draw = nullptr; - obj = nullptr; - } - break; - } - } - - Bool currentlyValid = FALSE; - ObjectID objectID = obj ? obj->getID() : INVALID_ID; - switch( command->getCommandType() ) - { - //Kris: June 06, 2002 - //This is a GUI command button that triggers a mode. In any of these modes, only one specific action - //can occur. If the mouse isn't over a valid target, then the conditions aren't met and the code will - //cause an invalid version of the cursor to be shown -- and should the user click, the action won't take place. - case GUICOMMANDMODE_CONVERT_TO_CARBOMB: - currentlyValid = TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_CONVERT_OBJECT_TO_CARBOMB, obj, InGameUI::SELECTION_ANY ); - break; - case GUICOMMANDMODE_HIJACK_VEHICLE: - currentlyValid = TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_HIJACK_VEHICLE, obj, InGameUI::SELECTION_ANY ); - break; - case GUICOMMANDMODE_SABOTAGE_BUILDING: - currentlyValid = TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_SABOTAGE_BUILDING, obj, InGameUI::SELECTION_ANY ); - break; -#ifdef ALLOW_SURRENDER - case GUICOMMANDMODE_PICK_UP_PRISONER: - currentlyValid = TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_PICK_UP_PRISONER, obj, InGameUI::SELECTION_ANY ); - break; -#endif - case GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT: - { - Object* unit = ThePlayerList->getLocalPlayer()->findMostReadyShortcutSpecialPowerOfType( command->getSpecialPowerTemplate()->getSpecialPowerType() ); - if( unit ) - currentlyValid = TheInGameUI->canSelectedObjectsDoSpecialPower( command, obj, pos, InGameUI::SELECTION_ANY, command->getOptions(), unit ); - else - currentlyValid = false; - break; - } - case GUI_COMMAND_SPECIAL_POWER: - currentlyValid = TheInGameUI->canSelectedObjectsDoSpecialPower( command, obj, pos, InGameUI::SELECTION_ANY, command->getOptions(), nullptr ); - break; - case GUI_COMMAND_FIRE_WEAPON: - currentlyValid = TheInGameUI->canSelectedObjectsEffectivelyUseWeapon( command, obj, pos, InGameUI::SELECTION_ANY ); - break; - case GUI_COMMAND_COMBATDROP: - currentlyValid = !obj ? TRUE : TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_COMBATDROP_INTO, obj, InGameUI::SELECTION_ANY ); - break; - } - - if( currentlyValid ) - { - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - switch( command->getCommandType() ) - { - case GUICOMMANDMODE_CONVERT_TO_CARBOMB: - case GUICOMMANDMODE_HIJACK_VEHICLE: - case GUICOMMANDMODE_SABOTAGE_BUILDING: - msgType = createEnterMessage( draw, type ); - break; -#ifdef ALLOW_SURRENDER - case GUICOMMANDMODE_PICK_UP_PRISONER: - msgType = issueAttackCommand( draw, type, command->getCommandType() ); - break; -#endif - case GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT: - { - Object* unit = ThePlayerList->getLocalPlayer()->findMostReadyShortcutSpecialPowerOfType( command->getSpecialPowerTemplate()->getSpecialPowerType() ); - if( unit ) - msgType = issueSpecialPowerCommand( command, type, draw, pos, unit ); - break; - } - case GUI_COMMAND_SPECIAL_POWER://lorenzen - msgType = issueSpecialPowerCommand( command, type, draw, pos, nullptr ); - break; - case GUI_COMMAND_FIRE_WEAPON: - msgType = issueFireWeaponCommand( command, type, draw, pos ); - break; - case GUI_COMMAND_COMBATDROP: - msgType = issueCombatDropCommand( command, type, draw, pos ); - break; - } - - // null out the GUI command if we're actually doing something - if( type == DO_COMMAND ) - { - TheInGameUI->setGUICommand( nullptr ); - } - - } - else - { - msgType = GameMessage::MSG_VALID_GUICOMMAND_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( objectID ); - } - } - else // not currently valid - { - msgType = GameMessage::MSG_INVALID_GUICOMMAND_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( objectID ); - } - - } - else if( command && (command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT - || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT_FROM_SHORTCUT) ) - { - //We're using the build placement interface to determine where to build our special power item. - //Because of that, we only care about DO_COMMAND. The context evaluation and hint feedback system - //is already taken care of. But what we need to do is trigger the special power to actually build - //the object and reset the timer. - if( type == DO_COMMAND ) - { - switch( command->getCommandType() ) - { - case GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT: - { - Object* unit = ThePlayerList->getLocalPlayer()->findMostReadyShortcutSpecialPowerOfType( command->getSpecialPowerTemplate()->getSpecialPowerType() ); - if( unit ) - msgType = issueSpecialPowerCommand( command, type, draw, pos, unit ); - break; - } - case GUI_COMMAND_SPECIAL_POWER://lorenzen - msgType = issueSpecialPowerCommand( command, type, draw, pos, nullptr ); - break; - } - } - } - - - // ******************************************************************************************** - else if( TheInGameUI->canSelectedObjectsOverrideSpecialPowerDestination( pos, InGameUI::SELECTION_ANY, SPECIAL_INVALID ) ) - { - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // do the command - msgType = GameMessage::MSG_DO_SPECIAL_POWER_OVERRIDE_DESTINATION; - if( type == DO_COMMAND ) - { - GameMessage *gameMsg = TheMessageStream->appendMessage( msgType ); - - gameMsg->appendLocationArgument( *pos ); - gameMsg->appendIntegerArgument( SPECIAL_INVALID ); - gameMsg->appendObjectIDArgument( INVALID_ID ); // no specific source - - } - - } - else - { - - // generate a hint message - msgType = GameMessage::MSG_DO_SPECIAL_POWER_OVERRIDE_DESTINATION_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - - } - } - - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_RESUME_CONSTRUCTION, obj, InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // do the command - msgType = GameMessage::MSG_RESUME_CONSTRUCTION; - if( type == DO_COMMAND ) - { - GameMessage *resumeMsg = TheMessageStream->appendMessage( msgType ); - - resumeMsg->appendObjectIDArgument( obj->getID() ); - - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_RESUME_CONSTRUCTION ); - - } - - } - else - { - - // generate a hint message - msgType = GameMessage::MSG_RESUME_CONSTRUCTION_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - - } - - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_DOCK_AT, - obj, - InGameUI::SELECTION_ALL ) ) - { - - // - // The actual logic is simply to AIUpdate::dock with the target, the hint is the - // only part that needs to be more specific. - // - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // Give the dock command - msgType = GameMessage::MSG_DOCK; - if( type == DO_COMMAND ) - { - GameMessage *dockMsg = TheMessageStream->appendMessage( msgType ); - - dockMsg->appendObjectIDArgument( obj->getID() ); - - // only make sounds if we really did the command messages - pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DOCK); - } - - } - else - { - - // make the hint - msgType = GameMessage::MSG_DOCK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - - } - - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_REPAIR_OBJECT, obj, InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // do the command - msgType = GameMessage::MSG_DO_REPAIR; - if( type == DO_COMMAND ) - { - GameMessage *healMsg = TheMessageStream->appendMessage( msgType ); - - healMsg->appendObjectIDArgument( obj->getID() ); - - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_REPAIR ); - - } - - } - else - { - - // generate a hint message - msgType = GameMessage::MSG_DO_REPAIR_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - - } - - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_GET_REPAIRED_AT, obj, InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // do the command - msgType = GameMessage::MSG_GET_REPAIRED; - if( type == DO_COMMAND ) - { - GameMessage *healMsg = TheMessageStream->appendMessage( msgType ); - - healMsg->appendObjectIDArgument( obj->getID() ); - - - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_GET_REPAIRED ); - - - } - - } - else - { - - // generate a hint message - msgType = GameMessage::MSG_GET_REPAIRED_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - - } - - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_GET_HEALED_AT, obj, InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // do the command - msgType = GameMessage::MSG_GET_HEALED; - if( type == DO_COMMAND ) - { - GameMessage *healMsg = TheMessageStream->appendMessage( msgType ); - - healMsg->appendObjectIDArgument( obj->getID() ); - - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_GET_HEALED ); - - } - - } - else - { - - // generate hint message - msgType = GameMessage::MSG_GET_HEALED_HINT; - hintMessage = TheMessageStream->appendMessage( msgType); - hintMessage->appendObjectIDArgument( obj->getID() ); - - } - - } - // ******************************************************************************************** - else if( draw && draw->getObject() && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_HIJACK_VEHICLE, - draw->getObject(), - InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // Now, this just tricks the AI into making the hijacker run towards the target vehicle - // I must add a test to keep him from actually entering an enemy vehicle (contained)... Lorenzen - msgType = createEnterMessage( draw, type ); - - } - else - { - - msgType = GameMessage::MSG_HIJACK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( draw->getObject()->getID() ); - - } - - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_CONVERT_OBJECT_TO_CARBOMB, obj, InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // issue the command (convert to carbomb is nearly identical to enter) - msgType = createEnterMessage( draw, type ); - - } - else - { - - msgType = GameMessage::MSG_CONVERT_TO_CARBOMB_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - - } - } - // ******************************************************************************************** - else if( draw && draw->getObject() && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_SABOTAGE_BUILDING, - draw->getObject(), - InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - msgType = createEnterMessage( draw, type ); - } - else - { - msgType = GameMessage::MSG_SABOTAGE_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( draw->getObject()->getID() ); - } - - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && canSelectionSalvage(obj) ) - { - GameMessage *msg; - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) { - msgType = GameMessage::MSG_DO_SALVAGE; - if (type == DO_COMMAND) { - msg = TheMessageStream->appendMessage(msgType); - msg->appendLocationArgument(*obj->getPosition()); - pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), msgType); - } - - } else { - msgType = GameMessage::MSG_DO_SALVAGE_HINT; - msg = TheMessageStream->appendMessage(msgType); - msg->appendLocationArgument(*obj->getPosition()); - } - - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_ENTER_OBJECT, obj, InGameUI::SELECTION_ANY, true ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // issue the command - msgType = createEnterMessage( draw, type ); - - } - else - { - - msgType = GameMessage::MSG_ENTER_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - } - - } - // ******************************************************************************************** - else if( draw && (result = TheInGameUI->getCanSelectedObjectsAttack( InGameUI::ACTIONTYPE_ATTACK_OBJECT, obj, InGameUI::SELECTION_ANY, TheInGameUI->isInForceAttackMode() )) == ATTACKRESULT_POSSIBLE ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // issue the attack order - msgType = issueAttackCommand( draw, type ); - - } - else - { - - // Generate an Attack hint - msgType = GameMessage::MSG_DO_ATTACK_OBJECT_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - - } - - } - // ******************************************************************************************** - else if( draw && result == ATTACKRESULT_POSSIBLE_AFTER_MOVING ) - { - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // issue the attack order - msgType = issueAttackCommand( draw, type ); - - } - else - { - - // Generate an Attack hint - msgType = GameMessage::MSG_DO_ATTACK_OBJECT_AFTER_MOVING_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - - } - - } - // ******************************************************************************************** - else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_CAPTURE_BUILDING, obj, InGameUI::SELECTION_ANY ) ) - { - - //@TODO: Kris - //PRELIMINARY CODE FOR HOOKING IN AUTO SPECIALS --- WILL BE REDONE! - Object *source = TheInGameUI->getFirstSelectedDrawable()->getObject(); - const CommandSet *set = TheControlBar->findCommandSet( source->getCommandSetString() ); - if( set ) - { - for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ ) - { - // get command button - const CommandButton *command = set->getCommandButton(i); - if( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER ) - { - SpecialPowerType spType = command->getSpecialPowerTemplate()->getSpecialPowerType(); - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - if( spType == SPECIAL_BLACKLOTUS_CAPTURE_BUILDING || - spType == SPECIAL_INFANTRY_CAPTURE_BUILDING ) - { - //Issue the capture building command - msgType = issueSpecialPowerCommand( command, type, draw, pos, nullptr ); - break; - } - } - else if( spType == SPECIAL_BLACKLOTUS_CAPTURE_BUILDING ) - { - //Issue the black lotus hack hint for capturing a building. - msgType = GameMessage::MSG_HACK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - } - else if( spType == SPECIAL_INFANTRY_CAPTURE_BUILDING ) - { - //Issue the infantry hint for capturing a building - msgType = GameMessage::MSG_CAPTUREBUILDING_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - } - } - } - } - } - // ******************************************************************************************** - else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_DISABLE_VEHICLE_VIA_HACKING, obj, InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - //@TODO: Kris - //PRELIMINARY CODE FOR HOOKING IN AUTO SPECIALS --- WILL BE REDONE! - Object *source = TheInGameUI->getFirstSelectedDrawable()->getObject(); - const CommandSet *set = TheControlBar->findCommandSet( source->getCommandSetString() ); - if( set ) - { - for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ ) - { - // get command button - const CommandButton *command = set->getCommandButton(i); - if( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER ) - { - SpecialPowerType spType = command->getSpecialPowerTemplate()->getSpecialPowerType(); - if( spType == SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK ) - { - msgType = issueSpecialPowerCommand( command, type, draw, pos, nullptr ); - break; - } - } - } - } - } - else - { - msgType = GameMessage::MSG_HACK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - } - - } - // ******************************************************************************************** - else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_STEAL_CASH_VIA_HACKING, obj, InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - //@TODO: Kris - //PRELIMINARY CODE FOR HOOKING IN AUTO SPECIALS --- WILL BE REDONE! - Object *source = TheInGameUI->getFirstSelectedDrawable()->getObject(); - const CommandSet *set = TheControlBar->findCommandSet( source->getCommandSetString() ); - if( set ) - { - for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ ) - { - // get command button - const CommandButton *command = set->getCommandButton(i); - if( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER ) - { - SpecialPowerType spType = command->getSpecialPowerTemplate()->getSpecialPowerType(); - if( spType == SPECIAL_BLACKLOTUS_STEAL_CASH_HACK ) - { - msgType = issueSpecialPowerCommand( command, type, draw, pos, nullptr ); - break; - } - } - } - } - } - else - { - msgType = GameMessage::MSG_HACK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - } - - } - // ******************************************************************************************** - else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_DISABLE_BUILDING_VIA_HACKING, obj, InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - //@TODO: Kris - //PRELIMINARY CODE FOR HOOKING IN AUTO SPECIALS --- WILL BE REDONE! - Object *source = TheInGameUI->getFirstSelectedDrawable()->getObject(); - const CommandSet *set = TheControlBar->findCommandSet( source->getCommandSetString() ); - if( set ) - { - for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ ) - { - // get command button - const CommandButton *command = set->getCommandButton(i); - if( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER ) - { - SpecialPowerType spType = command->getSpecialPowerTemplate()->getSpecialPowerType(); - if( spType == SPECIAL_HACKER_DISABLE_BUILDING ) - { - msgType = issueSpecialPowerCommand( command, type, draw, pos, nullptr ); - break; - } - } - } - } - } - else - { - msgType = GameMessage::MSG_HACK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - } - } -#ifdef ALLOW_SURRENDER - // ******************************************************************************************** - else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_PICK_UP_PRISONER, obj, InGameUI::SELECTION_ANY ) ) - { - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - - // issue the command - msgType = issueAttackCommand( draw, type, GUICOMMANDMODE_PICK_UP_PRISONER ); - - } - else - { - - msgType = GameMessage::MSG_PICK_UP_PRISONER_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - - } - - } -#endif - // ******************************************************************************************** - else if ( !draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_SET_RALLY_POINT, nullptr, InGameUI::SELECTION_ALL, FALSE )) - { - msgType = GameMessage::MSG_SET_RALLY_POINT; - - if (type == DO_COMMAND) { - const DrawableList *allSelectedDrawables = TheInGameUI->getAllSelectedDrawables(); - - for (DrawableList::const_iterator it = allSelectedDrawables->begin(); it != allSelectedDrawables->end(); ++it) { - Drawable *draw = (*it); - if (draw && draw->getObject()) { - GameMessage *newMsg = TheMessageStream->appendMessage(msgType); - newMsg->appendObjectIDArgument(draw->getObject()->getID()); - newMsg->appendLocationArgument(*pos); - } - } - } else if (type == DO_HINT) { - msgType = GameMessage::MSG_SET_RALLY_POINT_HINT; - hintMessage = TheMessageStream->appendMessage(msgType); - hintMessage->appendLocationArgument(*pos); - } - } - - // ******************************************************************************************** - else if( draw && result == ATTACKRESULT_INVALID_SHOT ) - { - msgType = GameMessage::MSG_IMPOSSIBLE_ATTACK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendLocationArgument( *pos ); - } - - // ******************************************************************************************** - else - { - - // - // NOTE: If you change this command evaluation function in what it will do - // if there is nothing picked ... you might want to edit the logic of the - // selection translator in that you can only select objects if there is - // no "interesting" command to do with the picked drawable ... which is determined - // by what we return in this function by default - // - - //Before we issue a move order or hint, check to see if we can even move there! - Bool validQuickPath = FALSE; - // Make sure to only to the check if the shroud is CLEARED. If it is fogged or shrouded, SKIP THE CHECK. jba [3/11/2003] - if( ThePartitionManager->getShroudStatusForPlayer( ThePlayerList->getLocalPlayer()->getPlayerIndex(), pos ) != CELLSHROUD_CLEAR ) - { - //If it's in the shroud, pretend we can move there -- skip the check. - validQuickPath = TRUE; - } - else - { - //Can we path there? - const DrawableList *allSelectedDrawables = TheInGameUI->getAllSelectedDrawables(); - for( DrawableList::const_iterator it = allSelectedDrawables->begin(); it != allSelectedDrawables->end(); ++it ) - { - Object *obj = (*it) ? (*it)->getObject() : nullptr; - AIUpdateInterface *ai = obj ? obj->getAI() : nullptr; - if( ai ) - { - if ( ai->isQuickPathAvailable( pos ) ) - { - validQuickPath = TRUE; - break; - } - // Wait! there are some units that CAN moveTo positions that Quickpath will reject, - // namely, Colonel Burton and the CombatBike. Both have CLIFF locomotors. - // We must detect whether the position is valid for these, before just invalidating the cursor, - // out of hand. - if ( ai->hasLocomotorForSurface( LOCOMOTORSURFACE_CLIFF ) ) - { - if ( TheTerrainLogic->isCliffCell( pos->x, pos->y ) ) - { - validQuickPath = TRUE;// yeah, not really quick, but you know... - break; - } - } - } - - - } - } - - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - // issue command - // Note: If draw is valid, then its one of ours and we don't have something more specific - // to do. Therefore, lets not issue a move command, and instead we'll return that there - // wasn't a command for us to perform. - - if ( draw == nullptr ) - msgType = issueMoveToLocationCommand( pos, drawableInWay, type ); - } - else - { - if( !validQuickPath ) - { - msgType = GameMessage::MSG_DO_INVALID_HINT; - } - else if( TheInGameUI->isInWaypointMode() ) - { - //Waypoint mode - msgType = GameMessage::MSG_ADD_WAYPOINT_HINT; - } - else if( TheInGameUI->isInAttackMoveToMode() ) - { - //THIS CODE WILL NEVER EVER GET CALLED! -- it's a context command now (READ: rip code out) - //Attack move - msgType = GameMessage::MSG_DO_ATTACKMOVETO_HINT; - } - else - { - //Normal and forced move. - msgType = GameMessage::MSG_DO_MOVETO_HINT; - } - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendLocationArgument( *pos ); - - } - - } - - } - - // return the message type - return msgType; - -} - - -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -//==================================================================================== -/** - * The Command Translator translates mouse events into object command messages - * such as move_to, attack, etc. - */ -GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage *msg) -{ - GameMessage::Type t = msg->getType(); - GameMessageDisposition disp = KEEP_MESSAGE; - // We want to always be able to get to the options menu even during no input times and a clear game data message should always go through - if (t != GameMessage::MSG_META_OPTIONS && t != GameMessage::MSG_CLEAR_GAME_DATA && - !TheInGameUI->getInputEnabled() && !isSystemMessage(msg)) - { - return DESTROY_MESSAGE; - } - -#if defined(RTS_DEBUG) - ExtentModType extentModType = EXTENTMOD_INVALID; - Real extentModAmount = 0.0f; -#endif - - switch (t) - { - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_SELECT_MATCHING_UNITS: - { - - TheInGameUI->selectUnitsMatchingCurrentSelection(); - - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_SELECT_NEXT_UNIT: - { - /* because list is prepended, iterate through backwards */ - - // if there is nothing on the screen, bail - if( TheGameClient->firstDrawable() == nullptr ) - break; - - // if nothing is selected - Drawable *temp; - - if( TheInGameUI->getSelectCount() == 0 ) - { - // get the last drawable - for( temp = TheGameClient->firstDrawable(); temp->getNextDrawable() != nullptr; temp = temp->getNextDrawable() ) - { - } - // temp is the last drawable - for( temp; temp != nullptr; temp = temp->getPrevDrawable() ) - { - const Object *object = temp->getObject(); - // if you've reached the end of the list, don't select anything - if( !object ) - { - break; - } - else if( object && object->isMobile() && object->isLocallyControlled() && !object->isContained() && !object->isKindOf( KINDOF_NO_SELECT ) ) - { - // create a new group. - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); - - //New group or add to group? Passed in value is true if we are creating a new group. - teamMsg->appendBooleanArgument( TRUE ); - - teamMsg->appendObjectIDArgument( object->getID() ); - - TheInGameUI->selectDrawable( temp ); - - // center on the unit - TheTacticalView->userLookAt(temp->getPosition()); - break; - } - } - } - else - { - Drawable *newDrawable = nullptr; - Bool hack = FALSE; - Drawable *selectedDrawable = TheInGameUI->getFirstSelectedDrawable(); - Object *selectedObject = selectedDrawable->getObject(); - if( selectedObject->isLocallyControlled() ) - { - // find the previous selectable drawable - temp = selectedDrawable->getPrevDrawable(); - //temp = selectedDrawable; - for( ; temp != selectedDrawable; temp = temp->getPrevDrawable() ) - { - if( hack == TRUE ) - { - temp = temp->getNextDrawable(); - hack = FALSE; - } - // if temp is null, set it to the last drawable and loop back to selected drawable - if( temp == nullptr ) - { - for(temp = selectedDrawable; temp->getNextDrawable() != nullptr; temp = temp->getNextDrawable() ) - { - } - hack = TRUE; - } - // else search for a previous selectable drawable - else - { - const Object *tempObject = temp->getObject(); - if( tempObject && tempObject->isMobile() && tempObject->isLocallyControlled() && !tempObject->isContained() && !tempObject->isKindOf( KINDOF_NO_SELECT ) ) - { - newDrawable = temp; - break; - //temp = selectedDrawable; // same as break - } - } - } - //if there is another selectable unit, select it - if(newDrawable != nullptr ) - { - //deselect other units - TheInGameUI->deselectAllDrawables(); - - // create a new group. - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); - - //New group or add to group? Passed in value is true if we are creating a new group. - teamMsg->appendBooleanArgument( TRUE ); - - teamMsg->appendObjectIDArgument( newDrawable->getObject()->getID() ); - - // select the unit - TheInGameUI->selectDrawable( newDrawable ); - - // center on the unit - TheTacticalView->userLookAt(newDrawable->getPosition()); - } - } - } - - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_SELECT_PREV_UNIT: - { - /* because list is prepended, iterate through forwards */ - - // if there is nothing on the screen, bail - if( TheGameClient->firstDrawable() == nullptr ) - break; - - Drawable *temp; - // if nothing is selected - if( TheInGameUI->getSelectCount() == 0 ) - { - // get the first drawable - temp = TheGameClient->firstDrawable(); - for( temp; temp != nullptr; temp = temp->getPrevDrawable() ) - { - const Object *object = temp->getObject(); - // if you've reached the end of the list, don't select anything - if( !object ) - { - break; - } - else if( object && object->isMobile() && object->isLocallyControlled() && !object->isContained() && !object->isKindOf( KINDOF_NO_SELECT ) ) - { - // create a new group. - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); - - //New group or add to group? Passed in value is true if we are creating a new group. - teamMsg->appendBooleanArgument( TRUE ); - - teamMsg->appendObjectIDArgument( object->getID() ); - - TheInGameUI->selectDrawable( temp ); - - // center on the unit - TheTacticalView->userLookAt(temp->getPosition()); - break; - } - } - } - else - { - Drawable *newDrawable = nullptr; - TheGameClient->getDrawableList(); - Bool hack = FALSE; // takes care of when for loop skips firstdrawable - Drawable *selectedDrawable = TheInGameUI->getFirstSelectedDrawable(); - Object *selectedObject = selectedDrawable->getObject(); - if( selectedObject->isLocallyControlled() ) - { - // find the next selectable drawable - temp = selectedDrawable->getNextDrawable(); - //temp = selectedDrawable; - for( temp; temp != selectedDrawable; temp = temp->getNextDrawable() ) - { - if( hack == TRUE ) - { - temp = TheGameClient->firstDrawable(); - hack = FALSE; - if( temp == selectedDrawable ) - { - break; - } - } - // if temp is null, set it to the first drawable and loop forward to selected drawable - if( temp == nullptr ) - { - temp = TheGameClient->firstDrawable(); - hack = TRUE; - const Object *tempObject = temp->getObject(); - // must take case of this case here or else the loop will break without getting newDrawable - if( tempObject && temp->getNextDrawable() == selectedDrawable && !temp->isSelected() - && tempObject->isMobile() && tempObject->isLocallyControlled() && !tempObject->isContained() && !tempObject->isKindOf( KINDOF_NO_SELECT ) ) - { - newDrawable = temp; - break; - } - } - // else search for a next selectable drawable - else - { - const Object *tempObject = temp->getObject(); - if( tempObject && !temp->isSelected() && tempObject->isMobile() && tempObject->isLocallyControlled() && !tempObject->isContained() ) - { - newDrawable = temp; - break; - } - } - } - //if there is another selectable unit, select it - if(newDrawable != nullptr ) - { - //deselect other units - TheInGameUI->deselectAllDrawables(); - // select the unit - - // create a new group. - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); - - //New group or add to group? Passed in value is true if we are creating a new group. - teamMsg->appendBooleanArgument( TRUE ); - - teamMsg->appendObjectIDArgument( newDrawable->getObject()->getID() ); - - TheInGameUI->selectDrawable( newDrawable ); - - // center on the unit - TheTacticalView->userLookAt(newDrawable->getPosition()); - } - } - } - - disp = DESTROY_MESSAGE; - break; - - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_SELECT_NEXT_WORKER: - { - /* because list is prepended, iterate through backwards */ - - // if there is nothing on the screen, bail - if( TheGameClient->firstDrawable() == nullptr ) - break; - - Drawable *temp; - // if nothing is selected - if( TheInGameUI->getSelectCount() == 0 ) - { - // get the last drawable - for( temp = TheGameClient->firstDrawable(); temp->getNextDrawable() != nullptr; temp = temp->getNextDrawable() ) - { - } - // temp is the last drawable - for( temp; temp != nullptr; temp = temp->getPrevDrawable() ) - { - const Object *object = temp->getObject(); - // if you've reached the end of the list, don't select anything - if( !object ) - { - break; - } - // make sure you select only workers - else if( object && object->isLocallyControlled() && !object->isContained() && object->isKindOf(KINDOF_DOZER) ) - { - // create a new group. - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); - //New group so pass in value true - teamMsg->appendBooleanArgument( TRUE ); - teamMsg->appendObjectIDArgument( object->getID() ); - TheInGameUI->selectDrawable( temp ); - - // play the units sound - AudioEventRTS soundEvent = *temp->getTemplate()->getVoiceSelect(); - soundEvent.setObjectID(object->getID()); - TheAudio->addAudioEvent( &soundEvent ); - - // center on the unit - TheTacticalView->userLookAt(temp->getPosition()); - break; - } - } - } - else - { - Drawable *newDrawable = nullptr; - Bool hack = FALSE; - Drawable *selectedDrawable = TheInGameUI->getFirstSelectedDrawable(); - Object *selectedObject = selectedDrawable->getObject(); - if( selectedObject->isLocallyControlled() ) - { - // find the previous selectable drawable - temp = selectedDrawable->getPrevDrawable(); - //temp = selectedDrawable; - for( ; temp != selectedDrawable; temp = temp->getPrevDrawable() ) - { - if( hack == TRUE ) - { - temp = temp->getNextDrawable(); - hack = FALSE; - } - // if temp is null, set it to the last drawable and loop back to selected drawable - if( temp == nullptr ) - { - for(temp = selectedDrawable; temp->getNextDrawable() != nullptr; temp = temp->getNextDrawable() ) - { - } - hack = TRUE; - } - // else search for a previous selectable drawable - else - { - const Object *tempObject = temp->getObject(); - if( tempObject && tempObject->isLocallyControlled() && !tempObject->isContained() && tempObject->isKindOf( KINDOF_DOZER ) ) - { - newDrawable = temp; - break; - //temp = selectedDrawable; // same as break - } - } - } - //if there is another selectable unit, select it - if(newDrawable != nullptr ) - { - //deselect other units - TheInGameUI->deselectAllDrawables(); - - // select the unit - // create a new group. - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); - - //New group so pass in value true - teamMsg->appendBooleanArgument( TRUE ); - teamMsg->appendObjectIDArgument( newDrawable->getObject()->getID() ); - TheInGameUI->selectDrawable( newDrawable ); - - // center on the unit - TheTacticalView->userLookAt(newDrawable->getPosition()); - } - } - } - - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_SELECT_PREV_WORKER: - { - /* because list is prepended, iterate through forwards */ - - // if there is nothing on the screen, bail - if( TheGameClient->firstDrawable() == nullptr ) - break; - - Drawable *temp; - // if nothing is selected - if( TheInGameUI->getSelectCount() == 0 ) - { - // get the first drawable - temp = TheGameClient->firstDrawable(); - for( temp; temp != nullptr; temp = temp->getPrevDrawable() ) - { - const Object *object = temp->getObject(); - // if you've reached the end of the list, don't select anything - if( !object ) - { - break; - } - else if( object && object->isMobile() && object->isLocallyControlled() && !object->isContained() && object->isKindOf( KINDOF_DOZER )) - { - // create a new group. - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); - - //New group or add to group? Passed in value is true if we are creating a new group. - teamMsg->appendBooleanArgument( TRUE ); - - teamMsg->appendObjectIDArgument( object->getID() ); - - TheInGameUI->selectDrawable( temp ); - - // center on the unit - TheTacticalView->userLookAt(temp->getPosition()); - break; - } - } - } - else - { - Drawable *newDrawable = nullptr; - TheGameClient->getDrawableList(); - Bool hack = FALSE; // takes care of when for loop skips firstdrawable - Drawable *selectedDrawable = TheInGameUI->getFirstSelectedDrawable(); - Object *selectedObject = selectedDrawable->getObject(); - if( selectedObject->isLocallyControlled() ) - { - // find the next selectable drawable - temp = selectedDrawable->getNextDrawable(); - //temp = selectedDrawable; - for( temp; temp != selectedDrawable; temp = temp->getNextDrawable() ) - { - if( hack == TRUE ) - { - temp = TheGameClient->firstDrawable(); - hack = FALSE; - if( temp == selectedDrawable ) - { - break; - } - } - // if temp is null, set it to the first drawable and loop forward to selected drawable - if( temp == nullptr ) - { - temp = TheGameClient->firstDrawable(); - hack = TRUE; - const Object *tempObject = temp->getObject(); - // must take case of this case here or else the loop will break without getting newDrawable - if( tempObject && temp->getNextDrawable() == selectedDrawable && !temp->isSelected() - && tempObject->isMobile() && tempObject->isLocallyControlled() && !tempObject->isContained() ) - { - newDrawable = temp; - break; - } - } - // else search for a next selectable drawable - else - { - const Object *tempObject = temp->getObject(); - if( tempObject && !temp->isSelected() && tempObject->isMobile() - && tempObject->isLocallyControlled() && !tempObject->isContained() && tempObject->isKindOf( KINDOF_DOZER ) ) - { - newDrawable = temp; - break; - } - } - } - //if there is another selectable unit, select it - if(newDrawable != nullptr ) - { - //deselect other units - TheInGameUI->deselectAllDrawables(); - // select the unit - - // create a new group. - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); - - //New group so passed in value true - teamMsg->appendBooleanArgument( TRUE ); - - teamMsg->appendObjectIDArgument( newDrawable->getObject()->getID() ); - - TheInGameUI->selectDrawable( newDrawable ); - - // center on the unit - TheTacticalView->userLookAt(newDrawable->getPosition()); - } - } - } - - disp = DESTROY_MESSAGE; - break; - - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_SELECT_NEXT_IDLE_WORKER: - { - TheInGameUI->selectNextIdleWorker(); - - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_SELECT_HERO: - { - // if there is nothing on the screen, bail - if( TheGameClient->firstDrawable() == nullptr ) - break; - - Object *hero = iNeedAHero(); - - if ( hero == nullptr ) - break; - - if ( hero->isContained() ) - hero = hero->getContainedBy(); - - Drawable *heroDraw = hero->getDrawable(); - - if ( heroDraw == nullptr ) - break; - - TheInGameUI->deselectAllDrawables(); - - // create a new group. - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); - - //New group so pass in value true - teamMsg->appendBooleanArgument( TRUE ); - teamMsg->appendObjectIDArgument( hero->getID() ); - TheInGameUI->selectDrawable( heroDraw ); - - // center on the unit - TheTacticalView->userLookAt(heroDraw->getPosition()); - - disp = DESTROY_MESSAGE; - break; - } - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_VIEW_COMMAND_CENTER: - viewCommandCenter(); - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_VIEW_LAST_RADAR_EVENT: - { - // You don't need radar for the space bar. That's silly. - Coord3D lastEvent; - - if( TheRadar->getLastEventLoc( &lastEvent ) ) - { - TheTacticalView->userLookAt( &lastEvent ); - } - - disp = DESTROY_MESSAGE; - break; - - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_SELECT_ALL: - case GameMessage::MSG_META_SELECT_ALL_AIRCRAFT: - { - KindOfMaskType requiredKindofs; - KindOfMaskType disqualifyingKindofs; - disqualifyingKindofs.set(KINDOF_DOZER); - disqualifyingKindofs.set(KINDOF_HARVESTER); - disqualifyingKindofs.set(KINDOF_IGNORES_SELECT_ALL); - Bool selectAircraft = FALSE; - - if( t == GameMessage::MSG_META_SELECT_ALL_AIRCRAFT ) - { - requiredKindofs.set(KINDOF_AIRCRAFT); - selectAircraft = TRUE; - } - - //Kris: Patch 1.03. We need to deselect all the units if any of the units we have selected - //are incompatible with the select all type we are triggering. This is a fix for the SCUDSTORM - //exploit. - const DrawableList *drawList = TheInGameUI->getAllSelectedDrawables(); - Drawable *draw; - for( DrawableListCIt it = drawList->begin(); it != drawList->end(); ++it ) - { - draw = *it; - if( selectAircraft && (draw->isAnyKindOf( disqualifyingKindofs ) || !draw->isKindOf( KINDOF_AIRCRAFT )) ) - { - TheInGameUI->deselectAllDrawables(); - break; - } - else if( !selectAircraft && (draw->isAnyKindOf( disqualifyingKindofs ) || draw->isKindOf( KINDOF_STRUCTURE )) ) - { - TheInGameUI->deselectAllDrawables(); - break; - } - } - - TheInGameUI->selectAllUnitsByType(requiredKindofs, disqualifyingKindofs); - - disp = DESTROY_MESSAGE; - break; - - - - - -/* - TheInGameUI->deselectAllDrawables(); - - GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP ); - // creating a new team so pass in true - teamMsg->appendBooleanArgument( TRUE ); - - // just loop through all the drawables in the world - Drawable *draw = TheGameClient->firstDrawable(); - - while( draw ) - { - const Object *object = draw->getObject(); - - //Only select the object if it is locally controlled and not contained by anything. - KindOfMaskType disqualifyingKindofs; - disqualifyingKindofs.set(KINDOF_DOZER); - disqualifyingKindofs.set(KINDOF_HARVESTER); - disqualifyingKindofs.set(KINDOF_IGNORES_SELECT_ALL); - if( object - && object->isMobile() - && object->isLocallyControlled() - && !object->isContained() - && !object->isAnyKindOf( disqualifyingKindofs ) - && !object->isEffectivelyDead() - && object->isMassSelectable() - ) - { - // enforce optional unit cap - if (TheInGameUI->getMaxSelectCount() > 0 && TheInGameUI->getSelectCount() >= TheInGameUI->getMaxSelectCount()) - { - if ( !TheInGameUI->getDisplayedMaxWarning() ) - { - TheInGameUI->setDisplayedMaxWarning( TRUE ); - TheInGameUI->message("GUI:MaxSelectionSize", TheInGameUI->getMaxSelectCount()); - } - } - else - { - TheInGameUI->selectDrawable(draw); - teamMsg->appendObjectIDArgument( draw->getObject()->getID() ); - TheInGameUI->setDisplayedMaxWarning( FALSE ); - } - } - - draw = draw->getNextDrawable(); - } - if( TheInGameUI->getSelectCount() ) - { - TheInGameUI->message("GUI:SelectedAcrossMap"); - } - - disp = DESTROY_MESSAGE; - break; -*/ - - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_SCATTER: - // This message always works on the currently selected team - TheMessageStream->appendMessage(GameMessage::MSG_DO_SCATTER); - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_STOP: - // This message always works on the currently selected team - TheMessageStream->appendMessage(GameMessage::MSG_DO_STOP); - - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_CREATE_FORMATION: - // This message always works on the currently selected team - TheMessageStream->appendMessage(GameMessage::MSG_CREATE_FORMATION); - - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEPLOY: - #ifdef RTS_DEBUG - DEBUG_CRASH(("unimplemented meta command MSG_META_DEPLOY !")); - #endif - /// @todo srj implement me - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_FOLLOW: - #ifdef RTS_DEBUG - DEBUG_CRASH(("unimplemented meta command MSG_META_FOLLOW !")); - #endif - /// @todo srj implement me - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - /* MDC - no such thing as chat to players right now - not until we have a diplomacy screen - case GameMessage::MSG_META_CHAT_PLAYERS: - if (TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInReplayGame()) - { - ToggleInGameChat(); - SetInGameChatType( INGAME_CHAT_PLAYERS ); - } - disp = DESTROY_MESSAGE; - break; - */ - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_CHAT_ALLIES: - if (TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInReplayGame()) - { - Player *localPlayer = ThePlayerList->getLocalPlayer(); - if ((localPlayer && localPlayer->isPlayerActive()) || !TheGlobalData->m_netMinPlayers) - { - ToggleInGameChat(); - SetInGameChatType( INGAME_CHAT_ALLIES ); - } - } - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_CHAT_EVERYONE: - if (TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInReplayGame()) - { - Player *localPlayer = ThePlayerList->getLocalPlayer(); - // TheSuperHackers @tweak skyaero 19/07/2025 Observers can now chat - if (localPlayer || !TheGlobalData->m_netMinPlayers) - { - ToggleInGameChat(); - SetInGameChatType( INGAME_CHAT_EVERYONE ); - } - } - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DIPLOMACY: - if (TheGameLogic->isInGame() && !TheGameLogic->isInShellGame()) - { - ToggleDiplomacy( FALSE ); - } - else if( TheShell && TheShell->isShellActive() && TheGameSpyBuddyMessageQueue) - GameSpyToggleOverlay(GSOVERLAY_BUDDY); - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_PLACE_BEACON: - if (TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInReplayGame() && - ThePlayerList->getLocalPlayer()->isPlayerActive() && - (TheGlobalData->m_netMinPlayers==0 || TheGameInfo->isMultiPlayer())) - { - Int count; - const ThingTemplate *thing = TheThingFactory->findTemplate( ThePlayerList->getLocalPlayer()->getPlayerTemplate()->getBeaconTemplate() ); - ThePlayerList->getLocalPlayer()->countObjectsByThingTemplate( 1, &thing, false, &count ); - DEBUG_LOG(("MSG_META_PLACE_BEACON - Player already has %d beacons active", count)); - if (count < TheMultiplayerSettings->getMaxBeaconsPerPlayer()) - { - const CommandButton *commandButton = TheControlBar->findCommandButton( "Command_PlaceBeacon" ); - TheInGameUI->setGUICommand( commandButton ); - } - } - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_REMOVE_BEACON: - if (TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInReplayGame()) - { - TheMessageStream->appendMessage( GameMessage::MSG_REMOVE_BEACON ); - } - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_OPTIONS: - - ToggleQuitMenu(); - disp = DESTROY_MESSAGE; - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_INCREASE_MAX_RENDER_FPS: - { - if (changeMaxRenderFps(FpsValueChange_Increase)) - { - disp = DESTROY_MESSAGE; - } - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DECREASE_MAX_RENDER_FPS: - { - if (changeMaxRenderFps(FpsValueChange_Decrease)) - { - disp = DESTROY_MESSAGE; - } - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_INCREASE_LOGIC_TIME_SCALE: - { - if (changeLogicTimeScale(FpsValueChange_Increase)) - { - disp = DESTROY_MESSAGE; - } - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DECREASE_LOGIC_TIME_SCALE: - { - if (changeLogicTimeScale(FpsValueChange_Decrease)) - { - disp = DESTROY_MESSAGE; - } - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_TOGGLE_LOWER_DETAILS: - { - if (TheGlobalData) - { - static Bool isLowDetails = FALSE; - static Bool oldShadowVolumsValue = TRUE; - static Bool oldLightMapValue = TRUE; - static Bool oldCloudMap = TRUE; - static Bool oldBehindBuildingMarkers = TRUE; - static Int oldMaxParticleCount = 0; - if(isLowDetails) - { - TheWritableGlobalData->m_useShadowVolumes = oldShadowVolumsValue; - TheWritableGlobalData->m_useLightMap = oldLightMapValue; - TheWritableGlobalData->m_useCloudMap = oldCloudMap; - TheWritableGlobalData->m_maxParticleCount = oldMaxParticleCount; - TheGameLogic->setShowBehindBuildingMarkers(oldBehindBuildingMarkers); - if(TheInGameUI) - TheInGameUI->message("GUI:ReturnGraphicsToPreviousSettings"); - } - else - { - oldShadowVolumsValue = TheGlobalData->m_useShadowVolumes; - TheWritableGlobalData->m_useShadowVolumes = FALSE; - - oldLightMapValue = TheGlobalData->m_useLightMap; - TheWritableGlobalData->m_useLightMap = FALSE; - - oldCloudMap = TheGlobalData->m_useCloudMap; - TheWritableGlobalData->m_useCloudMap = FALSE; - - oldBehindBuildingMarkers = TheGameLogic->getShowBehindBuildingMarkers(); - TheGameLogic->setShowBehindBuildingMarkers(FALSE); - - oldMaxParticleCount = TheGlobalData->m_maxParticleCount; - TheWritableGlobalData->m_maxParticleCount = DROPPED_MAX_PARTICLE_COUNT; - - if(TheInGameUI) - TheInGameUI->message("GUI:DetailsSetToLowest"); - } - } - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_TOGGLE_CONTROL_BAR: - { - if(TheShell->isShellActive()) - { - WindowLayout *win = TheShell->top(); - if(win) - { - win->hide(!win->isHidden()); - } - - } - else - { - Bool hide = false; - if (TheWindowManager) - { - Int id = (Int)TheNameKeyGenerator->nameToKey("ControlBar.wnd:ControlBarParent"); - GameWindow *window = TheWindowManager->winGetWindowFromId(nullptr, id); - - if (window) - hide = !window->winIsHidden(); - } - - ToggleControlBar(); - } - disp = DESTROY_MESSAGE; - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_TOGGLE_PLAYER_OBSERVER: - { - if (Player *lookAtPlayer = TheControlBar->getObserverLookAtPlayer()) - { - if (Player *observedPlayer = TheControlBar->getObservedPlayer()) - { - // Set no observed player. - rts::changeObservedPlayer(nullptr); - // But keep the look-at player. - TheControlBar->setObserverLookAtPlayer(lookAtPlayer); - } - else - { - // Set observed player to look-at player. - rts::changeObservedPlayer(lookAtPlayer); - } - disp = DESTROY_MESSAGE; - } - break; - } - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_TOGGLE_ATTACKMOVE: - TheInGameUI->toggleAttackMoveToMode(); - break; - - case GameMessage::MSG_META_BEGIN_CAMERA_ROTATE_LEFT: - DEBUG_ASSERTCRASH(!TheInGameUI->isCameraRotatingLeft(), ("Setting rotate camera left, but it's already set!")); - TheInGameUI->setCameraRotateLeft( true ); - break; - case GameMessage::MSG_META_END_CAMERA_ROTATE_LEFT: - DEBUG_ASSERTCRASH(TheInGameUI->isCameraRotatingLeft(), ("Clearing rotate camera left, but it's already clear!")); - TheInGameUI->setCameraRotateLeft( false ); - break; - case GameMessage::MSG_META_ALT_CAMERA_ROTATE_LEFT: - if (TheTacticalView->isCameraMovementFinished()) - TheTacticalView->rotateCamera(-1.0f / 8.0f, 500, 100, 400); - break; - case GameMessage::MSG_META_BEGIN_CAMERA_ROTATE_RIGHT: - DEBUG_ASSERTCRASH(!TheInGameUI->isCameraRotatingRight(), ("Setting rotate camera right, but it's already set!")); - TheInGameUI->setCameraRotateRight( true ); - break; - case GameMessage::MSG_META_END_CAMERA_ROTATE_RIGHT: - DEBUG_ASSERTCRASH(TheInGameUI->isCameraRotatingRight(), ("Clearing rotate camera right, but it's already clear!")); - TheInGameUI->setCameraRotateRight( false ); - break; - case GameMessage::MSG_META_ALT_CAMERA_ROTATE_RIGHT: - if (TheTacticalView->isCameraMovementFinished()) - TheTacticalView->rotateCamera(1.0f / 8.0f, 500, 100, 400); - break; - case GameMessage::MSG_META_BEGIN_CAMERA_ZOOM_IN: - DEBUG_ASSERTCRASH(!TheInGameUI->isCameraZoomingIn(), ("Setting zoom camera in, but it's already set!")); - TheInGameUI->setCameraZoomIn( true ); - break; - case GameMessage::MSG_META_END_CAMERA_ZOOM_IN: - DEBUG_ASSERTCRASH(TheInGameUI->isCameraZoomingIn(), ("Clearing zoom camera in, but it's already clear!")); - TheInGameUI->setCameraZoomIn( false ); - break; - case GameMessage::MSG_META_BEGIN_CAMERA_ZOOM_OUT: - DEBUG_ASSERTCRASH(!TheInGameUI->isCameraZoomingOut(), ("Setting zoom camera out, but it's already set!")); - TheInGameUI->setCameraZoomOut( true ); - break; - case GameMessage::MSG_META_END_CAMERA_ZOOM_OUT: - DEBUG_ASSERTCRASH(TheInGameUI->isCameraZoomingOut(), ("Clearing zoom camera out, but it's already clear!")); - TheInGameUI->setCameraZoomOut( false ); - break; - case GameMessage::MSG_META_CAMERA_RESET: - TheInGameUI->resetCamera(); - break; - case GameMessage::MSG_META_TOGGLE_CAMERA_TRACKING_DRAWABLE: - TheInGameUI->setCameraTrackingDrawable( true ); - break; - //-------------------------------------------------------------------------------------- - case GameMessage::MSG_META_TOGGLE_FAST_FORWARD_REPLAY: - { - if( TheGlobalData ) - { -#if !defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)//may be defined in GameCommon.h - if (TheGameLogic->isInReplayGame()) -#endif - { - TheWritableGlobalData->m_TiVOFastMode = 1 - TheGlobalData->m_TiVOFastMode; - TheInGameUI->messageNoFormat( TheGlobalData->m_TiVOFastMode - ? TheGameText->FETCH_OR_SUBSTITUTE("GUI:FF_ON", L"Fast Forward is on") - : TheGameText->FETCH_OR_SUBSTITUTE("GUI:FF_OFF", L"Fast Forward is off") - ); - } - } - - disp = DESTROY_MESSAGE; - break; - - } - case GameMessage::MSG_META_TOGGLE_PAUSE: - case GameMessage::MSG_META_TOGGLE_PAUSE_ALT: - { - if (!TheGameLogic->isInMultiplayerGame()) - { - if (TheGameLogic->isGamePaused()) - { - TheGameLogic->setGamePaused(FALSE); - } - else - { - Bool pause = TRUE; - Bool pauseMusic = FALSE; - Bool pauseInput = FALSE; - TheGameLogic->setGamePaused(pause, pauseMusic, pauseInput); - } - disp = DESTROY_MESSAGE; - } - break; - } - case GameMessage::MSG_META_STEP_FRAME: - case GameMessage::MSG_META_STEP_FRAME_ALT: - { - if (!TheGameLogic->isInMultiplayerGame()) - { - TheGameLogic->setGamePaused(FALSE); - TheGameLogic->setGamePausedInFrame(TheGameLogic->getFrame() + 1, TRUE); - disp = DESTROY_MESSAGE; - } - break; - } - -#if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)//may be defined in GameCommon.h - case GameMessage::MSG_CHEAT_RUNSCRIPT1: - case GameMessage::MSG_CHEAT_RUNSCRIPT2: - case GameMessage::MSG_CHEAT_RUNSCRIPT3: - case GameMessage::MSG_CHEAT_RUNSCRIPT4: - case GameMessage::MSG_CHEAT_RUNSCRIPT5: - case GameMessage::MSG_CHEAT_RUNSCRIPT6: - case GameMessage::MSG_CHEAT_RUNSCRIPT7: - case GameMessage::MSG_CHEAT_RUNSCRIPT8: - case GameMessage::MSG_CHEAT_RUNSCRIPT9: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - if( TheScriptEngine ) - { - Int script = t - GameMessage::MSG_CHEAT_RUNSCRIPT1 + 1; - AsciiString scriptName; - scriptName.format("KEY_F%d", script); - TheScriptEngine->runScript(scriptName); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugRunScript", L"Run script %d", script) ); - } - disp = DESTROY_MESSAGE; - } - break; - } - //-------------------------------------------------------------------------------------- - case GameMessage::MSG_CHEAT_TOGGLE_SPECIAL_POWER_DELAYS: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - if( TheGlobalData ) - { - - TheWritableGlobalData->m_specialPowerUsesDelay = 1 - TheGlobalData->m_specialPowerUsesDelay; - - if (TheGlobalData->m_specialPowerUsesDelay) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugSpecialPowerDelaysOn", L"Special Power (Superweapon) Delay is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugSpecialPowerDelaysOff", L"Special Power (Superweapon) Delay is OFF") ); - - } - - disp = DESTROY_MESSAGE; - } - break; - - } - //-------------------------------------------------------------------------------------- - case GameMessage::MSG_CHEAT_SWITCH_TEAMS: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - if (TheGameLogic->isInGame()) - { - Int idx; - for (Int i = 0; i < ThePlayerList->getPlayerCount(); i++) - { - if (ThePlayerList->getNthPlayer(i) == ThePlayerList->getLocalPlayer()) - { - idx = i; - break; - } - } - Int idxOrig = idx; - do - { - ++idx; - if (idx >= ThePlayerList->getPlayerCount()) - idx = 0; - - if (idx == idxOrig) - break; - - } while (ThePlayerList->getNthPlayer(idx) == ThePlayerList->getNeutralPlayer()); - - Player* player = ThePlayerList->getNthPlayer(idx); - rts::changeLocalPlayer(player); - } - disp = DESTROY_MESSAGE; - } - break; - } - //-------------------------------------------------------------------------------------- - case GameMessage::MSG_CHEAT_KILL_SELECTION: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - // THIS CALLS THE STANDARD DEBUG MESSAGE, WHICH IS CALLED: - TheMessageStream->appendMessage( GameMessage::MSG_DEBUG_KILL_SELECTION ); - disp = DESTROY_MESSAGE; - } - break; - } - case GameMessage::MSG_CHEAT_INSTANT_BUILD: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - // Doesn't make a valid network message - Player *localPlayer = ThePlayerList->getLocalPlayer(); - localPlayer->toggleInstantBuild(); - - if (localPlayer->buildsInstantly()) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugInstantBuildOn", L"Instant Build is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugInstantBuildOff", L"Instant Build is OFF") ); - - disp = DESTROY_MESSAGE; - } - break; - } - case GameMessage::MSG_CHEAT_ADD_CASH: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - Player *localPlayer = ThePlayerList->getLocalPlayer(); - Money *money = localPlayer->getMoney(); - money->deposit( 10000 ); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugAddCash", L"Add Cash") ); - } - break; - } - case GameMessage::MSG_CHEAT_GIVE_ALL_SCIENCES: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - Player *player = ThePlayerList->getLocalPlayer(); - if (player) - { - giveAllSciences(player); - } - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugGiveAllSciences", L"Granting all sciences!" ) ); - disp = DESTROY_MESSAGE; - } - break; - } - case GameMessage::MSG_CHEAT_GIVE_SCIENCEPURCHASEPOINTS: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - Player *player = ThePlayerList->getLocalPlayer(); - if (player) - player->addSciencePurchasePoints(1); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugGiveSciencePurchasePoint", L"Adding a SciencePurchasePoint" ) ); - disp = DESTROY_MESSAGE; - } - break; - } - case GameMessage::MSG_CHEAT_SHOW_HEALTH: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - TheWritableGlobalData->m_showObjectHealth = 1 - TheGlobalData->m_showObjectHealth; - - if (TheGlobalData->m_showObjectHealth) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugObjectHealthOn", L"Object Health is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugObjectHealthOff", L"Object Health is OFF") ); - } - break; - - } - case GameMessage::MSG_CHEAT_TOGGLE_MESSAGE_TEXT: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - - // toggle the message state - TheInGameUI->toggleMessages(); - - // when messages get turned on, display a message - if( TheInGameUI->isMessagesOn() ) - TheInGameUI->message("GUI:MessagesOn"); - - disp = DESTROY_MESSAGE; - } - break; - - } - - -#endif - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_BEGIN_FORCEMOVE: - DEBUG_ASSERTCRASH(!TheInGameUI->isInForceMoveToMode(), ("forceMoveToMode mismatch")); - TheInGameUI->setForceMoveMode( true ); - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_END_FORCEMOVE: - DEBUG_ASSERTCRASH(TheInGameUI->isInForceMoveToMode(), ("forceMoveToMode mismatch")); - TheInGameUI->setForceMoveMode( false ); - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_BEGIN_WAYPOINTS: -// DEBUG_ASSERTCRASH( !TheInGameUI->isInWaypointMode(), ("Setting m_waypointMode but it's already set!") ); - TheInGameUI->setWaypointMode( true ); - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_BEGIN_PREFER_SELECTION: - TheInGameUI->setPreferSelectionMode( true ); - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_END_PREFER_SELECTION: - TheInGameUI->setPreferSelectionMode( false ); - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_END_WAYPOINTS: -// DEBUG_ASSERTCRASH( TheInGameUI->isInWaypointMode(), ("Clearing m_waypointMode but it's already clear!") ); - TheInGameUI->setWaypointMode( false ); - break; - - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_BEGIN_FORCEATTACK: - TheInGameUI->setForceAttackMode( true ); - break; - - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_END_FORCEATTACK: - TheInGameUI->setForceAttackMode( false ); - break; - - // -------------------------------------------------------------------------------------------- - case GameMessage::MSG_META_ALL_CHEER: - { - if ( TheGameLogic->isInMultiplayerGame() ) - { - TheAudio->addAudioEvent(&TheAudio->getMiscAudio()->m_allCheerSound); - disp = DESTROY_MESSAGE; - TheMessageStream->appendMessage( GameMessage::MSG_DO_CHEER ); - } - break; - } - - // -------------------------------------------------------------------------------------------- - case GameMessage::MSG_META_TAKE_SCREENSHOT: - { - if (TheDisplay) - TheDisplay->takeScreenShot(); - disp = DESTROY_MESSAGE; - break; - } - - // -------------------------------------------------------------------------------------------- - case GameMessage::MSG_CREATE_SELECTED_GROUP: - case GameMessage::MSG_SELECT_TEAM0: - case GameMessage::MSG_SELECT_TEAM1: - case GameMessage::MSG_SELECT_TEAM2: - case GameMessage::MSG_SELECT_TEAM3: - case GameMessage::MSG_SELECT_TEAM4: - case GameMessage::MSG_SELECT_TEAM5: - case GameMessage::MSG_SELECT_TEAM6: - case GameMessage::MSG_SELECT_TEAM7: - case GameMessage::MSG_SELECT_TEAM8: - case GameMessage::MSG_SELECT_TEAM9: - { - // weed out unit responses for things we don't own. - DrawableList listOfUnits = *TheInGameUI->getAllSelectedDrawables(); - for (DrawableListIt it = listOfUnits.begin(); it != listOfUnits.end(); /* empty */) { - Drawable *draw = *it; - if (draw->getObject() && draw->getObject()->isLocallyControlled()) { - // This thing can emit a unit response. - ++it; - continue; - } else { - // remove it. - it = listOfUnits.erase(it); - } - } - if (!listOfUnits.empty()) { - pickAndPlayUnitVoiceResponse( &listOfUnits, GameMessage::MSG_CREATE_SELECTED_GROUP ); - } - - m_teamExists = true; - break; - } - - // -------------------------------------------------------------------------------------------- - case GameMessage::MSG_CREATE_SELECTED_GROUP_NO_SOUND: - case GameMessage::MSG_ADD_TEAM0: - case GameMessage::MSG_ADD_TEAM1: - case GameMessage::MSG_ADD_TEAM2: - case GameMessage::MSG_ADD_TEAM3: - case GameMessage::MSG_ADD_TEAM4: - case GameMessage::MSG_ADD_TEAM5: - case GameMessage::MSG_ADD_TEAM6: - case GameMessage::MSG_ADD_TEAM7: - case GameMessage::MSG_ADD_TEAM8: - case GameMessage::MSG_ADD_TEAM9: - { - m_teamExists = true; - break; - } - - - // -------------------------------------------------------------------------------------------- - case GameMessage::MSG_DESTROY_SELECTED_GROUP: - { - m_teamExists = false; - break; - } - - // -------------------------------------------------------------------------------------------- - // An object is mouseover'd. A hint of a command may be generated if something is selected - // -------------------------------------------------------------------------------------------- - case GameMessage::MSG_MOUSEOVER_DRAWABLE_HINT: - { - const CommandButton *command = TheInGameUI->getGUICommand(); - if( TheInGameUI->getSelectCount() > 0 - || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT) ) // If something is selected - { - /// @todo This as well as the one in GameMessage::MSG_DRAWABLE_PICKED below should possibly have a generalized CanAttack instead of simply checking isEnemyOf - Drawable *draw = TheGameClient->findDrawableByID( msg->getArgument( 0 )->drawableID ); - if( draw ) - { - - // - // given the drawable that we have moused over, pretend that we have actually - // "picked" that drawable, depending on what we have selected, our mode, - // and what "picked" is we would do a command ... but here we only will generate - // the hint message, *not* the actual command - // - if (TheInGameUI->isInForceAttackMode()) { - evaluateForceAttack(draw, draw->getPosition(), DO_HINT ); - } else { - evaluateContextCommand( draw, draw->getPosition(), DO_HINT ); - } - - // Do not eat this message, as it itself has another purpose in HintSpy - - } - } - } - break; - - //----------------------------------------------------------------------------- - // Terrain is mouseover'd. A hint of a command may be generated if something is selected - // - case GameMessage::MSG_MOUSEOVER_LOCATION_HINT: - { - Coord3D position = msg->getArgument( 0 )->location; - - // - // This message occurs whenever the mouse cursor moves off of a drawable, in which - // case we want to turn off the pick hint. - // - if (TheInGameUI->isInForceAttackMode()) { - evaluateForceAttack( nullptr, &position, DO_HINT ); - } else { - evaluateContextCommand( nullptr, &position, DO_HINT ); - } - - // Do not eat this message, as it will do something itself at HintSpy - break; - - } - - //----------------------------------------------------------------------------- - // TheSuperHackers @bugfix Treat the raw double click event identical to the raw button down event - // because it implicitly is a raw button down event as well. Failing to do so would mess with the - // button timings in later events on button up. - case GameMessage::MSG_RAW_MOUSE_RIGHT_DOUBLE_CLICK: - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN: - { - // There are two ways in which we can ignore this as a deselect: - // 1) 2-D position on screen - // 2) Time has exceeded the time which we allow for this to be a click. - m_mouseRightDragAnchor = msg->getArgument( 0 )->pixel; - m_mouseRightDown = (UnsignedInt) msg->getArgument( 2 )->integer; - - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: - { - // register this event for determining if the click was fast or short enough not to be a drag - m_mouseRightDragLift = msg->getArgument( 0 )->pixel; - m_mouseRightUp = (UnsignedInt) msg->getArgument( 2 )->integer; - - //Kris: July 7, 2003. Added this code to deselect build placement mode when right clicked. This fixes - //a bug where you couldn't cancel the sneak attack mode via right click. This only happened when you - //didn't have anything selected which is possible via the shortcut bar. Normally, it would get deselected - //via the deselect drawable code. - if( TheMouse->isClick(&m_mouseRightDragAnchor, &m_mouseRightDragLift, m_mouseRightDown, m_mouseRightUp) ) - { - TheInGameUI->placeBuildAvailable( nullptr, nullptr ); - } - - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_MOUSE_RIGHT_DOUBLE_CLICK: - { - if( TheGlobalData->m_useAlternateMouse && TheGlobalData->m_doubleClickAttackMove ) - { - // create the message and append arguments for a guard location - GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); - Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); - newMsg->appendLocationArgument(pos); - newMsg->appendIntegerArgument(GUARDMODE_NORMAL); - - ThePlayerList->getLocalPlayer()->getAcademyStats()->recordDoubleClickAttackMoveOrderGiven(); - - TheInGameUI->triggerDoubleClickAttackMoveGuardHint(); - - break; - } - FALLTHROUGH; //intentional fall through - } - case GameMessage::MSG_MOUSE_RIGHT_CLICK: - { - // right click is only actioned here if we're in alternate mouse mode - if (TheGlobalData->m_useAlternateMouse - && TheMouse->isClick(&m_mouseRightDragAnchor, &m_mouseRightDragLift, m_mouseRightDown, m_mouseRightUp)) - { - Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); - - // NOTE: RIGHT_CLICK is not transmitted if AREA_SELECTION or DRAWABLE_PICKED occurs. - // If we see this msg, no object was clicked on, therefore clicked on ground. - // Issue move command to all currently selected objects. - - // sanity - if( TheTacticalView == nullptr ) - break; - - // translate from screen coordinates to terrain coords - Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); - - const CommandButton *command = TheInGameUI->getGUICommand(); - Bool controllable = TheInGameUI->areSelectedObjectsControllable() - || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT); - if (isPoint && controllable) - { - UnsignedInt pickType = getPickTypesForContext( TheInGameUI->isInForceAttackMode() ); - Drawable *draw = TheTacticalView->pickDrawable(&msg->getArgument(0)->pixelRegion.lo, - TheInGameUI->isInForceAttackMode(), - (PickType) pickType); - - // TheSuperHackers @bugfix Stubbjax 07/08/2025 Prevent dead units blocking positional context commands - Object* obj = draw ? draw->getObject() : nullptr; - if (!obj || (obj->isEffectivelyDead() && !obj->isKindOf(KINDOF_ALWAYS_SELECTABLE))) - { - draw = nullptr; - } - - if (TheInGameUI->isInForceAttackMode()) { - evaluateForceAttack( draw, &pos, DO_COMMAND ); - } else { - evaluateContextCommand( draw, &pos, DO_COMMAND ); - } - - disp = DESTROY_MESSAGE; - TheInGameUI->clearAttackMoveToMode(); - } - } - - break; - } - - //----------------------------------------------------------------------------- - case GameMessage::MSG_MOUSE_LEFT_DOUBLE_CLICK: - { - if( !TheGlobalData->m_useAlternateMouse && TheGlobalData->m_doubleClickAttackMove ) - { - // create the message and append arguments for a guard location - GameMessage *newMsg = TheMessageStream->appendMessage( GameMessage::MSG_DO_GUARD_POSITION ); - Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); - newMsg->appendLocationArgument(pos); - newMsg->appendIntegerArgument(GUARDMODE_NORMAL); - - ThePlayerList->getLocalPlayer()->getAcademyStats()->recordDoubleClickAttackMoveOrderGiven(); - - TheInGameUI->triggerDoubleClickAttackMoveGuardHint(); - - break; - } - FALLTHROUGH; //intentional fall through - } - case GameMessage::MSG_MOUSE_LEFT_CLICK: - { - Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); - - // NOTE: LEFT_CLICK is not transmitted if AREA_SELECTION or DRAWABLE_PICKED occurs. - // If we see this msg, no object was clicked on, therefore clicked on ground. - // Issue move command to all currently selected objects. - - // sanity - if( TheTacticalView == nullptr ) - break; - - // translate from screen coordinates to terrain coords - Coord3D pos; - TheTacticalView->screenToTerrain( &msg->getArgument( 0 )->pixel, &pos ); - - const CommandButton *command = TheInGameUI->getGUICommand(); - // maintain this as the list of GUI button initiated commands that fire with left click in alt mouse mode - Bool isFiringGUICommand = (command && (command->getCommandType() == GUI_COMMAND_SPECIAL_POWER - || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT - || command->getCommandType() == GUI_COMMAND_FIRE_WEAPON - || command->getCommandType() == GUI_COMMAND_COMBATDROP - || command->getCommandType() == GUICOMMANDMODE_HIJACK_VEHICLE - || command->getCommandType() == GUICOMMANDMODE_CONVERT_TO_CARBOMB)); - - // in alternate mouse mode, this left click is only actioned here if we're firing a gui command - if ((TheGlobalData->m_useAlternateMouse) && (! isFiringGUICommand)) - break; - - Bool controllable = TheInGameUI->areSelectedObjectsControllable() - || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT); - if (isPoint && controllable) - { - UnsignedInt pickType = getPickTypesForContext( TheInGameUI->isInForceAttackMode() ); - Drawable *draw = TheTacticalView->pickDrawable(&msg->getArgument(0)->pixelRegion.lo, - TheInGameUI->isInForceAttackMode(), - (PickType) pickType); - - // TheSuperHackers @bugfix Stubbjax 07/08/2025 Prevent dead units blocking positional context commands - Object* obj = draw ? draw->getObject() : nullptr; - if (!obj || (obj->isEffectivelyDead() && !obj->isKindOf(KINDOF_ALWAYS_SELECTABLE))) - { - draw = nullptr; - } - - if (TheInGameUI->isInForceAttackMode()) { - evaluateForceAttack( draw, &pos, DO_COMMAND ); - } else { - evaluateContextCommand( draw, &pos, DO_COMMAND ); - } - - disp = DESTROY_MESSAGE; - TheInGameUI->clearAttackMoveToMode(); - - //issueMoveToLocationCommand( &pos, draw, DO_COMMAND ); - } - break; - - } - - case GameMessage::MSG_META_DEMO_INSTANT_QUIT: - { - TheGameLogic->quit(TRUE); - disp = DESTROY_MESSAGE; - break; - } - -#if defined(RTS_DEBUG) - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_SWITCH_TEAMS: - { - if (TheGameLogic->isInGame()) - { - Int idx; - for (Int i = 0; i < ThePlayerList->getPlayerCount(); i++) - { - if (ThePlayerList->getNthPlayer(i) == ThePlayerList->getLocalPlayer()) - { - idx = i; - break; - } - } - Int idxOrig = idx; - do - { - - ++idx; - if (idx >= ThePlayerList->getPlayerCount()) - idx = 0; - - if (idx == idxOrig) - { - break; - } - - } while (ThePlayerList->getNthPlayer(idx) == ThePlayerList->getNeutralPlayer()); - - Player* player = ThePlayerList->getNthPlayer(idx); - rts::changeLocalPlayer(player); - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_SWITCH_TEAMS_BETWEEN_CHINA_USA: - { - Player *p = ThePlayerList->getLocalPlayer(); - AsciiString side; - side.set(p->getSide()); - - if(side.compareNoCase("America") == 0) - { - for (Int i = 0; i < ThePlayerList->getPlayerCount(); i++) - { - Player *pt = ThePlayerList->getNthPlayer(i); - if(pt->getSide().compareNoCase("China") == 0) - { - rts::changeLocalPlayer(pt); - break; - } - } - } - - if(side.compareNoCase("China") == 0) - { - for (Int i = 0; i < ThePlayerList->getPlayerCount(); i++) - { - Player *pt = ThePlayerList->getNthPlayer(i); - if(pt->getSide().compareNoCase("America") == 0) - { - rts::changeLocalPlayer(pt); - break; - } - } - } - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_LOD_DECREASE: - { - const Int level = clamp(0, WW3D::Get_Texture_Reduction() - 1, 4); - TheGameClient->setTextureLOD(level); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugDecreaseLOD", L"Decrease LOD") ); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_LOD_INCREASE: - { - const Int level = clamp(0, WW3D::Get_Texture_Reduction() + 1, 4); - TheGameClient->setTextureLOD(level); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugIncreaseLOD", L"Increase LOD") ); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_HELP: - { - // for demo, they don't want the help menu showing up. I left this as a block comment because we - // might want to add back in the help menu at some point in time. -/* - if (TheWindowManager && TheNameKeyGenerator) - { - GameWindow *motd = TheWindowManager->winGetWindowFromId(nullptr, (Int)TheNameKeyGenerator->nameToKey("MOTD.wnd:MOTD")); - if (motd) - motd->winHide(!motd->winIsHidden()); - }*/ - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_BEHIND_BUILDINGS: - { - if (TheGlobalData) - { - - if(TheGameLogic->getShowBehindBuildingMarkers()) - { - TheGameLogic->setShowBehindBuildingMarkers(FALSE); - TheInGameUI->message("GUI:ShowBehindBuildings"); - } - else - { - TheGameLogic->setShowBehindBuildingMarkers(TRUE); - TheInGameUI->message("GUI:HideBehindBuildings"); - } - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_LETTERBOX: - { - if(TheShell->isShellActive()) - { - WindowLayout *win = TheShell->top(); - if(win) - { - win->hide(!win->isHidden()); - } - - } - else - { - Bool hide = false; - if (TheWindowManager) - { - Int id = (Int)TheNameKeyGenerator->nameToKey("ControlBar.wnd:ControlBarParent"); - GameWindow *window = TheWindowManager->winGetWindowFromId(nullptr, id); - - if (window) - hide = !window->winIsHidden(); - } - - if (hide) - HideControlBar(); - else - ShowControlBar(FALSE); - TheDisplay->toggleLetterBox(); - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_MESSAGE_TEXT: - { - - // toggle the message state - TheInGameUI->toggleMessages(); - - // when messages get turned on, display a message - if( TheInGameUI->isMessagesOn() ) - TheInGameUI->message("GUI:MessagesOn"); - - disp = DESTROY_MESSAGE; - break; - - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_MOTION_BLUR_ZOOM: - { Int mode; - if ((mode=TheTacticalView->getViewFilterType()) == FT_VIEW_MOTION_BLUR_FILTER) - { //mode already set, turn it off - TheTacticalView->setViewFilterMode(FM_NULL_MODE); - TheTacticalView->setViewFilter(FT_NULL_FILTER); - } - else - { - static Bool saturate = false; - FilterModes mode = FM_VIEW_MB_IN_AND_OUT_ALPHA; - if (saturate) { - mode = FM_VIEW_MB_IN_AND_OUT_SATURATE; - } - if (TheTacticalView->getCameraLock()!=0) { - mode = FM_VIEW_MB_PAN_ALPHA; - } - saturate = !saturate; - Coord3D curpos = TheTacticalView->getPosition(); - curpos.x += 200; - curpos.y += 200; - TheTacticalView->setViewFilterPos(&curpos); - - TheTacticalView->setViewFilterMode(mode); - TheTacticalView->setViewFilter(FT_VIEW_MOTION_BLUR_FILTER); - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_BW_VIEW: - { //We're not testing BW mode anymore, so use this message for toggling wireframe mode. - static Int mode=0; - if (mode == 0) - { //First turn on wireframe - TheTacticalView->set3DWireFrameMode(TRUE); - mode++; - disp = DESTROY_MESSAGE; - break; - } - if (mode == 1) - { - if ((TheTacticalView->getViewFilterType()) == FT_VIEW_CROSSFADE) - { //mode already set, turn it off - TheTacticalView->setViewFilterMode(FM_NULL_MODE); - TheTacticalView->setViewFilter(FT_NULL_FILTER); - TheTacticalView->setFadeParameters(0,-1); - } - else - { - TheScriptEngine->doFreezeTime(); - - //TheTacticalView->setViewFilterMode(FM_VIEW_CROSSFADE_CIRCLE); - TheTacticalView->setViewFilterMode(FM_VIEW_CROSSFADE_FB_MASK); - TheTacticalView->setViewFilter(FT_VIEW_CROSSFADE); - TheTacticalView->setFadeParameters(60,-1); - TheTacticalView->set3DWireFrameMode(FALSE); - mode++; - } - } - else - if (mode == 2) - { - TheScriptEngine->doUnfreezeTime(); - mode=0; //reset everything - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_RED_VIEW: - { - if ((TheTacticalView->getViewFilterType()) == FT_VIEW_BW_FILTER) - { //mode already set, turn it off - TheTacticalView->setViewFilterMode(FM_NULL_MODE); - TheTacticalView->setViewFilter(FT_NULL_FILTER); - TheTacticalView->setFadeParameters(30,-1); - } - else - { - TheTacticalView->setViewFilterMode(FM_VIEW_BW_RED_AND_WHITE); - TheTacticalView->setViewFilter(FT_VIEW_BW_FILTER); - TheTacticalView->setFadeParameters(30,1); - } - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_GREEN_VIEW: - { - if ((TheTacticalView->getViewFilterType()) == FT_VIEW_BW_FILTER) - { //mode already set, turn it off - TheTacticalView->setViewFilterMode(FM_NULL_MODE); - TheTacticalView->setViewFilter(FT_NULL_FILTER); - TheTacticalView->setFadeParameters(30,-1); - } - else - { - TheTacticalView->setViewFilterMode(FM_VIEW_BW_GREEN_AND_WHITE); - TheTacticalView->setViewFilter(FT_VIEW_BW_FILTER); - TheTacticalView->setFadeParameters(30,1); - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_CYCLE_LOD_LEVEL: - { - static Int level=DYNAMIC_GAME_LOD_VERY_HIGH; - - level--; - - if (level < DYNAMIC_GAME_LOD_LOW) - level = DYNAMIC_GAME_LOD_VERY_HIGH; - - TheGameLODManager->setDynamicLODLevel((DynamicGameLODLevel)level); - - const char* lodLevelName = TheGameLODManager->getDynamicGameLODLevelName((DynamicGameLODLevel)level); - TheInGameUI->message( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugDynamicLODLevel", L"Dynamic Game Detail %hs", lodLevelName) ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_DUMP_ASSETS: - { - TheDisplay->dumpModelAssets("UsedMapAssets.txt"); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_SHADOW_VOLUMES: - { - TheWritableGlobalData->m_useShadowVolumes = !TheGlobalData->m_useShadowVolumes; - TheWritableGlobalData->m_useShadowDecals = !TheGlobalData->m_useShadowDecals; - - if (TheWritableGlobalData->m_useShadowVolumes) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugShadowVolumesOn", L"Shadow Volumes is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugShadowVolumesOff", L"Shadow Volumes is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_FOGOFWAR: - { - TheWritableGlobalData->m_fogOfWarOn = !TheGlobalData->m_fogOfWarOn; - - if (TheWritableGlobalData->m_fogOfWarOn) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugFogOfWarOn", L"Fog of War is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugFogOfWarOff", L"Fog of War is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_KILL_SELECTION: - { - TheMessageStream->appendMessage( GameMessage::MSG_DEBUG_KILL_SELECTION ); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_KILL_ALL_ENEMIES: - { - for (Drawable *d = TheGameClient->firstDrawable(); d; d = d->getNextDrawable()) - { - Object* obj = d->getObject(); - if (obj && obj->getControllingPlayer() && obj->getControllingPlayer()->getRelationship(ThePlayerList->getLocalPlayer()->getDefaultTeam()) == ENEMIES) - { - obj->kill(); - } - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_GIVE_VETERANCY: - case GameMessage::MSG_META_DEBUG_TAKE_VETERANCY: - { - if (TheGameLogic->isInMultiplayerGame()) - break; - - const DrawableList *list = TheInGameUI->getAllSelectedDrawables(); - for (DrawableListCIt it = list->begin(); it != list->end(); ++it) - { - Drawable *pDraw = *it; - if (!pDraw) - continue; - - Object *pObject = pDraw->getObject(); - if (!pObject) - continue; - - ExperienceTracker *et = pObject->getExperienceTracker(); - if (!et || !et->isTrainable()) - continue; - - VeterancyLevel oldVet = et->getVeterancyLevel(); - VeterancyLevel newVet = oldVet; - - if (t == GameMessage::MSG_META_DEBUG_GIVE_VETERANCY) - { - if (oldVet < LEVEL_LAST) - { - newVet = (VeterancyLevel)((Int)oldVet + 1); - } - } - else - { - if (oldVet > LEVEL_FIRST) - { - newVet = (VeterancyLevel)((Int)oldVet - 1); - } - } - - et->setVeterancyLevel(newVet); - } - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_INCR_ANIM_SKATE_SPEED: - { - TheSkateDistOverride += 0.25f; - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugAnimSkateSpeed", L"Skate Distance Override is now %f", TheSkateDistOverride ) ); - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_DECR_ANIM_SKATE_SPEED: - { - TheSkateDistOverride -= 0.25f; - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugAnimSkateSpeed", L"Skate Distance Override is now %f", TheSkateDistOverride ) ); - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_CYCLE_EXTENT_TYPE: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_TYPE; - if (!extentModAmount) extentModAmount = 1.0f; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MAJOR: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MAJOR; - if (!extentModAmount) extentModAmount = 1.0f; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MAJOR_BIG: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MAJOR; - if (!extentModAmount) extentModAmount = EXTENT_BIG_CHANGE; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MAJOR: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MAJOR; - if (!extentModAmount) extentModAmount = -1.0f; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MAJOR_BIG: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MAJOR; - if (!extentModAmount) extentModAmount = -EXTENT_BIG_CHANGE; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MINOR: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MINOR; - if (!extentModAmount) extentModAmount = 1.0f; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_MINOR_BIG: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MINOR; - if (!extentModAmount) extentModAmount = EXTENT_BIG_CHANGE; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MINOR: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MINOR; - if (!extentModAmount) extentModAmount = -1.0f; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_MINOR_BIG: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_MINOR; - if (!extentModAmount) extentModAmount = -EXTENT_BIG_CHANGE; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_HEIGHT: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_HEIGHT; - if (!extentModAmount) extentModAmount = 1.0f; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_INCREASE_EXTENT_HEIGHT_BIG: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_HEIGHT; - if (!extentModAmount) extentModAmount = EXTENT_BIG_CHANGE; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_HEIGHT: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_HEIGHT; - if (!extentModAmount) extentModAmount = -1.0f; - FALLTHROUGH; - case GameMessage::MSG_META_DEBUG_DECREASE_EXTENT_HEIGHT_BIG: - if (extentModType == EXTENTMOD_INVALID) extentModType = EXTENTMOD_HEIGHT; - if (!extentModAmount) extentModAmount = -EXTENT_BIG_CHANGE; - { - const DrawableList *list = TheInGameUI->getAllSelectedDrawables(); - for (DrawableListCIt it = list->begin(); it != list->end(); ++it) - { - Drawable *pDraw = *it; - if (pDraw) - { - Object *pObject = pDraw->getObject(); - if (pObject) - { - const GeometryInfo oldGeometry = pObject->getGeometryInfo(); - - GeometryInfo newGeometry = oldGeometry; - newGeometry.tweakExtents(extentModType, extentModAmount); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugExtent", - L"Extent %hs --> %hs %d %g", oldGeometry.getDescriptiveString().str(), newGeometry.getDescriptiveString().str(), extentModType, extentModAmount ) ); - - DEBUG_LOG(("Extent %s --> %s %d %g", oldGeometry.getDescriptiveString().str(), newGeometry.getDescriptiveString().str(), extentModType, extentModAmount)); - - pObject->setGeometryInfo( newGeometry ); - } - } - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_LOCK_CAMERA_TO_SELECTION: - { - ObjectID id = INVALID_ID; - Drawable *d = nullptr; - for (d = TheGameClient->firstDrawable(); d; d = d->getNextDrawable()) - { - if (d->isSelected() && d->getObject()) - { - id = d->getObject()->getID(); - break; - } - } - if (id != 0 && TheTacticalView->getCameraLock() == id) - { - if (TheTacticalView->getCameraLockDrawable()) - { - id = INVALID_ID; // toggle it - d=nullptr; - TheTacticalView->forceRedraw(); //reset camera to normal - } - } - else - { - d = nullptr; - } - TheTacticalView->userSetCameraLock(id); - TheTacticalView->userSetCameraLockDrawable(d); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_SOUND: - { - if (TheAudio->isOn(AudioAffect_Sound)) - { - TheDisplay->stopMovie(); - TheInGameUI->stopMovie(); - TheAudio->setOn(false, AudioAffect_All); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugSoundOff", L"Sound is OFF") ); - } - else - { - TheAudio->setOn(true, AudioAffect_All); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugSoundOn", L"Sound is ON") ); - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_TRACKMARKS: - { - TheWritableGlobalData->m_makeTrackMarks = !TheGlobalData->m_makeTrackMarks; - - if (TheGlobalData->m_makeTrackMarks) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugTrackMarksOn", L"Track Marks is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugTrackMarksOff", L"Track Marks is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_WATERPLANE: - { - TheWritableGlobalData->m_useWaterPlane = !TheGlobalData->m_useWaterPlane; - - if (TheGlobalData->m_useWaterPlane) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugWaterPlaneOn", L"Water Plane is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugWaterPlaneOff", L"Water Plane is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TIME_OF_DAY: - { - TimeOfDay tod = TimeOfDay((Int) TheGlobalData->m_timeOfDay + 1); - if (tod < TIME_OF_DAY_FIRST || tod >= TIME_OF_DAY_COUNT) - tod = TIME_OF_DAY_FIRST; - if (TheWritableGlobalData->setTimeOfDay(tod)) - { - TheGameClient->setTimeOfDay(TheGlobalData->m_timeOfDay); - if (TheGlobalData->m_forceModelsToFollowTimeOfDay) - { - for (Object *obj = TheGameLogic->getFirstObject(); obj; obj = obj->getNextObject()) - { - Drawable* d = obj->getDrawable(); - if (d) - { - // this just forces a refresh. - ModelConditionFlags empty; - d->clearAndSetModelConditionFlags(empty, empty); - } - } - } - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugTimeOfDay", L"Time of Day set to %hs", TimeOfDayNames[tod]) ); - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_REMOVE_PREREQ: - { - // Doesn't make a valid network message - // TheSuperHackers @info In multiplayer, all clients need to enable this cheat at the same time, otherwise game will mismatch - Bool enable = !ThePlayerList->getLocalPlayer()->ignoresPrereqs(); - - for (Int n = 0; n < ThePlayerList->getPlayerCount(); ++n) - { - Player* player = ThePlayerList->getNthPlayer(n); - if (player->getPlayerType() == PLAYER_HUMAN) - player->enableIgnorePrereqs(enable); - } - - if (enable) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugIgnorePrereqOn", L"Ignore Prerequisites is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugIgnorePrereqOff", L"Ignore Prerequisites is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_INSTANT_BUILD: - { - // Doesn't make a valid network message - // TheSuperHackers @info In multiplayer, all clients need to enable this cheat at the same time, otherwise game will mismatch - if (!TheGameLogic->isInMultiplayerGame() || !hasThingsInProduction(PLAYER_HUMAN)) - { - Bool enable = !ThePlayerList->getLocalPlayer()->buildsInstantly(); - - for (Int n = 0; n < ThePlayerList->getPlayerCount(); ++n) - { - Player* player = ThePlayerList->getNthPlayer(n); - if (player->getPlayerType() == PLAYER_HUMAN) - player->enableInstantBuild(enable); - } - - if (enable) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugInstantBuildOn", L"Instant Build is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugInstantBuildOff", L"Instant Build is OFF") ); - - disp = DESTROY_MESSAGE; - } - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_FREE_BUILD: - { - // Doesn't make a valid network message - // TheSuperHackers @info In multiplayer, all clients need to enable this cheat at the same time, otherwise game will mismatch - Bool enable = !ThePlayerList->getLocalPlayer()->buildsForFree(); - - for (Int n = 0; n < ThePlayerList->getPlayerCount(); ++n) - { - Player* player = ThePlayerList->getNthPlayer(n); - if (player->getPlayerType() == PLAYER_HUMAN) - player->enableFreeBuild(enable); - } - - if (enable) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugFreeBuildOn", L"Free Build is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugFreeBuildOff", L"Free Build is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_RENDER: - { - TheWritableGlobalData->m_disableRender = !TheGlobalData->m_disableRender; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_ADD_CASH: - { - if ( !TheGameLogic->isInMultiplayerGame() ) - { - Player *localPlayer = ThePlayerList->getLocalPlayer(); - Money *money = localPlayer->getMoney(); - money->deposit( 10000 ); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugAddCash", L"Add Cash") ); - } - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_RUNSCRIPT1: - case GameMessage::MSG_META_DEMO_RUNSCRIPT2: - case GameMessage::MSG_META_DEMO_RUNSCRIPT3: - case GameMessage::MSG_META_DEMO_RUNSCRIPT4: - case GameMessage::MSG_META_DEMO_RUNSCRIPT5: - case GameMessage::MSG_META_DEMO_RUNSCRIPT6: - case GameMessage::MSG_META_DEMO_RUNSCRIPT7: - case GameMessage::MSG_META_DEMO_RUNSCRIPT8: - case GameMessage::MSG_META_DEMO_RUNSCRIPT9: - { - if( TheScriptEngine ) - { - Int script = t - GameMessage::MSG_META_DEMO_RUNSCRIPT1 + 1; - AsciiString scriptName; - scriptName.format("KEY_F%d", script); - TheScriptEngine->runScript(scriptName); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugRunScript", L"Run script %d", script) ); - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_KILL_AREA_SELECTION: - { - for( int i=1; igetArgumentCount(); i++ ) - { - Object *obj = TheGameLogic->findObjectByID( msg->getArgument( i )->objectID ); - if( obj ) - { - obj->kill(); - } - } - } - break; - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE1: - case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE2: - case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE3: - case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE4: - case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE5: - case GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE6: - case GameMessage::MSG_META_DEMO_NEXT_OBJECTIVE_MOVIE: - { - if (TheGameLogic->isInGame()) - { - if (t == GameMessage::MSG_META_DEMO_NEXT_OBJECTIVE_MOVIE) - { - m_objective++; - if (m_objective > 6) - m_objective = 1; - } - else - { - m_objective = t - GameMessage::MSG_META_DEMO_PLAY_OBJECTIVE_MOVIE1 + 1; - } - AsciiString name; - name.format("DemoObjective%02d", m_objective); - TheInGameUI->playMovie(name); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugObjectiveMove", L"Objective Movie %d", m_objective) ); - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_MILITARY_SUBTITLES: - { - - TheInGameUI->militarySubtitle("MSG:Testing", 10000); // use some innocuous string - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_MUSIC: - { - if (TheAudio->isMusicPlaying()) - { - TheAudio->stopAudio(AudioAffect_Music); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugMusicOn", L"Music is OFF") ); - } else - { - TheAudio->resumeAudio(AudioAffect_Music); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugMusicOff", L"Music is ON") ); - } - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_MUSIC_NEXT_TRACK: - { - AsciiString trackName = TheAudio->nextMusicTrack(); - TheInGameUI->message( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugMusicTrack", L"Playing Track: %hs", trackName.str()) ); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_MUSIC_PREV_TRACK: - { - AsciiString trackName = TheAudio->prevMusicTrack(); - TheInGameUI->message( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugMusicTrack", L"Playing Track: %hs", trackName.str()) ); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- -#ifdef PERF_TIMERS - case GameMessage::MSG_META_DEMO_TOGGLE_METRICS: - { - TheWritableGlobalData->m_showMetrics = !TheGlobalData->m_showMetrics; - if (TheGlobalData->m_showMetrics) { - TheDisplay->setDebugDisplayCallback(StatMetricsDisplay); - } else { - TheDisplay->setDebugDisplayCallback(nullptr); - } - break; - } -#endif // #ifdef PERF_TIMERS - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_AI_DEBUG: - { - TheWritableGlobalData->m_debugAI = (AIDebugOptions)((Int)TheGlobalData->m_debugAI + 1); - if (TheGlobalData->m_debugAI >= AI_DEBUG_END) - TheWritableGlobalData->m_debugAI=AI_DEBUG_NONE; - - UnicodeString line; - line.format(L"Level %d", TheGlobalData->m_debugAI); - if (TheGlobalData->m_debugAI != AI_DEBUG_NONE) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugAiDebugOn", L"Debug AI Mode is %s", line.str()) ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugAiDebugOff", L"Debug AI Mode is OFF") ); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_SUPPLY_CENTER_PLACEMENT: - { - TheWritableGlobalData->m_debugSupplyCenterPlacement = !TheWritableGlobalData->m_debugSupplyCenterPlacement; - - if (TheGlobalData->m_debugSupplyCenterPlacement) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugSupplyCenterPlacementOn", L"Log SupplyCenter Placement is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugSupplyCenterPlacementOff", L"Log SupplyCenter Placement is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_GIVE_SCIENCEPURCHASEPOINTS: - { - Player *player = ThePlayerList->getLocalPlayer(); - if (player) - player->addSciencePurchasePoints(1); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugGiveSciencePurchasePoint", L"Adding a SciencePurchasePoint") ); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_GIVE_ALL_SCIENCES: - { - // TheSuperHackers @info In multiplayer, all clients need to enable this cheat at the same time, otherwise game will mismatch - for (Int n = 0; n < ThePlayerList->getPlayerCount(); ++n) - { - Player* player = ThePlayerList->getNthPlayer(n); - if (player->getPlayerType() == PLAYER_HUMAN) - giveAllSciences(player); - } - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugGiveAllSciences", L"Granting all sciences!") ); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_GIVE_RANKLEVEL: - { - Player *player = ThePlayerList->getLocalPlayer(); - if (player) - player->setRankLevel(player->getRankLevel() + 1); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugAddRankLevel", L"Adding a Rank Level") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TAKE_RANKLEVEL: - { - Player *player = ThePlayerList->getLocalPlayer(); - if (player) - player->setRankLevel(player->getRankLevel() - 1); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugSubRankLevel", L"Subtracting a Rank Level") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_CAMERA_DEBUG: - { - TheWritableGlobalData->m_debugCamera = !TheGlobalData->m_debugCamera; - - if (TheTacticalView->isZoomLimited()) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugCameraModeOn", L"Debug Camera Mode is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugCameraModeOff", L"Debug Camera Mode is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_NO_DRAW: - { - const Bool isZero = TheGlobalData->m_noDraw == 0u; - TheWritableGlobalData->m_noDraw = isZero ? ~0u : 0u; - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_DUMP_PLAYER_OBJECTS: - case GameMessage::MSG_META_DEBUG_DUMP_ALL_PLAYER_OBJECTS: - { - AsciiString line; - line.format("*******************************"); - TheScriptEngine->AppendDebugMessage(line, FALSE); - line.format("Dumping player object counts"); - TheScriptEngine->AppendDebugMessage(line, FALSE); - for (Int i=0; igetNthPlayer(i); - if (!pPlayer || !pPlayer->getPlayerTemplate() || !pPlayer->getPlayerTemplate()->isPlayableSide()) - continue; - - Int numObjects = 0; - pPlayer->iterateObjects( countObjects, &numObjects ); - line.format("Player %d (%ls) has %d non-dead objects", i, pPlayer->getPlayerDisplayName().str(), numObjects); - TheScriptEngine->AppendDebugMessage(line, FALSE); - - if (numObjects && (numObjects <= 5 || t == GameMessage::MSG_META_DEBUG_DUMP_ALL_PLAYER_OBJECTS)) - { - line = "Objects are:"; - TheScriptEngine->AppendDebugMessage(line, FALSE); - pPlayer->iterateObjects( printObjects, nullptr ); - } - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_TOGGLE_NETWORK: - { - if (TheNetwork != nullptr) { - TheNetwork->toggleNetworkOn(); - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_PARTICLEDEBUG: - { - if (TheDisplay->getDebugDisplayCallback() == ParticleSystemDebugDisplay) - TheDisplay->setDebugDisplayCallback(nullptr); - else - TheDisplay->setDebugDisplayCallback(ParticleSystemDebugDisplay); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_VISIONDEBUG: - { - TheWritableGlobalData->m_debugVisibility = !TheGlobalData->m_debugVisibility; - - if (TheGlobalData->m_debugVisibility) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugVisionModeOn", L"Debug Vision Mode is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugVisionModeOff", L"Debug Vision Mode is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_PROJECTILEDEBUG: - { - TheWritableGlobalData->m_debugProjectilePath = !TheGlobalData->m_debugProjectilePath; - - if (TheGlobalData->m_debugProjectilePath) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugProjectilePathModeOn", L"Debug Projectile Path Mode is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugProjectilePathModeOff", L"Debug Projectile Path Mode is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_THREATDEBUG: - { - TheWritableGlobalData->m_debugThreatMap = !TheGlobalData->m_debugThreatMap; - if (TheGlobalData->m_debugThreatMap) { - TheWritableGlobalData->m_debugCashValueMap = false; - } - - if (TheGlobalData->m_debugThreatMap) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugThreadMapOn", L"Debug Threat Map is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugThreadMapOff", L"Debug Threat Map is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_CASHMAPDEBUG: - { - TheWritableGlobalData->m_debugCashValueMap = !TheGlobalData->m_debugCashValueMap ; - if (TheGlobalData->m_debugCashValueMap) { - TheWritableGlobalData->m_debugThreatMap = false; - } - - if (TheGlobalData->m_debugCashValueMap) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugCashValueMapOn", L"Debug Cash Value Map is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugCashValueMapOff", L"Debug Cash Value Map is OFF") ); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_GRAPHICALFRAMERATEBAR: - { - TheWritableGlobalData->m_debugShowGraphicalFramerate = !TheGlobalData->m_debugShowGraphicalFramerate; - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_SHOW_EXTENTS: - TheWritableGlobalData->m_showCollisionExtents = 1 - TheGlobalData->m_showCollisionExtents; - - if (TheGlobalData->m_showCollisionExtents) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugObjectExtentsOn", L"Show Object Extents is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugObjectExtentsOff", L"Show Object Extents is OFF") ); - - break; - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_SHOW_AUDIO_LOCATIONS: - TheWritableGlobalData->m_showAudioLocations = 1 - TheGlobalData->m_showAudioLocations; - - if (TheGlobalData->m_showAudioLocations) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugAudioLocationsOn", L"Show Audio Locations is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugAudioLocationsOff", L"Show Audio Locations is OFF") ); - - break; - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_SHOW_HEALTH: - { - - TheWritableGlobalData->m_showObjectHealth = 1 - TheGlobalData->m_showObjectHealth; - - if (TheGlobalData->m_showObjectHealth) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugObjectHealthOn", L"Object Health is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugObjectHealthOff", L"Object Health is OFF") ); - break; - - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_PLAY_CAMEO_MOVIE: - { - if (TheGameLogic->isInGame()) - { - if(TheInGameUI->cameoVideoBuffer() == nullptr) - TheInGameUI->playCameoMovie("CameoMovie"); - else - TheInGameUI->stopCameoMovie(); - } - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_ZOOM_LOCK: - { - - if( TheTacticalView ) - { - - TheTacticalView->setZoomLimited( !TheTacticalView->isZoomLimited() ); - - if (TheTacticalView->isZoomLimited()) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugCameraZoomLimitOn", L"Camera Zoom Limit is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugCameraZoomLimitOff", L"Camera Zoom Limit is OFF") ); - - } - - disp = DESTROY_MESSAGE; - break; - - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //--------------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_SPECIAL_POWER_DELAYS: - { - - if( TheGlobalData ) - { - - TheWritableGlobalData->m_specialPowerUsesDelay = 1 - TheGlobalData->m_specialPowerUsesDelay; - - if (TheGlobalData->m_specialPowerUsesDelay) - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugSpecialPowerDelaysOn", L"Special Power (Superweapon) Delay is ON") ); - else - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugSpecialPowerDelaysOff", L"Special Power (Superweapon) Delay is OFF") ); - - } - - disp = DESTROY_MESSAGE; - break; - - } - -#ifdef ALLOW_SURRENDER - //------------------------------------------------------------------------------- DEMO MESSAGES - //--------------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TEST_SURRENDER: - { - GameMessage* msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_SURRENDER ); - msg->appendObjectIDArgument(INVALID_ID); // zero means "surrender to anyone" - msg->appendBooleanArgument(true); - disp = DESTROY_MESSAGE; - break; - } -#endif - - //------------------------------------------------------------------------------- DEMO MESSAGES - // -------------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_BATTLE_CRY: - { - TheAudio->addAudioEvent(&TheAudio->getMiscAudio()->m_battleCrySound); - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - // -------------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_AVI: - { - if (TheDisplay) - TheDisplay->toggleMovieCapture(); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_VTUNE_ON: - { - TheScriptEngine->setEnableVTune(true); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugVTuneOff", L"VTune Gathering is ON") ); - disp = DESTROY_MESSAGE; - break; - } - - - //------------------------------------------------------------------------------- DEMO MESSAGES - // -------------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_VTUNE_OFF: - { - TheScriptEngine->setEnableVTune(false); - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugVTuneOff", L"VTune Gathering is OFF") ); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - // -------------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_TOGGLE_FEATHER_WATER: - { - --TheWritableGlobalData->m_featherWater; - if (TheGlobalData->m_featherWater < 0) - TheWritableGlobalData->m_featherWater = 5; - - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_WIN: - { - TheScriptEngine->debugVictory(); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE("GUI:DebugWin", L"Instant Win") ); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_TOGGLE_DEBUG_STATS: - { - if (TheDisplay->getDebugDisplayCallback() == StatDebugDisplay) - TheDisplay->setDebugDisplayCallback(nullptr); - else - TheDisplay->setDebugDisplayCallback(StatDebugDisplay); - disp = DESTROY_MESSAGE; - break; - } - - //------------------------------------------------------------------------DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_SLEEPY_UPDATE_PERFORMANCE: - { - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugIncreaseAnimSkateSpeed", - L"Number of Sleepy Modules: %d", TheGameLogic->getNumberSleepyUpdates() ) ); - break; - } - - //------------------------------------------------------------------------DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_OBJECT_ID_PERFORMANCE: - { - static __int64 startTime64; - static __int64 endTime64,freq64; - QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); - QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); - Int numberLookups = 10000; - Int testindex = 1; - for( ; testindex < numberLookups; testindex++ ) - { - Object *objPtr = TheGameLogic->findObjectByID((ObjectID)testindex); - objPtr++; - } - QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); - double timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugObjectIdPerformance", - L"Time to run %d ObjectID lookups is %f. Next index is %d", numberLookups, timeToUpdate, (Int)TheGameLogic->getObjectIDCounter() ) ); - - - QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); - QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); - numberLookups = 100000; - for( testindex = 1; testindex < numberLookups; testindex++ ) - { - Object *objPtr = TheGameLogic->findObjectByID((ObjectID)testindex); - objPtr++; - } - QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); - timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugObjectIdPerformance", - L"Time to run %d ObjectID lookups is %f. Next index is %d", numberLookups, timeToUpdate, (Int)TheGameLogic->getObjectIDCounter() ) ); - - - QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); - QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); - numberLookups = 1000000; - for( testindex = 1; testindex < numberLookups; testindex++ ) - { - Object *objPtr = TheGameLogic->findObjectByID((ObjectID)testindex); - objPtr++; - } - QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); - timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugObjectIdPerformance", - L"Time to run %d ObjectID lookups is %f. Next index is %d", numberLookups, timeToUpdate, (Int)TheGameLogic->getObjectIDCounter() ) ); - - break; - } - - //------------------------------------------------------------------------DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEBUG_DRAWABLE_ID_PERFORMANCE: - { - static __int64 startTime64; - static __int64 endTime64,freq64; - QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); - QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); - Int numberLookups = 10000; - Int testindex = 1; - for( ; testindex < numberLookups; testindex++ ) - { - Drawable *drawPtr = TheGameClient->findDrawableByID((DrawableID)testindex); - drawPtr++; - } - QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); - double timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugDrawableIdPerformance", - L"Time to run %d DrawableID lookups is %f. Next index is %d", numberLookups, timeToUpdate, (Int)TheGameClient->getDrawableIDCounter() ) ); - - - QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); - QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); - numberLookups = 100000; - for( testindex = 1; testindex < numberLookups; testindex++ ) - { - Drawable *drawPtr = TheGameClient->findDrawableByID((DrawableID)testindex); - drawPtr++; - } - QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); - timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugDrawableIdPerformance", - L"Time to run %d DrawableID lookups is %f. Next index is %d", numberLookups, timeToUpdate, (Int)TheGameClient->getDrawableIDCounter() ) ); - - - QueryPerformanceCounter((LARGE_INTEGER *)&startTime64); - QueryPerformanceFrequency((LARGE_INTEGER *)&freq64); - numberLookups = 1000000; - for( testindex = 1; testindex < numberLookups; testindex++ ) - { - Drawable *drawPtr = TheGameClient->findDrawableByID((DrawableID)testindex); - drawPtr++; - } - QueryPerformanceCounter((LARGE_INTEGER *)&endTime64); - timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64)); - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugDrawableIdPerformance", - L"Time to run %d DrawableID lookups is %f. Next index is %d", numberLookups, timeToUpdate, (Int)TheGameClient->getDrawableIDCounter() ) ); - - break; - } - - //--------------------------------------------------------------------------- END DEMO MESSAGES - //--------------------------------------------------------------------------- END DEMO MESSAGES - //--------------------------------------------------------------------------- END DEMO MESSAGES -#endif // #if defined(RTS_DEBUG) - - //------------------------------------------------------------------------DEMO MESSAGES - //----------------------------------------------------------------------------------------- -#if defined(RTS_DEBUG) - case GameMessage::MSG_META_DEMO_TOGGLE_AUDIODEBUG: - { - if (TheDisplay->getDebugDisplayCallback() == AudioDebugDisplay) - TheDisplay->setDebugDisplayCallback(nullptr); - else - TheDisplay->setDebugDisplayCallback(AudioDebugDisplay); - disp = DESTROY_MESSAGE; - break; - } - -#endif//defined(RTS_DEBUG) - -#ifdef DUMP_PERF_STATS - //------------------------------------------------------------------------DEMO MESSAGES - //----------------------------------------------------------------------------------------- - case GameMessage::MSG_META_DEMO_PERFORM_STATISTICAL_DUMP: - //Dump performance statistics for this frame. - TheWritableGlobalData->m_dumpPerformanceStatistics = TRUE; - - TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:DebugPerformStatisticalDump", - L"Statistics dump made on frame: %d", TheGameLogic->getFrame() ) ); - break; -#endif // DUMP_PERF_STATS - - - } - - - return disp; - -} - -static Bool isSystemMessage( const GameMessage *msg ) -{ - if (!msg) { - return false; - } - GameMessage::Type msgType = msg->getType(); - - switch (msgType) - { - case GameMessage::MSG_DESTROY_SELECTED_GROUP: - case GameMessage::MSG_LOGIC_CRC: - case GameMessage::MSG_SET_REPLAY_CAMERA: - case GameMessage::MSG_FRAME_TICK: - case GameMessage::MSG_META_DEMO_INSTANT_QUIT: - return TRUE; - } - return FALSE; -} diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/CountermeasuresBehavior.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/CountermeasuresBehavior.cpp index 8ba6677a21a..e7dbd7fed5b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/CountermeasuresBehavior.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/CountermeasuresBehavior.cpp @@ -159,8 +159,8 @@ ObjectID CountermeasuresBehavior::calculateCountermeasureToDivertTo( const Objec Real closestFlareDist = 1e15f; Object *closestFlare = nullptr; - const int volleySize = data->m_volleySize; - int volleyFlaresCounted = 0; + const UnsignedInt volleySize = max(data->m_volleySize, 1u); + UnsignedInt volleyFlaresCounted = 0; //Flares are pushed to the front of the list, but we only want to acquire the "newest" of the flares, therefore //Start at the end of the list and go towards the beginning. @@ -182,9 +182,13 @@ ObjectID CountermeasuresBehavior::calculateCountermeasureToDivertTo( const Objec // The non retail behaviour corrects the code to iterate through all flares in the volley break; #else - volleyFlaresCounted++; + ++volleyFlaresCounted; #endif } + +#if RETAIL_COMPATIBLE_CRC + ++volleyFlaresCounted; +#endif } if( closestFlare ) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp index 9bb57e08351..4757457d8e6 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AssistedTargetingUpdate.cpp @@ -49,7 +49,7 @@ //------------------------------------------------------------------------------------------------- void AssistedTargetingUpdateModuleData::buildFieldParse(MultiIniFieldParse& p) { - UpdateModuleData::buildFieldParse(p); + UpdateModuleData::buildFieldParse(p); static const FieldParse dataFieldParse[] = { { "AssistingClipSize", INI::parseInt, nullptr, offsetof( AssistedTargetingUpdateModuleData, m_clipSize ) }, @@ -58,7 +58,7 @@ void AssistedTargetingUpdateModuleData::buildFieldParse(MultiIniFieldParse& p) { "LaserToTarget", INI::parseAsciiString, nullptr, offsetof( AssistedTargetingUpdateModuleData, m_laserToTargetName ) }, { nullptr, nullptr, nullptr, 0 } }; - p.add(dataFieldParse); + p.add(dataFieldParse); } //------------------------------------------------------------------------------------------------- @@ -101,7 +101,6 @@ void AssistedTargetingUpdate::assistAttack( const Object *requestingObject, Obje me->setWeaponLock( md->m_weaponSlot, LOCKED_TEMPORARILY ); me->getAI()->aiAttackObject( victimObject, md->m_clipSize, CMD_FROM_AI ); - if( m_laserFromAssisted ) makeFeedbackLaser( m_laserFromAssisted, requestingObject, me ); if( m_laserToTarget ) @@ -120,9 +119,6 @@ void AssistedTargetingUpdate::makeFeedbackLaser( const ThingTemplate *laserTempl if( !laser ) return; - // Give it a good basis in reality to ensure it can draw when on screen. - laser->setPosition(from->getPosition()); - Drawable *draw = laser->getDrawable(); static const NameKeyType key_LaserUpdate = NAMEKEY( "LaserUpdate" ); LaserUpdate *update = (LaserUpdate*)draw->findClientUpdateModule( key_LaserUpdate ); @@ -132,6 +128,9 @@ void AssistedTargetingUpdate::makeFeedbackLaser( const ThingTemplate *laserTempl return; } + // Give it a good basis in reality to ensure it can draw when on screen. + laser->setPosition(from->getPosition()); + update->initLaser( getObject(), to, from->getPosition(), to->getPosition(), "" ); } @@ -139,14 +138,10 @@ void AssistedTargetingUpdate::makeFeedbackLaser( const ThingTemplate *laserTempl //------------------------------------------------------------------------------------------------- UpdateSleepTime AssistedTargetingUpdate::update() { - - const AssistedTargetingUpdateModuleData *d = getAssistedTargetingUpdateModuleData(); + const AssistedTargetingUpdateModuleData *d = getAssistedTargetingUpdateModuleData(); m_laserFromAssisted = TheThingFactory->findTemplate( d->m_laserFromAssistedName ); - - - m_laserToTarget =TheThingFactory->findTemplate( d->m_laserFromAssistedName ); - + m_laserToTarget = TheThingFactory->findTemplate( d->m_laserToTargetName ); return UPDATE_SLEEP_FOREVER; } @@ -185,12 +180,11 @@ void AssistedTargetingUpdate::xfer( Xfer *xfer ) // ------------------------------------------------------------------------------------------------ void AssistedTargetingUpdate::loadPostProcess() { - const AssistedTargetingUpdateModuleData *d = getAssistedTargetingUpdateModuleData(); + const AssistedTargetingUpdateModuleData *d = getAssistedTargetingUpdateModuleData(); m_laserFromAssisted = TheThingFactory->findTemplate( d->m_laserFromAssistedName ); - m_laserToTarget =TheThingFactory->findTemplate( d->m_laserFromAssistedName ); + m_laserToTarget = TheThingFactory->findTemplate( d->m_laserToTargetName ); // extend base class UpdateModule::loadPostProcess(); - } diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index edcd0bc3721..8bd6044be6a 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1597,9 +1597,16 @@ void W3DDisplay::gatherDebugStats() //display the x and y mouse coordinates const MouseIO *mouseIO = TheMouse->getMouseStatus(); Coord3D worldPos; - TheTacticalView->screenToTerrain(&mouseIO->pos, &worldPos); - unibuffer.format( L"Mouse position: screen: (%d, %d), world: (%g, %g, %g)", mouseIO->pos.x, mouseIO->pos.y, - worldPos.x, worldPos.y, worldPos.z); + if( TheTacticalView->screenToTerrain(&mouseIO->pos, &worldPos) ) + { + unibuffer.format( L"Mouse position: screen: (%d, %d), world: (%g, %g, %g)", + mouseIO->pos.x, mouseIO->pos.y, worldPos.x, worldPos.y, worldPos.z); + } + else + { + unibuffer.format( L"Mouse position: screen: (%d, %d), world: none", + mouseIO->pos.x, mouseIO->pos.y); + } m_displayStrings[MousePosition]->setText( unibuffer ); //display the number of particles in the world and being displayed on screen diff --git a/GeneralsMD/Code/Tools/GUIEdit/Include/HierarchyView.h b/GeneralsMD/Code/Tools/GUIEdit/Include/HierarchyView.h index 4b607bc6bab..9aa5f24dd4a 100644 --- a/GeneralsMD/Code/Tools/GUIEdit/Include/HierarchyView.h +++ b/GeneralsMD/Code/Tools/GUIEdit/Include/HierarchyView.h @@ -149,7 +149,7 @@ class HierarchyView } }; - typedef std::hash_map< ConstGameWindowPtr, HTREEITEM, hashConstGameWindowPtr, std::equal_to > TreeHash; + typedef std::hash_map< ConstGameWindowPtr, HTREEITEM, hashConstGameWindowPtr, std::equal_to/**/> TreeHash; TreeHash m_treeHash; ///< Speed up the search with a nice hash. #endif diff --git a/GeneralsMD/Code/Tools/WorldBuilder/include/GroveOptions.h b/GeneralsMD/Code/Tools/WorldBuilder/include/GroveOptions.h index ae70c511665..0e70e91697e 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/include/GroveOptions.h +++ b/GeneralsMD/Code/Tools/WorldBuilder/include/GroveOptions.h @@ -39,7 +39,7 @@ UnicodeString GetDisplayNameFromPair(const PairNameDisplayName *pNamePair); class GroveOptions : public COptionsPanel { protected: - std::vector > mVecGroup; + std::vector/**/> mVecGroup; VecPairNameDisplayName mVecDisplayNames; Int mNumTrees; diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp index 3480dc29baf..e1e654da19b 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -175,11 +175,11 @@ class PlaceholderView : public View Bool (*callback)( Drawable *draw, void *userData ), void *userData ) override {return 0;}; virtual WorldToScreenReturn worldToScreenTriReturn( const Coord3D *w, ICoord2D *s ) override { return WTS_INVALID; }; ///< Transform world coordinate "w" into screen coordinate "s" - virtual void screenToTerrain( const ICoord2D *screen, Coord3D *world ) override {}; ///< transform screen coord to a point on the 3D terrain - virtual void screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override {}; ///< transform screen point to world point at the specified world Z value - virtual void getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, + virtual Bool screenToTerrain( const ICoord2D *screen, Coord3D *world ) override { return false; } + virtual PlaneClass::IntersectionResType screenToWorldAtZ( const ICoord2D *s, Coord3D *w, Real z ) override { return PlaneClass::NO_INTERSECTION; } + virtual PlaneClass::IntersectionResType getScreenCornerWorldPointsAtZ( Coord3D *topLeft, Coord3D *topRight, Coord3D *bottomRight, Coord3D *bottomLeft, - Real z ) override {}; + Real z, ViewportClass viewPort = ViewportClass() ) override { return PlaneClass::NO_INTERSECTION; } virtual void drawView() override {}; ///< Render the world visible in this view. virtual void updateView() override {}; ///< Render the world visible in this view. diff --git a/docs/DEV_BLOG/2026-06-DIARY.md b/docs/DEV_BLOG/2026-06-DIARY.md index 98455bb3fed..f2748836044 100644 --- a/docs/DEV_BLOG/2026-06-DIARY.md +++ b/docs/DEV_BLOG/2026-06-DIARY.md @@ -1,5 +1,9 @@ # Development Diary - June 2026 +## 2026-06-27: Fix Voicelines on Linux and Disable Flatpak DXVK HUD + +- **Audio Backend Sample Counts**: Fixed an issue where `OpenALAudioManager` and `MiniAudioManager` were incorrectly returning `0` for available 2D/3D samples, which caused the engine to aggressively cull UI sounds (including voicelines). Updated `getNumAvailable2DSamples()` and `getNumAvailable3DSamples()` to return the correct calculation based on `m_playingSounds` and the configured maximum sample limits. +- **Flatpak DXVK FPS Overlay**: Disabled the `DXVK_HUD` FPS counter overlay by default in Flatpak run scripts for both Generals base game and Zero Hour. The game already features a native FPS counter, making the overlay redundant. ## 2026-06-26: Support D3DFMT_A4R4G4B4 and D3DFMT_R5G6B5 Downsampling on Linux - **DirectX 8 Downsampling Parity on Linux**: Backported the manual box filter downsampling logic for `D3DFMT_A4R4G4B4` and `D3DFMT_R5G6B5` from macOS to Linux in [d3dx8_compat.cpp](file:///home/felipe/Projects/GeneralsX/GeneralsMD/Code/CompatLib/Source/d3dx8_compat.cpp). Previously, the Linux port relied on the GLI library to generate mipmaps, which lacked support for these specific formats, causing `D3DXLoadSurfaceFromSurface` to fail. This failure resulted in team/house recolored textures on infantry rendering as solid black silhouettes at lower mipmap levels. Bypassing GLI for these formats and applying the manual box filter restores rendering parity with macOS and original Windows targets. diff --git a/flatpak/com.fbraz3.GeneralsX.yml b/flatpak/com.fbraz3.GeneralsX.yml index ba4d9baaa47..16025a79313 100644 --- a/flatpak/com.fbraz3.GeneralsX.yml +++ b/flatpak/com.fbraz3.GeneralsX.yml @@ -108,18 +108,17 @@ modules: # SagePatch (optional QoL: F11 screenshot, Scroll Lock cursor lock, # Ctrl+PgUp/Dn brightness, Ctrl+1..5 window snap). Loaded via LD_PRELOAD - # only if the .so is present in /app/lib. Default DXVK_HUD to "fps" when - # SagePatch is active so casual users see a frame counter. + # only if the .so is present in /app/lib. if [[ -f /app/lib/libsage_patch.so && "${SAGE_PATCH_DISABLED:-0}" != "1" ]]; then if [[ -n "${LD_PRELOAD:-}" ]]; then export LD_PRELOAD="/app/lib/libsage_patch.so:${LD_PRELOAD}" else export LD_PRELOAD="/app/lib/libsage_patch.so" fi - export DXVK_HUD="${DXVK_HUD:-fps}" - else - export DXVK_HUD="${DXVK_HUD:-0}" fi + + # DXVK HUD is disabled by default because Generals has a native FPS counter. + export DXVK_HUD="${DXVK_HUD:-0}" # Keep Vulkan ICD selection to the runtime/driver defaults unless user explicitly overrides. diff --git a/flatpak/com.fbraz3.GeneralsXZH.yml b/flatpak/com.fbraz3.GeneralsXZH.yml index 4a50e476f93..be0eeed40b7 100644 --- a/flatpak/com.fbraz3.GeneralsXZH.yml +++ b/flatpak/com.fbraz3.GeneralsXZH.yml @@ -109,18 +109,17 @@ modules: # SagePatch (optional QoL: F11 screenshot, Scroll Lock cursor lock, # Ctrl+PgUp/Dn brightness, Ctrl+1..5 window snap). Loaded via LD_PRELOAD - # only if the .so is present in /app/lib. Default DXVK_HUD to "fps" when - # SagePatch is active so casual users see a frame counter. + # only if the .so is present in /app/lib. if [[ -f /app/lib/libsage_patch.so && "${SAGE_PATCH_DISABLED:-0}" != "1" ]]; then if [[ -n "${LD_PRELOAD:-}" ]]; then export LD_PRELOAD="/app/lib/libsage_patch.so:${LD_PRELOAD}" else export LD_PRELOAD="/app/lib/libsage_patch.so" fi - export DXVK_HUD="${DXVK_HUD:-fps}" - else - export DXVK_HUD="${DXVK_HUD:-0}" fi + + # DXVK HUD is disabled by default because Generals has a native FPS counter. + export DXVK_HUD="${DXVK_HUD:-0}" # Keep Vulkan ICD selection to the runtime/driver defaults unless user explicitly overrides. diff --git a/scripts/cpp/unify_move_files.py b/scripts/cpp/unify_move_files.py index c8ef3e56bae..b95939719ec 100644 --- a/scripts/cpp/unify_move_files.py +++ b/scripts/cpp/unify_move_files.py @@ -545,13 +545,33 @@ def main(): #unify_file_lib(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/dx8indexbuffer.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/dx8indexbuffer.cpp") #unify_file_lib(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/dx8renderer.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/dx8renderer.cpp") #unify_file_lib(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/dx8vertexbuffer.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/dx8vertexbuffer.cpp") - + #unify_file_lib(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/sortingrenderer.h", Game.CORE, "Libraries/Source/WWVegas/WW3D2/sortingrenderer.h") #unify_file_lib(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp") #unify_move_file(Game.ZEROHOUR, "GameEngine/Include/Common/AcademyStats.h", Game.CORE, "GameEngine/Include/Common/AcademyStats.h") #unify_move_file(Game.ZEROHOUR, "GameEngine/Source/Common/RTS/AcademyStats.cpp", Game.CORE, "GameEngine/Source/Common/RTS/AcademyStats.cpp") + unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/CommandXlat.h", Game.CORE, "GameEngine/Include/GameClient/CommandXlat.h") + unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/GUICommandTranslator.h", Game.CORE, "GameEngine/Include/GameClient/GUICommandTranslator.h") + unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/HintSpy.h", Game.CORE, "GameEngine/Include/GameClient/HintSpy.h") + unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/HotKey.h", Game.CORE, "GameEngine/Include/GameClient/HotKey.h") + unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/LookAtXlat.h", Game.CORE, "GameEngine/Include/GameClient/LookAtXlat.h") + unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/MetaEvent.h", Game.CORE, "GameEngine/Include/GameClient/MetaEvent.h") + unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/PlaceEventTranslator.h", Game.CORE, "GameEngine/Include/GameClient/PlaceEventTranslator.h") + unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/SelectionXlat.h", Game.CORE, "GameEngine/Include/GameClient/SelectionXlat.h") + unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/WindowXlat.h", Game.CORE, "GameEngine/Include/GameClient/WindowXlat.h") + unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp", Game.CORE, "GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp") + unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp", Game.CORE, "GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp") + unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/MessageStream/HintSpy.cpp", Game.CORE, "GameEngine/Source/GameClient/MessageStream/HintSpy.cpp") + unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/MessageStream/HotKey.cpp", Game.CORE, "GameEngine/Source/GameClient/MessageStream/HotKey.cpp") + unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp", Game.CORE, "GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp") + unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp", Game.CORE, "GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp") + unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp", Game.CORE, "GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp") + unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp", Game.CORE, "GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp") + unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp", Game.CORE, "GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp") + unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/GameClientDispatch.cpp", Game.CORE, "GameEngine/Source/GameClient/GameClientDispatch.cpp") + return