TTD, the precursor of TTDPatch and OpenTTD, introduced a quite simplistic and inflexible system for handling vehicle prices and costs. It is build on so-called base costs where vehicle prices are derived from fixed base costs multiplied by byte-sized factors.
E.g., the base cost for train engines is £ 400,000, and the price for a vehicle with a factor n is set to 400,000 / 256 * n.
TTDPatch and OpenTTD improved that system by adding 'cost base multipliers' which allow to change base costs by factors of two. This allowed for much larger ranges for price and cost values, but, on the other hand, it also enlarges price/cost steps between factors, and made price finding even more convoluted, still limiting the scope for designing best fitting price and cost schemes.
With inflation and currency conversion added, this system makes it still hard for set developers to achieve 'real' (historic) prices and costs for vehicle sets. Thus, m4nfo not only supports the traditional approach with explicitly using price/cost factors and base cost multipliers, but offers a new strategy of 'real' price and cost handling.
To do so, in a first step, m4nfo calculates the needed base cost factor (see tables) to properly represent the price for the most expensive vehicle of a set (by functions maxengineprice() and maxwagonprice()), and then calculates correct price factors for every other vehicle using this base cost factor by property function price(), see example below.
Needless to say that prices entered that way still rely on game difficulty settings and inflation.
| Function | Description |
| setcurrency(<Currency>) | Currency to be used for price/cost calculations |
| maxengineprice(<Dword>) | Highest price for an engine in vehicle set |
| maxwagonprice(<Dword>) | Highest price for a coach or freight wagon in vehicle set |
| maxenginecost(<Dword>) | Highest running cost for an engine in vehicle set |
| maxwagoncost(<Dword>) | Highest running cost for a coach or freight wagon in vehicle set |
This function sets the currency to be used for price/cost calculations. Supported currencies are as follows:
| Currency | Description | Factor vs GBP |
| ATS | Austrian Schilling | 27 |
| BEF | Belgian Franc | 81 |
| CHF | Swiss Franc | 2 |
| CZK | Czech Koruna | 41 |
| DEM | German Mark | 4 |
| DKK | Danish Krone | 11 |
| ESP | Spanish Peseta | 333 |
| EUR | Euro | 2 |
| FIM | Finnish Markka | 12 |
| FRF | French Franc | 13 |
| GBP | British pound | 1 |
| GRD | Greek Drachma | 681 |
| HUF | Hungarian Forint | 378 |
| ITL | Italian Lira | 3873 |
| JPY | Japanese Yen | 220 |
| NLG | Dutch Guilder | 4 |
| NOK | Norwegian Krona | 12 |
| PLN | Polish Złoty | 6 |
| RUR | Russian Ruble | 50 |
| SEK | Swedish Krona | 13 |
| SKK | Slovak Koruna | 60 |
| USD | US Dollar | 2 |
This function must be used before functions maxengineprice(), maxwagonprice(), maxenginecost(), and maxwagoncost().
maxengineprice(<Dword>), maxwagonprice(<Dword>)
maxenginecost(<Dword>), maxwagoncost(<Dword>)
These functions have to be used to set price and cost ranges for engine vehicles and wagons, accordingly. Parameters must be the highest prices/costs for vehicles in the set. Parameter values may use 'digit grouping', i.e. "10'000", "10.000" and "10 000" are allowed, but no commas as delimiters!
To provide a proper mapping of prices and costs onto TTD's base costs, parameters for these four functions are limited:
| Function | GBP | USD | DEM | FRF | ESP | maxengineprice | 51'200'000 | 102'400'000 | 204'800'000 | 665'600'000 | 17'049'600'000 |
| maxenginecost | 614'400 | 1'228'800 | 2'457'600 | 7'987'200 | 204'595'200 |
| maxwagonprice | 256'000 | 512'000 | 1'024'000 | 3'328'000 | 85'248'000 |
| maxwagoncost | 204'800 | 409'600 | 819'200 | 2'662'400 | 68'198'400 |
These four functions return base cost multipliers, to be used inside function basecost(), see example below.
As can be seen, functions maxengineprice()/maxenginecost() and maxwagonprice()/maxwagoncost() need to be used to set the correct base cost multiplicators. You might use function eval() to modify the base cost multiplicators returned by said functions.
Please note that function enginetype() implicitly defines base costs to be used for said vehicle.
It is possible to set real prices dynamically by CB_PROP and helper functions setengineprice(), setwagonprice(), setenginecost(), and setwagoncost().
In case of distributed source files, it is important to "import" price and cost factors previously calculated by functions maxengineprice()/maxwagonprice() and maxenginecost()/maxwagoncost().
setcurrency(DEM) // prices & costs in D-Mark
// purchase prices
skipif(2, getowngrfparameter(1),!=,0)
// "low" ::= parameter1 == 0
basecost(
{BUILD_ENGINES, eval(maxengineprice(3'000'000) / 2)},
{BUILD_WAGONS, eval(maxwagonprice(500'000) / 2)}
)
skipif(2, getowngrfparameter(1),!=,2)
// "high" ::= parameter1 == 2
basecost(
{BUILD_ENGINES, eval(maxengineprice(3'000'000) * 2)},
{BUILD_WAGONS, eval(maxwagonprice(500'000) * 2)}
)
// "normal" ::= parameter1 == 1
skipif(2, getowngrfparameter(1),!=,1)
basecost(
{BUILD_ENGINES, maxengineprice(3'000'000)},
{BUILD_WAGONS, maxwagonprice(500'000)}
)
// running costs
skipif(2,getowngrfparameter(2),!=,0)
// "low" ::= parameter2 == 0
basecost(
{RUN_ENGINES, eval(maxenginecost(200'000) / 2)},
{RUN_WAGONS, eval(maxwagoncost(10'000) / 2)}
)
skipif(2,getowngrfparameter(2),!=,2)
// "high" ::= parameter2 == 2
basecost(
{RUN_ENGINES, eval(maxenginecost(200'000) * 2)},
{RUN_WAGONS, eval(maxwagoncost(10'000) * 2)}
)
// "normal" ::= parameter2 == 1 // *16 ; *2
skipif(2, getowngrfparameter(2),!=,1)
basecost(
{RUN_ENGINES, maxenginecost(200'000)},
{RUN_WAGONS, maxwagoncost(10'000)},
)
...
definevehicle(_V100, {"V 100 / 212 (DB)"},
newgraphics()
lifecycle(1-1-1962, 1990, 2010)
enginetype(DIESEL) // traction type & cost base
...
price(500'000)
runningcost(25'000)
)
...
definevehicle(_PDISTLONG, {"Passenger coach (main line)"},
newgraphics()
lifecycle(1-1-1950, 2040, 2050)
enginetype(COACH)
...
price(56'000)
runningcost(2'800)
)
setengineprice(<Dword>), setwagonprice(<Dword>), setenginecost(<Dword>), setwagoncost(<Dword>)