diff --git a/Core/GameEngine/Include/GameClient/CommandXlat.h b/Core/GameEngine/Include/GameClient/CommandXlat.h index 8c861646e62..0765459a123 100644 --- a/Core/GameEngine/Include/GameClient/CommandXlat.h +++ b/Core/GameEngine/Include/GameClient/CommandXlat.h @@ -65,6 +65,33 @@ class CommandTranslator : public GameMessageTranslator 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 ); + void resolveContextTarget( Drawable *&draw, Object *&obj, Drawable *&drawableInWay ); + void resolveGuiCommandTarget( const CommandButton *command, Drawable *&draw, Object *&obj ); + + GameMessage::Type handleWaypointModeCommand( const Coord3D *pos, Drawable *draw, CommandEvaluateType type ); + GameMessage::Type handleGuiCommand( const CommandButton *command, Drawable *draw, Object *obj, const Coord3D *pos, CommandEvaluateType type ); + GameMessage::Type handleSpecialPowerConstructCommand( const CommandButton *command, Drawable *draw, const Coord3D *pos, CommandEvaluateType type ); + GameMessage::Type handleSpecialPowerOverrideDestinationCommand( const Coord3D *pos, CommandEvaluateType type ); + GameMessage::Type handleResumeConstructionCommand( Object *obj, CommandEvaluateType type ); + GameMessage::Type handleDockCommand( Object *obj, CommandEvaluateType type ); + GameMessage::Type handleRepairObjectCommand( Object *obj, CommandEvaluateType type ); + GameMessage::Type handleGetRepairedCommand( Object *obj, CommandEvaluateType type ); + GameMessage::Type handleGetHealedCommand( Object *obj, CommandEvaluateType type ); + GameMessage::Type handleHijackVehicleCommand( Drawable *draw, CommandEvaluateType type ); + GameMessage::Type handleConvertToCarBombCommand( Drawable *draw, Object *obj, CommandEvaluateType type ); + GameMessage::Type handleSabotageBuildingCommand( Drawable *draw, CommandEvaluateType type ); + GameMessage::Type handleSalvageCommand( Object *obj, CommandEvaluateType type ); + GameMessage::Type handleEnterObjectCommand( Drawable *draw, Object *obj, CommandEvaluateType type ); + GameMessage::Type handleAttackObjectCommand( Drawable *draw, Object *obj, CommandEvaluateType type, GameMessage::Type hintType ); + GameMessage::Type handleCaptureBuildingCommand( Drawable *draw, Object *obj, const Coord3D *pos, CommandEvaluateType type ); + GameMessage::Type handleHackCommand( Drawable *draw, Object *obj, const Coord3D *pos, CommandEvaluateType type, SpecialPowerType hackPower ); +#ifdef ALLOW_SURRENDER + GameMessage::Type handlePickUpPrisonerCommand( Drawable *draw, Object *obj, CommandEvaluateType type ); +#endif + GameMessage::Type handleSetRallyPointCommand( const Coord3D *pos, CommandEvaluateType type ); + GameMessage::Type handleImpossibleAttackHint( const Coord3D *pos ); + GameMessage::Type handleDefaultMoveCommand( Drawable *draw, Drawable *drawableInWay, const Coord3D *pos, CommandEvaluateType type ); + virtual GameMessageDisposition translateGameMessage(const GameMessage *msg) override; }; diff --git a/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp index 7e322b28241..0d82bf856f7 100644 --- a/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp @@ -1538,29 +1538,18 @@ GameMessage::Type CommandTranslator::evaluateForceAttack( Drawable *draw, const 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 ) +void CommandTranslator::resolveContextTarget( Drawable *&draw, Object *&obj, Drawable *&drawableInWay ) { - 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) ) ) + 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. @@ -1569,895 +1558,1015 @@ GameMessage::Type CommandTranslator::evaluateContextCommand( Drawable *draw, } // 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)) { + if (obj && obj->isLocallyControlled() && obj->isKindOf(KINDOF_MINE)) + { draw = nullptr; obj = nullptr; } - if( TheInGameUI->isInForceMoveToMode() ) + 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() ) { + } + 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 CommandTranslator::handleWaypointModeCommand( const Coord3D *pos, Drawable *draw, CommandEvaluateType type ) +{ 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; + //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; + GameMessage* hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendLocationArgument( *pos ); + } - // Kris: Now that we can select non-controllable units/structures, don't allow any actions to be performed. - const CommandButton *command = TheInGameUI->getGUICommand(); + return msgType; +} - if (command && command->getCommandType() == GUICOMMANDMODE_PLACE_BEACON) +void CommandTranslator::resolveGuiCommandTarget( const CommandButton *command, Drawable *&draw, Object *&obj ) +{ + 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 ) ) { - msgType = GameMessage::MSG_VALID_GUICOMMAND_HINT; - TheMessageStream->appendMessage(msgType); + //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; } - else if( TheInGameUI->areSelectedObjectsControllable() - || (command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT)) + + //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 ) ) { - GameMessage *hintMessage; + Relationship relationship = ThePlayerList->getLocalPlayer()->getRelationship( obj->getTeam() ); - if( TheInGameUI->isInWaypointMode() ) + switch( relationship ) { - //Override any *other* commands with waypoint commands. - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - if( TheTerrainLogic ) + 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 ) ) { - msgType = issueMoveToLocationCommand( pos, draw, type ); + draw = nullptr; + obj = nullptr; } - } - else - { - msgType = GameMessage::MSG_ADD_WAYPOINT_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendLocationArgument( *pos ); - } - return msgType; + break; + case NEUTRAL: + if( !BitIsSet( command->getOptions(), NEED_TARGET_NEUTRAL_OBJECT ) ) + { + draw = nullptr; + obj = nullptr; + } + break; } + } +} - 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; - } +GameMessage::Type CommandTranslator::handleGuiCommand( const CommandButton *command, Drawable *draw, Object *obj, const Coord3D *pos, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - 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; - } + resolveGuiCommandTarget( command, draw, obj ); - //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; + } - Bool currentlyValid = FALSE; - ObjectID objectID = obj ? obj->getID() : INVALID_ID; + if( currentlyValid ) + { + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { 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 ); + msgType = createEnterMessage( draw, type ); break; #ifdef ALLOW_SURRENDER case GUICOMMANDMODE_PICK_UP_PRISONER: - currentlyValid = TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_PICK_UP_PRISONER, obj, InGameUI::SELECTION_ANY ); + 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 ) - currentlyValid = TheInGameUI->canSelectedObjectsDoSpecialPower( command, obj, pos, InGameUI::SELECTION_ANY, command->getOptions(), unit ); - else - currentlyValid = false; + msgType = issueSpecialPowerCommand( command, type, draw, pos, unit ); break; } - case GUI_COMMAND_SPECIAL_POWER: - currentlyValid = TheInGameUI->canSelectedObjectsDoSpecialPower( command, obj, pos, InGameUI::SELECTION_ANY, command->getOptions(), nullptr ); + case GUI_COMMAND_SPECIAL_POWER://lorenzen + msgType = issueSpecialPowerCommand( command, type, draw, pos, nullptr ); break; case GUI_COMMAND_FIRE_WEAPON: - currentlyValid = TheInGameUI->canSelectedObjectsEffectivelyUseWeapon( command, obj, pos, InGameUI::SELECTION_ANY ); + msgType = issueFireWeaponCommand( command, type, draw, pos ); break; case GUI_COMMAND_COMBATDROP: - currentlyValid = !obj ? TRUE : TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_COMBATDROP_INTO, obj, InGameUI::SELECTION_ANY ); + msgType = issueCombatDropCommand( command, type, draw, pos ); 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 + // null out the GUI command if we're actually doing something + if( type == DO_COMMAND ) { - msgType = GameMessage::MSG_INVALID_GUICOMMAND_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( objectID ); + TheInGameUI->setGUICommand( nullptr ); } } - else if( command && (command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT - || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT_FROM_SHORTCUT) ) + else { - //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; - } - } + 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 ); + } + + return msgType; +} +GameMessage::Type CommandTranslator::handleSpecialPowerConstructCommand( const CommandButton *command, Drawable *draw, const Coord3D *pos, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; - // ******************************************************************************************** - else if( TheInGameUI->canSelectedObjectsOverrideSpecialPowerDestination( pos, InGameUI::SELECTION_ANY, SPECIAL_INVALID ) ) + //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() ) { - if( type == DO_COMMAND || type == EVALUATE_ONLY ) + 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; + } + } - // do the command - msgType = GameMessage::MSG_DO_SPECIAL_POWER_OVERRIDE_DESTINATION; - if( type == DO_COMMAND ) - { - GameMessage *gameMsg = TheMessageStream->appendMessage( msgType ); + return msgType; +} - gameMsg->appendLocationArgument( *pos ); - gameMsg->appendIntegerArgument( SPECIAL_INVALID ); - gameMsg->appendObjectIDArgument( INVALID_ID ); // no specific source +GameMessage::Type CommandTranslator::handleSpecialPowerOverrideDestinationCommand( const Coord3D *pos, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - } + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { - } - else - { + // do the command + msgType = GameMessage::MSG_DO_SPECIAL_POWER_OVERRIDE_DESTINATION; + if( type == DO_COMMAND ) + { + GameMessage *gameMsg = TheMessageStream->appendMessage( msgType ); - // generate a hint message - msgType = GameMessage::MSG_DO_SPECIAL_POWER_OVERRIDE_DESTINATION_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); + gameMsg->appendLocationArgument( *pos ); + gameMsg->appendIntegerArgument( SPECIAL_INVALID ); + gameMsg->appendObjectIDArgument( INVALID_ID ); // no specific source - } } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_RESUME_CONSTRUCTION, obj, InGameUI::SELECTION_ANY ) ) - { + } + else + { - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { + // generate a hint message + msgType = GameMessage::MSG_DO_SPECIAL_POWER_OVERRIDE_DESTINATION_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); - // do the command - msgType = GameMessage::MSG_RESUME_CONSTRUCTION; - if( type == DO_COMMAND ) - { - GameMessage *resumeMsg = TheMessageStream->appendMessage( msgType ); + } - resumeMsg->appendObjectIDArgument( obj->getID() ); + return msgType; +} - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_RESUME_CONSTRUCTION ); +GameMessage::Type CommandTranslator::handleResumeConstructionCommand( Object *obj, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - } + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { - } - else - { + // do the command + msgType = GameMessage::MSG_RESUME_CONSTRUCTION; + if( type == DO_COMMAND ) + { + GameMessage *resumeMsg = TheMessageStream->appendMessage( msgType ); - // generate a hint message - msgType = GameMessage::MSG_RESUME_CONSTRUCTION_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); + resumeMsg->appendObjectIDArgument( obj->getID() ); - } + pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_RESUME_CONSTRUCTION ); } - // ******************************************************************************************** - 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 ); + } + else + { - dockMsg->appendObjectIDArgument( obj->getID() ); + // generate a hint message + msgType = GameMessage::MSG_RESUME_CONSTRUCTION_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( obj->getID() ); - // only make sounds if we really did the command messages - pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DOCK); - } + } - } - else - { + return msgType; +} - // make the hint - msgType = GameMessage::MSG_DOCK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); +GameMessage::Type CommandTranslator::handleDockCommand( Object *obj, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - } + // + // 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 ) + { - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_REPAIR_OBJECT, obj, InGameUI::SELECTION_ANY ) ) + // Give the dock command + msgType = GameMessage::MSG_DOCK; + if( type == DO_COMMAND ) { + GameMessage *dockMsg = TheMessageStream->appendMessage( msgType ); - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { + dockMsg->appendObjectIDArgument( obj->getID() ); - // do the command - msgType = GameMessage::MSG_DO_REPAIR; - if( type == DO_COMMAND ) - { - GameMessage *healMsg = TheMessageStream->appendMessage( msgType ); + // only make sounds if we really did the command messages + pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DOCK); + } - healMsg->appendObjectIDArgument( obj->getID() ); + } + else + { - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_REPAIR ); + // make the hint + msgType = GameMessage::MSG_DOCK_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( obj->getID() ); - } + } - } - else - { + return msgType; +} - // generate a hint message - msgType = GameMessage::MSG_DO_REPAIR_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); +GameMessage::Type CommandTranslator::handleRepairObjectCommand( Object *obj, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - } + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_GET_REPAIRED_AT, obj, InGameUI::SELECTION_ANY ) ) + // do the command + msgType = GameMessage::MSG_DO_REPAIR; + if( type == DO_COMMAND ) { + GameMessage *healMsg = TheMessageStream->appendMessage( msgType ); - 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() ); - healMsg->appendObjectIDArgument( obj->getID() ); + pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_REPAIR ); + } - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_GET_REPAIRED ); + } + else + { + // generate a hint message + msgType = GameMessage::MSG_DO_REPAIR_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( obj->getID() ); - } + } - } - else - { + return msgType; +} - // generate a hint message - msgType = GameMessage::MSG_GET_REPAIRED_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); +GameMessage::Type CommandTranslator::handleGetRepairedCommand( Object *obj, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - } + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_GET_HEALED_AT, obj, InGameUI::SELECTION_ANY ) ) + // do the command + msgType = GameMessage::MSG_GET_REPAIRED; + if( type == DO_COMMAND ) { + GameMessage *healMsg = TheMessageStream->appendMessage( msgType ); - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { + healMsg->appendObjectIDArgument( obj->getID() ); - // 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_REPAIRED ); - pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_GET_HEALED ); - } + } - } - else - { + } + else + { - // generate hint message - msgType = GameMessage::MSG_GET_HEALED_HINT; - hintMessage = TheMessageStream->appendMessage( msgType); - hintMessage->appendObjectIDArgument( obj->getID() ); + // generate a hint message + msgType = GameMessage::MSG_GET_REPAIRED_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 ) ) - { + return msgType; +} - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { +GameMessage::Type CommandTranslator::handleGetHealedCommand( Object *obj, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - // 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 ); + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { - } - else - { + // do the command + msgType = GameMessage::MSG_GET_HEALED; + if( type == DO_COMMAND ) + { + GameMessage *healMsg = TheMessageStream->appendMessage( msgType ); - msgType = GameMessage::MSG_HIJACK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( draw->getObject()->getID() ); + healMsg->appendObjectIDArgument( obj->getID() ); - } + pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_GET_HEALED ); } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_CONVERT_OBJECT_TO_CARBOMB, obj, InGameUI::SELECTION_ANY ) ) - { - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { + } + else + { - // issue the command (convert to carbomb is nearly identical to enter) - msgType = createEnterMessage( draw, type ); + // generate hint message + msgType = GameMessage::MSG_GET_HEALED_HINT; + hintMessage = TheMessageStream->appendMessage( msgType); + hintMessage->appendObjectIDArgument( obj->getID() ); - } - else - { + } - msgType = GameMessage::MSG_CONVERT_TO_CARBOMB_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); + return msgType; +} - } - } - // ******************************************************************************************** - else if( draw && draw->getObject() && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_SABOTAGE_BUILDING, - draw->getObject(), - InGameUI::SELECTION_ANY ) ) - { +GameMessage::Type CommandTranslator::handleHijackVehicleCommand( Drawable *draw, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - 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() ); - } + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && canSelectionSalvage(obj) ) - { - GameMessage *msg; + // 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 ); - 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 + { - } else { - msgType = GameMessage::MSG_DO_SALVAGE_HINT; - msg = TheMessageStream->appendMessage(msgType); - msg->appendLocationArgument(*obj->getPosition()); - } + msgType = GameMessage::MSG_HIJACK_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( draw->getObject()->getID() ); - } - // ******************************************************************************************** - else if( draw && !TheInGameUI->isInForceAttackMode() && - TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_ENTER_OBJECT, obj, InGameUI::SELECTION_ANY, true ) ) - { + } - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { + return msgType; +} - // issue the command - msgType = createEnterMessage( draw, type ); +GameMessage::Type CommandTranslator::handleConvertToCarBombCommand( Drawable *draw, Object *obj, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - } - else - { + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { - msgType = GameMessage::MSG_ENTER_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - } + // issue the command (convert to carbomb is nearly identical to enter) + msgType = createEnterMessage( draw, type ); - } - // ******************************************************************************************** - else if( draw && (result = TheInGameUI->getCanSelectedObjectsAttack( InGameUI::ACTIONTYPE_ATTACK_OBJECT, obj, InGameUI::SELECTION_ANY, TheInGameUI->isInForceAttackMode() )) == ATTACKRESULT_POSSIBLE ) - { + } + else + { - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { + msgType = GameMessage::MSG_CONVERT_TO_CARBOMB_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( obj->getID() ); - // issue the attack order - msgType = issueAttackCommand( draw, type ); + } - } - else - { + return msgType; +} - // Generate an Attack hint - msgType = GameMessage::MSG_DO_ATTACK_OBJECT_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); +GameMessage::Type CommandTranslator::handleSabotageBuildingCommand( Drawable *draw, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - } + 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() ); + } + + return msgType; +} + +GameMessage::Type CommandTranslator::handleSalvageCommand( Object *obj, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + 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 if( draw && result == ATTACKRESULT_POSSIBLE_AFTER_MOVING ) - { - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { - // issue the attack order - msgType = issueAttackCommand( draw, type ); + } else { + msgType = GameMessage::MSG_DO_SALVAGE_HINT; + msg = TheMessageStream->appendMessage(msgType); + msg->appendLocationArgument(*obj->getPosition()); + } - } - else - { + return msgType; +} + +GameMessage::Type CommandTranslator::handleEnterObjectCommand( Drawable *draw, Object *obj, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - // Generate an Attack hint - msgType = GameMessage::MSG_DO_ATTACK_OBJECT_AFTER_MOVING_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { - } + // issue the command + msgType = createEnterMessage( draw, type ); - } - // ******************************************************************************************** - else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_CAPTURE_BUILDING, obj, InGameUI::SELECTION_ANY ) ) - { + } + else + { + + msgType = GameMessage::MSG_ENTER_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( obj->getID() ); + } + + return msgType; +} + +GameMessage::Type CommandTranslator::handleAttackObjectCommand( Drawable *draw, Object *obj, CommandEvaluateType type, GameMessage::Type hintType ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; + + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { + + // issue the attack order + msgType = issueAttackCommand( draw, type ); + + } + else + { - //@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 ) + // Generate an Attack hint + msgType = hintType; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( obj->getID() ); + + } + + return msgType; +} + +GameMessage::Type CommandTranslator::handleCaptureBuildingCommand( Drawable *draw, Object *obj, const Coord3D *pos, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; + + //@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 ) { - for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ ) + SpecialPowerType spType = command->getSpecialPowerTemplate()->getSpecialPowerType(); + if( type == DO_COMMAND || type == EVALUATE_ONLY ) { - // get command button - const CommandButton *command = set->getCommandButton(i); - if( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER ) + if( spType == SPECIAL_BLACKLOTUS_CAPTURE_BUILDING || + spType == SPECIAL_INFANTRY_CAPTURE_BUILDING ) { - 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() ); - } + //Issue the capture building command + msgType = issueSpecialPowerCommand( command, type, draw, pos, nullptr ); + break; } } - } - } - // ******************************************************************************************** - 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 ) + else if( spType == SPECIAL_BLACKLOTUS_CAPTURE_BUILDING ) { - 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; - } - } - } + //Issue the black lotus hack hint for capturing a building. + msgType = GameMessage::MSG_HACK_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( obj->getID() ); } - } - 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 ) + else if( spType == SPECIAL_INFANTRY_CAPTURE_BUILDING ) { - 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; - } - } - } + //Issue the infantry hint for capturing a building + msgType = GameMessage::MSG_CAPTUREBUILDING_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( obj->getID() ); } } - 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 ) + return msgType; +} + +GameMessage::Type CommandTranslator::handleHackCommand( Drawable *draw, Object *obj, const Coord3D *pos, CommandEvaluateType type, SpecialPowerType hackPower ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; + + 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++ ) { - //@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 ) + // get command button + const CommandButton *command = set->getCommandButton(i); + if( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER ) { - for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ ) + SpecialPowerType spType = command->getSpecialPowerTemplate()->getSpecialPowerType(); + if( spType == hackPower ) { - // 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; - } - } + msgType = issueSpecialPowerCommand( command, type, draw, pos, nullptr ); + break; } } } - else - { - msgType = GameMessage::MSG_HACK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); - } } + } + else + { + msgType = GameMessage::MSG_HACK_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( obj->getID() ); + } + + return msgType; +} + #ifdef ALLOW_SURRENDER - // ******************************************************************************************** - else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_PICK_UP_PRISONER, obj, InGameUI::SELECTION_ANY ) ) - { +GameMessage::Type CommandTranslator::handlePickUpPrisonerCommand( Drawable *draw, Object *obj, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; - if( type == DO_COMMAND || type == EVALUATE_ONLY ) - { + if( type == DO_COMMAND || type == EVALUATE_ONLY ) + { - // issue the command - msgType = issueAttackCommand( draw, type, GUICOMMANDMODE_PICK_UP_PRISONER ); + // issue the command + msgType = issueAttackCommand( draw, type, GUICOMMANDMODE_PICK_UP_PRISONER ); - } - else - { + } + else + { - msgType = GameMessage::MSG_PICK_UP_PRISONER_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendObjectIDArgument( obj->getID() ); + msgType = GameMessage::MSG_PICK_UP_PRISONER_HINT; + hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendObjectIDArgument( obj->getID() ); - } + } - } + return msgType; +} #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(); +GameMessage::Type CommandTranslator::handleSetRallyPointCommand( const Coord3D *pos, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_SET_RALLY_POINT; + GameMessage *hintMessage; + + 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); + } + + return msgType; +} + +GameMessage::Type CommandTranslator::handleImpossibleAttackHint( const Coord3D *pos ) +{ + GameMessage::Type msgType = GameMessage::MSG_IMPOSSIBLE_ATTACK_HINT; + GameMessage *hintMessage = TheMessageStream->appendMessage( msgType ); + hintMessage->appendLocationArgument( *pos ); + + return msgType; +} - 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); +GameMessage::Type CommandTranslator::handleDefaultMoveCommand( Drawable *draw, Drawable *drawableInWay, const Coord3D *pos, CommandEvaluateType type ) +{ + GameMessage::Type msgType = GameMessage::MSG_INVALID; + GameMessage *hintMessage; + + // + // 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; } } - } else if (type == DO_HINT) { - msgType = GameMessage::MSG_SET_RALLY_POINT_HINT; - hintMessage = TheMessageStream->appendMessage(msgType); - hintMessage->appendLocationArgument(*pos); } + + } + } + + 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. - // ******************************************************************************************** - else if( draw && result == ATTACKRESULT_INVALID_SHOT ) + if ( draw == nullptr ) + msgType = issueMoveToLocationCommand( pos, drawableInWay, type ); + } + else + { + if( !validQuickPath ) { - msgType = GameMessage::MSG_IMPOSSIBLE_ATTACK_HINT; - hintMessage = TheMessageStream->appendMessage( msgType ); - hintMessage->appendLocationArgument( *pos ); + 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 ); - // - // 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; - } - } - } + return msgType; +} +// ------------------------------------------------------------------------------------------------ +/** 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; + resolveContextTarget( draw, obj, drawableInWay ); - } - } + // Then we should determine if the game currently prefers selection events. If it does, then return + // the invalid message. + if( obj && obj->isLocallyControlled() && TheInGameUI->isInPreferSelectionMode() ) + { + return GameMessage::MSG_INVALID; + } - 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. + // Kris: Now that we can select non-controllable units/structures, don't allow any actions to be performed. + const CommandButton *command = TheInGameUI->getGUICommand(); - 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 ); + if( command && command->getCommandType() == GUICOMMANDMODE_PLACE_BEACON ) + { + GameMessage::Type msgType = GameMessage::MSG_VALID_GUICOMMAND_HINT; + TheMessageStream->appendMessage( msgType ); + return msgType; + } - } + const Bool canPerformActions = TheInGameUI->areSelectedObjectsControllable() + || ( command && command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT ); - } + if( !canPerformActions ) + { + return GameMessage::MSG_INVALID; + } + if( TheInGameUI->isInWaypointMode() ) + { + return handleWaypointModeCommand( pos, draw, type ); } - // return the message type - return msgType; + CanAttackResult result; + + if(command && + (command->isContextCommand() + || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER + || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT)) + { + return handleGuiCommand( command, draw, obj, pos, type ); + } + else if( command && (command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT + || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT_FROM_SHORTCUT) ) + { + return handleSpecialPowerConstructCommand( command, draw, pos, type ); + } + + + // ******************************************************************************************** + else if( TheInGameUI->canSelectedObjectsOverrideSpecialPowerDestination( pos, InGameUI::SELECTION_ANY, SPECIAL_INVALID ) ) + { + return handleSpecialPowerOverrideDestinationCommand( pos, type ); + } + // ******************************************************************************************** + else if( draw && !TheInGameUI->isInForceAttackMode() && + TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_RESUME_CONSTRUCTION, obj, InGameUI::SELECTION_ANY ) ) + { + return handleResumeConstructionCommand( obj, type ); + } + // ******************************************************************************************** + else if( draw && !TheInGameUI->isInForceAttackMode() && + TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_DOCK_AT, + obj, + InGameUI::SELECTION_ALL ) ) + { + return handleDockCommand( obj, type ); + } + // ******************************************************************************************** + else if( draw && !TheInGameUI->isInForceAttackMode() && + TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_REPAIR_OBJECT, obj, InGameUI::SELECTION_ANY ) ) + { + return handleRepairObjectCommand( obj, type ); + } + // ******************************************************************************************** + else if( draw && !TheInGameUI->isInForceAttackMode() && + TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_GET_REPAIRED_AT, obj, InGameUI::SELECTION_ANY ) ) + { + return handleGetRepairedCommand( obj, type ); + } + // ******************************************************************************************** + else if( draw && !TheInGameUI->isInForceAttackMode() && + TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_GET_HEALED_AT, obj, InGameUI::SELECTION_ANY ) ) + { + return handleGetHealedCommand( obj, type ); + } + // ******************************************************************************************** + else if( draw && draw->getObject() && !TheInGameUI->isInForceAttackMode() && + TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_HIJACK_VEHICLE, + draw->getObject(), + InGameUI::SELECTION_ANY ) ) + { + return handleHijackVehicleCommand( draw, type ); + } + // ******************************************************************************************** + else if( draw && !TheInGameUI->isInForceAttackMode() && + TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_CONVERT_OBJECT_TO_CARBOMB, obj, InGameUI::SELECTION_ANY ) ) + { + return handleConvertToCarBombCommand( draw, obj, type ); + } + // ******************************************************************************************** + else if( draw && draw->getObject() && !TheInGameUI->isInForceAttackMode() && + TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_SABOTAGE_BUILDING, + draw->getObject(), + InGameUI::SELECTION_ANY ) ) + { + return handleSabotageBuildingCommand( draw, type ); + } + // ******************************************************************************************** + else if( draw && !TheInGameUI->isInForceAttackMode() && canSelectionSalvage(obj) ) + { + return handleSalvageCommand( obj, type ); + } + // ******************************************************************************************** + else if( draw && !TheInGameUI->isInForceAttackMode() && + TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_ENTER_OBJECT, obj, InGameUI::SELECTION_ANY, true ) ) + { + return handleEnterObjectCommand( draw, obj, type ); + } + // ******************************************************************************************** + else if( draw && (result = TheInGameUI->getCanSelectedObjectsAttack( InGameUI::ACTIONTYPE_ATTACK_OBJECT, obj, InGameUI::SELECTION_ANY, TheInGameUI->isInForceAttackMode() )) == ATTACKRESULT_POSSIBLE ) + { + return handleAttackObjectCommand( draw, obj, type, GameMessage::MSG_DO_ATTACK_OBJECT_HINT ); + } + // ******************************************************************************************** + else if( draw && result == ATTACKRESULT_POSSIBLE_AFTER_MOVING ) + { + return handleAttackObjectCommand( draw, obj, type, GameMessage::MSG_DO_ATTACK_OBJECT_AFTER_MOVING_HINT ); + } + // ******************************************************************************************** + else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_CAPTURE_BUILDING, obj, InGameUI::SELECTION_ANY ) ) + { + return handleCaptureBuildingCommand( draw, obj, pos, type ); + } + // ******************************************************************************************** + else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_DISABLE_VEHICLE_VIA_HACKING, obj, InGameUI::SELECTION_ANY ) ) + { + return handleHackCommand( draw, obj, pos, type, SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK ); + } + // ******************************************************************************************** + else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_STEAL_CASH_VIA_HACKING, obj, InGameUI::SELECTION_ANY ) ) + { + return handleHackCommand( draw, obj, pos, type, SPECIAL_BLACKLOTUS_STEAL_CASH_HACK ); + } + // ******************************************************************************************** + else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_DISABLE_BUILDING_VIA_HACKING, obj, InGameUI::SELECTION_ANY ) ) + { + return handleHackCommand( draw, obj, pos, type, SPECIAL_HACKER_DISABLE_BUILDING ); + } +#ifdef ALLOW_SURRENDER + // ******************************************************************************************** + else if( draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_PICK_UP_PRISONER, obj, InGameUI::SELECTION_ANY ) ) + { + return handlePickUpPrisonerCommand( draw, obj, type ); + } +#endif + // ******************************************************************************************** + else if ( !draw && TheInGameUI->canSelectedObjectsDoAction( InGameUI::ACTIONTYPE_SET_RALLY_POINT, nullptr, InGameUI::SELECTION_ALL, FALSE )) + { + return handleSetRallyPointCommand( pos, type ); + } + + // ******************************************************************************************** + else if( draw && result == ATTACKRESULT_INVALID_SHOT ) + { + return handleImpossibleAttackHint( pos ); + } + + // ******************************************************************************************** + else + { + return handleDefaultMoveCommand( draw, drawableInWay, pos, type ); + } }