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