VisitResult ResourceUnitFinder::Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from) { if (!worker.Player->AiEnabled && !Map.Field(pos)->playerInfo.IsExplored(*worker.Player)) { return VisitResult_DeadEnd; } CUnit *mine = Map.Field(pos)->UnitCache.find(res_finder); if (mine && mine != *resultMine && MineIsUsable(*mine)) { ResourceUnitFinder::ResourceUnitFinder_Cost cost; cost.SetFrom(*mine, deposit, check_usage); if (cost < bestCost) { *resultMine = mine; if (cost.IsMin()) { return VisitResult_Finished; } bestCost = cost; } } if (CanMoveToMask(pos, movemask)) { // reachable if (terrainTraversal.Get(pos) < maxRange) { return VisitResult_Ok; } else { return VisitResult_DeadEnd; } } else { // unreachable return VisitResult_DeadEnd; } }
VisitResult NearReachableTerrainFinder::Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from) { //Wyrmgus start // if (!player.AiEnabled && !Map.Field(pos)->playerInfo.IsExplored(player)) { if (!Map.Field(pos)->playerInfo.IsExplored(player)) { //Wyrmgus end return VisitResult_DeadEnd; } // Look if found what was required. if (CanMoveToMask(pos, movemask)) { if (resPos) { *resPos = from; } return VisitResult_Finished; } if (Map.Field(pos)->CheckMask(resmask)) { // reachable if (terrainTraversal.Get(pos) <= maxDist) { return VisitResult_Ok; } else { return VisitResult_DeadEnd; } } else { // unreachable return VisitResult_DeadEnd; } }
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; } }
VisitResult UnitFinder::Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from) { if (!player.AiEnabled && !Map.Field(pos)->playerInfo.IsExplored(player)) { return VisitResult_DeadEnd; } // Look if found what was required. CUnit *unit = FindUnitAtPos(pos); if (unit) { *unitP = unit; return VisitResult_Finished; } if (CanMoveToMask(pos, movemask)) { // reachable if (terrainTraversal.Get(pos) <= maxDist) { return VisitResult_Ok; } else { return VisitResult_DeadEnd; } } else { // unreachable return VisitResult_DeadEnd; } }
static int AiFindMiningPlace(const CUnit &worker, const CUnitType &type, int nx, int ny, Vec2i *dpos, int resource) { const Vec2i offset[] = {{0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1}}; Vec2i pos; Vec2i rpos; int wp; int ep; unsigned char *m; CUnit *mine; pos.x = (nx != -1 ? nx : worker.tilePos.x); pos.y = (ny != -1 ? ny : worker.tilePos.y); int size = Map.Info.MapWidth * Map.Info.MapHeight / 4; Vec2i *points = new Vec2i[size]; // // Make movement matrix. FIXME: can create smaller matrix. // unsigned char *morg = MakeMatrix(); int w = Map.Info.MapWidth + 2; unsigned char *matrix = morg + w + w + 2; points[0] = pos; int rp = 0; //if(worker->tilePos == pos) matrix[pos.x + pos.y * w] = 1; // mark start point ep = wp = 1; // start with one point int mask = worker.Type->MovementMask; // // Pop a point from stack, push all neighbors 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 there is a mine area // if ((mine = ResourceOnMap(pos, resource, false)) && AiFindBuildingPlace2(worker, type, mine->tilePos.x, mine->tilePos.y, dpos)) { delete[] morg; delete[] points; return 1; } 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[] morg; delete[] points; return 0; }
/** ** Find free building place for lumber mill. (flood fill version) ** ** @param worker Worker to build building. ** @param type Type of building. ** @param nx Start search X position (if == -1 then unit X pos used). ** @param ny Start search X position (if == -1 then unit X pos used). ** @param dpos Pointer for position returned. ** ** @return True if place found, false if not found. ** ** @todo FIXME: This is slow really slow, using two flood ** fills, is not a perfect solution. */ static int AiFindLumberMillPlace(const CUnit &worker, const CUnitType &type, int nx, int ny, 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 rpos; int mask; int wp; int rp; int ep; int i; int w; unsigned char *m; unsigned char *morg; unsigned char *matrix; Vec2i pos; pos.x = nx != -1 ? nx : worker.tilePos.x; pos.y = ny != -1 ? ny : worker.tilePos.y; size = Map.Info.MapWidth * Map.Info.MapHeight / 4; points = new Vec2i[size]; // // Make movement matrix. // morg = MakeMatrix(); w = Map.Info.MapWidth + 2; matrix = morg + w + w + 2; points[0] = pos; rp = 0; matrix[pos.x + pos.y * w] = 1; // mark start point ep = wp = 1; // start with one point mask = worker.Type->MovementMask; // // Pop a point from stack, push all neightbors which could be entered. // for (;;) { while (rp != ep) { rpos = points[rp]; for (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 there is wood // if (Map.ForestOnMap(pos)) { if (AiFindBuildingPlace2(worker, type, pos.x, pos.y, dpos)) { delete[] morg; delete[] points; return 1; } } 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[] morg; delete[] points; return 0; }
/** ** Find building place for hall. (flood fill version) ** ** The best place: ** 1) near to goldmine. ** !2) near to wood. ** !3) near to worker and must be reachable. ** 4) no enemy near it. ** 5) no hall already near ** !6) enough gold in mine ** ** @param worker Worker to build building. ** @param type Type of building. ** @param nx Start search X position (if == -1 then unit X pos used). ** @param ny Start search Y position (if == -1 then unit Y pos used). ** @param dpos Pointer for position returned. ** ** @return True if place found, false if not found. ** ** @todo FIXME: This is slow really slow, using ** two flood fills, is not a perfect solution. */ static int AiFindHallPlace(const CUnit &worker, const CUnitType &type, int nx, int ny, Vec2i *dpos, int resource = GoldCost) { 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; Vec2i rpos; int mask; int wp; int rp; int ep; int w; unsigned char *m; unsigned char *morg; unsigned char *matrix; CUnit *mine; pos.x = (nx != -1 ? nx : worker.tilePos.x); pos.y = (ny != -1 ? ny : worker.tilePos.y); size = Map.Info.MapWidth * Map.Info.MapHeight / 4; points = new Vec2i[size]; // // Make movement matrix. FIXME: can create smaller matrix. // morg = MakeMatrix(); w = Map.Info.MapWidth + 2; matrix = morg + w + w + 2; points[0] = pos; rp = 0; matrix[pos.x + pos.y * w] = 1; // mark start point ep = wp = 1; // start with one point mask = worker.Type->MovementMask; // // Pop a point from stack, push all neighbors 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 there is a mine // if ((mine = ResourceOnMap(pos, resource))) { int buildings; int j; int nunits; CUnit *units[UnitMax]; buildings = 0; // // Check units around mine // Vec2i minpos = {mine->tilePos.x - 5, mine->tilePos.y - 5}; Vec2i maxpos = {mine->tilePos.x + mine->Type->TileWidth + 5, mine->tilePos.y + mine->Type->TileHeight + 5 }; Map.FixSelectionArea(minpos, maxpos); nunits = Map.SelectFixed(minpos, maxpos, units); for (j = 0; j < nunits; ++j) { // Enemy near mine if (AiPlayer->Player->Enemy & (1 << units[j]->Player->Index)) { break; } // Town hall near mine if (units[j]->Type->CanStore[resource]) { break; } // Town hall may not be near but we may be using it, check // for 2 buildings near it and assume it's been used if (units[j]->Type->Building && !units[j]->Type->GivesResource == resource) { ++buildings; if (buildings == 2) { break; } } } if (j == nunits) { if (AiFindBuildingPlace2(worker, type, pos.x, pos.y, dpos)) { delete[] morg; delete[] points; return 1; } } } 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[] morg; delete[] points; return 0; }
/** ** 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; }
/** ** Can move to this point, applying mask. ** ** @param pos map tile position. ** @param mask Mask for movement to apply. ** ** @return True if could be entered, false otherwise. */ bool CheckedCanMoveToMask(const Vec2i &pos, int mask) { return Map.Info.IsPointOnMap(pos) && CanMoveToMask(pos, mask); }