/** * Find a suitable spot for an airport, walking all towns hoping to find one. * When a town is used, it is marked as such and not re-used. */ function WrightAI::FindSuitableAirportSpot(airportTypes, airport1_tile, large_aircraft, small_aircraft, helicopter) { local town_list = AITownList(); /* Remove all the towns we already used */ town_list.RemoveList(this.towns_used); /* Remove towns we have tried recently */ town_list.RemoveList(this.triedTowns); if (AIController.GetSetting("cities_only")) { town_list.Valuate(AITown.IsCity); town_list.KeepValue(1); } town_list.Valuate(AITown.GetLastMonthProduction, this.cargoId); town_list.KeepAboveValue(LuDiAIAfterFix.cargoClass == AICargo.CC_PASSENGERS ? 70 : 18); if (AIController.GetSetting("pick_random")) { town_list.Valuate(AIBase.RandItem); } else { town_list.Sort(AIList.SORT_BY_VALUE, false); } /* Keep the best 10, if we can't find a station in there, just leave it anyway */ town_list.KeepTop(10); if (town_list.Count() <= 1) { this.triedTowns.Clear(); } /* Now find a suitable town */ for (local town = town_list.Begin(); town_list.HasNext(); town = town_list.Next()) { /* Don't make this a CPU hog */ AIController.Sleep(1); local town_tile = AITown.GetLocation(town); // AILog.Info("Checking town " + AITown.GetName(town)); for (local i = airportTypes.Begin(); airportTypes.HasNext(); i = airportTypes.Next()) { local a = airportTypes.GetValue(i); local airport_x = AIAirport.GetAirportWidth(a); local airport_y = AIAirport.GetAirportHeight(a); local airport_rad = AIAirport.GetAirportCoverageRadius(a); // AILog.Info("Checking airport of type " + a); if (!AIAirport.IsValidAirportType(a)) continue; if (large_aircraft && a != AIAirport.AT_INTERCON && a != AIAirport.AT_INTERNATIONAL && a != AIAirport.AT_METROPOLITAN && a != AIAirport.AT_LARGE) { continue; } if (small_aircraft && a != AIAirport.AT_INTERCON && a != AIAirport.AT_INTERNATIONAL && a != AIAirport.AT_METROPOLITAN && a != AIAirport.AT_LARGE && a != AIAirport.AT_SMALL && a != AIAirport.AT_COMMUTER) { continue; } if (helicopter && a != AIAirport.AT_HELISTATION && a != AIAirport.AT_HELIDEPOT && a != AIAirport.AT_HELIPORT) { if (AIAirport.IsValidAirportType(AIAirport.AT_HELISTATION) || AIAirport.IsValidAirportType(AIAirport.AT_HELIDEPOT)) { continue; } } local engine_list = null; if (large_aircraft) { engine_list = this.GetBestAirportEngine(AIAirport.AT_LARGE, true); } else if (small_aircraft) { engine_list = this.GetBestAirportEngine(AIAirport.AT_SMALL, true); } else if (helicopter) { engine_list = this.GetBestAirportEngine(AIAirport.AT_HELIPORT, true); } else { engine_list = this.GetBestAirportEngine(a, true); } if (engine_list == null) continue; local engine = WrightAI.GetBestEngineIncome(engine_list); if (engine[0] == null) continue; local fakedist = engine[1]; /* Best engine is unprofitable enough */ if (fakedist == 0) continue; local rectangleCoordinates = this.TownAirportRadRect(a, town); local tileList = AITileList(); tileList.AddRectangle(rectangleCoordinates[0], rectangleCoordinates[1]); tileList.Valuate(AITile.GetClosestTown); tileList.KeepValue(town); if (tileList.Count() == 0) continue; if (airport1_tile != 0) { /* If we have the tile of the first airport, we don't want the second airport to be as close or as further */ tileList.Valuate(AITile.GetDistanceSquareToTile, airport1_tile); local max_order_dist = WrightAI.GetMaximumOrderDistance(engine[0]); local max_dist = max_order_dist > AIMap.GetMapSize() ? AIMap.GetMapSize() : max_order_dist; local min_order_dist = (fakedist / 2) * (fakedist / 2); local min_dist = min_order_dist > max_dist * 3 / 4 ? max_dist * 3 / 4 > AIMap.GetMapSize() / 8 ? AIMap.GetMapSize() / 8 : max_dist * 3 / 4 : min_order_dist; tileList.KeepBetweenValue(min_dist, max_dist); // AILog.Info("KeepBetweenValue " + min_dist + " and " + max_dist); tileList.Valuate(WrightAI.DistanceRealFake, airport1_tile); tileList.KeepBelowValue(fakedist * 11 / 10); if (tileList.Count() == 0) continue; } tileList.Valuate(AITile.IsBuildableRectangle, airport_x, airport_y); tileList.KeepValue(1) if (tileList.Count() == 0) continue; /* Sort on acceptance, remove places that don't have acceptance */ tileList.Valuate(AITile.GetCargoAcceptance, this.cargoId, airport_x, airport_y, airport_rad); tileList.RemoveBelowValue(10); if (tileList.Count() == 0) continue; tileList.Valuate(AITile.GetCargoProduction, this.cargoId, airport_x, airport_y, airport_rad); tileList.RemoveBelowValue(LuDiAIAfterFix.cargoClass == AICargo.CC_PASSENGERS ? 70 : 18); /* Couldn't find a suitable place for this town, skip to the next */ if (tileList.Count() == 0) continue; tileList.Sort(AIList.SORT_BY_VALUE, false); /* Walk all the tiles and see if we can build the airport at all */ local good_tile = 0; for (local tile = tileList.Begin(); tileList.HasNext(); tile = tileList.Next()) { local adjacentStationId = checkAdjacentStation(tile, a); local nearest_town; if (adjacentStationId == AIStation.STATION_NEW) { nearest_town = AITile.GetClosestTown(tile); } else { nearest_town = AIStation.GetNearestTown(adjacentStationId); if (nearest_town != town) { adjacentStationId = AIStation.STATION_NEW; nearest_town = AITile.GetClosestTown(tile); } } local noise = AIAirport.GetNoiseLevelIncrease(tile, a); local allowed_noise = AITown.GetAllowedNoise(AIAirport.GetNearestTown(tile, a)); if (noise > allowed_noise) continue; /* Don't build airport if there is any competitor station in the vicinity, or an airport of mine */ local airportcoverage = this.TownAirportRadRect(a, tile, false); local tileList2 = AITileList(); tileList2.AddRectangle(airportcoverage[0], airportcoverage[1]); local nearby_station = false; for (local t = tileList2.Begin(); tileList2.HasNext(); t = tileList2.Next()) { if (AITile.IsStationTile(t) && (AIAirport.IsAirportTile(t) || AITile.GetOwner(t) != AICompany.ResolveCompanyID(AICompany.COMPANY_SELF) && AIController.GetSetting("is_friendly"))) { nearby_station = true; break; } } if (nearby_station) continue; // AISign.BuildSign(tile, ("" + noise + " <= " + allowed_noise + "")); AIController.Sleep(1); if (AITestMode() && !AIAirport.BuildAirport(tile, a, adjacentStationId)) continue; good_tile = tile; AILog.Info("Found a good spot for an airport near " + AITown.GetName(nearest_town) + " at tile " + good_tile); /* Mark the town as used, so we don't use it again */ assert(!towns_used.HasItem(nearest_town) && !triedTowns.HasItem(nearest_town) && nearest_town == town); this.triedTowns.AddItem(nearest_town, good_tile); if (a == AIAirport.AT_INTERCON || a == AIAirport.AT_INTERNATIONAL || a == AIAirport.AT_METROPOLITAN || a == AIAirport.AT_LARGE) { large_aircraft = true; } if (a == AIAirport.AT_SMALL || a == AIAirport.AT_COMMUTER) { small_aircraft = true; } if (a == AIAirport.AT_HELISTATION || a == AIAirport.AT_HELIDEPOT || a == AIAirport.AT_HELIPORT) { helicopter = true; } return [good_tile, a, large_aircraft, small_aircraft, helicopter, adjacentStationId]; } } /* All airport types were tried on this town and no suitable location was found */ assert(!triedTowns.HasItem(town)); this.triedTowns.AddItem(town, town_tile); } /* We haven't found a suitable location for any airport type in any town */ return [-1, AIAirport.AT_INVALID, large_aircraft, small_aircraft, helicopter, -1]; }