//Wyrmgus start //int AiEnemyUnitsInDistance(const CUnit &unit, unsigned range) int AiEnemyUnitsInDistance(const CUnit &unit, unsigned range, int z) //Wyrmgus end { //Wyrmgus start // return AiEnemyUnitsInDistance(*unit.Player, unit.Type, unit.tilePos, range); return AiEnemyUnitsInDistance(*unit.Player, unit.Type, unit.tilePos, range, z); //Wyrmgus end }
VisitResult AiForceRallyPointFinder::Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from) { const int minDist = 15; if (AiEnemyUnitsInDistance(*startUnit.Player, NULL, pos, minDist) == false && Distance(pos, startPos) <= abs(distance - minDist)) { *resultPos = pos; return VisitResult_Finished; } if (CanMoveToMask(pos, movemask)) { // reachable return VisitResult_Ok; } else { // unreachable return VisitResult_DeadEnd; } }
/** ** Get a suitable depot for better resource harvesting. ** ** @param worker Worker itself. ** @param oldDepot Old assigned depot. ** @param resUnit Resource to harvest from, if succeed ** ** @return new depot if found, NULL otherwise. */ CUnit *AiGetSuitableDepot(const CUnit &worker, const CUnit &oldDepot, CUnit **resUnit) { Assert(worker.CurrentAction() == UnitActionResource); COrder_Resource &order = *static_cast<COrder_Resource *>(worker.CurrentOrder()); const int resource = order.GetCurrentResource(); std::vector<CUnit *> depots; const Vec2i offset(MaxMapWidth, MaxMapHeight); for (std::vector<CUnit *>::iterator it = worker.Player->UnitBegin(); it != worker.Player->UnitEnd(); ++it) { CUnit &unit = **it; if (unit.Type->CanStore[resource] && !unit.IsUnusable()) { depots.push_back(&unit); } } // If there aren't any alternatives, exit if (depots.size() < 2) { return NULL; } std::sort(depots.begin(), depots.end(), CompareDepotsByDistance(worker)); for (std::vector<CUnit *>::iterator it = depots.begin(); it != depots.end(); ++it) { CUnit &unit = **it; const unsigned int tooManyWorkers = 15; const int range = 15; if (&oldDepot == &unit) { continue; } if (unit.Refs > tooManyWorkers) { continue; } //Wyrmgus start // if (AiEnemyUnitsInDistance(worker, range)) { if (AiEnemyUnitsInDistance(worker, range, worker.MapLayer)) { //Wyrmgus end continue; } CUnit *res = UnitFindResource(worker, unit, range, resource, unit.Player->AiEnabled); if (res) { *resUnit = res; return &unit; } } return NULL; }
/** ** Find free building place. (flood fill version) ** ** @param worker Worker to build building. ** @param type Type of building. ** @param ox Original X position to try building ** @param oy Original Y position to try building ** @param dpos Pointer for position returned. ** ** @return True if place found, false if no found. */ static int AiFindBuildingPlace2(const CUnit &worker, const CUnitType &type, int ox, int oy, Vec2i *dpos) { const Vec2i offset[] = {{0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1}}; Vec2i *points; int size; Vec2i pos = {ox, oy}; Vec2i rpos; int mask; int wp; int rp; int ep; unsigned char *m; Vec2i backupPos = {-1, -1}; bool backupok; // // Look if we can build at current place. // if (CanBuildUnitType(&worker, type, pos, 1) && !AiEnemyUnitsInDistance(worker.Player, NULL, pos, 8)) { if (AiCheckSurrounding(worker, type, pos.x, pos.y, backupok)) { *dpos = pos; return 1; } else if (backupok) { backupPos = pos; } } size = Map.Info.MapWidth * Map.Info.MapHeight / 4; points = new Vec2i[size]; // // Make movement matrix. // unsigned char *matrix = CreateMatrix(); const int w = Map.Info.MapWidth + 2; mask = worker.Type->MovementMask; // Ignore all possible mobile units. mask &= ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit); points[0] = pos; // also use the bottom right if ((type.TileWidth > 1 || type.TileHeight > 1) && pos.x + type.TileWidth - 1 < Map.Info.MapWidth && pos.y + type.TileHeight - 1 < Map.Info.MapHeight) { points[1].x = pos.x + type.TileWidth - 1; points[1].y = pos.y + type.TileHeight - 1; ep = wp = 2; // start with two points } else { ep = wp = 1; // start with one point } matrix += w + w + 2; rp = 0; matrix[pos.x + pos.y * w] = 1; // mark start point // // Pop a point from stack, push all neighbours which could be entered. // for (;;) { while (rp != ep) { rpos = points[rp]; for (int i = 0; i < 8; ++i) { // mark all neighbors pos = rpos + offset[i]; m = matrix + pos.x + pos.y * w; if (*m) { // already checked continue; } // // Look if we can build here and no enemies nearby. // if (CanBuildUnitType(&worker, type, pos, 1) && !AiEnemyUnitsInDistance(worker.Player, NULL, pos, 8)) { if (AiCheckSurrounding(worker, type, pos.x, pos.y, backupok)) { *dpos = pos; delete[] points; return 1; } else if (backupok && backupPos.x == -1) { backupPos = pos; } } if (CanMoveToMask(pos, mask)) { // reachable *m = 1; points[wp] = pos; // push the point if (++wp >= size) { // round about wp = 0; } } else { // unreachable *m = 99; } } if (++rp >= size) { // round about rp = 0; } } // // Continue with next frame. // if (rp == wp) { // unreachable, no more points available break; } ep = wp; } delete[] points; if (backupPos.x != -1) { *dpos = backupPos; return 1; } return 0; }
/** ** Enemy units in distance. ** ** @param unit Find in distance for this unit. ** @param range Distance range to look. ** ** @return Number of enemy units. */ int AiEnemyUnitsInDistance(const CUnit &unit, unsigned range) { return AiEnemyUnitsInDistance(unit.Player, unit.Type, unit.tilePos, range); }
/** ** Check if there's a unit that should be repaired. */ static void AiCheckRepair() { int i; int j; int k; int n; bool repair_flag; n = AiPlayer->Player->TotalNumUnits; k = 0; // Selector for next unit for (i = n - 1; i >= 0; --i) { CUnit *unit = AiPlayer->Player->Units[i]; if (unit && UnitNumber(*unit) == AiPlayer->LastRepairBuilding) { k = i + 1; } } for (i = k; i < n; ++i) { CUnit &unit = *AiPlayer->Player->Units[i]; repair_flag = true; if (!unit.IsAliveOnMap()) { continue; } // Unit damaged? // Don't repair attacked unit (wait 5 sec before repairing) if (unit.Type->RepairHP && unit.CurrentAction() != UnitActionBuilt && unit.CurrentAction() != UnitActionUpgradeTo && unit.Variable[HP_INDEX].Value < unit.Variable[HP_INDEX].Max && unit.Attacked + 5 * CYCLES_PER_SECOND < GameCycle) { // // FIXME: Repair only units under control // if (AiEnemyUnitsInDistance(unit, unit.Stats->Variables[SIGHTRANGE_INDEX].Max)) { continue; } // // Must check, if there are enough resources // for (j = 1; j < MaxCosts; ++j) { if (unit.Stats->Costs[j] && AiPlayer->Player->Resources[j] < 99) { repair_flag = false; break; } } // // Find a free worker, who can build this building can repair it? // if (repair_flag) { AiRepairUnit(unit); AiPlayer->LastRepairBuilding = UnitNumber(unit); return; } } // Building under construction but no worker if (unit.CurrentAction() == UnitActionBuilt) { int j; for (j = 0; j < AiPlayer->Player->TotalNumUnits; ++j) { COrderPtr order = AiPlayer->Player->Units[j]->CurrentOrder(); if (order->Action == UnitActionRepair && order->GetGoal() == &unit) { break; } } if (j == AiPlayer->Player->TotalNumUnits) { // Make sure we have enough resources first for (j = 0; j < MaxCosts; ++j) { // FIXME: the resources don't necessarily have to be in storage if (AiPlayer->Player->Resources[j] < unit.Stats->Costs[j]) { break; } } if (j == MaxCosts) { AiRepairUnit(unit); AiPlayer->LastRepairBuilding = UnitNumber(unit); return; } } } } AiPlayer->LastRepairBuilding = 0; }
/** ** Check if there's a unit that should be repaired. */ static void AiCheckRepair() { const int n = AiPlayer->Player->GetUnitCount(); int k = 0; // Selector for next unit for (int i = n - 1; i >= 0; --i) { const CUnit &unit = AiPlayer->Player->GetUnit(i); if (UnitNumber(unit) == AiPlayer->LastRepairBuilding) { k = i + 1; } } for (int i = k; i < n; ++i) { CUnit &unit = AiPlayer->Player->GetUnit(i); bool repair_flag = true; if (!unit.IsAliveOnMap()) { continue; } // Unit damaged? // Don't repair attacked unit (wait 5 sec before repairing) if (unit.Type->RepairHP //Wyrmgus start // && unit.CurrentAction() != UnitActionBuilt && (unit.CurrentAction() != UnitActionBuilt || unit.Type->BoolFlag[BUILDEROUTSIDE_INDEX].value) //Wyrmgus end && unit.CurrentAction() != UnitActionUpgradeTo //Wyrmgus start // && unit.Variable[HP_INDEX].Value < unit.Variable[HP_INDEX].Max && unit.Variable[HP_INDEX].Value < unit.GetModifiedVariable(HP_INDEX, VariableMax) // && unit.Attacked + 5 * CYCLES_PER_SECOND < GameCycle) { ) { //Wyrmgus end // // FIXME: Repair only units under control // //Wyrmgus start // if (AiEnemyUnitsInDistance(unit, unit.Stats->Variables[SIGHTRANGE_INDEX].Max)) { if (AiEnemyUnitsInDistance(unit, unit.Variable[SIGHTRANGE_INDEX].Max, unit.MapLayer)) { //Wyrmgus end continue; } // // Must check, if there are enough resources // for (int j = 1; j < MaxCosts; ++j) { if (unit.Stats->Costs[j] && (AiPlayer->Player->Resources[j] + AiPlayer->Player->StoredResources[j]) < 99) { repair_flag = false; break; } } // // Find a free worker, who can build this building can repair it? // if (repair_flag) { AiRepairUnit(unit); AiPlayer->LastRepairBuilding = UnitNumber(unit); return; } } // Building under construction but no worker if (unit.CurrentAction() == UnitActionBuilt) { int j; for (j = 0; j < AiPlayer->Player->GetUnitCount(); ++j) { COrder *order = AiPlayer->Player->GetUnit(j).CurrentOrder(); if (order->Action == UnitActionRepair) { COrder_Repair &orderRepair = *static_cast<COrder_Repair *>(order); if (orderRepair.GetReparableTarget() == &unit) { break; } } } if (j == AiPlayer->Player->GetUnitCount()) { // Make sure we have enough resources first for (j = 0; j < MaxCosts; ++j) { // FIXME: the resources don't necessarily have to be in storage if (AiPlayer->Player->Resources[j] + AiPlayer->Player->StoredResources[j] < unit.Stats->Costs[j]) { break; } } if (j == MaxCosts) { AiRepairUnit(unit); AiPlayer->LastRepairBuilding = UnitNumber(unit); return; } } } } AiPlayer->LastRepairBuilding = 0; }