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; }
void CBuilderCAI::ExecuteReclaim(Command& c) { CBuilder* builder = (CBuilder*) owner; // not all builders are reclaim-capable by default if (!owner->unitDef->canReclaim) return; if (c.params.size() == 1 || c.params.size() == 5) { const int signedId = (int) c.params[0]; if (signedId < 0) { LOG_L(L_WARNING, "Trying to reclaim unit or feature with id < 0 (%i), aborting.", signedId); return; } const unsigned int uid = signedId; //FIXME add a per-unit solution to better balance the load? const bool checkForBetterTarget = (gs->frameNum % (5 * UNIT_SLOWUPDATE_RATE)) < UNIT_SLOWUPDATE_RATE; if (checkForBetterTarget && (c.options & INTERNAL_ORDER) && (c.params.size() >= 5)) { // regular check if there is a closer reclaim target CSolidObject* obj; if (uid >= uh->MaxUnits()) { obj = featureHandler->GetFeature(uid - uh->MaxUnits()); } else { obj = uh->GetUnit(uid); } if (obj) { const float3 pos(c.params[1], c.params[2], c.params[3]); const float radius = c.params[4]; const float curdist = pos.SqDistance2D(obj->pos); const bool recUnits = !!(c.options & META_KEY); const bool recEnemyOnly = (c.options & META_KEY) && (c.options & CONTROL_KEY); const bool recSpecial = !!(c.options & CONTROL_KEY); ReclaimOption recopt = REC_NORESCHECK; if (recUnits) recopt |= REC_UNITS; if (recEnemyOnly) recopt |= REC_ENEMYONLY; if (recSpecial) recopt |= REC_SPECIAL; const int rid = FindReclaimTarget(pos, radius, c.options, recopt, curdist); if ((rid > 0) && (rid != uid)) { FinishCommand(); RemoveUnitFromReclaimers(owner); RemoveUnitFromFeatureReclaimers(owner); return; } } } if (uid >= uh->MaxUnits()) { // reclaim feature CFeature* feature = featureHandler->GetFeature(uid - uh->MaxUnits()); if (feature != NULL) { bool featureBeingResurrected = IsFeatureBeingResurrected(feature->id, owner); featureBeingResurrected &= (c.options & INTERNAL_ORDER) && !(c.options & CONTROL_KEY); if (featureBeingResurrected || !ReclaimObject(feature)) { StopMove(); FinishCommand(); RemoveUnitFromFeatureReclaimers(owner); } else { AddUnitToFeatureReclaimers(owner); } } else { StopMove(); FinishCommand(); RemoveUnitFromFeatureReclaimers(owner); } RemoveUnitFromReclaimers(owner); } else { // reclaim unit CUnit* unit = uh->GetUnit(uid); if (unit != NULL && c.params.size() == 5) { const float3 pos(c.params[1], c.params[2], c.params[3]); const float radius = c.params[4] + 100.0f; // do not walk too far outside reclaim area const bool outOfReclaimRange = (pos.SqDistance2D(unit->pos) > radius * radius) || (builder->curReclaim == unit && unit->isMoving && !IsInBuildRange(unit)); const bool busyAlliedBuilder = unit->unitDef->builder && !unit->commandAI->commandQue.empty() && teamHandler->Ally(owner->allyteam, unit->allyteam); if (outOfReclaimRange || busyAlliedBuilder) { StopMove(); RemoveUnitFromReclaimers(owner); FinishCommand(); RemoveUnitFromFeatureReclaimers(owner); return; } } if (unit != NULL && unit != owner && unit->unitDef->reclaimable && UpdateTargetLostTimer(unit->id) && unit->AllowedReclaim(owner)) { if (!ReclaimObject(unit)) { StopMove(); FinishCommand(); } else { AddUnitToReclaimers(owner); } } else { RemoveUnitFromReclaimers(owner); FinishCommand(); } RemoveUnitFromFeatureReclaimers(owner); } } else if (c.params.size() == 4) { // area reclaim const float3 pos = c.GetPos(0); const float radius = c.params[3]; const bool recUnits = !!(c.options & META_KEY); const bool recEnemyOnly = (c.options & META_KEY) && (c.options & CONTROL_KEY); const bool recSpecial = !!(c.options & CONTROL_KEY); RemoveUnitFromReclaimers(owner); RemoveUnitFromFeatureReclaimers(owner); builder->StopBuild(); ReclaimOption recopt = REC_NORESCHECK; if (recUnits) recopt |= REC_UNITS; if (recEnemyOnly) recopt |= REC_ENEMYONLY; if (recSpecial) recopt |= REC_SPECIAL; if (FindReclaimTargetAndReclaim(pos, radius, c.options, recopt)) { inCommand = false; SlowUpdate(); return; } if(!(c.options & ALT_KEY)){ FinishCommand(); } } else { // wrong number of parameters RemoveUnitFromReclaimers(owner); RemoveUnitFromFeatureReclaimers(owner); FinishCommand(); } }