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) { // 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 { 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) { 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; }