SuperLib: Helper, Direction, Tile, ... libraries

Discuss the new AI features ("NoAI") introduced into OpenTTD 0.7, allowing you to implement custom AIs, and the new Game Scripts available in OpenTTD 1.2 and higher.

Moderator: OpenTTD Developers

Post Reply
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

SuperLib: Helper, Direction, Tile, ... libraries

Post by Zuu »

SuperLib information

Hello!

SuperLib is
  • A utility library for AIs and Game Scripts
  • divided into sub libraries (Helper, Tile, Direction, Road, Station, etc.)
  • based on code that has been refactored out of CluelessPlus, PAXLink and a few more of my AI/GS projects. Mostly it is functions that more than one AI or GS project uses. But also in some cases it is methods that just might be useful for others or fit well in the library.
  • licensed under the GPL 2 license
  • automatically downloaded when you download most of my AIs and Game Scripts

SuperLib is not
  • SuperLib is not useful for players unless it is a dependency for an AI or GS you want to use or write.

The Name
"Super" comes from that it is a library consisting of many sub libraries.


Sub libraries
  • Log
    A log system with support for log levels and user selection of which levels to print.

    Helper
    Sign functions, List functions, Max/Min/Clamp etc., GetPAXCargo

    Money
    Get information about available amonut of money etc. Also, take temporary max loans and re-store the old balance.

    Tile
    GetTileRelative, GetNeighbours (4 and 8), IsUpSlope(tile, direction), IsBuildOnSlope_UpSlope(tile, direction), etc.

    Direction
    Contains functions and constants for working with directions between tiles.
    Also see this image: http://wiki.openttd.org/Image:Directions.png

    Engine
    Get travel time for new engines over some distance. Check if there exist an engine for a given cargo.

    Vehicle
    Where are the vehicles? On a station? Within a given tile list? Does a given tile list has one or more vehicles on it?

    Industry
    Is a given cargo produced by a given industry?

    Station
    Check if a given cargo is accepted by a station. Get a list of all the front tiles or why not demolish a station? ;-) It can also get a list of all vehicles that visit a station and get the type of station that a given vehicle needs.

    Airport
    Build/upgrade airports for industries and towns.

    Order
    Get the current destination of a vehicle (could for example be a depot not in the order list). Removal of all orders of a vehicle with shared orders without breaking the shared-status. Get a list of stations from a vehicle etc.

    OrderList
    1. Create an instance of this class
    2. Build a list of desired orders
    3. Tell it to apply the desired orders to a vehicle
    4. Repeat 3. for any number of vehicles you want.
    OrderList has been designed to not remove orders more than necessary when changing orders of a vehicle, to reduce the risk of it loosing the current destination it heads towards.

    RoadPathFinder
    A wrapper around the A* based road path finder library. It changes some costs and adds ability to cross rail/canals with bridges.

    RoadBuilder
    A class that connects two tiles by first path finding and then building road. If road building fails, it repeats a few times before giving up. This class also contains a static member to replace a level rail crossing with a road bridge.

    Road
    Build road stops for industries and towns.

    Rail
    Check if two adjacent rail tiles are connected.

    Story
    Helper methods for working with GSStoryBook. (this sub library is only available in the GS edition)
(in main.nut in the repository you can see an always up-to-date list of sub libraries from the development version of SuperLib: http://dev.openttdcoop.org/projects/sup ... in.nut#L58 )


Usage
As a bonus from my decision to put the shared code between my AIs in a library it will be easier for other AI developers to reuse this code by simply loading the library. A short explanation on how the library is intended to be included and used follows here.

Code: Select all

import("util.superlib", "SuperLib", 2); // Import SuperLib version 2

/* For the sub libraries that you want to use,
 * you might want to give them shorter names
 * like this:
 */
Helper <- SuperLib.Helper;
Tile <- SuperLib.Tile;
Direction <- SuperLib.Direction;
To use a function you then just do

Code: Select all

Helper.SetSign(tile, "my sign");

// Or if you didn't create the "Helper" short name:
SuperLib.Helper.SetSign(tile, "my sign");
Extract the tar file of the version you want to use and study the corresponding nut file for each sub library to find documentation about what functions that are included in the sub libraries. All/most functions has usage comments at the top of the files where the functions are declared. For some you need to find the implementation/definition further down in the file (for SetSign and BreakPoint I'd recommend reading the implementation to know exactly the conditions for when debug signs/break points are placed and not)

You can also browse the source code here: http://hg.openttdcoop.org/superlib


Get SuperLib Note that there are two editions of SuperLib. One for AIs and one for Game Scripts. In BaNaNaS, the AI edition is called "SuperLib" and the Game Script version is called "SuperLib for NoGo". (NoGo is the name of the API for game scripts in OpenTTD if you didn't knew) If you grab the hg version, you will get the AI edition. In order to get the NoGo version, you have to use the conversion script which is included in the repository. Before executing it, I recommend taking a look on what assumptions it make on the file system organization and possible alter it to fit your situation.

Old versions
Old AI editions can be found here: http://noai.openttd.org/downloads/Libraries/
For GS, check out from VCS the revision of that version, edit nogo_translator.py so that the paths there work for you and then run the script to compile the GS edition from the master edition which is for AIs.


Uploading of AIs (or GSs) that use SuperLib to BaNaNaS
When you upload an AI or GS via the web interface for BaNaNaS, you can currently only set the last version of each library as dependencies. So either you need to get that changed by convincing TrueBrain to do that, or you have to make sure your AI works with the last version of SuperLib.

If you need to specify an old version as dependency, it is possible if you use musa instead of the web interface.

I will not make any promises regarding backward compatibility etc. as this library was mainly created to give me somewhere to put shared code. (2012: However over the years since I first started SuperLib, the backward compatibility have been hold for most cases except fixed bugs. The only thing that I really can think of is that I from time to time update the library to use the API version of the last released stable, but at that time most users should have already upgraded to that stable.)


Contributions
Contributions to the library are welcome.




-------------------------------------------------------

Old first post

Hello!

As you probably know I maintain both PAXLink and CluelessPlus. While they behaviour quite differently to the player they still share quite some code. Maintaining the same code at two locations is not good when this code grows. Therefore I have decided to move towards creating libraries of the common code so that it can be shared between the two AIs. As a bonus other people will have easier to access and reuse this code.

My utility functions are organized as static functions in different classes depending on the category of the function.

Since only one main class can exist in a NoAI libraries I had two choises
  • Make one library of each utility class.
  • Make one super class and then add the utility classes as sub classes.
[/list]

For now I have went for the first option. This may in the future create a quite large set of libraries which could be an argument of trying to make one big library containing all the utility functions. For me it would probably be easier to maintain one library than many but my first attempts of creating a super-library failed so for now I have made three separate libraries. Making a big library will also solve the problem that you can't have cyclic dependant libraries which already has required me to duplicate one function.

Preview
Below I've listed some functions that exist in the three different libraries and attached them. I'll upload them to BaNaNaS either as separate libraries or as a super-library depending on how I choose to continue when I will upload next CluelessPlus or PAXLink version.

Util.Helper
Sign functions, List functions, Max/Min/Clamp etc., GetPAXCargo
Util.Helper.tar
(12 KiB) Downloaded 823 times
Util.Direction
Depends on Helper
Contains functions and constants for working with directions between tiles.
Also see this image: http://wiki.openttd.org/Image:Directions.png
Util.Direction.tar
(14 KiB) Downloaded 1004 times
Util.Tile
Depends on Helper and Direction
GetTileRelative, GetNeighbours (4 and 8), IsUpSlope(tile, direction), IsBuildOnSlope_UpSlope(tile, direction), etc.
Util.Tile.tar
(15.5 KiB) Downloaded 788 times

If you think it is a better idea I could release my libraries in a 'Zuu' category.


Edit: 2010-03-10: I've disabled smilies, so that "8)" isn't turned into a smiley.
Last edited by Zuu on 19 Jul 2013 08:31, edited 16 times in total.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
Kogut
Tycoon
Tycoon
Posts: 2493
Joined: 26 Aug 2009 06:33
Location: Poland

Re: Util.Helper, Util.Direction, Util.Tile libraries

Post by Kogut »

Code: Select all

function Helper::GetPAXCargo()
{
	local cargo_list = AICargoList();
	cargo_list.Valuate(AICargo.HasCargoClass, AICargo.CC_PASSENGERS);
	cargo_list.KeepValue(1);
	cargo_list.Valuate(AICargo.GetTownEffect);
	cargo_list.KeepValue(AICargo.TE_PASSENGERS);

	if(!AICargo.IsValidCargo(cargo_list.Begin()))
	{
		AILog.Error("PAX Cargo do not exist");
	}

	return cargo_list.Begin();
}
Is it really needed?

Code: Select all

cargo_list.Valuate(AICargo.GetTownEffect);
cargo_list.KeepValue(AICargo.TE_PASSENGERS);
Correct me If I am wrong - PM me if my English is bad
AIAI - AI for OpenTTD
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Util.Helper, Util.Direction, Util.Tile libraries

Post by Zuu »

I don't remember, but it shouldn't hurt.


In most cases you can even assume that cargo id 0 is passengers, but that could be changed by NewGRFs. This function makes sure you get a passenger cargo that uses bus stops, is generated by towns and that you can get the town production of the found PAX cargo via AITown.

I don't remember if the last check that you quoted is necessary, but since NewGRFs can do all kind of nasty things if they want it is better to do an extra check than being sorry.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
Kogut
Tycoon
Tycoon
Posts: 2493
Joined: 26 Aug 2009 06:33
Location: Poland

Re: Util.Helper, Util.Direction, Util.Tile libraries

Post by Kogut »

One more thing with passenger detection, I just added following lines:

cargo_list.Valuate(AICargo.GetCargoIncome, 1, 1); //Elimination ECS tourists
cargo_list.KeepBottom(1);
Correct me If I am wrong - PM me if my English is bad
AIAI - AI for OpenTTD
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Util.Helper, Util.Direction, Util.Tile libraries

Post by Zuu »

Thanks Kogut I'll include.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Util.Helper, Util.Direction, Util.Tile libraries

Post by Yexo »

Filtering tourist is a good idea, but that's not the best code to use for it. If tourist ever get a lower payment then normal passengers that code would fail. In AdmiralAI when there are several passenger-type cargoes (normal and tourist for example) I find the biggest city and then get the highest acceptence in the center of that city. That too is not foolproof, but less likely to fail then relying on payment.
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Util.Helper, Util.Direction, Util.Tile libraries

Post by Zuu »

With some help from Yexo, I have been able to figure out how to make a big library that contains all my sub-libraries in separate classes without polluting the global scope.

This is how the solution looks like:

Code: Select all

class SuperLib
{
  static Tile = class
  {
    function GetName(tile)
    {
      return "My name is Tile " + tile;
    }
 
    // ... more functions
  }

  // .. more child classes 
}
The child classes can call functions declared futher down in the file without problem and when you import the library they will not be placed in the global scope.

Having all code in one file without separete declarations and definitions is not something I really like, so I've created a ruby script that takes my library nut files helper.nut, direction.nut and tile.nut and make a main.nut out of them that works with OpenTTD. This way I can still have my pretty and readable sub library files.

The attached file contains

Source files:
  • helper.nut
  • tile.nut
  • direction.nut
  • library.nut
and
make_dist.rb - creates main.nut
main.nut - created by make_dist.rb
SuperLib.zip
(13.28 KiB) Downloaded 587 times
How to use

Code: Select all

import("util.superlib", "SuperLib", 1);

Helper <- SuperLib.Helper;
Direction <- SuperLib.Direction;
Tile <- SuperLib.Tile;
I have not yet added the suggested code to reject ECS tourists.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Util.Helper, Util.Direction, Util.Tile libraries

Post by Zuu »

Oh well. I found out that the child classes, since they were anonymous, couldn't access other child classes with the names "Helper" etc., unless the user of the library created those names globally when they imported the library. That kind of defeats the whole purpose with not placing the child classes at the global scope.

Therefore, I have now taken a step back and put my sub libraries at the global scope using fairly unique names that shouldn't give anyone problems. These names will only be used internally by SuperLib but will technically reside at the global scope, so you can't use these names in your AI.

For example Helper is internally known as _SuperLib_Helper. The AI that uses it will however know it as SuperLib.Helper and may put it under another name globally by doing:

MyHelper <- SuperLib.Helper;


When things have settled and I know if bananas accept *.nut or just main.nut and library.nut in the tars etc. I'll write some more straight forward instructions.

Oh and btw, SuperLIb is available at noai.openttd.org as well: http://noai.openttd.org/projects/show/lib-super
SuperLib.tar
(40 KiB) Downloaded 529 times
Edit: I have implemented the strategy Yexo proposed for GetPAXCargo().

Edit2: The attachment above contains SuperLib 1 which has been uploaded to BaNaNaS. It is used by the last CluelessPlus also available at bananas.
Last edited by Zuu on 19 Mar 2010 12:33, edited 1 time in total.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
Blustuff
Engineer
Engineer
Posts: 112
Joined: 21 Aug 2008 09:37
Location: France

Re: Util.Helper, Util.Direction, Util.Tile libraries

Post by Blustuff »

Zuu wrote:Oh well. I found out that the child classes, since they were anonymous
Classes are always anonymous in Squirrel. This is why you can't get the classname of an instance. However, I believed that Library importation didn't import the global scope. In this case, you could do something like that :

Code: Select all

include("tile.nut");
// ... more includes


class SuperLib
{
  static Tile = ::Tile; // the :: are not needed
  // ... more child classes 
}
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: SuperLib: Helper, Direction, Tile libraries

Post by Zuu »

That will place the class name used in tile.nut in the global scope, accessible for the AI.

Actually, this is exactly what I use at the moment. The main class in tile.nut is just called _SuperLib_Tile so that it shouldn't do too much harm in the global scope for the AIs.


What I did before was something like:

Code: Select all

class Abc
{
  static def = class
  {
     function ghj()
     {
     }
   }
   static Tile = class
   {
     // ..
   }
}
Then def points on a class that has no name. So when a function in the Tile class wants to call ghj(), there is no class name it can use to call the function.

Edit: Here is another longer example why it does not work: http://paste.openttd.org/225296 (OpenTTD would complain about line 41 in this example)

Edit2: I forgot to include in that example that SuperAI calls Direction.GetAdjacentTileInDirection.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
Blustuff
Engineer
Engineer
Posts: 112
Joined: 21 Aug 2008 09:37
Location: France

Re: SuperLib: Helper, Direction, Tile libraries

Post by Blustuff »

Zuu wrote:That will place the class name used in tile.nut in the global scope, accessible for the AI.
Isn't the import function supposed to only import one class ? (and thus doesn't affect global scope more than to provide this class)
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: SuperLib: Helper, Direction, Tile libraries

Post by Zuu »

It is maybe what it is supposed to do in the context of using libraries, but unfortunately its not what happens. It does rename the library class to what you specify but everything else at the global scope of the library will end up at the global scope of the AI.

I think the problem is that the library will not have its own "global scope" when it is used by an AI, instead their global scopes will be merged into one scope making it impossible for the library to have type/variable names that are global to the library but invisible to the AI. Even a workaround like having "this_lib" point at the library main class would require a per library scope to support multiple libraries loaded at the same time.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
Blustuff
Engineer
Engineer
Posts: 112
Joined: 21 Aug 2008 09:37
Location: France

Re: SuperLib: Helper, Direction, Tile libraries

Post by Blustuff »

Ok. The only thing I see would be to use the scope of a function, but using classes as free variables requires to declare those free variables unless Squirrel 3 is released.
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: SuperLib: Helper, Direction, Tile libraries

Post by Zuu »

I just want to let you know that I've updated the first post with general information about SuperLib. A version 2 was released recently with only a small addition that was needed for CluelessPlus 18. I'm not sure if I'll announce all new SuperLib versions in this thread since I already announce new versions to my AIs, and most new SuperLib releases will probably be due to changes needed for one of my AIs.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: SuperLib: Helper, Direction, Tile libraries

Post by Zuu »

Hello,

In case someone is using the Direction library, I've found and fixed a bug in that library. Direction::GetDirectionToTile returned the opposite directions than it should according to the documentation. In SVN, I've changed it so it works like the documentation says. This makes it consistent with Direction::GetDirectionToAdjacentTile. However the SVN version is a moving target at the moment as I'm working on the next version of CluelessPlus. The three sub libraries that are in version 2 are more or less the same. I can't remember that I have broken anything present in v2, other than fixing the bug mentioned above. Some of the new sub libraries however are more in subject for future possible changes before v3 is out which will probably not happen until just before CluelessPlus v19 is out.

If any AI writer find any of the libraries useful, I'm glad to hear as it is impossible for me to track if any AIs other than my own on BaNaNaS use the library or not.

If you consider using the library and would like to have a version on BaNaNaS with the bug fixed, it is a quite simple task for me to make a v3 with that fix in. Let me know if that's the case.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: SuperLib: Helper, Direction, Tile libraries

Post by Zuu »

Version 3

A new version has been released with many new functions and sub libraries.

Changes in sub libraries existing in v2
Helper
  • New function GetTownProducedCargoList()
    : returns an AIList with cargos that towns can possible produce
  • New function GetTownAcceptedCargoList()
    : returns an AIList with cargos that towns can possible accept
Direction
  • New function GetAllDirsInRandomOrder()
    : returns AIList with all directions in random order
  • New function GetMainDirsInRandomOrder()
    : returns AIList with main directions in random order
  • New function GetDiagonalDirsInRandomOrder()
    : returns AIList with diagonal directions in random order
  • New function TurnDirClockwise90Deg(dir, num_90_deg)
    : returns a direction
  • New function TurnDirAntiClockwise90Deg(dir, num_90_deg)
    : returns a direction
  • New function OppositeDir(dir, num_90_deg)
    : returns a direction
  • Fixed bug in GetDirectionToTile(tile1, tile2): It now returns the correct direction according to the documentation and not 180 degree wrong as it did in version 2 of the library.
Tile
  • New function IsBuildOnSlope_FlatForBridgeInDirection(tile_id, dirrection)
    : returns boolean
    New function IsBuildOnSlope_FlatForTerminusInDirection(tile_id, dirrection)
    : returns boolean
    New function GetBridgeAboveStart(tile, bridge_search_direction)
    : returns bridge start tile or -1
    New function GetRoadStopType(tile);
    : returns an AIroad.RoadVehicleType of the road stop at the tile or -1 if no road stop is present.
New sub libraries
  • Log - A logger class with support for different log levels and an AI setting to choose what to print. You can provide your own function for filtering what to print and not to print.
  • Money
  • Engine
  • Vehicle
  • Industry
  • Station
  • Order
  • OrderList - A class that can be used to first build a set of wanted orders and then apply that set to one or more vehicles. The apply-operation is fairly stable and keeps the number of vehicles that lose their current order to a minimum.
By default, SuperLib only prints some fatal messages to the log. If you want more/or less output you should read the help in main.nut and log.nut for info on how to either integrate Log in your AI or keep your log system and just tell SuperLib how much it should log.
Attachments
SuperLib-v3.tar
(110 KiB) Downloaded 481 times
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: SuperLib: Helper, Direction, Tile, ... libraries

Post by Zuu »

Update - Version 5
This is a bug fix release of version 3. (version 4 was also a bug-fix release)

The Vehicle sub library now contains a new function: GetVehicleCargoType that was missing. (It's used by the Station sub library)
Attachments
SuperLib-v5.tar
(110 KiB) Downloaded 491 times
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
Kogut
Tycoon
Tycoon
Posts: 2493
Joined: 26 Aug 2009 06:33
Location: Poland

Re: SuperLib: Helper, Direction, Tile, ... libraries

Post by Kogut »

Stupid typo in 44 line of log.nut
* You can use one of the tree functions Info, Warning and Error that
Correct me If I am wrong - PM me if my English is bad
AIAI - AI for OpenTTD
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: SuperLib: Helper, Direction, Tile, ... libraries

Post by Zuu »

Thanks for the heads up. Though I don't see why you always need to call mistakes "stupid".
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
User avatar
fanioz
Transport Coordinator
Transport Coordinator
Posts: 320
Joined: 19 Dec 2008 05:03
Location: Indonesia
Contact:

Re: SuperLib: Helper, Direction, Tile, ... libraries

Post by fanioz »

Hello zuu, :D

SuperLib.Engine.GetFullSpeedTraveltime(engine, distance)

file : engine.nut
line : 98

Code: Select all

if(AIEngine.GetVehicleType(engine) == AIVehicle.VT_AIR)
{
	local plane_speed = AIGameSettings.GetValue("plane_speed");
	tile_speed = tile_speed / plane_speed;
}
I don't think that piece of code would be needed, AFAIK AIEngine.GetMaxSpeed(engine) would return the correct plane speed. ie: a 479 km/h plane would return 119 if plane_speed setting was 1/4.
Applying this code would get 29.75 and does make the travel time longer, less income ..etc..

CMIIW
Correct me If I am wrong - PM me if my English was bad :D

**[OpenTTD AI]** Image
***[NewGRF] *** Image
Post Reply

Return to “OpenTTD AIs and Game Scripts”

Who is online

Users browsing this forum: No registered users and 11 guests