From 54fdcc90bfd280c376199b16b867379799bc74fd Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Thu, 18 Jun 2026 19:16:13 +0200 Subject: [PATCH] unify(messagestream): Move all client message translator files to Core --- Core/GameEngine/CMakeLists.txt | 38 +- .../Include/GameClient/CommandXlat.h | 0 .../Include/GameClient/GUICommandTranslator.h | 0 .../GameEngine/Include/GameClient/HintSpy.h | 0 .../GameEngine/Include/GameClient/HotKey.h | 0 .../Include/GameClient/LookAtXlat.h | 0 .../GameEngine/Include/GameClient/MetaEvent.h | 0 .../Include/GameClient/PlaceEventTranslator.h | 0 .../Include/GameClient/SelectionXlat.h | 0 .../Include/GameClient/WindowXlat.h | 0 .../Source/GameClient/GameClientDispatch.cpp | 0 .../GameClient/MessageStream/CommandXlat.cpp | 0 .../MessageStream/GUICommandTranslator.cpp | 0 .../GameClient/MessageStream/HintSpy.cpp | 0 .../GameClient/MessageStream/HotKey.cpp | 0 .../GameClient/MessageStream/LookAtXlat.cpp | 0 .../GameClient/MessageStream/MetaEvent.cpp | 0 .../MessageStream/PlaceEventTranslator.cpp | 0 .../MessageStream/SelectionXlat.cpp | 0 .../GameClient/MessageStream/WindowXlat.cpp | 0 Generals/Code/GameEngine/CMakeLists.txt | 38 +- .../Include/GameClient/CommandXlat.h | 124 - .../Include/GameClient/GUICommandTranslator.h | 48 - .../GameEngine/Include/GameClient/HintSpy.h | 38 - .../GameEngine/Include/GameClient/HotKey.h | 112 - .../Include/GameClient/LookAtXlat.h | 92 - .../GameEngine/Include/GameClient/MetaEvent.h | 488 -- .../Include/GameClient/PlaceEventTranslator.h | 42 - .../Include/GameClient/SelectionXlat.h | 78 - .../Include/GameClient/WindowXlat.h | 41 - .../Source/GameClient/GameClientDispatch.cpp | 56 - .../GameClient/MessageStream/CommandXlat.cpp | 5539 ----------------- .../MessageStream/GUICommandTranslator.cpp | 512 -- .../GameClient/MessageStream/HintSpy.cpp | 139 - .../GameClient/MessageStream/HotKey.cpp | 231 - .../GameClient/MessageStream/LookAtXlat.cpp | 779 --- .../GameClient/MessageStream/MetaEvent.cpp | 1016 --- .../MessageStream/PlaceEventTranslator.cpp | 355 -- .../MessageStream/SelectionXlat.cpp | 1323 ---- .../GameClient/MessageStream/WindowXlat.cpp | 357 -- GeneralsMD/Code/GameEngine/CMakeLists.txt | 38 +- scripts/cpp/unify_move_files.py | 22 +- 42 files changed, 78 insertions(+), 11428 deletions(-) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameClient/CommandXlat.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameClient/GUICommandTranslator.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameClient/HintSpy.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameClient/HotKey.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameClient/LookAtXlat.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameClient/MetaEvent.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameClient/PlaceEventTranslator.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameClient/SelectionXlat.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameClient/WindowXlat.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/GameClientDispatch.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/MessageStream/HotKey.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp (100%) delete mode 100644 Generals/Code/GameEngine/Include/GameClient/CommandXlat.h delete mode 100644 Generals/Code/GameEngine/Include/GameClient/GUICommandTranslator.h delete mode 100644 Generals/Code/GameEngine/Include/GameClient/HintSpy.h delete mode 100644 Generals/Code/GameEngine/Include/GameClient/HotKey.h delete mode 100644 Generals/Code/GameEngine/Include/GameClient/LookAtXlat.h delete mode 100644 Generals/Code/GameEngine/Include/GameClient/MetaEvent.h delete mode 100644 Generals/Code/GameEngine/Include/GameClient/PlaceEventTranslator.h delete mode 100644 Generals/Code/GameEngine/Include/GameClient/SelectionXlat.h delete mode 100644 Generals/Code/GameEngine/Include/GameClient/WindowXlat.h delete mode 100644 Generals/Code/GameEngine/Source/GameClient/GameClientDispatch.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp delete mode 100644 Generals/Code/GameEngine/Source/GameClient/MessageStream/WindowXlat.cpp diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index bf41a6c8708..d3d17ced516 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/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/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/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/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/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/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp b/Core/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/GUICommandTranslator.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp b/Core/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp 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 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp b/Core/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/PlaceEventTranslator.cpp diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp rename to Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp 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/Generals/Code/GameEngine/CMakeLists.txt b/Generals/Code/GameEngine/CMakeLists.txt index 37a1e2a5d7e..1d56ec356d5 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/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/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 76c736131a0..00000000000 --- a/Generals/Code/GameEngine/Include/GameClient/MetaEvent.h +++ /dev/null @@ -1,488 +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: - struct KeyDownInfo - { - KeyDownInfo() : m_modStateBits(0) {} - - static UnsignedInt getMaxKeyModStateCount() - { - return 7; - } - - static MappableKeyModState toKeyModState(UnsignedInt index) - { - switch (index) - { - case 0: return CTRL; - case 1: return ALT; - case 2: return SHIFT; - case 3: return CTRL_ALT; - case 4: return SHIFT_CTRL; - case 5: return SHIFT_ALT; - case 6: return SHIFT_ALT_CTRL; - } - return NONE; - } - - static UnsignedInt toIndex(MappableKeyModState modState) - { - switch (modState) - { - case CTRL: return 0; - case ALT: return 1; - case SHIFT: return 2; - case CTRL_ALT: return 3; - case SHIFT_CTRL: return 4; - case SHIFT_ALT: return 5; - case SHIFT_ALT_CTRL: return 6; - } - return 7; - } - - Bool isKeyDown() const - { - return m_modStateBits != 0; - } - - MappableKeyModState getKeyModState(UnsignedInt index) - { - if (BitIsSet(m_modStateBits, 1 << index)) - { - return toKeyModState(index); - } - return NONE; - } - - void clearKeyModState(UnsignedInt index) - { - BitClear(m_modStateBits, 1 << index); - } - - Bool hasKeyModState(MappableKeyModState modState) const - { - return BitIsSet(m_modStateBits, 1 << toIndex(modState)); - } - - void setKeyModState(MappableKeyModState modState) - { - BitSet(m_modStateBits, 1 << toIndex(modState)); - } - - void clearKeyModState(MappableKeyModState modState) - { - BitClear(m_modStateBits, 1 << toIndex(modState)); - } - - private: - UnsignedByte m_modStateBits; ///< Fits all combinations of CTRL+ALT+SHIFT, storing 1 bit for each - }; - - KeyDownInfo m_keyDownInfos[KEY_COUNT]; - - 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); - void onKeyModStateRemoved(GameMessageDisposition &disp, MappableKeyModState keyModState); - void onKeyPressed(GameMessageDisposition &disp, Int systemKeyState, MappableKeyType keyType, MappableKeyModState keyModState); - - static MappableKeyType getActionKeyType(Int systemKey); ///< CRTL, ALT, SHIFT will be treated as MK_NONE - static MappableKeyModState getKeyModState(Int systemKeyState); ///< Extract CTRL, ALT, SHIFT key mod state -}; - -//----------------------------------------------------------------------------- -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/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/MessageStream/CommandXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp deleted file mode 100644 index 9f70ad3049f..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp +++ /dev/null @@ -1,5539 +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. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// 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/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 10eb2016a0d..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/HintSpy.cpp +++ /dev/null @@ -1,139 +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_SABOTAGE_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 60ae04c5384..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ /dev/null @@ -1,779 +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; - - if (TheDisplay->getWindowed()) - { - if ((m_screenEdgeScrollMode & ScreenEdgeScrollMode_EnabledInWindowedApp) == 0) - return false; - } - else - { - if ((m_screenEdgeScrollMode & ScreenEdgeScrollMode_EnabledInFullscreenApp) == 0) - return false; - } - - 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 b6705cd43c4..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/MetaEvent.cpp +++ /dev/null @@ -1,1016 +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() - - -#define dont_DUMP_ALL_KEYS_TO_LOG - - -#ifdef DUMP_ALL_KEYS_TO_LOG -#include "GameClient/Keyboard.h" -#endif - -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_CAMERA_TRACKING_DRAWABLE", GameMessage::MSG_META_TOGGLE_CAMERA_TRACKING_DRAWABLE }, - { "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(_ALLOW_DEBUG_CHEATS_IN_RELEASE)//may be defined in GameCommon.h - { "CHEAT_RUNSCRIPT1", GameMessage::MSG_CHEAT_RUNSCRIPT1 }, - { "CHEAT_RUNSCRIPT2", GameMessage::MSG_CHEAT_RUNSCRIPT2 }, - { "CHEAT_RUNSCRIPT3", GameMessage::MSG_CHEAT_RUNSCRIPT3 }, - { "CHEAT_RUNSCRIPT4", GameMessage::MSG_CHEAT_RUNSCRIPT4 }, - { "CHEAT_RUNSCRIPT5", GameMessage::MSG_CHEAT_RUNSCRIPT5 }, - { "CHEAT_RUNSCRIPT6", GameMessage::MSG_CHEAT_RUNSCRIPT6 }, - { "CHEAT_RUNSCRIPT7", GameMessage::MSG_CHEAT_RUNSCRIPT7 }, - { "CHEAT_RUNSCRIPT8", GameMessage::MSG_CHEAT_RUNSCRIPT8 }, - { "CHEAT_RUNSCRIPT9", GameMessage::MSG_CHEAT_RUNSCRIPT9 }, - { "CHEAT_TOGGLE_SPECIAL_POWER_DELAYS", GameMessage::MSG_CHEAT_TOGGLE_SPECIAL_POWER_DELAYS }, - { "CHEAT_SWITCH_TEAMS", GameMessage::MSG_CHEAT_SWITCH_TEAMS }, - { "CHEAT_KILL_SELECTION", GameMessage::MSG_CHEAT_KILL_SELECTION }, - { "CHEAT_TOGGLE_HAND_OF_GOD_MODE", GameMessage::MSG_CHEAT_TOGGLE_HAND_OF_GOD_MODE }, - { "CHEAT_INSTANT_BUILD", GameMessage::MSG_CHEAT_INSTANT_BUILD }, - { "CHEAT_DESHROUD", GameMessage::MSG_CHEAT_DESHROUD }, - { "CHEAT_ADD_CASH", GameMessage::MSG_CHEAT_ADD_CASH }, - { "CHEAT_GIVE_ALL_SCIENCES", GameMessage::MSG_CHEAT_GIVE_ALL_SCIENCES }, - { "CHEAT_GIVE_SCIENCEPURCHASEPOINTS", GameMessage::MSG_CHEAT_GIVE_SCIENCEPURCHASEPOINTS }, - { "CHEAT_SHOW_HEALTH", GameMessage::MSG_CHEAT_SHOW_HEALTH }, - { "CHEAT_TOGGLE_MESSAGE_TEXT", GameMessage::MSG_CHEAT_TOGGLE_MESSAGE_TEXT }, - -#endif - -#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_AUDIO_LOCATIONS", GameMessage::MSG_META_DEBUG_SHOW_AUDIO_LOCATIONS }, - { "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_SUPPLY_CENTER_PLACEMENT", GameMessage::MSG_META_DEMO_TOGGLE_SUPPLY_CENTER_PLACEMENT }, - { "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 }, - { "DEBUG_OBJECT_ID_PERFORMANCE", GameMessage::MSG_META_DEBUG_OBJECT_ID_PERFORMANCE }, - { "DEBUG_DRAWABLE_ID_PERFORMANCE", GameMessage::MSG_META_DEBUG_DRAWABLE_ID_PERFORMANCE }, - { "DEBUG_SLEEPY_UPDATE_PERFORMANCE", GameMessage::MSG_META_DEBUG_SLEEPY_UPDATE_PERFORMANCE }, -#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() -{ - 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; - } - } -} - -//------------------------------------------------------------------------------------------------- -void MetaEventTranslator::onKeyEvent(const GameMessage *msg, GameMessageDisposition &disp) -{ - const Int systemKey = msg->getArgument(0)->integer; - const Int systemKeyState = msg->getArgument(1)->integer; - - const MappableKeyType keyType = getActionKeyType(systemKey); - const MappableKeyModState keyModState = getKeyModState(systemKeyState); - - const Bool modStateRemoved = (keyType == MK_NONE) && (msg->getType() == GameMessage::MSG_RAW_KEY_UP); - - if (modStateRemoved) - { - onKeyModStateRemoved(disp, keyModState); - } - else - { - onKeyPressed(disp, systemKeyState, keyType, keyModState); - } -} - -//------------------------------------------------------------------------------------------------- -void MetaEventTranslator::onKeyModStateRemoved(GameMessageDisposition &disp, MappableKeyModState keyModState) -{ - // TheSuperHackers @fix The key handler now ignores the order in which modifier keys are released. - // This avoids frustrating experiences where a wrong button release order would skip an important key event. - - for (Int keyDownIndex = 0; keyDownIndex < ARRAY_SIZE(m_keyDownInfos); ++keyDownIndex) - { - const MappableKeyType keyDown = (MappableKeyType)keyDownIndex; - KeyDownInfo &keyDownInfo = m_keyDownInfos[keyDownIndex]; - - if (!keyDownInfo.isKeyDown()) - continue; - - for (UnsignedInt modStateIndex = 0; modStateIndex < KeyDownInfo::getMaxKeyModStateCount(); ++modStateIndex) - { - const MappableKeyModState keyDownModState = keyDownInfo.getKeyModState(modStateIndex); - - if (keyDownModState == NONE) - continue; - - if (BitsAreSet(keyModState, keyDownModState)) - continue; - - // Forget that this key and mod state are pressed. - keyDownInfo.clearKeyModState(modStateIndex); - - for (const MetaMapRec *map = TheMetaMap->getFirstMetaMapRec(); map; map = map->m_next) - { - if (!isMessageUsable(map->m_usableIn)) - continue; - - const Bool isMatchingKeyCombo = map->m_key == keyDown && map->m_modState == keyDownModState; - const Bool isTransitionUp = map->m_transition == UP; - - if (!(isMatchingKeyCombo && isTransitionUp)) - continue; - - TheMessageStream->appendMessage(map->m_meta); - disp = DESTROY_MESSAGE; - } - } - } -} - -//------------------------------------------------------------------------------------------------- -void MetaEventTranslator::onKeyPressed(GameMessageDisposition &disp, Int systemKeyState, MappableKeyType keyType, MappableKeyModState keyModState) -{ - // TheSuperHackers @info The regular key handler only triggers events when the mapped key is pressed, - // not when the modifier (CTRL, ALT, SHIFT) is pressed, unless the key is MK_NONE. - - for (const MetaMapRec *map = TheMetaMap->getFirstMetaMapRec(); map; map = map->m_next) - { - if (!isMessageUsable(map->m_usableIn)) - continue; - - const Bool isMatchingKeyCombo = map->m_key == keyType && map->m_modState == keyModState; - const Bool isMatchingTransitionUp = map->m_transition == UP && (systemKeyState & KEY_STATE_UP) != 0; - const Bool isMatchingTransitionDown = map->m_transition == DOWN && (systemKeyState & KEY_STATE_DOWN) != 0; - //const Bool isMatchingTransitionDoubleDown = map->m_transition == DOUBLEDOWN && (systemKeyState & KEY_STATE_DOWN) && m_lastKeyDown == key; - - if (isMatchingKeyCombo && (isMatchingTransitionUp || isMatchingTransitionDown /*|| isMatchingTransitionDoubleDown*/)) - { - 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 (systemKeyState & KEY_STATE_DOWN) - { -#ifdef DUMP_ALL_KEYS_TO_LOG - WideChar Wkey = TheKeyboard->getPrintableKey(keyType, 0); - UnicodeString uKey; - uKey.set(&Wkey); - AsciiString aKey; - aKey.translate(uKey); - DEBUG_LOG(("^%s ", aKey.str())); -#endif - - if (keyModState != NONE) - { - // Remember that this key and mod state are pressed. - m_keyDownInfos[keyType].setKeyModState(keyModState); - } - } - else - { - if (keyModState != NONE) - { - DEBUG_ASSERTCRASH(keyType != MK_NONE, ("Key is expected to be not MK_NONE")); - - // Forget that this key and mod state are pressed. - m_keyDownInfos[keyType].clearKeyModState(keyModState); - } - } -} - -//------------------------------------------------------------------------------------------------- -MappableKeyType MetaEventTranslator::getActionKeyType(Int systemKey) -{ - switch (systemKey) - { - case KEY_LCTRL: - case KEY_RCTRL: - case KEY_LSHIFT: - case KEY_RSHIFT: - case KEY_LALT: - case KEY_RALT: - return MK_NONE; - default: - return (MappableKeyType)systemKey; - } -} - -//------------------------------------------------------------------------------------------------- -MappableKeyModState MetaEventTranslator::getKeyModState(Int systemKeyState) -{ - // for our purposes here, we don't care to distinguish between right and left keys, - // so just fudge a little to simplify things. - Int keyModState = 0; - - if( systemKeyState & KEY_STATE_CONTROL ) - { - keyModState |= CTRL; - } - - if( systemKeyState & KEY_STATE_SHIFT ) - { - keyModState |= SHIFT; - } - - if( systemKeyState & KEY_STATE_ALT ) - { - keyModState |= ALT; - } - - return (MappableKeyModState)keyModState; -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- - -//------------------------------------------------------------------------------------------------- -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/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index 76928a04764..b8b2ce9c110 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 @@ -794,15 +794,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/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