From 6259d73ef6704380fbb71f1e7f0e9af8e7c7bd5f Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Thu, 13 Nov 2025 22:06:03 +1100 Subject: [PATCH 1/3] feat: Add ability to rotate the camera in 45 degree increments using the mouse --- .../Code/GameEngine/Include/GameClient/LookAtXlat.h | 1 + .../Source/GameClient/MessageStream/LookAtXlat.cpp | 11 +++++++++-- .../Code/GameEngine/Include/GameClient/LookAtXlat.h | 1 + .../Source/GameClient/MessageStream/LookAtXlat.cpp | 11 +++++++++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameClient/LookAtXlat.h b/Generals/Code/GameEngine/Include/GameClient/LookAtXlat.h index 8aa865f59a9..91522d87b1a 100644 --- a/Generals/Code/GameEngine/Include/GameClient/LookAtXlat.h +++ b/Generals/Code/GameEngine/Include/GameClient/LookAtXlat.h @@ -71,6 +71,7 @@ class LookAtTranslator : public GameMessageTranslator 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 ALT pitch rotation diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index f2f60953063..918b0a96e56 100644 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -291,6 +291,7 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage 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; m_timestamp = TheGameClient->getFrame(); @@ -360,10 +361,16 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage if (m_isRotating) { const Real FACTOR = 0.01f; + Real angle = FACTOR * (m_currentPos.x - m_originalAnchor.x); + Real targetAngle = m_anchorAngle + angle; - Real angle = FACTOR * (m_currentPos.x - m_anchor.x); + if (TheInGameUI->isInForceAttackMode()) + { + const Real snapRadians = DEG_TO_RADF(45); + targetAngle = WWMath::Round(targetAngle / snapRadians) * snapRadians; + } - TheTacticalView->setAngle( TheTacticalView->getAngle() + angle ); + TheTacticalView->setAngle(targetAngle); m_anchor = msg->getArgument( 0 )->pixel; } diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/LookAtXlat.h b/GeneralsMD/Code/GameEngine/Include/GameClient/LookAtXlat.h index d69dfe48580..e91b98f66ec 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/LookAtXlat.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/LookAtXlat.h @@ -71,6 +71,7 @@ class LookAtTranslator : public GameMessageTranslator 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 ALT pitch rotation diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index c5b76e705f5..213ce0fd7cd 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -290,6 +290,7 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage 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; m_timestamp = TheGameClient->getFrame(); @@ -359,10 +360,16 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage if (m_isRotating) { const Real FACTOR = 0.01f; + Real angle = FACTOR * (m_currentPos.x - m_originalAnchor.x); + Real targetAngle = m_anchorAngle + angle; - Real angle = FACTOR * (m_currentPos.x - m_anchor.x); + if (TheInGameUI->isInForceAttackMode()) + { + const Real snapRadians = DEG_TO_RADF(45); + targetAngle = WWMath::Round(targetAngle / snapRadians) * snapRadians; + } - TheTacticalView->setAngle( TheTacticalView->getAngle() + angle ); + TheTacticalView->setAngle(targetAngle); m_anchor = msg->getArgument( 0 )->pixel; } From 90112177498687370ad1c0837b9d42e330a24a68 Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Thu, 13 Nov 2025 22:22:24 +1100 Subject: [PATCH 2/3] refactor: Missed a const --- .../GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp | 2 +- .../GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index 918b0a96e56..b596bcabed1 100644 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -361,7 +361,7 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage if (m_isRotating) { const Real FACTOR = 0.01f; - Real angle = FACTOR * (m_currentPos.x - m_originalAnchor.x); + const Real angle = FACTOR * (m_currentPos.x - m_originalAnchor.x); Real targetAngle = m_anchorAngle + angle; if (TheInGameUI->isInForceAttackMode()) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index 213ce0fd7cd..7dbdb44c631 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -360,7 +360,7 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage if (m_isRotating) { const Real FACTOR = 0.01f; - Real angle = FACTOR * (m_currentPos.x - m_originalAnchor.x); + const Real angle = FACTOR * (m_currentPos.x - m_originalAnchor.x); Real targetAngle = m_anchorAngle + angle; if (TheInGameUI->isInForceAttackMode()) From fa00d78a15886232c20597c98154fcd0e9ac918e Mon Sep 17 00:00:00 2001 From: Stubbjax Date: Thu, 13 Nov 2025 22:23:03 +1100 Subject: [PATCH 3/3] docs: Add comments --- .../GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp | 2 ++ .../GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index b596bcabed1..c77e045a11e 100644 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -364,6 +364,8 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage 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); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index 7dbdb44c631..b9990857def 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -363,6 +363,8 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage 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);