/** * Build an airport route. Find 2 cities that are big enough and try to build airport in both cities. * Then we can build an aircraft and make some money. */ function WrightAI::BuildAirportRoute() { /* Check if we can build more aircraft. */ if (GetAircraftCount() >= AIGameSettings.GetValue("max_aircraft")) return 0; local engine = null; local engine_list = AIEngineList(AIVehicle.VT_AIR); engine_list.Valuate(AIEngine.CanRefitCargo, this.cargoId); engine_list.KeepValue(1); /* There are no engines available. Abort construction. */ if (engine_list.Count() == 0) return 0; local airportTypes = AIList(); airportTypes.AddItem(0, AIAirport.AT_INTERCON); // 7 airportTypes.AddItem(1, AIAirport.AT_INTERNATIONAL); // 4 airportTypes.AddItem(2, AIAirport.AT_METROPOLITAN); // 3 airportTypes.AddItem(3, AIAirport.AT_LARGE); // 1 airportTypes.AddItem(4, AIAirport.AT_COMMUTER); // 5 airportTypes.AddItem(5, AIAirport.AT_SMALL); // 0 airportTypes.AddItem(6, AIAirport.AT_HELISTATION); // 8 airportTypes.AddItem(7, AIAirport.AT_HELIDEPOT); // 6 airportTypes.AddItem(8, AIAirport.AT_HELIPORT); // 2 AILog.Info("Trying to build an airport route"); local small_aircraft = false; // local helicopter = false; local airport1_type; local tile_1; for (local i = 0; i < airportTypes.Count() ; i++) { local a1 = airportTypes.GetValue(i); if (AIAirport.IsValidAirportType(a1)) { /* When looking for a location for smaller airports, ensure we're not using big planes */ if (a1 == AIAirport.AT_SMALL || a1 == AIAirport.AT_COMMUTER) { engine_list.Valuate(AIEngine.GetPlaneType); engine_list.RemoveValue(AIAirport.PT_BIG_PLANE); /* When we're left with no engines available, abort construction. */ if (engine_list.Count() == 0) { return 0; } small_aircraft = true; } /* When looking for a location for heliports, ensure there are helicopters */ if (a1 == AIAirport.AT_HELISTATION || a1 == AIAirport.AT_HELIDEPOT || a1 == AIAirport.AT_HELIPORT) { engine_list.Valuate(AIEngine.GetPlaneType); engine_list.KeepValue(AIAirport.PT_HELICOPTER); /* No helicopters available */ if (engine_list.Count() == 0) { return 0; } // helicopter = true; } tile_1 = this.FindSuitableAirportSpot(a1, 0); airport1_type = a1; if (tile_1 != -1) { break; } } } if (tile_1 < 0) { AILog.Info("Couldn't find a suitable town to build the first airport in"); return -1; } if (airport1_type == AIAirport.AT_HELIPORT) { airportTypes.RemoveValue(AIAirport.AT_HELIPORT); } local airport2_type; local tile_2; for (local i = 0; i < airportTypes.Count() ; i++) { local a2 = airportTypes.GetValue(i); if (AIAirport.IsValidAirportType(a2) ) { if (small_aircraft && (a2 == AIAirport.AT_INTERCON || a2 == AIAirport.AT_INTERNATIONAL || a2 == AIAirport.AT_METROPOLITAN || a2 == AIAirport.AT_LARGE)) { continue; } tile_2 = this.FindSuitableAirportSpot(a2, tile_1); airport2_type = a2; if (tile_2 != -1) { break; } } } if (tile_2 < 0) { AILog.Info("Couldn't find a suitable town to build the second airport in"); this.towns_used.RemoveValue(tile_1); return -2; } local adjacentStationId = checkAdjacentStation(tile_1); /* Build the airports for real */ if (!AIAirport.BuildAirport(tile_1, airport1_type, adjacentStationId)) { if (!AIAirport.BuildAirport(tile_1, airport1_type, AIStation.STATION_NEW)) { AILog.Warning("Although the testing told us we could build 2 airports, it still failed on the first airport at tile " + tile_1 + "."); this.towns_used.RemoveValue(tile_1); this.towns_used.RemoveValue(tile_2); return -3; } } adjacentStationId = checkAdjacentStation(tile_2); if (!AIAirport.BuildAirport(tile_2, airport2_type, adjacentStationId)) { if (!AIAirport.BuildAirport(tile_2, airport2_type, AIStation.STATION_NEW)) { AILog.Warning("Although the testing told us we could build 2 airports, it still failed on the second airport at tile " + tile_2 + "."); AIAirport.RemoveAirport(tile_1); this.towns_used.RemoveValue(tile_1); this.towns_used.RemoveValue(tile_2); return -4; } } local ret = this.BuildAircraft(tile_1, tile_2); if (ret < 0) { AIAirport.RemoveAirport(tile_1); AIAirport.RemoveAirport(tile_2); this.towns_used.RemoveValue(tile_1); this.towns_used.RemoveValue(tile_2); return ret; } AILog.Info("Done building a route"); return ret; } /** * Build an aircraft with orders from tile_1 to tile_2. * The best available aircraft of that time will be bought. */ function WrightAI::BuildAircraft(tile_1, tile_2) { /* Check if we can build more aircraft. */ if (GetAircraftCount() >= AIGameSettings.GetValue("max_aircraft")) return 0; /* Build an aircraft */ local hangar = AIAirport.GetAirportType(tile_1) == AIAirport.AT_HELIPORT ? AIAirport.GetHangarOfAirport(tile_2) : AIAirport.GetHangarOfAirport(tile_1); local engine = null; local engine_list = AIEngineList(AIVehicle.VT_AIR); // /* When bank balance < 300000, buy cheaper planes */ // local balance = AICompany.GetBankBalance(AICompany.COMPANY_SELF); // engine_list.Valuate(AIEngine.GetPrice); // engine_list.KeepBelowValue(balance < 300000 ? 50000 : (balance < 1000000 ? 300000 : 1000000)); engine_list.Valuate(AIEngine.CanRefitCargo, this.cargoId); engine_list.KeepValue(1); local small_aircraft = AIAirport.GetAirportType(tile_1) == AIAirport.AT_SMALL || AIAirport.GetAirportType(tile_2) == AIAirport.AT_SMALL || AIAirport.GetAirportType(tile_1) == AIAirport.AT_COMMUTER ||AIAirport.GetAirportType(tile_2) == AIAirport.AT_COMMUTER; if (small_aircraft) { engine_list.Valuate(AIEngine.GetPlaneType); engine_list.RemoveValue(AIAirport.PT_BIG_PLANE); } local helicopter = AIAirport.GetAirportType(tile_1) == AIAirport.AT_HELIPORT || AIAirport.GetAirportType(tile_2) == AIAirport.AT_HELIPORT || AIAirport.GetAirportType(tile_1) == AIAirport.AT_HELIDEPOT || AIAirport.GetAirportType(tile_2) == AIAirport.AT_HELIDEPOT || AIAirport.GetAirportType(tile_1) == AIAirport.AT_HELISTATION || AIAirport.GetAirportType(tile_2) == AIAirport.AT_HELISTATION; if (helicopter) { engine_list.Valuate(AIEngine.GetPlaneType); engine_list.KeepValue(AIAirport.PT_HELICOPTER); } engine_list.Valuate(AIEngine.GetMaxSpeed); engine_list.KeepTop(1); engine = engine_list.Begin(); if (!AIEngine.IsValidEngine(engine)) { AILog.Error("Couldn't find a suitable engine"); return -5; } local vehicle = AIVehicle.BuildVehicle(hangar, engine); if (!AIVehicle.IsValidVehicle(vehicle)) { AILog.Error("Couldn't build the aircraft"); return -6; } if (!AIVehicle.RefitVehicle(vehicle, this.cargoId)) { AILog.Error("Couldn't refit the aircraft"); AIVehicle.SellVehicle(vehicle); return -7; } /* Send him on his way */ local order_1 = AIAirport.IsHangarTile(tile_1) ? AIMap.GetTileIndex(AIMap.GetTileX(tile_1), AIMap.GetTileY(tile_1) + 1) : tile_1; local order_2 = AIAirport.IsHangarTile(tile_2) ? AIMap.GetTileIndex(AIMap.GetTileX(tile_2), AIMap.GetTileY(tile_2) + 1) : tile_2; AIOrder.AppendOrder(vehicle, order_1, AIOrder.AIOF_NONE); AIOrder.AppendOrder(vehicle, order_2, AIOrder.AIOF_NONE); AIVehicle.StartStopVehicle(vehicle); this.distance_of_route.rawset(vehicle, AIMap.DistanceManhattan(tile_1, tile_2)); local dist = this.distance_of_route.rawget(vehicle); local route_list = AIVehicleList_Station(AIStation.GetStationID(tile_1)); route_list.Valuate(AIVehicle.GetVehicleType); route_list.KeepValue(AIVehicle.VT_AIR); route_list.Valuate(AIVehicle.GetState); route_list.RemoveValue(AIVehicle.VS_CRASHED); local count = route_list.Count(); local max_count = (dist / 35) + 1; AILog.Info("Built " + AIVehicle.GetName(vehicle) + " from " + AIStation.GetName(AIStation.GetStationID(tile_1)) + " to " + AIStation.GetName(AIStation.GetStationID(tile_2)) + " (" + this.distance_of_route.rawget(vehicle) + " tiles apart, " + count + "/" + max_count + " aircraft)"); return 0; } /** * 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(airport_type, center_tile) { local airport_x = AIAirport.GetAirportWidth(airport_type); local airport_y = AIAirport.GetAirportHeight(airport_type); local allow_station = airport_x <= AIGameSettings.GetValue("station_spread") && airport_y <= AIGameSettings.GetValue("station_spread"); if (!allow_station) return -1; local airport_rad = AIAirport.GetAirportCoverageRadius(airport_type); local town_list = AITownList(); /* Remove all the towns we already used */ town_list.RemoveList(this.towns_used); town_list.Valuate(AITown.GetLastMonthProduction, this.cargoId); town_list.KeepAboveValue(LuDiAIAfterFix.cargoClass == AICargo.CC_PASSENGERS ? 70 : 18); // /* Keep the best 10, if we can't find a station in there, just leave it anyway */ // town_list.KeepTop(10); town_list.Sort(AIList.SORT_BY_VALUE, false); /* 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 */ Sleep(1); local tile = AITown.GetLocation(town); local tileList = AITileList(); local rectangleCoordinates = this.TownAirportRadRect(airport_type, town); tileList.AddRectangle(rectangleCoordinates[0], rectangleCoordinates[1]); tileList.Valuate(AITile.IsBuildableRectangle, airport_x, airport_y); tileList.KeepValue(1) if (center_tile != 0) { /* If we have a tile defined, we don't want to be within 35 tiles of this tile */ tileList.Valuate(AITile.GetDistanceManhattanToTile, center_tile); tileList.KeepAboveValue(35); } /* 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); tileList.Valuate(AITile.GetCargoProduction, this.cargoId, airport_x, airport_y, airport_rad); tileList.RemoveBelowValue(10); tileList.Sort(AIList.SORT_BY_VALUE, false); /* Couldn't find a suitable place for this town, skip to the next */ if (tileList.Count() == 0) continue; /* Walk all the tiles and see if we can build the airport at all */ { local test = AITestMode(); local good_tile = 0; for (tile = tileList.Begin(); tileList.HasNext(); tile = tileList.Next()) { Sleep(1); if (!AIAirport.BuildAirport(tile, airport_type, AIStation.STATION_NEW)) continue; good_tile = tile; break; } /* Did we find a place to build the airport on? */ if (good_tile == 0) continue; } local adjacentStationId = checkAdjacentStation(tile); local nearest_town; if (adjacentStationId == AIStation.STATION_NEW) { nearest_town = AITile.GetClosestTown(tile); } else { nearest_town = AIStation.GetNearestTown(adjacentStationId); } AILog.Info("Found a good spot for an airport near " + AITown.GetName(nearest_town) + " at tile " + tile); /* Make the town as used, so we don't use it again */ this.towns_used.AddItem(nearest_town, tile); return tile; } return -1; }