bool CCommandAI::AllowedCommand(const Command& c) { const UnitDef* ud = owner->unitDef; switch (c.id) { case CMD_ATTACK: case CMD_DGUN: { if (!ud->canAttack || !isAttackCapable()) return false; break; } case CMD_MOVE: if (!ud->canmove) return false; break; case CMD_FIGHT: if (!ud->canFight) return false; break; case CMD_GUARD: if (!ud->canGuard) return false; break; case CMD_PATROL: if (!ud->canPatrol) return false; break; case CMD_CAPTURE: if (!ud->canCapture) return false; break; case CMD_RECLAIM: if (!ud->canReclaim) return false; break; case CMD_RESTORE: if (!ud->canRestore) return false; break; case CMD_RESURRECT: if (!ud->canResurrect) return false; break; case CMD_REPAIR: { if (!ud->canRepair && !ud->canAssist) return false; break; } } if((c.id == CMD_RECLAIM) && (c.params.size() == 1)){ const int unitID = (int)c.params[0]; if(unitID < MAX_UNITS){ // not a feature CUnit* unit = uh->units[unitID]; if(unit && !unit->unitDef->reclaimable) return false; } else { CFeature* feature = featureHandler->features[unitID - MAX_UNITS]; if (feature && !feature->def->reclaimable) return false; } } if((c.id == CMD_REPAIR) && (c.params.size() == 1)){ CUnit* unit = uh->units[(int)c.params[0]]; if (unit && ((unit->beingBuilt && !ud->canAssist) || (!unit->beingBuilt && !ud->canRepair))) return false; } if (c.id == CMD_FIRE_STATE && (c.params.empty() || ud->noAutoFire || (ud->weapons.empty() && ud->type!="Factory"))) return false; if (c.id == CMD_MOVE_STATE && (c.params.empty() || (!ud->canmove && !ud->builder))) return false; if (c.id == CMD_REPEAT && (c.params.empty() || !ud->canRepeat)) return false; if (c.id == CMD_TRAJECTORY && (c.params.empty() || ud->highTrajectoryType<2)) return false; if (c.id == CMD_ONOFF && (c.params.empty() || !ud->onoffable || owner->beingBuilt)) return false; if (c.id == CMD_CLOAK && (c.params.empty() || !ud->canCloak)) return false; if(c.id == CMD_STOCKPILE && !stockpileWeapon) return false; return true; }
int CCommandAI::GetDefaultCmd(CUnit* pointed, 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), 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 an unit or a position on the ground"; possibleCommands.push_back(c); } if (owner->unitDef->canDGun) { c.id = CMD_DGUN; c.action = "dgun"; c.type = CMDTYPE_ICON_MAP; c.name = "DGun"; c.mouseicon = c.name; c.tooltip = "DGun: Attacks using the units special 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("2"); 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("1"); 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 = 0; } 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) { // check if the command is in the map first switch (c.id) { 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_DGUN: case CMD_UNLOAD_UNIT: case CMD_UNLOAD_UNITS: if (!isCommandInMap(c)) { return false; } break; default: // build commands if (c.id < 0 && !isCommandInMap(c)) { return false; } break; } const UnitDef* ud = owner->unitDef; int maxHeightDiff = SQUARE_SIZE; // AI's may do as they like bool aiOrder = (teamHandler->Team(owner->team) && teamHandler->Team(owner->team)->isAI); switch (c.id) { case CMD_DGUN: if (!owner->unitDef->canDGun) return false; case CMD_ATTACK: { if (!isAttackCapable()) return false; if (c.params.size() == 3) { // check if attack ground is really attack ground if (!aiOrder && !fromSynced && fabs(c.params[1] - ground->GetHeight2(c.params[0], c.params[2])) > maxHeightDiff) { return false; } } break; } case CMD_MOVE: if (!ud->canmove) return false; break; case CMD_FIGHT: if (!ud->canFight) return false; break; case CMD_GUARD: if (!ud->canGuard) return false; break; case CMD_PATROL: if (!ud->canPatrol) return false; break; case CMD_CAPTURE: if (!ud->canCapture) return false; break; case CMD_RECLAIM: if (!ud->canReclaim) return false; break; case CMD_RESTORE: if (!ud->canRestore) return false; break; case CMD_RESURRECT: if (!ud->canResurrect) return false; break; case CMD_REPAIR: { if (!ud->canRepair && !ud->canAssist) return false; break; } } if ((c.id == CMD_RECLAIM) && (c.params.size() == 1 || c.params.size() == 5)) { const unsigned int unitID = (unsigned int) c.params[0]; if (unitID < uh->MaxUnits()) { // not a feature CUnit* unit = uh->units[unitID]; if (unit && !unit->unitDef->reclaimable) return false; if (unit && !unit->AllowedReclaim(owner)) return false; } else { const CFeatureSet& fset = featureHandler->GetActiveFeatures(); CFeatureSet::const_iterator f = fset.find(unitID - uh->MaxUnits()); if (f != fset.end() && !(*f)->def->reclaimable) return false; } } if ((c.id == CMD_REPAIR) && (c.params.size() == 1 || c.params.size() == 5)) { CUnit* unit = uh->units[(int) c.params[0]]; if (unit && ((unit->beingBuilt && !ud->canAssist) || (!unit->beingBuilt && !ud->canRepair))) return false; } if (c.id == CMD_FIRE_STATE && (c.params.empty() || !CanChangeFireState())) { return false; } if (c.id == CMD_MOVE_STATE && (c.params.empty() || (!ud->canmove && !ud->builder))) { return false; } if (c.id == CMD_REPEAT && (c.params.empty() || !ud->canRepeat)) { return false; } if (c.id == CMD_TRAJECTORY && (c.params.empty() || ud->highTrajectoryType < 2)) { return false; } if (c.id == CMD_ONOFF && (c.params.empty() || !ud->onoffable || owner->beingBuilt)) { return false; } if (c.id == CMD_CLOAK && (c.params.empty() || !ud->canCloak)) { return false; } if (c.id == CMD_STOCKPILE && !stockpileWeapon) { return false; } return true; }
bool CCommandAI::AllowedCommand(const Command& c, bool fromSynced) { // check if the command is in the map first switch (c.id) { 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_DGUN: case CMD_UNLOAD_UNIT: case CMD_UNLOAD_UNITS: { if (!IsCommandInMap(c)) { return false; } } break; default: { // build commands if (c.id < 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()); switch (c.id) { case CMD_DGUN: if (!ud->canDGun) 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->GetHeight2(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 (!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.IsAreaCommand()) { const unsigned int reclaimeeFeatureID(c.params[0]); if (!c.params.empty() && 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 (c.id == CMD_FIRE_STATE && (c.params.empty() || !CanChangeFireState())) { return false; } if (c.id == CMD_MOVE_STATE && (c.params.empty() || (!ud->canmove && !ud->builder))) { return false; } if (c.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 (c.id == CMD_TRAJECTORY && (c.params.empty() || ud->highTrajectoryType < 2)) { return false; } if (c.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 (c.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 (c.id == CMD_STOCKPILE && !stockpileWeapon) { return false; } return true; }