RoadAI-4/ 0000755 0001750 0000144 00000000000 11645753260 011502 5 ustar daniel users RoadAI-4/network.nut 0000755 0001750 0000144 00000045770 12776060132 013736 0 ustar daniel users /*
* This file is part of RoadAI, which is an AI for OpenTTD
*
* RoadAI 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 3 of the License
*
* RoadAI 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 RoadAI; 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;
lastNewTown = null;
lastUpdateEngine = null;
towns = null;
blacklist = null;
vehicles = null;
defaultEngine = null;
center = null;
size = null;
replace = null;
noReplace = null;
constructor(epicenter = null) {
this.towns = [];
this.vehicles = [];
this.blacklist = AIList();
this.defaultEngine = null;
this.center = epicenter;
this.size = 1;
}
function TownDistValuator(town1,town2,targetDistance);
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);
}
function Network::TownDistValuator(town1,town2,targetDistance)
{
return Helper.Abs(AIMap.DistanceManhattan(AITown.GetLocation(town1), AITown.GetLocation(town2))-targetDistance);
}
function Network::ManageNetwork()
{
Log.Info("=========================================");
Log.Info("==========MANAGING NEXT NETWORK==========");
Log.Info("=========================================");
// Verify there is no shortage on the vehicle limit
if(Vehicle.GetVehiclesLeft(AIVehicle.VT_ROAD)<50) {
AILog.Warning("Vehicle Limit Reached! Please increase the vehicle limit in the advanced settings. Until then, this AI will do nothing.");
AIController.Sleep(1000);
return;
}
if(this.towns.len()==0) {
Log.Info("======================Building First City");
this.defaultEngine=Engine.GetEngine_PAXLink(0, AIVehicle.VT_ROAD);
this.lastUpdateEngine=AIController.GetTick();
Log.Info("Default engine is " + this.defaultEngine);
local town1;
if(center==null) {
Log.Info("No city specified, finding instead");
local townlist=AITownList();
townlist.RemoveList(this.blacklist);
townlist.Valuate(AITown.GetPopulation);
townlist.Sort(AIList.SORT_BY_VALUE,false);
town1=townlist.Begin();
}
else town1=center;
if(town1==null) Log.Error("Cannot create initial city");
this.center=AITown.GetLocation(town1);
if(!this.AddTown(town1)) {
// Town was not added
// Add to blacklist so that we do not try this city again
this.blacklist.AddItem(town1);
return;
}
this.ExpandStation(towns[0].stations[0]);
Log.Info("First City built");
local town2=this.FindTown(towns[0],true);
if(town2) towns[0].connections.AddItem(towns[towns.len()-1].stations[0],0);
//AddTown(town2);
//Connect(town1,town2);
this.replace = false;
}
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();
}
this.lastUpdateEngine=AIController.GetTick();
}
local frontTiles;
local i=0;
for(local i=0;i365) {
Log.Info("Sending " + AIVehicle.GetName(vehicles[i]) + " due to lack of income from vehicle");
AIVehicle.SendVehicleToDepot(vehicles[i]);
}
}
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.Warning("Town is no longer overloaded, un suspendeding");
town.suspended=false;
}
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, it is more accurate!
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.Warning("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())<50) {
// First off, always ensure the proper 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;
}
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;
}
}*/
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) {
if(station == town.stations[0]) {
Log.Info("Skipping the town because it will cause an infinate loop");
continue;
}
bestStation=station;
bestWait=AIStation.GetCargoWaiting(station,Helper.GetPAXCargo());
}
}
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)*/) {
Log.Warning("Entered if statement!!!");
local myResult;
if(town.newStationTries>3) myResult=FindTown(town,true);
else myResult=FindTown(town);
continue;
}
// Ensure that there is a road from here to there
local result = false;
Log.Info("Checking roads...");
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
if(AIStation.GetCargoRating(town.stations[0],Helper.GetPAXCargo())<50) this.BuyVehicles(town.depot,defaultEngine,2,town.stations[0],bestStation);
else this.BuyVehicles(town.depot,defaultEngine,AIStation.GetCargoWaiting(town.stations[0],Helper.GetPAXCargo())/AIEngine.GetCapacity(defaultEngine),town.stations[0],bestStation);
// Wait a little
AIController.Sleep(50);
}
}
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.OF_FULL_LOAD);
orders.AddStop(order2,AIOrder.OF_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 (for now)
foreach(network in aiInstance.networks) {
foreach (town in network.towns) {
townlist.RemoveItem(town.id);
}
}
townlist.Valuate(AITown.GetPopulation);
townlist.RemoveBelowValue(300); //cities must be at least 300 in population in order to be considered for use!
townlist.Valuate(TownDistValuator, chosenCity.id, 50);
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) townlist.RemoveAboveValue(40);
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
this.ExpandStation(builtTown.stations[0]);
// Build a road between them
local result=Connect(AIStation.GetLocation(chosenCity.stations[0]),AIStation.GetLocation(builtTown.stations[0]));
if(!result) {
Log.Info("Pathfinding failed. Leaving Town...");
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 = Town(theTown);
local result=newTown.Begin();
if(result) this.towns.append(newTown);
else {
Log.Info("Could not build the town...");
return null;
}
return newTown;
}
function Network::LeaveTown(index) {
this.blacklist.AddItem(this.towns[index].id,0);
this.towns[index].End();
this.towns.remove(index);
}
function Network::Connect(point1,point2) {
Log.Info("Connecting 2 points...");
local pathfinder=RoadBuilder();
pathfinder.Init(point1,point2,false,500);
local result=pathfinder.ConnectTiles();
if(result!=RoadBuilder.CONNECT_SUCCEEDED) 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;
foreach(vehicle in vehicles) {
if(AIVehicle.GetEngineType(vehicle) == defaultEngine) continue;
else {
done = false;
if(AIVehicle.IsStoppedInDepot(vehicle)) {
// 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);
}
else this.noReplace++;
}
}
if(done || this.noReplace > 5) this.replace = false;
}
}
function Network::ExpandStation(station) {
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 :(");
}
}
RoadAI-4/town.nut 0000755 0001750 0000144 00000004443 12776055427 013237 0 ustar daniel users /*
* This file is part of RoadAI, which is an AI for OpenTTD
*
* RoadAI 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 3 of the License
*
* RoadAI 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 RoadAI; If not, see or
* write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
class Town
{
id = null;
outerLayer = null;
stations = null;
depot = null;
suspended = null;
newStationTries = null;
connections = null;
constructor(townid) {
this.id = townid;
this.outerLayer = true;
this.stations = [];
this.depot = null;
this.connections = AIList();
}
function Begin();
function BuildStation();
function End();
}
function Town::Begin() {
/*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 BACKUP
Log.Info("Attempting to build station and depot");
local station=Road.BuildStopInTown(this.id,AIRoad.ROADVEHTYPE_BUS,Helper.GetPAXCargo(),Helper.GetPAXCargo());
if(!station) {
Log.Warning("Could not build station!");
return false;
}
this.stations.append(AIStation.GetStationID(station));
this.depot=Road.BuildDepotNextToRoad(station, 25, 125);
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