/** ** Check if we can build the building. ** ** @param type Unit that can build the building. ** @param building Building to be build. ** ** @return True if made, false if can't be made. ** ** @note We must check if the dependencies are fulfilled. */ static int AiBuildBuilding(const CUnitType &type, CUnitType &building, int near_x, int near_y) { CUnit *table[UnitMax]; int num = 0; // // Remove all workers on the way building something // const int nunits = FindPlayerUnitsByType(AiPlayer->Player, type, table); for (int i = 0; i < nunits; ++i) { CUnit& unit = *table[i]; int j; for (j = 0; j < unit.OrderCount; ++j) { int action = unit.Orders[j]->Action; if (action == UnitActionBuild || action == UnitActionRepair || action == UnitActionReturnGoods || (action == UnitActionResource && unit.SubAction > 55) /* SUB_START_GATHERING */) { break; } } if (j == unit.OrderCount) { table[num++] = &unit; } } if (num == 0) { // No workers available to build return 0; } CUnit& unit = (num == 1) ? *table[0] : *table[SyncRand() % num]; Vec2i pos; // Find a place to build. if (AiFindBuildingPlace(unit, building, near_x, near_y, &pos)) { CommandBuildBuilding(unit, pos, building, FlushCommands); return 1; } else { //when first worker can't build then rest also won't be able (save CPU) if (near_x != -1 && near_y != -1) { //Crush CPU !!!!! for (int i = 0; i < num && table[i] != &unit; ++i) { // Find a place to build. if (AiFindBuildingPlace(*table[i], building, near_x, near_y, &pos)) { CommandBuildBuilding(*table[i], pos, building, FlushCommands); return 1; } } } } return 0; }
//Wyrmgus start //static bool AiRepairBuilding(const CPlayer &player, const CUnitType &type, CUnit &building) static bool AiRepairBuilding(const CPlayer &player, const CUnitType &type, CUnit &building) //Wyrmgus end { if (type.RepairRange == 0) { return false; } // We need to send all nearby free workers to repair that building // AI shouldn't send workers that are far away from repair point // Selection of mining workers. std::vector<CUnit *> table; FindPlayerUnitsByType(*AiPlayer->Player, type, table, true); int num = 0; for (size_t i = 0; i != table.size(); ++i) { CUnit &unit = *table[i]; if (IsReadyToRepair(unit)) { table[num++] = &unit; } } table.resize(num); if (table.empty()) { return false; } TerrainTraversal terrainTraversal; //Wyrmgus start // terrainTraversal.SetSize(Map.Info.MapWidth, Map.Info.MapHeight); terrainTraversal.SetSize(Map.Info.MapWidths[building.MapLayer], Map.Info.MapHeights[building.MapLayer]); //Wyrmgus end terrainTraversal.Init(); terrainTraversal.PushUnitPosAndNeighboor(building); const int maxRange = 15; const int movemask = type.MovementMask & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit); CUnit *unit = NULL; //Wyrmgus start // UnitFinder unitFinder(player, table, maxRange, movemask, &unit); UnitFinder unitFinder(player, table, maxRange, movemask, &unit, building.MapLayer); //Wyrmgus end if (terrainTraversal.Run(unitFinder) && unit != NULL) { const Vec2i invalidPos(-1, -1); //Wyrmgus start // CommandRepair(*unit, invalidPos, &building, FlushCommands); CommandRepair(*unit, invalidPos, &building, FlushCommands, building.MapLayer); //Wyrmgus end return true; } return false; }
/** ** Check if we can repair the building. ** ** @param type Unit that can repair the building. ** @param building Building to be repaired. ** ** @return True if can repair, false if can't repair.. */ static bool AiRepairBuilding(const CPlayer &player, const CUnitType &type, CUnit &building) { if (type.RepairRange == 0) { return false; } // Remove all workers not mining. on the way building something // FIXME: It is not clever to use workers with gold // Idea: Antonis: Put the rest of the workers in a table in case // miners can't reach but others can. This will be useful if AI becomes // more flexible (e.g.: transports workers to an island) // FIXME: too hardcoded, not nice, needs improvement. // FIXME: too many workers repair the same building! // Selection of mining workers. std::vector<CUnit *> table; FindPlayerUnitsByType(*AiPlayer->Player, type, table); int num = 0; for (size_t i = 0; i != table.size(); ++i) { CUnit &unit = *table[i]; if (IsReadyToRepair(unit)) { table[num++] = &unit; } } table.resize(num); if (table.empty()) { return false; } TerrainTraversal terrainTraversal; terrainTraversal.SetSize(Map.Info.MapWidth, Map.Info.MapHeight); terrainTraversal.Init(); terrainTraversal.PushUnitPosAndNeighboor(building); const int maxRange = 100; const int movemask = type.MovementMask & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit); CUnit *unit = NULL; UnitFinder unitFinder(player, table, maxRange, movemask, &unit); if (terrainTraversal.Run(unitFinder) && unit != NULL) { const Vec2i invalidPos(-1, -1); CommandRepair(*unit, invalidPos, &building, FlushCommands); return true; } return false; }
/** ** Check if we can research the upgrade. ** ** @param type Unit that can research the upgrade. ** @param what What should be researched. ** ** @return True if made, false if can't be made. ** ** @note We must check if the dependencies are fulfilled. */ static bool AiResearchUpgrade(const CUnitType &type, CUpgrade &what) { std::vector<CUnit *> table; FindPlayerUnitsByType(*AiPlayer->Player, type, table); for (size_t i = 0; i != table.size(); ++i) { CUnit &unit = *table[i]; if (unit.IsIdle()) { CommandResearch(unit, what, FlushCommands); return true; } } return false; }
/** ** Check if we can upgrade to unit-type. ** ** @param type Unit that can upgrade to unit-type ** @param what To what should be upgraded. ** ** @return True if made, false if can't be made. ** ** @note We must check if the dependencies are fulfilled. */ static bool AiUpgradeTo(const CUnitType &type, CUnitType &what) { std::vector<CUnit *> table; // Remove all units already doing something. FindPlayerUnitsByType(*AiPlayer->Player, type, table); for (size_t i = 0; i != table.size(); ++i) { CUnit &unit = *table[i]; if (unit.IsIdle()) { CommandUpgradeTo(unit, what, FlushCommands); return true; } } return false; }
/** ** Check if we can train the unit. ** ** @param type Unit that can train the unit. ** @param what What to be trained. ** ** @return True if made, false if can't be made. ** ** @note We must check if the dependencies are fulfilled. */ static bool AiTrainUnit(const CUnitType &type, CUnitType &what) { std::vector<CUnit *> table; FindPlayerUnitsByType(*AiPlayer->Player, type, table, true); for (size_t i = 0; i != table.size(); ++i) { CUnit &unit = *table[i]; if (unit.IsIdle()) { //Wyrmgus start // CommandTrainUnit(unit, what, FlushCommands); CommandTrainUnit(unit, what, AiPlayer->Player->Index, FlushCommands); //Wyrmgus end return true; } } return false; }
/** ** Check if we can build the building. ** ** @param type Unit that can build the building. ** @param building Building to be build. ** ** @return True if made, false if can't be made. ** ** @note We must check if the dependencies are fulfilled. */ static int AiBuildBuilding(const CUnitType &type, CUnitType &building, const Vec2i &nearPos) { std::vector<CUnit *> table; FindPlayerUnitsByType(*AiPlayer->Player, type, table); int num = 0; // Remove all workers on the way building something for (size_t i = 0; i != table.size(); ++i) { CUnit &unit = *table[i]; if (IsAlreadyWorking(unit) == false) { table[num++] = &unit; } } if (num == 0) { // No workers available to build return 0; } CUnit &unit = (num == 1) ? *table[0] : *table[SyncRand() % num]; Vec2i pos; // Find a place to build. if (AiFindBuildingPlace(unit, building, nearPos, &pos)) { CommandBuildBuilding(unit, pos, building, FlushCommands); return 1; } else { //when first worker can't build then rest also won't be able (save CPU) if (Map.Info.IsPointOnMap(nearPos)) { //Crush CPU !!!!! for (int i = 0; i < num && table[i] != &unit; ++i) { // Find a place to build. if (AiFindBuildingPlace(*table[i], building, nearPos, &pos)) { CommandBuildBuilding(*table[i], pos, building, FlushCommands); return 1; } } } } return 0; }
/** ** Check if we can upgrade to unit-type. ** ** @param type Unit that can upgrade to unit-type ** @param what To what should be upgraded. ** ** @return True if made, false if can't be made. ** ** @note We must check if the dependencies are fulfilled. */ static int AiUpgradeTo(const CUnitType &type, CUnitType &what) { CUnit *table[UnitMax]; int num = 0; // Remove all units already doing something. const int nunits = FindPlayerUnitsByType(AiPlayer->Player, type, table); for (int i = 0; i < nunits; ++i) { CUnit *unit = table[i]; if (unit->IsIdle()) { table[num++] = unit; } } for (int i = 0; i < num; ++i) { CUnit &unit = *table[i]; CommandUpgradeTo(unit, what, FlushCommands); return 1; } return 0; }
/** ** Check if we can repair the building. ** ** @param type Unit that can repair the building. ** @param building Building to be repaired. ** ** @return True if can repair, false if can't repair.. */ static int AiRepairBuilding(const CUnitType &type, CUnit &building) { // Remove all workers not mining. on the way building something // FIXME: It is not clever to use workers with gold // Idea: Antonis: Put the rest of the workers in a table in case // miners can't reach but others can. This will be useful if AI becomes // more flexible (e.g.: transports workers to an island) // FIXME: too hardcoded, not nice, needs improvement. // FIXME: too many workers repair the same building! // Selection of mining workers. CUnit *table[UnitMax]; int nunits = FindPlayerUnitsByType(AiPlayer->Player, type, table); int num = 0; for (int i = 0; i < nunits; ++i) { CUnit &unit = *table[i]; if (unit.Type->RepairRange && unit.OrderCount == 1 && ((unit.CurrentAction() == UnitActionResource && unit.SubAction <= 55) /* SUB_START_GATHERING */ || unit.CurrentAction() == UnitActionStill)) { table[num++] = &unit; } } // Sort by distance loops -Antonis- int distance[UnitMax]; for (int i = 0; i < num; ++i) { CUnit &unit = *table[i]; int rX = unit.tilePos.x - building.tilePos.x; int rY = unit.tilePos.y - building.tilePos.y; // FIXME: Probably calculated from top left corner of building rX = std::max(rX, -rX); rY = std::max(rY, -rY); distance[i] = std::min(rX, rY); } for (int i = 0; i < num; ++i) { int r_temp = distance[i]; int index_temp = i; for (int j = i; j < num; ++j) { if (distance[j] < r_temp) { r_temp = distance[j]; index_temp = j; } } if (index_temp > i) { std::swap(distance[i], distance[index_temp]); std::swap(table[i], table[index_temp]); } } // Check if building is reachable and try next trio of workers int nbworker = AiPlayer->TriedRepairWorkers[UnitNumber(building)]; if (nbworker > num) { nbworker = AiPlayer->TriedRepairWorkers[UnitNumber(building)] = 0; } int k = nbworker; for (int i = nbworker; i < num && i < nbworker + 3; ++i) { CUnit &unit = *table[i]; if (UnitReachable(unit, building, unit.Type->RepairRange)) { const Vec2i invalidPos = {-1, -1}; CommandRepair(unit, invalidPos, &building, FlushCommands); return 1; } k = i; } AiPlayer->TriedRepairWorkers[UnitNumber(building)] = k + 1; return 0; }