SynTrans-2/ 40777 0 0 0 11651637156 6030 5 SynTrans-2/info.nut 100777 0 0 4040 11651631222 7575 0 /*
* This file is part of SynTrans, which is an AI for OpenTTD
*
* SynTrans is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* SynTrans is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SynTrans; If not, see or
* write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
class SynTrans extends AIInfo {
function GetAuthor() { return "11Runner"; }
function GetName() { return "SynTrans"; }
function GetShortName() { return "SNTS"; }
function GetDescription() { return "SynTrans is an AI which its name stands for 'Synaptic Transportation'. It builds a massive, rapidly expanding road, air, and hopefully soon train network!"; }
function GetAPIVersion() { return "1.0"; }
function GetVersion() { return 2; }
function GetDate() { return "2011-10-14"; }
function GetUrl() { return "http://www.tt-forums.net/viewtopic.php?f=65&t=57136"; }
function CreateInstance() { return "SynTrans"; }
function MinVersionToLoad() { return 1; }
function GetSettings() {
AddSetting({name = "log_level", description = "The amount of AI messages to display in the AI log. Higher=More messages", easy_value = 1, medium_value = 1, hard_value = 1, custom_value = 1, min_value = 1, max_value = 3, flags = AICONFIG_INGAME});
AddSetting({name = "max_networks", description = "The maximum number of separate transport networks for the roads SynTrans may build", easy_value = 1, medium_value = 3, hard_value = 5, custom_value = 3, min_value = 1, max_value = 10, flags = AICONFIG_INGAME});
}
}
/* Tell the core we are an AI */
RegisterAI(SynTrans());
SynTrans-2/main.nut 100777 0 0 15445 11650727270 7631 0 /*
* This file is part of SynTrans, which is an AI for OpenTTD
*
* SynTrans is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* SynTrans is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SynTrans; If not, see or
* write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
// Add all the files for libraries here
import("util.superlib","SuperLib",13);
import("pathfinder.road", "RoadPathFinder", 3);
// Add all your files here
require("network.nut");
require("town.nut");
//require("util.nut");
Result <- SuperLib.Result;
Log <- SuperLib.Log;
Helper <- SuperLib.Helper;
ScoreList <- SuperLib.ScoreList;
Money <- SuperLib.Money;
Tile <- SuperLib.Tile;
Direction <- SuperLib.Direction;
Engine <- SuperLib.Engine;
Vehicle <- SuperLib.Vehicle;
Station <- SuperLib.Station;
Airport <- SuperLib.Airport;
Industry <- SuperLib.Industry;
//Town <- SuperLib.Town;
Order <- SuperLib.Order;
OrderList <- SuperLib.OrderList;
Road <- SuperLib.Road;
RoadBuilder <- SuperLib.RoadBuilder;
aiInstance <- null;
// Add all the files for the entire project here
// ex. require("globals.nut");
class SynTrans extends AIController {
networks = null;
airnet = null;
enableAir = null;
saved = null;
constructor() {
networks = [];
enableAir = true;
saved = false;
//airnet = AirNet();
}
function Start();
function Save();
function Load(version,data);
}
function SynTrans::Start()
{
this.Sleep(5);
aiInstance = this;
AIRoad.SetCurrentRoadType(AIRoad.ROADTYPE_ROAD);
Log.Info("SynTrans Started");
if(this.saved == true) {
Log.Info("Loading networks...");
local stationlist = null;
// Load RoadNetwork
if(!Vehicle.IsVehicleTypeDisabledByAISettings(AIVehicle.VT_ROAD)) {
local depots = AIDepotList(AITile.TRANSPORT_ROAD);
local newNet=Network(AIVehicle.VT_ROAD);
stationlist = AIStationList(AIStation.STATION_BUS_STOP);
foreach(station, _ in stationlist)
{
local town = AIStation.GetNearestTown(station);
Log.Info("Processing town " + AITown.GetName(town));
//newNet.AddTown(town);
local theTown = Town(town,AIStation.STATION_BUS_STOP);
theTown.stations.append(station);
// Find the depot for the station... it should not be that far away
//local tiles = Tile.MakeTileRectAroundTile(AIStation.GetLocation(station),20);
foreach(depot, _ in depots) {
local dtilex = AIMap.GetTileX(depot);
Log.Info("Depot Tile X: " + dtilex);
local dtiley = AIMap.GetTileY(depot);
Log.Info("Depot Tile Y: " + dtiley);
local stilex = AIMap.GetTileX(AIStation.GetLocation(station));
Log.Info("Station Tile X: " + stilex);
local stiley = AIMap.GetTileY(AIStation.GetLocation(station));
Log.Info("Station Tile Y: " + stiley);
for(local i = 10;i < 100;i+=5) {
if(stilex - i < dtilex && stilex + i > dtilex && stiley - i < dtilex && stiley + i > dtiley) {
theTown.depot = depot;
continue;
}
}
if(!theTown.depot) Log.Error("Could not find a depot for this city. I wonder why...");
}
newNet.towns.append(theTown);
}
newNet.defaultEngine=Engine.GetEngine_PAXLink(0,AIVehicle.VT_ROAD);
networks.append(newNet);
}
// Load AirNetwork
if(!Vehicle.IsVehicleTypeDisabledByAISettings(AIVehicle.VT_AIR)) {
airnet=Network(AIVehicle.VT_AIR);
stationlist = AIStationList(AIStation.STATION_AIRPORT);
foreach(station, _ in stationlist)
{
local town = AIStation.GetNearestTown(station);
Log.Info("Processing town " + AITown.GetName(town));
//airnet.AddTown(town);
local theTown = Town(town,AIStation.STATION_AIRPORT);
theTown.stations.append(station);
theTown.depot = Airport.GetHangarTile(station);
airnet.towns.append(theTown);
}
airnet.defaultEngine=Engine.GetEngine_PAXLink(0,AIVehicle.VT_AIR);
}
} else {
if(Vehicle.IsVehicleTypeDisabledByAISettings(AIVehicle.VT_ROAD) && Vehicle.IsVehicleTypeDisabledByAISettings(AIVehicle.VT_AIR)) {
Log.Error("This is a road and air only AI. Please enable AI these building in Advanced settings!");
}
// Name the company
if(!AICompany.SetName("Synchronized Transport Inc.")) {
if(!AICompany.SetName("Another Synchronized Transport Inc.")) {
if(!AICompany.SetName("Yet Another Synchronized Transport Inc.")) {
local i=2;
while(!AICompany.SetName("Synchronized Transport Copier #" + i)) i++;
}
}
}
// Make initial network
if(!Vehicle.IsVehicleTypeDisabledByAISettings(AIVehicle.VT_ROAD)) {
local newNet=Network(AIVehicle.VT_ROAD);
networks.append(newNet);
this.enableAir = true;
}
// Make (but dont start) Airnet
if(!Vehicle.IsVehicleTypeDisabledByAISettings(AIVehicle.VT_AIR)) airnet=Network(AIVehicle.VT_AIR);
}
local townlist;
local networkStart;
local event;
while(true)
{
// Manage events...
while(AIEventController.IsEventWaiting()) {
event=AIEventController.GetNextEvent();
switch(event.GetEventType()) {
case AIEvent.AI_ET_ENGINE_PREVIEW:
local preview=AIEventEnginePreview.Convert(event);
preview.AcceptPreview();
Log.Info("Accepted preview for vehicle " + preview.GetName());
break;
}
}
if(!Vehicle.IsVehicleTypeDisabledByAISettings(AIVehicle.VT_ROAD)) foreach(network in networks) network.ManageNetwork();
if(!Vehicle.IsVehicleTypeDisabledByAISettings(AIVehicle.VT_AIR)) if(enableAir) airnet.ManageNetwork();
// Should we build a new network?
if(!Vehicle.IsVehicleTypeDisabledByAISettings(AIVehicle.VT_ROAD)) {
if(AIController.GetSetting("max_networks") > networks.len()) {
if(AICompany.GetBankBalance(AICompany.COMPANY_SELF) > 250000) {
Log.Info("==========BUILDING NEW NETWORK!==========");
townlist = AITownList();
// take out the cities we already own
foreach(network in networks) {
foreach(town in network.towns) {
townlist.RemoveItem(town.id);
}
}
// now find the biggest city
townlist.Valuate(AITown.GetPopulation)
townlist.Sort(AIList.SORT_BY_VALUE, false);
networkStart=townlist.Begin();
local newNet=Network(AIVehicle.VT_ROAD,networkStart);
networks.append(newNet);
}
}
}
/*if(AICompany.GetBankBalance(AICompany.COMPANY_SELF)>500000 && !enableAir) {
Log.Info("==========STARTING AIRCRAFT SYSTEM==========");
enableAir=true;
}*/
Log.Info("Waiting...");
this.Sleep(500);
}
}
function SynTrans::Save()
{
local thetable = {};
return thetable;
}
function SynTrans::Load(version,data)
{
this.saved = true;
}
SynTrans-2/network.nut 100777 0 0 61767 11651637156 10412 0 /*
* This file is part of SynTrans, which is an AI for OpenTTD
*
* SynTrans is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* SynTrans is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SynTrans; If not, see or
* write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
class Network
{
lastVehicleManage = null;
lastVehicleBuild = null;
lastNewTown = null;
lastUpdateEngine = null;
lastStartUpgrade = null;
towns = null;
blacklist = null;
vehicles = null;
defaultEngine = null;
center = null;
size = null;
type = null;
replace = null;
noReplace = null;
constructor(vtype,epicenter = null) {
this.towns = [];
this.vehicles = [];
this.blacklist = AIList();
this.defaultEngine = null;
this.center = epicenter;
this.size = 1;
this.type = vtype;
}
function ManageNetwork();
function ManageVehicles();
function CreateLink();
function BuyVehicles(depot,engine,number,order1,order2);
function SellVehicle(vehicle);
function FindTown(chosenCity = null, desprate = false);
function FindCloseConnection(town);
function AddTown(theTown);
function LeaveTown(index);
function Connect(point1,point2);
function PerformFullUpgrade();
function ExpandStation(station = null);
}
// Function from TutorialAI's Road Tutorial
function TownDistValuator(town1,town2,targetDistance)
{
local myval=Helper.Abs(AIMap.DistanceManhattan(AITown.GetLocation(town1), AITown.GetLocation(town2))-targetDistance);
return myval;
}
function Network::ManageNetwork()
{
Log.Info("=========================================");
Log.Info("==========MANAGING NEXT NETWORK==========");
Log.Info("=========================================");
if(type==AIVehicle.VT_AIR) Log.Warning("This is AIRNET!!!");
// Verify there is no shortage on the vehicle limit
if(Vehicle.GetVehiclesLeft(AIVehicle.VT_ROAD)<5 && this.type == AIVehicle.VT_ROAD) {
AILog.Warning("Road vehicle Limit Reached! Please increase the vehicle limit in the advanced settings. Until then, this AI will do nothing regarding road vehicles.");
//AIController.Sleep(1000);
return;
}
if(Vehicle.GetVehiclesLeft(AIVehicle.VT_AIR)<2 && this.type == AIVehicle.VT_AIR) {
AILog.Warning("Aircraft vehicle Limit Reached! Please increase the vehicle limit in the advanced settings. Until then, this AI will do nothing regarding aircraft.");
//AIController.Sleep(1000);
return;
}
if(this.towns.len()==0) {
Log.Info("======================Building First City====");
this.defaultEngine=Engine.GetEngine_PAXLink(0,type);
this.lastUpdateEngine=AIController.GetTick();
Log.Info("Default engine is " + this.defaultEngine);
local town1;
local townlist=AITownList();
townlist.Valuate(AITown.GetPopulation);
if(type == AIVehicle.VT_AIR) townlist.RemoveAboveValue(10000);
townlist.Sort(AIList.SORT_BY_VALUE,false);
townlist.RemoveList(this.blacklist);
if(center==null) {
Log.Info("No city specified, finding instead");
town1=townlist.Begin();
}
else {
town1=this.center;
townlist.Begin();
}
if(town1==null) Log.Error("Cannot create initial city");
this.center=AITown.GetLocation(town1);
local result=this.AddTown(town1);
if(!result) {
Log.Warning("Failed to build the inital city. Leaving and finding a new one next time we have the chance on this network.");
this.blacklist.AddItem(town1,0);
this.center=null;
return;
}
if(type != AIVehicle.VT_AIR) this.ExpandStation(towns[0].stations[0]);
Log.Info("First City built");
local town2=this.FindTown(towns[0],true);
if(!town2) {
Log.Info("Failed to build airport in second town. Will retry next time");
this.LeaveTown(0);
this.blacklist.AddItem(town1,0);
this.center = null;
return;
}
//AddTown(town2);
//Connect(town1,town2);
}
if(AICompany.GetBankBalance(AICompany.COMPANY_SELF)>20000+(AIEngine.GetPrice(defaultEngine)*2) && this.lastNewTown (AIEngine.GetPrice(defaultEngine) * this.vehicles.len()) - (AIEngine.GetPrice(oldEngine) * this.vehicles.len())) this.PerformFullUpgrade();
else upgrade = false;
// If this is the aircraft network, might as well upgrade stations as well if possible
if(upgrade && type == AIVehicle.VT_AIR && AICompany.GetBankBalance(AICompany.COMPANY_SELF) > 2000 * this.towns.len()) this.ExpandStation();
}
this.lastUpdateEngine = AIController.GetTick();
}
local frontTiles;
local i=0;
for(local i = 0;i < this.vehicles.len();i++) {
// Get rid of the sold vehicles in the depot
if(AIVehicle.IsStoppedInDepot(vehicles[i])) {
AIVehicle.SellVehicle(vehicles[i]);
this.vehicles.remove(i);
continue;
}
// Sell non-profitable vehicles
if(AIVehicle.GetProfitLastYear(vehicles[i])<0 && AIVehicle.GetAge(vehicles[i])>365) {
Log.Info("Sending " + AIVehicle.GetName(vehicles[i]) + " due to lack of income from vehicle");
AIVehicle.SendVehicleToDepot(vehicles[i]);
}
}
local usedTowns = AIList();
foreach(town in this.towns) {
// check, if more than 30 people are waiting at this station, and suspended is on, turn it off
if(town.suspended && AIStation.GetCargoWaiting(town.stations[0],Helper.GetPAXCargo())>30) {
Log.Info("Town is no longer overloaded, un suspendeding");
town.suspended = false;
}
// if town is already suspended, than why bother spending the time to figure out if it needs more vehicles?
if(town.suspended) continue;
local skip = false;
// check to see if the town has already been added vehicles to
foreach(used, _ in usedTowns) {
if(town.id == used) {
Log.Warning("Skipping used town " + AITown.GetName());
skip = true;
}
}
if(skip) continue;
Log.Info("Checking to improve town " + AITown.GetName(town.id));
// Grow the station
local numTiles;
local numVehicleTiles = 0;
// check the front tile of every singe station peice.
if(type == AIVehicle.VT_ROAD) {
foreach(stationpiece, _ in Station.GetRoadFrontTiles(town.stations[0])) {
local stationtiles=Tile.MakeTileRectAroundTile(AIStation.GetLocation(town.stations[0]),4);
stationtiles.Valuate(AIRoad.IsRoadTile);
stationtiles.KeepValue(1);
numTiles=stationtiles.Count();
// Loop to see if vehicles are on each tile, if numVehicleTiles>0.5*numTiles->grow station
local vehiclelist;
foreach(tile, _ in stationtiles) {
vehiclelist=Vehicle.GetVehiclesAtTile(tile);
if(!vehiclelist.IsEmpty()) numVehicleTiles++;
}
}
Log.Info("Number of road tiles around station: " + numTiles);
Log.Info("Number of vehicles on those road tiles: " + numVehicleTiles);
local stationPlace=AITileList_StationType(town.stations[0],AIStation.STATION_BUS_STOP);
local good=true;
foreach(stationPeice, item in stationPlace) {
if(Vehicle.GetVehiclesAtTile(stationPeice).Count()<2) good=false;
}
if(numVehicleTiles>numTiles*0.15 && AITileList_StationType(town.stations[0],AIStation.STATION_BUS_STOP).Count()<5 && good) this.ExpandStation(town.stations[0]);
// Control suspended attribute, to ensure not to many vehicles get sent to this station. like blacklist
if(Station.GetRoadFrontTiles(town.stations[0]).Count()==5 && AIStation.GetCargoWaiting(town.stations[0],Helper.GetPAXCargo())<5) {
Log.Info("Station is suspended. Suspending the sending of vehicles to it");
town.suspended=true;
}
}
//frontTiles=Station.GetRoadFrontTiles(town.stations[0]);
// Add more vehicles to the station
if(AIStation.GetCargoWaiting(town.stations[0],Helper.GetPAXCargo())>AIEngine.GetCapacity(defaultEngine) || AIStation.GetCargoRating(town.stations[0],Helper.GetPAXCargo())<40) {
// First off, always ensure to have a reasonable amount of cash :)
if(!Money.MakeSureToHaveAmount(AIEngine.GetPrice(defaultEngine)*(AIStation.GetCargoWaiting(town.stations[0],Helper.GetPAXCargo())/AIEngine.GetCapacity(defaultEngine)))) {
Log.Info("Not enough cash to create needed vehicles for now");
continue;
}
// On the other hand, for aircraft, the AI should only build a maximum of 1 extra each month
Log.Info("Buying more vehicles for " + AITown.GetName(town.id));
// Variables to help us
local destinations=[];
local list;
// Get each town that goes to this station
local same=false;
/*foreach(vehicle in this.vehicles) {
if(Order.HasStationInOrders(vehicle,town.stations[0])) {
list=Order.GetStationListFromOrders(vehicle);
list.RemoveItem(town.stations[0]);
// Ensure this station does not already exist
foreach(destiny in destinations) {
if(destiny==list.Begin()) same=true;
}
if(!same) destinations.append(list.Begin());
same=false;
}
}*/ // This may help speed up the process of finding destinations considerably!
Log.Info("LENGTH OF DEST: " + destinations.len());
// OR find stations that are nearby this station
local townprep=[];
// Add items from our network (while we are at it scan previous destinations for suspended stations)
foreach(otherTown in towns) {
for(local i=0;ibestWait) {
bestStation=station;
bestWait=AIStation.GetCargoWaiting(station,Helper.GetPAXCargo());
}
}
AIController.Sleep(1);
Log.Info("BestStation: " + AIStation.GetName(bestStation));
// If the best station does not have many passengers, make a new city connection
if(!bestStation) continue;
if(AIStation.GetCargoWaiting(bestStation,Helper.GetPAXCargo())<10/* && AICompany.GetBankBalance(AICompany.COMPANY_SELF)>20000+(AIEngine.GetPrice(defaultEngine)*2)*/) {
local myResult;
if(town.newStationTries>3) myResult=FindTown(town,true);
else myResult=FindTown(town);
//if(!myResult) town.newStationTries++; // test feature, needs work
continue;
}
// Ensure there is a road between the two stations (if road network)
if(type != AIVehicle.VT_AIR) {
Log.Info("Checking roads...");
local result = false;
foreach(connection, _ in town.connections) {
Log.Warning("I see station " + AIStation.GetName(connection));
if(connection == bestStation) result = true;
}
//Log.Warning("After foreach loop...");
if(!result) {
Log.Info("Town is not connected to the other city. Connecting it now...");
if(!this.Connect(AIStation.GetLocation(town.stations[0]),AIStation.GetLocation(bestStation))) {
Log.Warning("Could not connect roads. Cancelling...");
continue;
}
// Add town to the list of both towns
town.connections.AddItem(bestStation,0);
foreach(townp in townprep) {
if(townp.stations[0] == bestStation) {
Log.Warning("Adding to list of connected stations");
townp.connections.AddItem(town.stations[0],0);
}
}
}
else Log.Info("Stations " + AIStation.GetName(town.stations[0]) + " and " + AIStation.GetName(bestStation) + " are already connected.");
}
Log.Info("Building the vehicles to " + AIStation.GetName(bestStation));
// We now (finally) build the vehicles
local number = AIStation.GetCargoWaiting(town.stations[0],Helper.GetPAXCargo())/AIEngine.GetCapacity(defaultEngine);
if(number > 3 && type == AIVehicle.VT_AIR) number = 3;
else if(number > 5) number = 5;
if(AIStation.GetCargoRating(town.stations[0],Helper.GetPAXCargo())<40 && type==AIVehicle.VT_ROAD) this.BuyVehicles(town.depot,defaultEngine,2,town.stations[0],bestStation);
else if(type == AIVehicle.VT_AIR) this.BuyVehicles(town.depot,defaultEngine,number,town.stations[0],bestStation);
else this.BuyVehicles(town.depot,defaultEngine,number,town.stations[0],bestStation);
// Add the other city to used towns
// usedTowns.AddItem(bestStation,0);
// Wait a little
AIController.Sleep(5);
}
}
this.lastVehicleManage=AIController.GetTick();
}
function Network::CreateLink() {
local newTown=FindTown();
this.AddTown(newTown);
local index=this.FindCloseConnection(town);
this.Connect(AIStation.GetLocation(newTown.stations[0]),AIStation.GetLocation(towns[index].stations[0]));
}
function Network::BuyVehicles(depot,engine,number,order1,order2) {
if(!depot || !engine) {
Log.Warning("Cannot build vehicles because depot or engine is not valid");
}
Log.Info("Building " + number + " vehicles of " + AIEngine.GetName(engine));
local newVehicle=AIVehicle.BuildVehicle(depot,engine);
if(!AIVehicle.IsValidVehicle(newVehicle)) {
Log.Warning("Could not build a vehicle: " + AIError.GetLastErrorString());
return false;
}
this.vehicles.append(newVehicle);
local orders=OrderList();
orders.AddStop(order1,AIOrder.AIOF_FULL_LOAD);
orders.AddStop(order2,AIOrder.AIOF_FULL_LOAD);
orders.ApplyToVehicle(newVehicle);
AIVehicle.StartStopVehicle(newVehicle);
local nextVehicle;
for(local i=1;ichosenWait) {
chosenCity=town;
chosenWait=AIStation.GetCargoWaiting(town.stations[0],Helper.GetPAXCargo());
}
}
}
Log.Info("Adding a new town for " + AITown.GetName(chosenCity.id));
local townlist=AITownList();
townlist.RemoveList(blacklist);
foreach(town in this.towns) {
townlist.RemoveItem(town.id);
}
// Remove towns from other networks if not aircraft network
if(type != AIVehicle.VT_AIR) {
foreach(network in aiInstance.networks) {
foreach (town in network.towns) {
townlist.RemoveItem(town.id);
}
}
}
townlist.Valuate(AITown.GetPopulation);
townlist.RemoveBelowValue(500); //cities must be at least 500 in population in order to be considered for use!
//Log.Warning("townlist.Begin(): " + AITown.GetLocation(townlist.Begin()));
//Log.Warning("chosenCity.id: " + AITown.GetLocation(chosenCity.id));
//Log.Warning("Return of the locations: " + Helper.Abs(AIMap.DistanceSquare(AITown.GetLocation(townlist.Begin()),AITown.GetLocation(chosenCity.id))));
local value=TownDistValuator(townlist.Begin(),chosenCity.id,50);
//Log.Warning("Return of TownDistValuator: " + value);
if(type == AIVehicle.VT_ROAD) townlist.Valuate(TownDistValuator, chosenCity.id, 50);
else townlist.Valuate(TownDistValuator, chosenCity.id, 300);
townlist.Sort(AIList.SORT_BY_VALUE, true);
Log.Info("DUMP: ");
Log.Info(AITown.GetName(townlist.Begin()) + " : " + townlist.GetValue(townlist.Begin()));
Log.Info(AITown.GetName(townlist.Next()) + " : " + townlist.GetValue(townlist.Next()));
if(!desprate && type == AIVehicle.VT_AIR) townlist.RemoveAboveValue(100);
else if(!desprate && type == AIVehicle.VT_ROAD) townlist.RemoveAboveValue(80);
if(townlist.IsEmpty()) {
AILog.Info("Could not find a good enough town to connect to this city.");
return false;
}
local newTown=townlist.Begin();
if(newTown==null) {
Log.Warning("Could not connect to a new city in the network");
return false;
}
// Now set up the city
local builtTown=AddTown(newTown);
if(!builtTown) {
Log.Info("Because we could not build the town connecting the town is cancelled.");
return false;
}
// expand the station
if(type == AIVehicle.VT_ROAD) this.ExpandStation(builtTown.stations[0]);
// If air then build a road between them
if(type == AIVehicle.VT_ROAD) {
local result=Connect(AIStation.GetLocation(chosenCity.stations[0]),AIStation.GetLocation(builtTown.stations[0]));
if(!result) {
Log.Info("Pathfinding failed. Leaving Town...");
this.blacklist.AddItem(this.towns[towns.len()-1].id,0);
this.LeaveTown(towns.len()-1);
return false;
}
}
// Add the chosen town to the connected towns list
builtTown.connections.AddItem(chosenCity.stations[0],0);
chosenCity.connections.AddItem(builtTown.stations[0],0);
// And now some vehicles
BuyVehicles(builtTown.depot,defaultEngine,2,builtTown.stations[0],chosenCity.stations[0]);
chosenCity.outerLayer=false;
Log.Info("Finished building new link :D");
this.lastNewTown=AIController.GetTick();
return true;
}
function Network::FindCloseConnection(town) {
}
function Network::AddTown(theTown) {
Log.Info("==========Adding town " + AITown.GetName(theTown) + "==========");
local newTown;
if(this.type == AIVehicle.VT_AIR) newTown = Town(theTown,AIStation.STATION_AIRPORT);
else newTown = Town(theTown,AIStation.STATION_BUS_STOP);
local result
if(this.type == AIVehicle.VT_AIR) result=newTown.Begin(AIStation.STATION_AIRPORT);
else result=newTown.Begin(AIStation.STATION_BUS_STOP);
if(result) this.towns.append(newTown);
else {
Log.Info("Could not build the town...");
return null;
}
return newTown;
}
function Network::LeaveTown(index) {
this.towns[index].End();
this.towns.remove(index);
}
function Network::Connect(point1,point2) {
Log.Info("Connecting the points...");
/*local pathfinder=RoadBuilder();
pathfinder.Init(point1,point2,false,500);
local result=pathfinder.ConnectTiles();
if(result!=RoadBuilder.CONNECT_SUCCEEDED) return false;*/
local convoy = ConvoyFunc();
local result = convoy.BuildRoad(point1,point2);
Log.Warning("Result: " + result);
if(!result) return false;
if(result < 1) return false;
return true;
}
function Network::PerformFullUpgrade() {
Log.Info("----------PERFORMING FULL UPGRADE----------");
//Log.Warning("Full upgrade not yet implemented");
// First look through all the vehicles, and find the ones not upgraded. from there, upgrade them
if(!replace) {
Log.Info("Beginning to upgrade vehicles...");
foreach(vehicle in vehicles) {
if(AIVehicle.GetEngineType(vehicle) != defaultEngine) AIVehicle.SendVehicleToDepot(vehicle);
}
replace = true;
}
// When this function is recalled, upgrade any vehicles that have entered the depot.
else {
Log.Info("Continuing to upgrade vehicles...");
local done = true;
local replaced = false;
foreach(vehicle in vehicles) {
if(AIVehicle.GetEngineType(vehicle) == defaultEngine) continue;
else {
done = false;
if(AIVehicle.IsStoppedInDepot(vehicle)) {
if(!Money.MakeSureToHaveAmount((AIEngine.GetPrice(defaultEngine)))) return;
// Copy orders and depot
local stationlist = Order.GetStationListFromOrders(vehicle);
local origdepot = AIVehicle.GetLocation(vehicle);
// Sell Vehicle
AIVehicle.SellVehicle(vehicle);
// Rebuild vehicle and send out
this.BuyVehicles(origdepot,defaultEngine,1,stationlist.Begin(),stationlist.Next());
//AIVehicle.StartStopVehicle(vehicle);
replaced = true;
//noReplace = 0;
}
}
}
if(!replaced) this.noReplace++;
Log.Warning("NOREPLACE: " + this.noReplace);
if(done || this.noReplace > 10 || this.lastStartUpgrade < AIController.GetTick()-10000) {
this.replace = false;
// make sure that vehicles are moving even if not upgraded
foreach(vehicle in vehicles) {
Log.Info("----------Finishing Upgrade Process----------");
if(AIVehicle.IsStoppedInDepot(vehicle)) AIVehicle.StartStopVehicle(vehicle);
}
}
}
}
function Network::ExpandStation(station = null) {
// This function is equivalent to updating the station in airport mode
if(type == AIVehicle.VT_ROAD) {
Log.Info("Trying to expand station " + AIStation.GetName(station));
local theResult=Road.GrowStationParallel(station,AIStation.STATION_BUS_STOP);
if(Result.IsFail(theResult)) {
Log.Info("Failed to grow station parallel, trying not paralell...");
theResult=Road.GrowStation(station,AIStation.STATION_BUS_STOP);
if(Result.IsFail(theResult)) Log.Warning("Failed to grow station :(");
}
}
else {
// if station is null, upgrade everything
if(!station) {
Log.Info("Expanding aircraft stations...");
// Get perferred station
local stype = Airport.GetLastAvailableAirportType(Engine.GetEngine_PAXLink(0,AIVehicle.VT_AIR));
if(!stype) return;
local airlist = [];
airlist.append(stype);
for(local i = 0;i < towns.len();i++) {
if(AIAirport.GetAirportType(AIStation.GetLocation(towns[i].stations[0])) == stype) continue;
local result = Airport.UpgradeAirportInTown(towns[i].id,towns[i].stations[0], airlist, Helper.GetPAXCargo(), Helper.GetPAXCargo());
if(Result.IsFail(result)) {
Log.Warning("Failed to upgrade station :(");
if(result == Result.REBUILD_FAILED) {
Log.Warning("Even worse, rebuild failed. It is easiest for now just to leave the town.");
this.LeaveTown(i);
}
}
}
}
}
}
SynTrans-2/town.nut 100777 0 0 31634 11651635176 7676 0 /*
* This file is part of SynTrans, which is an AI for OpenTTD
*
* SynTrans is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* SynTrans is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SynTrans; If not, see or
* write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
//function BuildBusStop(tile);
//function FindLineBusStopLocation(town, pass_cargo_id, estimate);
// The following functions in this class are from convoy ( I made some minor modifications to make this AI work with these functions)
class ConvoyFunc {
err = null;
constructor() {
err = AIError.ERR_NONE;
}
function BuildRoad(start, target);
function GetAdjacentTiles(tile);
function BuildBusStop(tile);
function FindLineBusStopLocation(town, pass_cargo_id, estimate);
}
function ConvoyFunc::BuildRoad(start, target)
{
if(start == null || target == null) return false;
// Log.Warning("BuildRoad called");
local retry_find = false;
local plan_retries = 0;
local pathfinder = RoadPathFinder();
local path_len = 0;
if(start == null || target == null ) {
Log.Warning("PathFinder: BuildRoad: null tiles");
return false;
}
if( !AIMap.IsValidTile(start) || !AIMap.IsValidTile(target)) {
Log.Warning("PF:BuildRoad: no valid tile" );
return false;
}
do {
retry_find = false;
pathfinder.InitializePath([start], [target]);
pathfinder.cost.slope = 50;
local path = false;
while (path == false) {
path = pathfinder.FindPath(100);
AIController.Sleep(1);
}
// AILog.Info("PathFinder: FindPath ready " + (path == null));
while (path != null) {
path_len = path_len + 1;
if (path.GetParent() != null) {
local parnt = path.GetParent().GetTile();
if (!AIRoad.AreRoadTilesConnected(path.GetTile(), parnt)
&& (!AIBridge.IsBridgeTile(path.GetTile())
|| AIBridge.GetOtherBridgeEnd(path.GetTile()) != parnt)) {
local retry_build = false;
local build_retries = 0;
do {
retry_build = false;
if (AIMap.DistanceManhattan(path.GetTile(), parnt) == 1 ) {
// AILog.Info("PathFinder: tiles " +
// AIMap.GetTileX(path.GetTile()) + " " + AIMap.GetTileY(path.GetTile()) +
// AIMap.GetTileX(parnt) + " " + AIMap.GetTileY(parnt));
local built_road = AIRoad.BuildRoad(path.GetTile(), parnt);
if (!built_road) {
err = AIError.GetLastError();
switch (err) {
/* ignore these errors */
case AIError.ERR_NONE:
case AIError.ERR_ALREADY_BUILT:
/* decrement retry counter, so it does not limit the nr of retries
else after 35 tiles over existing road, the building stops
*/
if (build_retries) build_retries = build_retries - 1;
break;
/* can't handle this locally, return unsuccessful */
case AIError.ERR_PRECONDITION_FAILED:
case AIError.ERR_NEWGRF_SUPPLIED_ERROR:
case AIError.ERR_NOT_ENOUGH_CASH:
case AIError.ERR_LOCAL_AUTHORITY_REFUSES:
Log.Warning("Build road failed(fatal)"+ AIError.GetLastErrorString()+" "+
AIMap.GetTileX(parnt)+" " + AIMap.GetTileY(parnt)
+" "+AIMap.GetTileX(path.GetTile())+" " + AIMap.GetTileY(path.GetTile())+" " + AITile.GetSlope(path.GetTile())+" " +
AITile.GetSlope(parnt));
return false;
break;
case AIError.ERR_VEHICLE_IN_THE_WAY:
Log.Warning("Build road failed (retry)"+ AIError.GetLastErrorString()+" "+
AIMap.GetTileX(parnt)+" " + AIMap.GetTileY(parnt)
+" "+AIMap.GetTileX(path.GetTile())+" " + AIMap.GetTileY(path.GetTile())+" " + AITile.GetSlope(path.GetTile())+" " +
AITile.GetSlope(parnt));
AIController.Sleep(1);
retry_build = true;
break;
case AIError.ERR_AREA_NOT_CLEAR:
Log.Warning("Build road failed (demolish + retry)"+ AIError.GetLastErrorString()+" "+
AIMap.GetTileX(parnt)+" " + AIMap.GetTileY(parnt)
+" "+AIMap.GetTileX(path.GetTile())+" " +
AIMap.GetTileY(path.GetTile())+" " + AITile.GetSlope(path.GetTile())+" " +
AITile.GetSlope(parnt));
AITile.DemolishTile(path.GetTile());
retry_build = false;
retry_find = true;
break;
case AIError.ERR_OWNED_BY_ANOTHER_COMPANY :
case AIError.ERR_FLAT_LAND_REQUIRED:
case AIError.ERR_LAND_SLOPED_WRONG:
case AIError.ERR_SITE_UNSUITABLE:
case AIError.ERR_TOO_CLOSE_TO_EDGE:
Log.Warning("Build road failed (replan)"+ AIError.GetLastErrorString()+" "+
AIMap.GetTileX(parnt)+" " + AIMap.GetTileY(parnt)
+" "+AIMap.GetTileX(path.GetTile())+" " + AIMap.GetTileY(path.GetTile())+" " + AITile.GetSlope(path.GetTile())+" " +
AITile.GetSlope(parnt));
retry_build = false;
retry_find = true;
break;
case AIError.ERR_UNKNOWN:
default:
Log.Warning("Build road failed (replan)"+ AIError.GetLastErrorString()+" "+
AIMap.GetTileX(parnt)+" " + AIMap.GetTileY(parnt)
+" "+AIMap.GetTileX(path.GetTile())+" " +AIMap.GetTileY(path.GetTile())+" " + AITile.GetSlope(path.GetTile())+" " +
AITile.GetSlope(parnt));
retry_find = true;
break;
}
}
build_retries++;
}
else {
Log.Info("PathFinder: build bridge");
/* Build a bridge or tunnel. */
if (!AIBridge.IsBridgeTile(path.GetTile()) && !AITunnel.IsTunnelTile(path.GetTile())) {
/* If it was a road tile, demolish it first. Do this to work around expended roadbits. */
if (AIRoad.IsRoadTile(path.GetTile())) AITile.DemolishTile(path.GetTile());
if (AITunnel.GetOtherTunnelEnd(path.GetTile()) == parnt) {
if (!AITunnel.BuildTunnel(AIVehicle.VT_ROAD, path.GetTile())) {
Log.Warning("Build tunnel failed");
}
} else {
local bridge_list = AIBridgeList_Length(AIMap.DistanceManhattan(path.GetTile(), parnt) + 1);
bridge_list.Valuate(AIBridge.GetMaxSpeed);
bridge_list.Sort(AIAbstractList.SORT_BY_VALUE, false);
if (!AIBridge.BuildBridge(AIVehicle.VT_ROAD, bridge_list.Begin(), path.GetTile(), parnt)) {
Log.Warning("Build bridge failed");
}
}
}
}
} while (retry_build && build_retries < 80 && !retry_find);
}
}
path = path.GetParent();
}
plan_retries++;
} while (retry_find && (plan_retries < 10));
return path_len;
}
function ConvoyFunc::GetAdjacentTiles(tile)
{
local adjTiles = AITileList();
adjTiles.AddTile(tile - AIMap.GetTileIndex(1,0));
adjTiles.AddTile(tile - AIMap.GetTileIndex(0,1));
adjTiles.AddTile(tile - AIMap.GetTileIndex(-1,0));
adjTiles.AddTile(tile - AIMap.GetTileIndex(0,-1));
return adjTiles;
}
function ConvoyFunc::BuildBusStop(tile)
{
local found = false;
local success = false;
local adjacentTiles = this.GetAdjacentTiles(tile);
for(local tile2 = adjacentTiles.Begin();
adjacentTiles.HasNext() && !found;
tile2 = adjacentTiles.Next()) {
if(AIRoad.IsRoadTile(tile2) ) {
local count = 0;
while(!success && (count < 100)){
local pathlen = this.BuildRoad(tile2, tile);
// AILog.Info("Build busstop pathlen " + pathlen);
if (pathlen == 2) {
success = true;
} else {
count = count + 1;
}
}
local truck = AIRoad.ROADVEHTYPE_BUS;
local adjacent = AIStation.STATION_NEW;
if (success) {
success = AIRoad.BuildRoadStation(tile, tile2, truck, adjacent);
}
found = true;
}
}
if (!success) {
Log.Warning("Build busstop failed "+ AIError.GetLastErrorString());
// AISign.BuildSign(tile,"bbs");
}
return success;
}
function ConvoyFunc::FindLineBusStopLocation(town, pass_cargo_id, estimate)
{
local tl = AITileList();
local aitile = null;
local tile = AITown.GetLocation(town);
local found = false;
local ret_tile = null;
tl.AddRectangle(tile + AIMap.GetTileIndex(-8, -8), tile + AIMap.GetTileIndex(8, 8));
/* remove all tiles that are already covered by a station */
local tl2 = AITileList();
tl2.AddList(tl);
tl2.Valuate(AIRoad.IsRoadStationTile);
tl2.KeepValue(1);
for (local rstl = tl2.Begin(); tl2.HasNext() ; rstl = tl2.Next()){
/* Keep our own stations a bit apart */
if (AITile.GetOwner(rstl) == AICompany.ResolveCompanyID(AICompany.COMPANY_SELF)) {
tl.RemoveRectangle(rstl + AIMap.GetTileIndex(-4, -4), rstl + AIMap.GetTileIndex(4, 4));
}
else { /* but don't be so modest with other players stations ... */
tl.RemoveRectangle(rstl + AIMap.GetTileIndex(-1, -1), rstl + AIMap.GetTileIndex(1, 1));
}
}
if (tl.Count()) {
/* find all tiles that are next to a road tile */
tl.Valuate(AIRoad.GetNeighbourRoadCount);
tl.KeepAboveValue(0);
if (tl.Count()) {
/* find all tiles that are not road */
tl.Valuate(AIRoad.IsRoadTile);
tl.KeepValue(0);
if (tl.Count()) {
/* find all tiles that are not sloped */
tl.Valuate(AITile.GetSlope);
tl.KeepValue(0);
if (tl.Count()) {
tl.Valuate(AITile.GetCargoAcceptance, pass_cargo_id,
1, 1,
AIStation.GetCoverageRadius (AIStation.STATION_BUS_STOP));
for (aitile = tl.Begin(); tl.HasNext(); aitile = tl.Next()){
// AISign.BuildSign(aitile,"ex"+tl.GetValue(aitile));
if (tl.GetValue(aitile) >= 15){
found = AITile.IsBuildable(aitile);
if (estimate) {
found = true;
}
if (!found) {
found = AITile.DemolishTile(aitile);
}
if (found) {
ret_tile = aitile;
break;
}
}
else {
Log.Info("Find busstop location, acceptance too low " + tl.GetValue(aitile));
}
}
}
else {
Log.Info("Find busstop location, no unsloped tiles present");
}
}
else {
Log.Info("Find busstop location, no tiles that are not road present");
}
}
else {
Log.Info("Find busstop location, no tiles next to road present");
}
}
if (found) {
// AISign.BuildSign(aitile,"ex"+tl.GetValue(aitile));
return ret_tile;
}
else {
return null;
}
}
class Town
{
id = null;
outerLayer = null;
stations = null;
depot = null;
suspended = null;
newStationTries = null;
stationType = null;
connections = null;
constructor(townid,stype) {
this.id = townid;
this.outerLayer = true;
this.stations = [];
this.depot = null;
this.stationType = stype;
this.connections = AIList();
}
function Begin(stationType);
function BuildStation();
function End();
}
function Town::Begin(stationType) {
/*AILog.Warning("BUILDING STATION IN CITIES");
local station=Road.BuildMagicDTRSNextToRoad(AITown.GetLocation(id),AIRoad.ROADTYPE_ROAD, 2,-1,-1,25,125);
if(station.result) {
this.stations.append(station.station_id);
this.depot=station.depot_tile;
}
return station.result;*/ // DTRS OLD
this.connections = AIList();
Log.Info("Attempting to build station and depot");
this.stationType=stationType;
local stationId;
if(this.stationType==AIStation.STATION_BUS_STOP) {
local cfunctions = ConvoyFunc();
local theTile = cfunctions.FindLineBusStopLocation(this.id, Helper.GetPAXCargo(), false);
if(!theTile) {
Log.Warning("Could not find a good place to build in " + this.id);
return false;
}
local result = cfunctions.BuildBusStop(theTile);
if(result) stationId = theTile;
}
else stationId=Airport.BuildAirportInTown(this.id,Airport.GetLastAvailableAirportType(Engine.GetEngine_PAXLink(0,AIVehicle.VT_AIR)),Helper.GetPAXCargo(),Helper.GetPAXCargo());
if(!stationId) {
Log.Warning("Could not build station in this city");
return false;
}
local station;
/*if(this.stationType != AIStation.STATION_BUS_STOP)*/ station=AIStation.GetStationID(stationId);
//station = stationId;
Log.Info("STATION NAME: " + AIStation.GetName(station));
if(!AIStation.IsValidStation(station)) {
Log.Info("Could not build the station");
return false;
}
this.stations.append(station);
if(this.stationType==AIStation.STATION_BUS_STOP) this.depot=Road.BuildDepotNextToRoad(stationId, 50, 150);
else this.depot=Airport.GetHangarTile(station);
if(!this.depot) {
Log.Warning("Could not build depot!");
return false;
}
this.suspended=false;
this.newStationTries=0;
return true;
}
function Town::BuildStation() {
// Not yet implemented
Log.Info("Empty Function");
}
function Town::End() {
for(local i=0;i