int CCommandAI::GetDefaultCmd(const CUnit* pointed, const CFeature* feature) { if (pointed) { if (!teamHandler->Ally(gu->myAllyTeam, pointed->allyteam)) { if (IsAttackCapable()) { return CMD_ATTACK; } } } return CMD_STOP; }
CCommandAI::CCommandAI(CUnit* owner): stockpileWeapon(0), lastUserCommand(-1000), selfDCountdown(0), lastFinishCommand(0), owner(owner), orderTarget(0), targetDied(false), inCommand(false), selected(false), repeatOrders(false), lastSelectedCommandPage(0), unimportantMove(false), targetLostTimer(TARGET_LOST_TIMER) { owner->commandAI = this; CommandDescription c; c.id = CMD_STOP; c.action = "stop"; c.type = CMDTYPE_ICON; c.name = "Stop"; c.mouseicon = c.name; c.tooltip = "Stop: Cancel the units current actions"; possibleCommands.push_back(c); if (IsAttackCapable()) { c.id = CMD_ATTACK; c.action = "attack"; c.type = CMDTYPE_ICON_UNIT_OR_MAP; c.name = "Attack"; c.mouseicon = c.name; c.tooltip = "Attack: Attacks a unit or a position on the ground"; possibleCommands.push_back(c); } if (owner->unitDef->canManualFire) { c.id = CMD_MANUALFIRE; c.action = "manualfire"; c.type = CMDTYPE_ICON_MAP; c.name = "ManualFire"; c.mouseicon = c.name; c.tooltip = "ManualFire: Attacks with manually-fired weapon"; possibleCommands.push_back(c); } c.id = CMD_WAIT; c.action = "wait"; c.type = CMDTYPE_ICON; c.name = "Wait"; c.mouseicon = c.name; c.tooltip = "Wait: Tells the unit to wait until another units handles it"; possibleCommands.push_back(c); // nonQueingCommands.insert(CMD_WAIT); c.id = CMD_TIMEWAIT; c.action = "timewait"; c.type = CMDTYPE_NUMBER; c.name = "TimeWait"; c.mouseicon=c.name; c.tooltip = "TimeWait: Wait for a period of time before continuing"; c.params.push_back("1"); // min c.params.push_back("60"); // max c.hidden = true; possibleCommands.push_back(c); c.hidden = false; c.params.clear(); // only for games with 2 ally teams -- checked later c.id = CMD_DEATHWAIT; c.action = "deathwait"; c.type = CMDTYPE_ICON_UNIT_OR_RECTANGLE; c.name = "DeathWait"; c.mouseicon=c.name; c.tooltip = "DeathWait: Wait until units die before continuing"; c.hidden = true; possibleCommands.push_back(c); c.hidden = false; c.id = CMD_SQUADWAIT; c.action = "squadwait"; c.type = CMDTYPE_NUMBER; c.name = "SquadWait"; c.mouseicon=c.name; c.tooltip = "SquadWait: Wait for a number of units to arrive before continuing"; c.params.push_back("2"); // min c.params.push_back("100"); // max c.hidden = true; possibleCommands.push_back(c); c.hidden = false; c.params.clear(); c.id = CMD_GATHERWAIT; c.action = "gatherwait"; c.type = CMDTYPE_ICON; c.name = "GatherWait"; c.mouseicon=c.name; c.tooltip = "GatherWait: Wait until all units arrive before continuing"; c.hidden = true; possibleCommands.push_back(c); c.hidden = false; if (owner->unitDef->canSelfD) { c.id = CMD_SELFD; c.action = "selfd"; c.type = CMDTYPE_ICON; c.name = "SelfD"; c.mouseicon = c.name; c.tooltip = "SelfD: Tells the unit to self destruct"; c.hidden = true; possibleCommands.push_back(c); c.hidden = false; } // nonQueingCommands.insert(CMD_SELFD); if(CanChangeFireState()) { c.id = CMD_FIRE_STATE; c.action = "firestate"; c.type = CMDTYPE_ICON_MODE; c.name = "Fire state"; c.mouseicon = c.name; c.params.push_back(IntToString(FIRESTATE_FIREATWILL)); c.params.push_back("Hold fire"); c.params.push_back("Return fire"); c.params.push_back("Fire at will"); c.tooltip = "Fire State: Sets under what conditions an\n unit will start to fire at enemy units\n without an explicit attack order"; possibleCommands.push_back(c); nonQueingCommands.insert(CMD_FIRE_STATE); } if (owner->unitDef->canmove || owner->unitDef->builder) { c.params.clear(); c.id = CMD_MOVE_STATE; c.action = "movestate"; c.type = CMDTYPE_ICON_MODE; c.name = "Move state"; c.mouseicon = c.name; c.params.push_back(IntToString(MOVESTATE_MANEUVER)); c.params.push_back("Hold pos"); c.params.push_back("Maneuver"); c.params.push_back("Roam"); c.tooltip = "Move State: Sets how far out of its way\n an unit will move to attack enemies"; possibleCommands.push_back(c); nonQueingCommands.insert(CMD_MOVE_STATE); } else { owner->moveState = MOVESTATE_HOLDPOS; } if (owner->unitDef->canRepeat) { c.params.clear(); c.id = CMD_REPEAT; c.action = "repeat"; c.type = CMDTYPE_ICON_MODE; c.name = "Repeat"; c.mouseicon = c.name; c.params.push_back("0"); c.params.push_back("Repeat off"); c.params.push_back("Repeat on"); c.tooltip = "Repeat: If on the unit will continously\n push finished orders to the end of its\n order queue"; possibleCommands.push_back(c); nonQueingCommands.insert(CMD_REPEAT); } if (owner->unitDef->highTrajectoryType>1) { c.params.clear(); c.id = CMD_TRAJECTORY; c.action = "trajectory"; c.type = CMDTYPE_ICON_MODE; c.name = "Trajectory"; c.mouseicon = c.name; c.params.push_back("0"); c.params.push_back("Low traj"); c.params.push_back("High traj"); c.tooltip = "Trajectory: If set to high, weapons that\n support it will try to fire in a higher\n trajectory than usual (experimental)"; possibleCommands.push_back(c); nonQueingCommands.insert(CMD_TRAJECTORY); } if (owner->unitDef->onoffable) { c.params.clear(); c.id = CMD_ONOFF; c.action = "onoff"; c.type = CMDTYPE_ICON_MODE; c.name = "Active state"; c.mouseicon = c.name; if (owner->unitDef->activateWhenBuilt) { c.params.push_back("1"); } else { c.params.push_back("0"); } c.params.push_back(" Off "); c.params.push_back(" On "); c.tooltip = "Active State: Sets the active state of the unit to on or off"; possibleCommands.push_back(c); nonQueingCommands.insert(CMD_ONOFF); } if (owner->unitDef->canCloak) { c.params.clear(); c.id = CMD_CLOAK; c.action = "cloak"; c.type = CMDTYPE_ICON_MODE; c.name = "Cloak state"; c.mouseicon = c.name; if (owner->unitDef->startCloaked) { c.params.push_back("1"); } else { c.params.push_back("0"); } c.params.push_back("UnCloaked"); c.params.push_back("Cloaked"); c.tooltip = "Cloak State: Sets whether the unit is cloaked or not"; possibleCommands.push_back(c); nonQueingCommands.insert(CMD_CLOAK); } }
bool CCommandAI::AllowedCommand(const Command& c, bool fromSynced) { // TODO check if the command is in the map first, for more commands switch (c.GetID()) { case CMD_MOVE: case CMD_ATTACK: case CMD_AREA_ATTACK: case CMD_RECLAIM: case CMD_REPAIR: case CMD_RESURRECT: case CMD_PATROL: case CMD_RESTORE: case CMD_FIGHT: case CMD_MANUALFIRE: case CMD_UNLOAD_UNIT: case CMD_UNLOAD_UNITS: { if (!IsCommandInMap(c)) { return false; } } break; default: { // build commands if (c.GetID() < 0 && !IsCommandInMap(c)) { return false; } } break; } const UnitDef* ud = owner->unitDef; // AI's may do as they like const CSkirmishAIHandler::ids_t& saids = skirmishAIHandler.GetSkirmishAIsInTeam(owner->team); const bool aiOrder = (!saids.empty()); const int& cmd_id = c.GetID(); switch (cmd_id) { case CMD_MANUALFIRE: if (!ud->canManualFire) return false; case CMD_ATTACK: { if (!IsAttackCapable()) return false; if (c.params.size() == 1) { const CUnit* attackee = GetCommandUnit(c, 0); if (attackee && !attackee->pos.IsInBounds()) { return false; } } else { if (c.params.size() == 3) { const float3 cPos(c.params[0], c.params[1], c.params[2]); // check if attack ground is really attack ground if (!aiOrder && !fromSynced && fabs(cPos.y - ground->GetHeightReal(cPos.x, cPos.z)) > SQUARE_SIZE) { return false; } } } break; } case CMD_MOVE: if (!ud->canmove) return false; break; case CMD_FIGHT: if (!ud->canFight) return false; break; case CMD_GUARD: { const CUnit* guardee = GetCommandUnit(c, 0); if (!ud->canGuard) { return false; } if (owner && !owner->pos.IsInBounds()) { return false; } if (guardee && !guardee->pos.IsInBounds()) { return false; } } break; case CMD_PATROL: { if (!ud->canPatrol) { return false; } } break; case CMD_CAPTURE: { const CUnit* capturee = GetCommandUnit(c, 0); if (!ud->canCapture) { return false; } if (capturee && !capturee->pos.IsInBounds()) { return false; } } break; case CMD_RECLAIM: { const CUnit* reclaimeeUnit = GetCommandUnit(c, 0); const CFeature* reclaimeeFeature = NULL; if (c.IsAreaCommand()) { return true; } if (!ud->canReclaim) { return false; } if (reclaimeeUnit && !reclaimeeUnit->unitDef->reclaimable) { return false; } if (reclaimeeUnit && !reclaimeeUnit->AllowedReclaim(owner)) { return false; } if (reclaimeeUnit && !reclaimeeUnit->pos.IsInBounds()) { return false; } if (reclaimeeUnit == NULL && !c.params.empty()) { const unsigned int reclaimeeFeatureID(c.params[0]); if (reclaimeeFeatureID >= uh->MaxUnits()) { reclaimeeFeature = featureHandler->GetFeature(reclaimeeFeatureID - uh->MaxUnits()); if (reclaimeeFeature && !reclaimeeFeature->def->reclaimable) { return false; } } } } break; case CMD_RESTORE: { if (!ud->canRestore || mapDamage->disabled) { return false; } } break; case CMD_RESURRECT: { if (!ud->canResurrect) { return false; } } break; case CMD_REPAIR: { const CUnit* repairee = GetCommandUnit(c, 0); if (!ud->canRepair && !ud->canAssist) { return false; } if (repairee && !repairee->pos.IsInBounds()) { return false; } if (repairee && ((repairee->beingBuilt && !ud->canAssist) || (!repairee->beingBuilt && !ud->canRepair))) { return false; } } break; } if (cmd_id == CMD_FIRE_STATE && (c.params.empty() || !CanChangeFireState())) { return false; } if (cmd_id == CMD_MOVE_STATE && (c.params.empty() || (!ud->canmove && !ud->builder))) { return false; } if (cmd_id == CMD_REPEAT && (c.params.empty() || !ud->canRepeat || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmd_id == CMD_TRAJECTORY && (c.params.empty() || ud->highTrajectoryType < 2)) { return false; } if (cmd_id == CMD_ONOFF && (c.params.empty() || !ud->onoffable || owner->beingBuilt || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmd_id == CMD_CLOAK && (c.params.empty() || !ud->canCloak || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmd_id == CMD_STOCKPILE && !stockpileWeapon) { return false; } return true; }
bool CCommandAI::AllowedCommand(const Command& c, bool fromSynced) { const int cmdID = c.GetID(); // TODO check if the command is in the map first, for more commands switch (cmdID) { case CMD_MOVE: case CMD_ATTACK: case CMD_AREA_ATTACK: case CMD_RECLAIM: case CMD_REPAIR: case CMD_RESURRECT: case CMD_PATROL: case CMD_RESTORE: case CMD_FIGHT: case CMD_MANUALFIRE: case CMD_UNLOAD_UNIT: case CMD_UNLOAD_UNITS: { if (!IsCommandInMap(c)) { return false; } } break; default: { // build commands if (cmdID < 0) { if (!IsCommandInMap(c)) return false; const CBuilderCAI* bcai = dynamic_cast<const CBuilderCAI*>(this); const CFactoryCAI* fcai = dynamic_cast<const CFactoryCAI*>(this); // non-builders cannot ever execute these // we can get here if a factory is selected along with the // unit it is currently building and a build-order is given // to the former if (fcai == NULL && bcai == NULL) return false; // {Builder,Factory}CAI::GiveCommandReal (should) handle the // case where buildOptions.find(cmdID) == buildOptions.end() } } break; } const UnitDef* ud = owner->unitDef; // AI's may do as they like const CSkirmishAIHandler::ids_t& saids = skirmishAIHandler.GetSkirmishAIsInTeam(owner->team); const bool aiOrder = (!saids.empty()); switch (cmdID) { case CMD_MANUALFIRE: if (!ud->canManualFire) return false; // fall through case CMD_ATTACK: { if (!IsAttackCapable()) return false; if (c.params.size() == 1) { const CUnit* attackee = GetCommandUnit(c, 0); if (attackee == NULL) return false; if (!attackee->pos.IsInBounds()) return false; } else { if (c.params.size() >= 3) { const float3 cPos = c.GetPos(0); // FIXME: is fromSynced really sync-safe??? // NOTE: // uses gHeight = min(cPos.y, GetHeightAboveWater) instead // of gHeight = GetHeightReal because GuiTraceRay can stop // at water surface, so the attack-position would be moved // UNDERWATER and cause ground-attack orders to fail // const float gHeight = std::min(cPos.y, ground->GetHeightAboveWater(cPos.x, cPos.z, fromSynced)); const float gHeight = std::min(cPos.y, ground->GetHeightAboveWater(cPos.x, cPos.z, true)); #if 0 // check if attack-ground is really attack-ground // // NOTE: // problematic if command contains value from UHM // but is evaluated in synced context against SHM // after roundtrip (when UHM and SHM differ a lot) // // instead just clamp the elevation, which creates // fewer issues overall (eg. artillery force-firing // at positions outside LOS where UHM and SHM do not // match will not be broken) // if (!aiOrder && math::fabs(cPos.y - gHeight) > SQUARE_SIZE) { return false; } #else if (!aiOrder) { Command& cc = const_cast<Command&>(c); cc.params[1] = gHeight; } return true; #endif } } break; } case CMD_MOVE: if (!ud->canmove) return false; break; case CMD_FIGHT: if (!ud->canFight) return false; break; case CMD_GUARD: { const CUnit* guardee = GetCommandUnit(c, 0); if (!ud->canGuard) { return false; } if (owner && !owner->pos.IsInBounds()) { return false; } if (guardee && !guardee->pos.IsInBounds()) { return false; } } break; case CMD_PATROL: { if (!ud->canPatrol) { return false; } } break; case CMD_CAPTURE: { const CUnit* capturee = GetCommandUnit(c, 0); if (!ud->canCapture) { return false; } if (capturee && !capturee->pos.IsInBounds()) { return false; } } break; case CMD_RECLAIM: { const CUnit* reclaimeeUnit = GetCommandUnit(c, 0); const CFeature* reclaimeeFeature = NULL; if (c.IsAreaCommand()) { return true; } if (!ud->canReclaim) { return false; } if (reclaimeeUnit && !reclaimeeUnit->unitDef->reclaimable) { return false; } if (reclaimeeUnit && !reclaimeeUnit->AllowedReclaim(owner)) { return false; } if (reclaimeeUnit && !reclaimeeUnit->pos.IsInBounds()) { return false; } if (reclaimeeUnit == NULL && !c.params.empty()) { const unsigned int reclaimeeFeatureID(c.params[0]); if (reclaimeeFeatureID >= unitHandler->MaxUnits()) { reclaimeeFeature = featureHandler->GetFeature(reclaimeeFeatureID - unitHandler->MaxUnits()); if (reclaimeeFeature && !reclaimeeFeature->def->reclaimable) { return false; } } } } break; case CMD_RESTORE: { if (!ud->canRestore || mapDamage->disabled) { return false; } } break; case CMD_RESURRECT: { if (!ud->canResurrect) { return false; } } break; case CMD_REPAIR: { const CUnit* repairee = GetCommandUnit(c, 0); if (!ud->canRepair && !ud->canAssist) { return false; } if (repairee && !repairee->pos.IsInBounds()) { return false; } if (repairee && ((repairee->beingBuilt && !ud->canAssist) || (!repairee->beingBuilt && !ud->canRepair))) { return false; } } break; } if (cmdID == CMD_FIRE_STATE && (c.params.empty() || !CanChangeFireState())) { return false; } if (cmdID == CMD_MOVE_STATE && (c.params.empty() || (!ud->canmove && !ud->builder))) { return false; } if (cmdID == CMD_REPEAT && (c.params.empty() || !ud->canRepeat || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmdID == CMD_TRAJECTORY && (c.params.empty() || ud->highTrajectoryType < 2)) { return false; } if (cmdID == CMD_ONOFF && (c.params.empty() || !ud->onoffable || owner->beingBuilt || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmdID == CMD_CLOAK && (c.params.empty() || !ud->canCloak || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmdID == CMD_STOCKPILE && !stockpileWeapon) { return false; } return true; }
bool CCommandAI::AllowedCommand(const Command& c, bool fromSynced) { // TODO check if the command is in the map first, for more commands switch (c.GetID()) { case CMD_MOVE: case CMD_ATTACK: case CMD_AREA_ATTACK: case CMD_RECLAIM: case CMD_REPAIR: case CMD_RESURRECT: case CMD_PATROL: case CMD_RESTORE: case CMD_FIGHT: case CMD_MANUALFIRE: case CMD_UNLOAD_UNIT: case CMD_UNLOAD_UNITS: { if (!IsCommandInMap(c)) { return false; } } break; default: { // build commands if (c.GetID() < 0 && !IsCommandInMap(c)) { return false; } } break; } const UnitDef* ud = owner->unitDef; // AI's may do as they like const CSkirmishAIHandler::ids_t& saids = skirmishAIHandler.GetSkirmishAIsInTeam(owner->team); const bool aiOrder = (!saids.empty()); const int& cmd_id = c.GetID(); switch (cmd_id) { case CMD_MANUALFIRE: if (!ud->canManualFire) return false; case CMD_ATTACK: { if (!IsAttackCapable()) return false; if (c.params.size() == 1) { const CUnit* attackee = GetCommandUnit(c, 0); if (attackee == NULL) return false; if (!attackee->pos.IsInBounds()) return false; } else { if (c.params.size() >= 3) { const float3 cPos(c.params[0], c.params[1], c.params[2]); //FIXME is fromSynced really sync-safe??? const float gHeight = ground->GetHeightReal(cPos.x, cPos.z, fromSynced); const float gHeight = ground->GetHeightReal(cPos.x, cPos.z, true); #if 0 // check if attack-ground is really attack-ground // // NOTE: // problematic if command contains value from UHM // but is evaluated in synced context against SHM // after roundtrip (when UHM and SHM differ a lot) // // instead just clamp the elevation, which creates // fewer issues overall (eg. artillery force-firing // at positions outside LOS where UHM and SHM do not // match will not be broken) // if (!aiOrder && math::fabs(cPos.y - gHeight) > SQUARE_SIZE) { return false; } #else if (!aiOrder) { Command& cc = const_cast<Command&>(c); cc.params[1] = gHeight; } return true; #endif } } break; } case CMD_MOVE: if (!ud->canmove) return false; break; case CMD_FIGHT: if (!ud->canFight) return false; break; case CMD_GUARD: { const CUnit* guardee = GetCommandUnit(c, 0); if (!ud->canGuard) { return false; } if (owner && !owner->pos.IsInBounds()) { return false; } if (guardee && !guardee->pos.IsInBounds()) { return false; } } break; case CMD_PATROL: { if (!ud->canPatrol) { return false; } } break; case CMD_CAPTURE: { const CUnit* capturee = GetCommandUnit(c, 0); if (!ud->canCapture) { return false; } if (capturee && !capturee->pos.IsInBounds()) { return false; } } break; case CMD_RECLAIM: { const CUnit* reclaimeeUnit = GetCommandUnit(c, 0); const CFeature* reclaimeeFeature = NULL; if (c.IsAreaCommand()) { return true; } if (!ud->canReclaim) { return false; } if (reclaimeeUnit && !reclaimeeUnit->unitDef->reclaimable) { return false; } if (reclaimeeUnit && !reclaimeeUnit->AllowedReclaim(owner)) { return false; } if (reclaimeeUnit && !reclaimeeUnit->pos.IsInBounds()) { return false; } if (reclaimeeUnit == NULL && !c.params.empty()) { const unsigned int reclaimeeFeatureID(c.params[0]); if (reclaimeeFeatureID >= uh->MaxUnits()) { reclaimeeFeature = featureHandler->GetFeature(reclaimeeFeatureID - uh->MaxUnits()); if (reclaimeeFeature && !reclaimeeFeature->def->reclaimable) { return false; } } } } break; case CMD_RESTORE: { if (!ud->canRestore || mapDamage->disabled) { return false; } } break; case CMD_RESURRECT: { if (!ud->canResurrect) { return false; } } break; case CMD_REPAIR: { const CUnit* repairee = GetCommandUnit(c, 0); if (!ud->canRepair && !ud->canAssist) { return false; } if (repairee && !repairee->pos.IsInBounds()) { return false; } if (repairee && ((repairee->beingBuilt && !ud->canAssist) || (!repairee->beingBuilt && !ud->canRepair))) { return false; } } break; } if (cmd_id == CMD_FIRE_STATE && (c.params.empty() || !CanChangeFireState())) { return false; } if (cmd_id == CMD_MOVE_STATE && (c.params.empty() || (!ud->canmove && !ud->builder))) { return false; } if (cmd_id == CMD_REPEAT && (c.params.empty() || !ud->canRepeat || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmd_id == CMD_TRAJECTORY && (c.params.empty() || ud->highTrajectoryType < 2)) { return false; } if (cmd_id == CMD_ONOFF && (c.params.empty() || !ud->onoffable || owner->beingBuilt || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmd_id == CMD_CLOAK && (c.params.empty() || !ud->canCloak || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmd_id == CMD_STOCKPILE && !stockpileWeapon) { return false; } return true; }
bool CCommandAI::AllowedCommand(const Command& c, bool fromSynced) { const int cmdID = c.GetID(); // TODO check if the command is in the map first, for more commands switch (cmdID) { case CMD_MOVE: case CMD_ATTACK: case CMD_AREA_ATTACK: case CMD_RECLAIM: case CMD_REPAIR: case CMD_RESURRECT: case CMD_PATROL: case CMD_RESTORE: case CMD_FIGHT: case CMD_MANUALFIRE: case CMD_UNLOAD_UNIT: case CMD_UNLOAD_UNITS: { if (!IsCommandInMap(c)) { return false; } } break; default: { // build commands if (cmdID < 0) { if (!IsCommandInMap(c)) return false; const CBuilderCAI* bcai = dynamic_cast<const CBuilderCAI*>(this); const CFactoryCAI* fcai = dynamic_cast<const CFactoryCAI*>(this); // non-builders cannot ever execute these // we can get here if a factory is selected along with the // unit it is currently building and a build-order is given // to the former if (fcai == NULL && bcai == NULL) return false; // {Builder,Factory}CAI::GiveCommandReal (should) handle the // case where buildOptions.find(cmdID) == buildOptions.end() } } break; } const UnitDef* ud = owner->unitDef; // AI's may do as they like const CSkirmishAIHandler::ids_t& saids = skirmishAIHandler.GetSkirmishAIsInTeam(owner->team); const bool aiOrder = (!saids.empty()); switch (cmdID) { case CMD_MANUALFIRE: if (!ud->canManualFire) return false; // fall through case CMD_ATTACK: { if (!IsAttackCapable()) return false; if (c.params.size() == 1) { const CUnit* attackee = GetCommandUnit(c, 0); if (attackee == NULL) return false; if (!attackee->pos.IsInBounds()) return false; } else { AdjustGroundAttackCommand(c, fromSynced, aiOrder); } break; } case CMD_MOVE: if (!ud->canmove) return false; break; case CMD_FIGHT: if (!ud->canFight) return false; break; case CMD_GUARD: { const CUnit* guardee = GetCommandUnit(c, 0); if (!ud->canGuard) { return false; } if (owner && !owner->pos.IsInBounds()) { return false; } if (guardee && !guardee->pos.IsInBounds()) { return false; } } break; case CMD_PATROL: { if (!ud->canPatrol) { return false; } } break; case CMD_CAPTURE: { const CUnit* capturee = GetCommandUnit(c, 0); if (!ud->canCapture) { return false; } if (capturee && !capturee->pos.IsInBounds()) { return false; } } break; case CMD_RECLAIM: { const CUnit* reclaimeeUnit = GetCommandUnit(c, 0); const CFeature* reclaimeeFeature = NULL; if (c.IsAreaCommand()) { return true; } if (!ud->canReclaim) { return false; } if (reclaimeeUnit && !reclaimeeUnit->unitDef->reclaimable) { return false; } if (reclaimeeUnit && !reclaimeeUnit->AllowedReclaim(owner)) { return false; } if (reclaimeeUnit && !reclaimeeUnit->pos.IsInBounds()) { return false; } if (reclaimeeUnit == NULL && !c.params.empty()) { const unsigned int reclaimeeFeatureID(c.params[0]); if (reclaimeeFeatureID >= unitHandler->MaxUnits()) { reclaimeeFeature = featureHandler->GetFeature(reclaimeeFeatureID - unitHandler->MaxUnits()); if (reclaimeeFeature && !reclaimeeFeature->def->reclaimable) { return false; } } } } break; case CMD_RESTORE: { if (!ud->canRestore || mapDamage->disabled) { return false; } } break; case CMD_RESURRECT: { if (!ud->canResurrect) { return false; } } break; case CMD_REPAIR: { const CUnit* repairee = GetCommandUnit(c, 0); if (!ud->canRepair && !ud->canAssist) { return false; } if (repairee && !repairee->pos.IsInBounds()) { return false; } if (repairee && ((repairee->beingBuilt && !ud->canAssist) || (!repairee->beingBuilt && !ud->canRepair))) { return false; } } break; } if (cmdID == CMD_FIRE_STATE && (c.params.empty() || !CanChangeFireState())) { return false; } if (cmdID == CMD_MOVE_STATE && (c.params.empty() || (!ud->canmove && !ud->builder))) { return false; } if (cmdID == CMD_REPEAT && (c.params.empty() || !ud->canRepeat || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmdID == CMD_TRAJECTORY && (c.params.empty() || ud->highTrajectoryType < 2)) { return false; } if (cmdID == CMD_ONOFF && (c.params.empty() || !ud->onoffable || owner->beingBuilt || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmdID == CMD_CLOAK && (c.params.empty() || !ud->canCloak || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */)) { return false; } if (cmdID == CMD_STOCKPILE && !stockpileWeapon) { return false; } return true; }