/**
* 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;
}