FS#3799 - AI: would be nice to have a way to get cargo acceptance/production for a station

Attached to Project: OpenTTD
Opened by Ian Hickson (Hixie) - Monday, 26 April 2010, 07:49 GMT
Last edited by andythenorth (andythenorth) - Friday, 01 September 2017, 10:15 GMT
Type Feature Request
Category Script → NoAI
Status Assigned   Reopened
Assigned To andythenorth (andythenorth)
Operating System All
Severity Low
Priority Normal
Reported Version 1.0.0
Due in Version Undecided
Due Date Undecided
Percent Complete 0%
Votes 1
Private No


It would be very useful if GetCargoAcceptance() and GetCargoProduction() were available on AIStation, so that you could find out what kinds of cargo a station could handle without having to find all the tiles that the station covers and then manually walk each tile figuring out each tile's radius and so forth.
This task depends upon

Comment by Ian Hickson (Hixie) - Monday, 26 April 2010, 07:53 GMT
In fact right now it's essentially impossible to get an accurate picture since even with the list of tiles, you can't work out what each tile's station type is and thus what each tile's radius is. (You can fake it if the AI only creates stations of a particular type or in a particular configuration, if you keep track of what kind of station each station is, but that's rather a pain.)
Comment by Leif Linse (Zuu) - Sunday, 02 May 2010, 12:20 GMT
You can work out each tiles station type. First make a list of all rail tiles, then all dock tiles, then all bus/truck stops etc. A station can only have one airport and even if they could, there is AIAirport.GetAirportType(tile) so you could handle that if that were possible.

Please note that the way station acceptance work in OpenTTD is different from how the check works to see what producers that are in range. Station acceptance is just a big rectangle with the highest coverage radius of the station types available at the station.

I haven't synced my SuperLib work to SVN for a while so my implementation of Station.IsCargoAccepted is not in SVN. Instead I post it here. You need SuperLib::Tile::GrowTileRect (available in SVN and maybe even v2) and SuperLib::Helper::ListValueSum (available in v2 @ content download)

/*static*/ function _SuperLib_Station::IsCargoAccepted(station_id, cargo_id)
// Get the max coverage radius
local max_coverage_radius = 0;

if(AIStation.HasStationType(station_id, AIStation.STATION_AIRPORT))
local airport_tile = _SuperLib_Station.GetAirportTile(station_id); // todo get from pax link
local airport_type = AIAirport.GetAirportType(airport_tile);
local coverage_radius = AIAirport.GetAirportCoverageRadius(airport_type);

if(coverage_radius > max_coverage_radius)
max_coverage_radius = coverage_radius;

if(max_coverage_radius < 5 && AIStation.HasStationType(station_id, AIStation.STATION_DOCK))
max_coverage_radius = 5;

if(max_coverage_radius < 4 && AIStation.HasStationType(station_id, AIStation.STATION_TRAIN))
max_coverage_radius = 4;

if(max_coverage_radius < 3 && AIStation.HasStationType(station_id, AIStation.STATION_BUS_STOP) || AIStation.HasStationType(station_id, AIStation.STATION_TRUCK_STOP))
max_coverage_radius = 3;

// Get the coverage tiles
local station_tiles = AITileList_StationType(station_id, AIStation.STATION_ANY);
local acceptance_tiles = _SuperLib_Tile.GrowTileRect(station_tiles, max_coverage_radius);

// Now finally acceptance_tiles contains all tiles that the station covers

// Valuate the list with the acceptance for each individual tile
acceptance_tiles.Valuate(AITile.GetCargoAcceptance, cargo_id, 1, 1, 1);

// Return true if the sum over all tiles is >= 8
local total_acceptance = _SuperLib_Helper.ListValueSum(acceptance_tiles);
return total_acceptance >= 8;

Whenever SuperLib v3 is released it will contain this function.

All that said, I wouldn't mind if these two functions were added so that if the acceptance/production coverage logic changes, then there is one thing less to change in the AIs. Though I wouldn't be surprised if my AIs would broke by that anyways.
Comment by Thijs Marinussen (Yexo) - Tuesday, 08 November 2011, 15:47 GMT
I've added AICargoList_StationAccepting in r23134. A list of cargos that is being produced near a station might be useful too, I'll give that some more thought.
Comment by Thijs Marinussen (Yexo) - Tuesday, 08 November 2011, 15:53 GMT
I think your function can now be reduced to:

/*static*/ function _SuperLib_Station::IsCargoAccepted(station_id, cargo_id)
local list = AICargoList_StationAccepting(station_id);
return list.HasItem(cargo_id);
Comment by frosch (frosch) - Saturday, 24 November 2012, 20:44 GMT
From an IRC discussion.

A list of cargos a station supplies does not make a lot of sense.
* ScriptCargoList_StationAccepting reports cargos which are _currently_ accepted. There is no such thing as _current_ production.
* A list of cargos that might be produced in case the industries are services (as displayed in the build station window) is also quite useless, as it does not tell the conditions for prodution.

So instead these methods might be useful:
* A list of industries in range of the station, which might deliver cargo to it. (basically the inverse of ScriptTileList_IndustryProducing after construction of a station). (This might also be a more useful information for human players than a list of cargos, in case there are multiple industries)
* For houses the issue is a bit more tricker. Maybe there it indeed needs a list of unconditionally produced cargos. (but then ScriptTile::GetCargoProduction maybe also should only count houses, and not industries?)