bool CBuilderCAI::FindCaptureTargetAndCapture(const float3& pos, float radius, unsigned char options, bool healthyOnly) { const std::vector<CUnit*> &cu = quadField->GetUnits(pos, radius); std::vector<CUnit*>::const_iterator ui; const CUnit* best = NULL; float bestDist = 1.0e30f; bool stationary = false; for (ui = cu.begin(); ui != cu.end(); ++ui) { CUnit* unit = *ui; if ((((options & CONTROL_KEY) && owner->team != unit->team) || !teamHandler->Ally(owner->allyteam, unit->allyteam)) && (unit != owner) && (unit->losStatus[owner->allyteam] & (LOS_INRADAR|LOS_INLOS)) && !unit->beingBuilt && unit->unitDef->capturable) { if(unit->IsMoving() && stationary) { // capture stationary targets first continue; } if(healthyOnly && unit->health < unit->maxHealth && unit->captureProgress <= 0.0f) { continue; } const float dist = f3SqDist(unit->pos, owner->pos); if (dist < bestDist || (!stationary && !unit->IsMoving())) { if (!owner->unitDef->canmove && !IsInBuildRange(unit)) { continue; } if(!stationary && !unit->IsMoving()) { stationary = true; } bestDist = dist; best = unit; } } } if (best) { Command nc(CMD_CAPTURE, options | INTERNAL_ORDER, best->id); commandQue.push_front(nc); return true; } return false; }
void CBuilderCAI::ExecuteCapture(Command& c) { // not all builders are capture-capable by default if (!owner->unitDef->canCapture) return; if (c.params.size() == 1 || c.params.size() == 5) { // capture unit CUnit* unit = unitHandler->GetUnit(c.params[0]); if (unit == NULL) { FinishCommand(); return; } if (c.params.size() == 5) { const float3& pos = c.GetPos(1); const float radius = c.params[4] + 100; // do not walk too far outside capture area if (((pos - unit->pos).SqLength2D() > (radius * radius) || (ownerBuilder->curCapture == unit && unit->IsMoving() && !IsInBuildRange(unit)))) { StopMove(); FinishCommand(); return; } } if (unit->unitDef->capturable && unit->team != owner->team && UpdateTargetLostTimer(unit->id)) { if (MoveInBuildRange(unit)) { ownerBuilder->SetCaptureTarget(unit); } } else { StopMove(); FinishCommand(); } } else if (c.params.size() == 4) { // area capture const float3 pos = c.GetPos(0); const float radius = c.params[3]; ownerBuilder->StopBuild(); if (FindCaptureTargetAndCapture(pos, radius, c.options, (c.options & META_KEY))) { inCommand = false; SlowUpdate(); return; } if (!(c.options & ALT_KEY)) { FinishCommand(); } } else { FinishCommand(); } }
void CBuilderCAI::ExecuteReclaim(Command& c) { // 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; const bool checkForBetterTarget = ((++randomCounter % 5) == 0); if (checkForBetterTarget && (c.options & INTERNAL_ORDER) && (c.params.size() >= 5)) { // regular check if there is a closer reclaim target CSolidObject* obj; if (uid >= unitHandler->MaxUnits()) { obj = featureHandler->GetFeature(uid - unitHandler->MaxUnits()); } else { obj = unitHandler->GetUnit(uid); } if (obj) { const float3& pos = c.GetPos(1); 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 >= unitHandler->MaxUnits()) { // reclaim feature CFeature* feature = featureHandler->GetFeature(uid - unitHandler->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 = unitHandler->GetUnit(uid); if (unit != NULL && c.params.size() == 5) { const float3& pos = c.GetPos(1); 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) || (ownerBuilder->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); ownerBuilder->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(); } }
void CBuilderCAI::ExecuteRepair(Command& c) { // not all builders are repair-capable by default if (!owner->unitDef->canRepair) return; if (c.params.size() == 1 || c.params.size() == 5) { // repair unit CUnit* unit = unitHandler->GetUnit(c.params[0]); if (unit == NULL) { FinishCommand(); return; } if (tempOrder && owner->moveState <= MOVESTATE_MANEUVER) { // limit how far away we go when not roaming if (LinePointDist(commandPos1, commandPos2, unit->pos) > std::max(500.0f, GetBuildRange(unit->radius))) { StopMove(); FinishCommand(); return; } } if (c.params.size() == 5) { const float3& pos = c.GetPos(1); const float radius = c.params[4] + 100.0f; // do not walk too far outside repair area if ((pos - unit->pos).SqLength2D() > radius * radius || (unit->IsMoving() && (((c.options & INTERNAL_ORDER) && !TargetInterceptable(unit, unit->speed.Length2D())) || ownerBuilder->curBuild == unit) && !IsInBuildRange(unit))) { StopMove(); FinishCommand(); return; } } // do not consider units under construction irreparable // even if they can be repaired bool canRepairUnit = true; canRepairUnit &= ((unit->beingBuilt) || (unit->unitDef->repairable && (unit->health < unit->maxHealth))); canRepairUnit &= ((unit != owner) || owner->unitDef->canSelfRepair); canRepairUnit &= (!unit->soloBuilder || (unit->soloBuilder == owner)); canRepairUnit &= (!(c.options & INTERNAL_ORDER) || (c.options & CONTROL_KEY) || !IsUnitBeingReclaimed(unit, owner)); canRepairUnit &= (UpdateTargetLostTimer(unit->id) != 0); if (canRepairUnit) { if (MoveInBuildRange(unit)) { ownerBuilder->SetRepairTarget(unit); } } else { StopMove(); FinishCommand(); } } else if (c.params.size() == 4) { // area repair const float3 pos = c.GetPos(0); const float radius = c.params[3]; ownerBuilder->StopBuild(); if (FindRepairTargetAndRepair(pos, radius, c.options, false, (c.options & META_KEY))) { inCommand = false; SlowUpdate(); return; } if (!(c.options & ALT_KEY)) { FinishCommand(); } } else { FinishCommand(); } }