Skip to content

Commit 3712493

Browse files
committed
refactor: Refactor evaluateContextCommand phase 1 (#1192)
- Refactor context input normalization into separate function - Refactor GUI command target normalization into separate function - Refactor waypoint mode command into separate function - Clarify intent of early returns
1 parent 05e518d commit 3712493

2 files changed

Lines changed: 115 additions & 103 deletions

File tree

GeneralsMD/Code/GameEngine/Include/GameClient/CommandXlat.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ class CommandTranslator : public GameMessageTranslator
4141

4242
enum CommandEvaluateType { DO_COMMAND, DO_HINT, EVALUATE_ONLY };
4343

44-
4544
GameMessage::Type evaluateForceAttack( Drawable *draw, const Coord3D *pos, CommandEvaluateType type );
4645
GameMessage::Type evaluateContextCommand( Drawable *draw, const Coord3D *pos, CommandEvaluateType type );
4746

@@ -64,6 +63,10 @@ class CommandTranslator : public GameMessageTranslator
6463
GameMessage::Type issueSpecialPowerCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos, Object* ignoreSelObj );
6564
GameMessage::Type issueFireWeaponCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos );
6665
GameMessage::Type issueCombatDropCommand( const CommandButton *command, CommandEvaluateType commandType, Drawable *target, const Coord3D *pos );
66+
67+
void normalizeContextInputs( Drawable*& draw, Object*& obj, Drawable*& drawableInWay );
68+
GameMessage::Type handleWaypointModeCommand( const Coord3D* pos, Drawable* draw, const CommandEvaluateType& type );
69+
void normalizeGuiCommandTarget( const CommandButton* command, Drawable*& draw, Object*& obj );
6770

6871
virtual GameMessageDisposition translateGameMessage(const GameMessage *msg) override;
6972
};

GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp

Lines changed: 111 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,30 +1540,18 @@ GameMessage::Type CommandTranslator::evaluateForceAttack( Drawable *draw, const
15401540
return retVal;
15411541
}
15421542

1543-
// ------------------------------------------------------------------------------------------------
1544-
/** This method and the order of operations in the check here, determine what command would
1545-
* actually happen (if type parameter == DO_COMMAND) if the user clicked on the drawable
1546-
* 'draw'. If type == DO_HINT, then the user hasn't actually clicked, but has moused over
1547-
* the drawable 'draw' and we want to generate a hint message as to what the actual
1548-
* command would be if clicked
1549-
* NOTE: draw can be null, in which case we give a hint for the location */
1550-
// ------------------------------------------------------------------------------------------------
1551-
GameMessage::Type CommandTranslator::evaluateContextCommand( Drawable *draw,
1552-
const Coord3D *pos,
1553-
CommandEvaluateType type )
1554-
{
1555-
Object *obj = draw ? draw->getObject() : nullptr;
1556-
Drawable *drawableInWay = draw;
1557-
1543+
// TheSuperHackers @refactor RiQQ 15/5/2026 Extracted from evaluateContextCommand monolith. Preparation for proper refactor
1544+
void CommandTranslator::normalizeContextInputs(Drawable*& draw, Object*& obj, Drawable*& drawableInWay) {
15581545
//This piece of code is used to prevent interaction with unselectable objects or masked objects. When we
15591546
//call this function, we typically pass in both a position and a drawable (if applicable), so if the
15601547
//drawable is invalid... then convert it to a position to be evaluated instead.
15611548
//Added: shrubberies are the exception for interactions...
15621549
//Removed: GS Took out ObjectStatusUnselectable, since that status only prevents selection, not everything
1563-
if( obj == nullptr ||
1564-
( obj->getStatusBits().test( OBJECT_STATUS_MASKED ) &&
1565-
!obj->isKindOf(KINDOF_SHRUBBERY) && !obj->isKindOf(KINDOF_FORCEATTACKABLE) ) )
1566-
{
1550+
if ( obj == nullptr ||
1551+
( obj->getStatusBits().test( OBJECT_STATUS_MASKED ) &&
1552+
!obj->isKindOf(KINDOF_SHRUBBERY) &&
1553+
!obj->isKindOf(KINDOF_FORCEATTACKABLE) )
1554+
) {
15671555
//Nulling out the draw and obj pointer will force the remainder of this code to evaluate
15681556
//a position interaction.
15691557
draw = nullptr;
@@ -1576,116 +1564,137 @@ GameMessage::Type CommandTranslator::evaluateContextCommand( Drawable *draw,
15761564
obj = nullptr;
15771565
}
15781566

1579-
if( TheInGameUI->isInForceMoveToMode() )
1580-
{
1567+
if ( TheInGameUI->isInForceMoveToMode() ) {
15811568
//Nulling out the draw and obj pointer will force the remainder of this code to evaluate
15821569
//a position interaction.
15831570
draw = nullptr;
15841571
obj = nullptr;
1585-
} else if (TheInGameUI->isInForceAttackMode() ) {
1572+
}
1573+
else if (TheInGameUI->isInForceAttackMode() ) {
15861574
// setting the drawableInWay to draw will allow us to force attack in the issue move command
15871575
// if there is a location to which we should attack.
15881576
drawableInWay = draw;
15891577
}
1578+
}
15901579

1580+
// TheSuperHackers @refactor RiQQ 15/5/2026 Extracted from evaluateContextCommand monolith. Preparation for proper refactor
1581+
GameMessage::Type CommandTranslator::handleWaypointModeCommand(const Coord3D* pos, Drawable* draw, const CommandEvaluateType& type) {
15911582
GameMessage::Type msgType = GameMessage::MSG_INVALID;
15921583

1584+
//Override any *other* commands with waypoint commands.
1585+
if( type == DO_COMMAND || type == EVALUATE_ONLY ) {
1586+
if( TheTerrainLogic ) {
1587+
msgType = issueMoveToLocationCommand( pos, draw, type );
1588+
}
1589+
}
1590+
else {
1591+
msgType = GameMessage::MSG_ADD_WAYPOINT_HINT;
1592+
GameMessage* hintMessage = TheMessageStream->appendMessage( msgType );
1593+
hintMessage->appendLocationArgument( *pos );
1594+
}
1595+
1596+
return msgType;
1597+
}
1598+
1599+
// TheSuperHackers @refactor RiQQ 15/5/2026 Extracted from evaluateContextCommand monolith. Preparation for proper refactor
1600+
void CommandTranslator::normalizeGuiCommandTarget( const CommandButton* command, Drawable*& draw, Object*& obj ) {
1601+
if( obj && obj->isKindOf( KINDOF_SHRUBBERY ) && !BitIsSet( command->getOptions(), ALLOW_SHRUBBERY_TARGET ) ) {
1602+
//If our object is a shrubbery, and we don't allow targeting it... then null it out.
1603+
//Nulling out the draw and obj pointer will force the remainder of this code to evaluate
1604+
//a position interaction.
1605+
draw = nullptr;
1606+
obj = nullptr;
1607+
}
1608+
1609+
if( obj && obj->isKindOf( KINDOF_MINE ) && !BitIsSet( command->getOptions(), ALLOW_MINE_TARGET ) ) {
1610+
//If our object is a mine, and we don't allow targeting it... then null it out.
1611+
//Nulling out the draw and obj pointer will force the remainder of this code to evaluate
1612+
//a position interaction.
1613+
draw = nullptr;
1614+
obj = nullptr;
1615+
}
1616+
1617+
//Kris: September 27, 2002
1618+
//Added relationship tests to make sure we're not attempting a context-command on a restricted relationship.
1619+
//This case prevents rebels from using tranq darts on allies.
1620+
if( obj && BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) ) {
1621+
Relationship relationship = ThePlayerList->getLocalPlayer()->getRelationship( obj->getTeam() );
1622+
1623+
switch( relationship ) {
1624+
case ALLIES:
1625+
if( !BitIsSet( command->getOptions(), NEED_TARGET_ALLY_OBJECT ) ) {
1626+
draw = nullptr;
1627+
obj = nullptr;
1628+
}
1629+
break;
1630+
case ENEMIES:
1631+
if( !BitIsSet( command->getOptions(), NEED_TARGET_ENEMY_OBJECT ) ) {
1632+
draw = nullptr;
1633+
obj = nullptr;
1634+
}
1635+
break;
1636+
case NEUTRAL:
1637+
if( !BitIsSet( command->getOptions(), NEED_TARGET_NEUTRAL_OBJECT ) ) {
1638+
draw = nullptr;
1639+
obj = nullptr;
1640+
}
1641+
break;
1642+
}
1643+
}
1644+
}
1645+
1646+
// ------------------------------------------------------------------------------------------------
1647+
/** This method and the order of operations in the check here, determine what command would
1648+
* actually happen (if type parameter == DO_COMMAND) if the user clicked on the drawable
1649+
* 'draw'. If type == DO_HINT, then the user hasn't actually clicked, but has moused over
1650+
* the drawable 'draw' and we want to generate a hint message as to what the actual
1651+
* command would be if clicked
1652+
* NOTE: draw can be null, in which case we give a hint for the location */
1653+
// ------------------------------------------------------------------------------------------------
1654+
GameMessage::Type CommandTranslator::evaluateContextCommand(
1655+
Drawable *draw,
1656+
const Coord3D *pos,
1657+
CommandEvaluateType type
1658+
) {
1659+
Object *obj = draw ? draw->getObject() : nullptr;
1660+
Drawable *drawableInWay = draw;
1661+
normalizeContextInputs(draw, obj, drawableInWay);
1662+
15931663
// Then we should determine if the game currently prefers selection events. If it does, then return
15941664
// the invalid message.
1595-
if (obj) {
1596-
if (obj->isLocallyControlled() && TheInGameUI->isInPreferSelectionMode()) {
1597-
return msgType;
1598-
}
1665+
if (obj && obj->isLocallyControlled() && TheInGameUI->isInPreferSelectionMode()) {
1666+
return GameMessage::MSG_INVALID;
15991667
}
16001668

16011669
// Kris: Now that we can select non-controllable units/structures, don't allow any actions to be performed.
16021670
const CommandButton *command = TheInGameUI->getGUICommand();
1671+
GameMessage::Type msgType = GameMessage::MSG_INVALID;
16031672

1604-
if (command && command->getCommandType() == GUICOMMANDMODE_PLACE_BEACON)
1605-
{
1673+
if (command && command->getCommandType() == GUICOMMANDMODE_PLACE_BEACON) {
16061674
msgType = GameMessage::MSG_VALID_GUICOMMAND_HINT;
16071675
TheMessageStream->appendMessage(msgType);
1676+
return msgType;
1677+
}
1678+
1679+
const bool canPerformActions = (
1680+
TheInGameUI->areSelectedObjectsControllable() ||
1681+
(command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT)
1682+
);
1683+
if ( !canPerformActions ) {
1684+
return GameMessage::MSG_INVALID;
16081685
}
1609-
else if( TheInGameUI->areSelectedObjectsControllable()
1610-
|| (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT))
1611-
{
1612-
GameMessage *hintMessage;
16131686

1614-
if( TheInGameUI->isInWaypointMode() )
1615-
{
1616-
//Override any *other* commands with waypoint commands.
1617-
if( type == DO_COMMAND || type == EVALUATE_ONLY )
1618-
{
1619-
if( TheTerrainLogic )
1620-
{
1621-
msgType = issueMoveToLocationCommand( pos, draw, type );
1622-
}
1623-
}
1624-
else
1625-
{
1626-
msgType = GameMessage::MSG_ADD_WAYPOINT_HINT;
1627-
hintMessage = TheMessageStream->appendMessage( msgType );
1628-
hintMessage->appendLocationArgument( *pos );
1687+
{
1688+
if( TheInGameUI->isInWaypointMode() ) {
1689+
msgType = handleWaypointModeCommand(pos, draw, type);
1690+
if (msgType != GameMessage::MSG_INVALID) {
1691+
return msgType;
16291692
}
1630-
return msgType;
16311693
}
16321694

16331695
CanAttackResult result;
1696+
GameMessage *hintMessage;
16341697

1635-
if(command &&
1636-
(command->isContextCommand()
1637-
|| command->getCommandType() == GUI_COMMAND_SPECIAL_POWER
1638-
|| command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT))
1639-
{
1640-
if( obj && obj->isKindOf( KINDOF_SHRUBBERY ) && !BitIsSet( command->getOptions(), ALLOW_SHRUBBERY_TARGET ) )
1641-
{
1642-
//If our object is a shrubbery, and we don't allow targeting it... then null it out.
1643-
//Nulling out the draw and obj pointer will force the remainder of this code to evaluate
1644-
//a position interaction.
1645-
draw = nullptr;
1646-
obj = nullptr;
1647-
}
1648-
1649-
if( obj && obj->isKindOf( KINDOF_MINE ) && !BitIsSet( command->getOptions(), ALLOW_MINE_TARGET ) )
1650-
{
1651-
//If our object is a mine, and we don't allow targeting it... then null it out.
1652-
//Nulling out the draw and obj pointer will force the remainder of this code to evaluate
1653-
//a position interaction.
1654-
draw = nullptr;
1655-
obj = nullptr;
1656-
}
1657-
1658-
//Kris: September 27, 2002
1659-
//Added relationship tests to make sure we're not attempting a context-command on a restricted relationship.
1660-
//This case prevents rebels from using tranq darts on allies.
1661-
if( obj && BitIsSet( command->getOptions(), COMMAND_OPTION_NEED_OBJECT_TARGET ) )
1662-
{
1663-
Relationship relationship = ThePlayerList->getLocalPlayer()->getRelationship( obj->getTeam() );
1664-
switch( relationship )
1665-
{
1666-
case ALLIES:
1667-
if( !BitIsSet( command->getOptions(), NEED_TARGET_ALLY_OBJECT ) )
1668-
{
1669-
draw = nullptr;
1670-
obj = nullptr;
1671-
}
1672-
break;
1673-
case ENEMIES:
1674-
if( !BitIsSet( command->getOptions(), NEED_TARGET_ENEMY_OBJECT ) )
1675-
{
1676-
draw = nullptr;
1677-
obj = nullptr;
1678-
}
1679-
break;
1680-
case NEUTRAL:
1681-
if( !BitIsSet( command->getOptions(), NEED_TARGET_NEUTRAL_OBJECT ) )
1682-
{
1683-
draw = nullptr;
1684-
obj = nullptr;
1685-
}
1686-
break;
1687-
}
1688-
}
16891698

16901699
Bool currentlyValid = FALSE;
16911700
ObjectID objectID = obj ? obj->getID() : INVALID_ID;

0 commit comments

Comments
 (0)