void CAttackTask::Execute(CCircuitUnit* unit, bool isUpdating) { Unit* u = unit->GetUnit(); CCircuitAI* circuit = manager->GetCircuit(); CTerrainManager* terrainManager = circuit->GetTerrainManager(); float minSqDist; CEnemyUnit* bestTarget = FindBestTarget(unit, minSqDist); if (bestTarget == nullptr) { if (!isUpdating) { float x = rand() % (terrainManager->GetTerrainWidth() + 1); float z = rand() % (terrainManager->GetTerrainHeight() + 1); position = AIFloat3(x, circuit->GetMap()->GetElevationAt(x, z), z); } } else { position = bestTarget->GetPos(); float range = u->GetMaxRange(); if (minSqDist < range * range) { u->Attack(bestTarget->GetUnit(), UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 300); return; } } u->Fight(position, UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 300); }
void CRetreatTask::OnUnitIdle(CCircuitUnit* unit) { CCircuitAI* circuit = manager->GetCircuit(); int frame = circuit->GetLastFrame(); CFactoryManager* factoryManager = circuit->GetFactoryManager(); AIFloat3 haven = (repairer != nullptr) ? repairer->GetPos(frame) : factoryManager->GetClosestHaven(unit); if (haven == -RgtVector) { haven = circuit->GetSetupManager()->GetBasePos(); } if (unit->GetCircuitDef()->IsPlane()) { // force rearm/repair | CMD_FIND_PAD unit->GetUnit()->Fight(haven, UNIT_COMMAND_OPTION_RIGHT_MOUSE_KEY, frame + FRAMES_PER_SEC * 60); return; } const float maxDist = factoryManager->GetAssistDef()->GetBuildDistance(); const AIFloat3& unitPos = unit->GetPos(frame); if (unitPos.SqDistance2D(haven) > maxDist * maxDist) { // TODO: push MoveAction into unit? to avoid enemy fire unit->GetUnit()->MoveTo(haven, UNIT_COMMAND_OPTION_RIGHT_MOUSE_KEY, frame + FRAMES_PER_SEC * 1); // TODO: Add fail counter? } else { // TODO: push WaitAction into unit // unit->GetUnit()->ExecuteCustomCommand(CMD_PRIORITY, {0.0f}); AIFloat3 pos = unitPos; const float size = SQUARE_SIZE * 16; CTerrainManager* terrainManager = circuit->GetTerrainManager(); float centerX = terrainManager->GetTerrainWidth() / 2; float centerZ = terrainManager->GetTerrainHeight() / 2; pos.x += (pos.x > centerX) ? size : -size; pos.z += (pos.z > centerZ) ? size : -size; AIFloat3 oldPos = pos; terrainManager->CorrectPosition(pos); if (oldPos.SqDistance2D(pos) > SQUARE_SIZE * SQUARE_SIZE) { pos = unitPos; pos.x += (pos.x > centerX) ? -size : size; pos.z += (pos.z > centerZ) ? -size : size; } CTerrainManager::TerrainPredicate predicate = [unitPos](const AIFloat3& p) { return unitPos.SqDistance2D(p) > SQUARE(SQUARE_SIZE * 8); }; pos = terrainManager->FindBuildSite(unit->GetCircuitDef(), pos, maxDist, UNIT_COMMAND_BUILD_NO_FACING, predicate); unit->GetUnit()->PatrolTo(pos); IUnitAction* act = static_cast<IUnitAction*>(unit->End()); if (act->IsAny(IUnitAction::Mask::MOVE | IUnitAction::Mask::FIGHT)) { static_cast<ITravelAction*>(act)->SetFinished(true); } } }
void CBPatrolTask::Execute(CCircuitUnit* unit) { CCircuitAI* circuit = manager->GetCircuit(); Unit* u = unit->GetUnit(); TRY_UNIT(circuit, unit, u->ExecuteCustomCommand(CMD_PRIORITY, {0.0f}); const float size = SQUARE_SIZE * 100; CTerrainManager* terrainManager = circuit->GetTerrainManager(); AIFloat3 pos = position; pos.x += (pos.x > terrainManager->GetTerrainWidth() / 2) ? -size : size; pos.z += (pos.z > terrainManager->GetTerrainHeight() / 2) ? -size : size; u->PatrolTo(pos); ) }
void IBuilderTask::FindBuildSite(CCircuitUnit* builder, const AIFloat3& pos, float searchRadius) { CTerrainManager* terrainManager = manager->GetCircuit()->GetTerrainManager(); // facing = UNIT_COMMAND_BUILD_NO_FACING; float terWidth = terrainManager->GetTerrainWidth(); float terHeight = terrainManager->GetTerrainHeight(); if (math::fabs(terWidth - 2 * pos.x) > math::fabs(terHeight - 2 * pos.z)) { facing = (2 * pos.x > terWidth) ? UNIT_FACING_WEST : UNIT_FACING_EAST; } else { facing = (2 * pos.z > terHeight) ? UNIT_FACING_NORTH : UNIT_FACING_SOUTH; } CTerrainManager::TerrainPredicate predicate = [terrainManager, builder](const AIFloat3& p) { return terrainManager->CanBuildAt(builder, p); }; buildPos = terrainManager->FindBuildSite(buildDef, pos, searchRadius, facing, predicate); }
void CBReclaimTask::Execute(CCircuitUnit* unit) { Unit* u = unit->GetUnit(); // u->ExecuteCustomCommand(CMD_PRIORITY, {ClampPriority()}); int frame = manager->GetCircuit()->GetLastFrame(); if (target == nullptr) { AIFloat3 pos; float reclRadius; if ((radius == .0f) || (position == -RgtVector)) { CTerrainManager* terrainManager = manager->GetCircuit()->GetTerrainManager(); float width = terrainManager->GetTerrainWidth() / 2; float height = terrainManager->GetTerrainHeight() / 2; pos = AIFloat3(width, 0, height); reclRadius = sqrtf(width * width + height * height); } else { pos = position; reclRadius = radius; } u->ReclaimInArea(pos, reclRadius, UNIT_COMMAND_OPTION_INTERNAL_ORDER, frame + FRAMES_PER_SEC * 60); } else { u->ReclaimUnit(target->GetUnit(), UNIT_COMMAND_OPTION_INTERNAL_ORDER, frame + FRAMES_PER_SEC * 60); } }
void IBuilderTask::Execute(CCircuitUnit* unit) { Unit* u = unit->GetUnit(); u->ExecuteCustomCommand(CMD_PRIORITY, {static_cast<float>(priority)}); CCircuitAI* circuit = manager->GetCircuit(); if (target != nullptr) { Unit* tu = target->GetUnit(); u->Build(target->GetCircuitDef()->GetUnitDef(), tu->GetPos(), tu->GetBuildingFacing(), UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 60); return; } CTerrainManager* terrainManager = circuit->GetTerrainManager(); UnitDef* buildUDef = buildDef->GetUnitDef(); if (buildPos != -RgtVector) { if (circuit->GetMap()->IsPossibleToBuildAt(buildUDef, buildPos, facing)) { u->Build(buildUDef, buildPos, facing, UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 60); return; } else { terrainManager->RemoveBlocker(buildDef, buildPos, facing); // FIXME: If enemy blocked position then reset will have no effect // terrain->ResetBuildFrame(); } } circuit->GetThreatMap()->SetThreatType(unit); // FIXME: Replace const 999.0f with build time? if (circuit->IsAllyAware() && (cost > 999.0f)) { // circuit->UpdateFriendlyUnits(); auto friendlies = std::move(circuit->GetCallback()->GetFriendlyUnitsIn(position, cost)); for (Unit* au : friendlies) { CCircuitUnit* alu = circuit->GetFriendlyUnit(au); if (alu == nullptr) { continue; } if ((*alu->GetCircuitDef() == *buildDef) && au->IsBeingBuilt()) { const AIFloat3& pos = au->GetPos(); if (terrainManager->CanBuildAt(unit, pos)) { u->Build(buildUDef, pos, au->GetBuildingFacing(), UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 60); utils::free_clear(friendlies); return; } } } utils::free_clear(friendlies); } // Alter/randomize position AIFloat3 pos; if (isShake) { AIFloat3 offset((float)rand() / RAND_MAX - 0.5f, 0.0f, (float)rand() / RAND_MAX - 0.5f); pos = position + offset * SQUARE_SIZE * 16; } else { pos = position; } const float searchRadius = 200.0f * SQUARE_SIZE; FindBuildSite(unit, pos, searchRadius); if (buildPos != -RgtVector) { terrainManager->AddBlocker(buildDef, buildPos, facing); u->Build(buildUDef, buildPos, facing, UNIT_COMMAND_OPTION_INTERNAL_ORDER, circuit->GetLastFrame() + FRAMES_PER_SEC * 60); } else { // TODO: Select new proper BasePos, like near metal cluster. int terWidth = terrainManager->GetTerrainWidth(); int terHeight = terrainManager->GetTerrainHeight(); float x = terWidth / 4 + rand() % (int)(terWidth / 2 + 1); float z = terHeight / 4 + rand() % (int)(terHeight / 2 + 1); AIFloat3 pos(x, circuit->GetMap()->GetElevationAt(x, z), z); circuit->GetSetupManager()->SetBasePos(pos); // Fallback to Guard/Assist/Patrol manager->FallbackTask(unit); } }