7373#include " GameClient/Drawable.h"
7474#include " GameClient/Eva.h"
7575#include " GameClient/GameText.h"
76+ #include " GameClient/GameWindowTransitions.h"
7677#include " GameClient/GameWindowManager.h"
7778#include " GameClient/GUICallbacks.h"
7879#include " GameClient/InGameUI.h"
@@ -264,8 +265,10 @@ void GameLogic::clearGameData( Bool showScoreScreen )
264265 if ((!isInShellGame () || !isInGame ()) && showScoreScreen && !TheGlobalData->m_headless )
265266 {
266267 shellGame = TRUE ;
268+ TheTransitionHandler->setGroup (" FadeWholeScreen" );
267269 TheShell->push (" Menus/ScoreScreen.wnd" );
268270 TheShell->showShell (FALSE ); // by passing in false, we don't want to run the Init on the shell screen we just pushed on
271+ TheTransitionHandler->reverse (" FadeWholeScreen" );
269272
270273 void FixupScoreScreenMovieWindow ();
271274 FixupScoreScreenMovieWindow ();
@@ -656,6 +659,31 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData )
656659 break ;
657660 }
658661
662+ case GameMessage::MSG_ENABLE_RETALIATION_MODE:
663+ {
664+ #if RETAIL_COMPATIBLE_CRC
665+ // Logically turns on or off retaliation mode for a specified player.
666+ const Int playerIndex = msg->getArgument ( 0 )->integer ;
667+ const Bool enableRetaliation = msg->getArgument ( 1 )->boolean ;
668+
669+ Player *player = ThePlayerList->getNthPlayer ( playerIndex );
670+ if ( player )
671+ {
672+ DEBUG_ASSERTCRASH (player == msgPlayer,
673+ (" Retaliation mode of player '%ls' was illegally set by player '%ls'. Before: '%d', after: '%d'." ,
674+ player->getPlayerDisplayName ().str (), msgPlayer->getPlayerDisplayName ().str (),
675+ player->isLogicalRetaliationModeEnabled (), enableRetaliation) );
676+
677+ player->setLogicalRetaliationModeEnabled ( enableRetaliation );
678+ }
679+ #else
680+ // TheSuperHackers @fix stephanmeesters 08/03/2026 Ensure that players can only set their own retaliation mode.
681+ const Bool enableRetaliation = msg->getArgument ( 0 )->boolean ;
682+ msgPlayer->setLogicalRetaliationModeEnabled ( enableRetaliation );
683+ #endif
684+ break ;
685+ }
686+
659687 // ---------------------------------------------------------------------------------------------
660688 case GameMessage::MSG_DO_WEAPON_AT_LOCATION:
661689 {
@@ -728,22 +756,28 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData )
728756 // ---------------------------------------------------------------------------------------------
729757 case GameMessage::MSG_DO_SPECIAL_POWER_AT_LOCATION:
730758 {
759+ const Bool hasAngle = msg->getArgumentCount () >= 6 ;
760+ Int argumentIndex = 0 ;
761+
731762 // first argument is the special power ID
732- UnsignedInt specialPowerID = msg->getArgument ( 0 )->integer ;
763+ UnsignedInt specialPowerID = msg->getArgument ( argumentIndex++ )->integer ;
733764
734765 // Location argument 2 is destination
735- Coord3D targetCoord = msg->getArgument (1 )->location ;
766+ Coord3D targetCoord = msg->getArgument ( argumentIndex++ )->location ;
767+
768+ // Angle argument 3 is the orientation of the special power (if applicable)
769+ Real angle = hasAngle ? msg->getArgument ( argumentIndex++ )->real : INVALID_ANGLE;
736770
737771 // Object in way -- if applicable (some specials care, others don't)
738- ObjectID objectID = msg->getArgument ( 2 )->objectID ;
772+ ObjectID objectID = msg->getArgument ( argumentIndex++ )->objectID ;
739773 Object *objectInWay = findObjectByID ( objectID );
740774
741775 // Command button options -- special power may care about variance options
742- UnsignedInt options = msg->getArgument ( 3 )->integer ;
776+ UnsignedInt options = msg->getArgument ( argumentIndex++ )->integer ;
743777
744778 // check for possible specific source, ignoring selection.
745- ObjectID sourceID = msg->getArgument (4 )->objectID ;
746- Object* source = findObjectByID (sourceID);
779+ ObjectID sourceID = msg->getArgument ( argumentIndex++ )->objectID ;
780+ Object* source = findObjectByID ( sourceID );
747781 if (source != nullptr )
748782 {
749783#if !RETAIL_COMPATIBLE_CRC
@@ -760,7 +794,7 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData )
760794
761795 AIGroupPtr theGroup = TheAI->createGroup ();
762796 theGroup->add (source);
763- theGroup->groupDoSpecialPowerAtLocation ( specialPowerID, &targetCoord, INVALID_ANGLE , objectInWay, options );
797+ theGroup->groupDoSpecialPowerAtLocation ( specialPowerID, &targetCoord, angle , objectInWay, options );
764798#if RETAIL_COMPATIBLE_AIGROUP
765799 TheAI->destroyGroup (theGroup);
766800#else
@@ -772,7 +806,7 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData )
772806 // Use the selected group!
773807 if ( currentlySelectedGroup )
774808 {
775- currentlySelectedGroup->groupDoSpecialPowerAtLocation ( specialPowerID, &targetCoord, INVALID_ANGLE , objectInWay, options );
809+ currentlySelectedGroup->groupDoSpecialPowerAtLocation ( specialPowerID, &targetCoord, angle , objectInWay, options );
776810 }
777811 }
778812 break ;
@@ -977,7 +1011,7 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData )
9771011 break ;
9781012 }
9791013
980- #if defined(RTS_DEBUG)
1014+ #if defined(RTS_DEBUG) || defined (_ALLOW_DEBUG_CHEATS_IN_RELEASE)
9811015 // ---------------------------------------------------------------------------------------------
9821016 case GameMessage::MSG_DEBUG_KILL_SELECTION:
9831017 {
0 commit comments