FIRS cargo payment calculation
Moderator: OpenTTD Developers
FIRS cargo payment calculation
Hi, can someone give me some insight on how the cargo payment in FIRS new grf is calculated?
I got this process worked out in vanilla open ttd, using this formula and cargo parameters (https://wiki.openttd.org/Cargo_income)
for example:
Passengers: base=3185, c1 days=0, c2 days=24
you transfer 200 passengers across 100 tiles in 25 days (with loading/unloading) => 25>c1+c2, so time factor would be 255-2*(25-0)+24 = 229
therefore payment: 3185 (base) * 200 (passengers) * 100 (tiles) * 229 (time factor) / 2^21 = 6,955.77 GBP
from my observations in-game, it is correct
As for FIRS, I found out there's some different approach used, the payment parameters don't look like in base version at all (eg for price_factor='109' for ACID in https://hg.openttdcoop.org/firs/files/9 ... src/cargos)
I know the document says price_factor='109' is for 10 units of cargo across 20 tiles
Still, no matter how I try to tackle the problem I can't get those numbers right
Can someone enlighten me?
Thanks!
I got this process worked out in vanilla open ttd, using this formula and cargo parameters (https://wiki.openttd.org/Cargo_income)
for example:
Passengers: base=3185, c1 days=0, c2 days=24
you transfer 200 passengers across 100 tiles in 25 days (with loading/unloading) => 25>c1+c2, so time factor would be 255-2*(25-0)+24 = 229
therefore payment: 3185 (base) * 200 (passengers) * 100 (tiles) * 229 (time factor) / 2^21 = 6,955.77 GBP
from my observations in-game, it is correct
As for FIRS, I found out there's some different approach used, the payment parameters don't look like in base version at all (eg for price_factor='109' for ACID in https://hg.openttdcoop.org/firs/files/9 ... src/cargos)
I know the document says price_factor='109' is for 10 units of cargo across 20 tiles
Still, no matter how I try to tackle the problem I can't get those numbers right
Can someone enlighten me?
Thanks!
Re: FIRS cargo payment calculation
income calculation for NewGRF cargos can be found here: https://newgrf-specs.tt-wiki.net/wiki/A ... 11.2C12.29
Re: FIRS cargo payment calculation
Hi, thanks a lot for the link that's immensely helpful
Still, the numbers don't match, using this formula:
income=((((distance/2) * timefactor * amount_moved) >> 7) * cargopricefactor) >> 13
continuing previous example, in FIRS we have:
Passengers: pricefactor=105, c1 days=0, c2 days=22
you transfer 200 passengers across 100 tiles in 25 days (with loading/unloading) => 25>c1+c2, so time factor would be 255-(25-0)-(25-22-0)=227
therefore payment:
step 1) 50 (distance in tiles/2) * 227 (timefactor) * 100 (passengers) = 1,135,000.00
step 2) shift right 1,135,000.00 by 7 bits => 8867 (i'm using excel BITRSHIFT and checked with some online bit calculator)
step 3) 8867 * 105 (cargo price factor) = 931,035.00
step 4) shift right 931,035.00 by 13 bits => 113.00 GBP profit per 1 trip
that's way too low
where's the catch?
Still, the numbers don't match, using this formula:
income=((((distance/2) * timefactor * amount_moved) >> 7) * cargopricefactor) >> 13
continuing previous example, in FIRS we have:
Passengers: pricefactor=105, c1 days=0, c2 days=22
you transfer 200 passengers across 100 tiles in 25 days (with loading/unloading) => 25>c1+c2, so time factor would be 255-(25-0)-(25-22-0)=227
therefore payment:
step 1) 50 (distance in tiles/2) * 227 (timefactor) * 100 (passengers) = 1,135,000.00
step 2) shift right 1,135,000.00 by 7 bits => 8867 (i'm using excel BITRSHIFT and checked with some online bit calculator)
step 3) 8867 * 105 (cargo price factor) = 931,035.00
step 4) shift right 931,035.00 by 13 bits => 113.00 GBP profit per 1 trip
that's way too low
where's the catch?
Re: FIRS cargo payment calculation
have you considered the conversion from game days (74 ticks) to cargo age units (185 ticks, can be changed by some vehicles)? if you're transporting for 25 game days, the cargo only aged 10 times, not 25 times.
Re: FIRS cargo payment calculation
no, but that's not it
that only means cargo payments function counts game days in "2.5 day" batches => if your cargo travelled exactly 16 game days, you'd get a payment for 17.5 days (2.5x7 batches) - that's how I understand it at least and it made sense with vanilla game calculations
here, in firs, the error is more of a factor of 100x than 2x
that only means cargo payments function counts game days in "2.5 day" batches => if your cargo travelled exactly 16 game days, you'd get a payment for 17.5 days (2.5x7 batches) - that's how I understand it at least and it made sense with vanilla game calculations
here, in firs, the error is more of a factor of 100x than 2x
Re: FIRS cargo payment calculation
no, that's not how that works. if the cargo was loaded 16 days ago, then "days_in_transit" in all the relevant formulas will be 6drsh1 wrote:if your cargo travelled exactly 16 game days, you'd get a payment for 17.5 days (2.5x7 batches) - that's how I understand it at least
it could be that firs hides some factor elsewhere in its code... have you tried other industry GRFs?here, in firs, the error is more of a factor of 100x than 2x
Re: FIRS cargo payment calculation
But it only applies to new grfs then? I'm sure I got numbers for vanilla game right and this wasn't the case there.Eddi wrote:no, that's not how that works. if the cargo was loaded 16 days ago, then "days_in_transit" in all the relevant formulas will be 6
Plus, I investigated the cargo payment graphs ingame and it seems you're right - the graphs are shifted. By default, the graph should be a downward trending line with turning points in "day1" and "day2" value where slope becomes steeper. With FIRS active, it looks like the turning points are in values for "day1", "day2" x2.5 than in documentation (eg for wood day1=about 60 when it should be 24)
As for the calculation, I run through code and found a formula that makes even less sense for me:
Code: Select all
Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type)
{
/* non-important */
const CargoSpec *cs = CargoSpec::Get(cargo_type);
if (!cs->IsValid()) {
/* User changed newgrfs and some vehicle still carries some cargo which is no longer available. */
return 0;
}
/* Use callback to calculate cargo profit, if available */
/* starts here */
if (HasBit(cs->callback_mask, CBM_CARGO_PROFIT_CALC)) {
/* bitwise sum of distance, amount moved, transit days */
uint32 var18 = min(dist, 0xFFFF) | (min(num_pieces, 0xFF) << 16) | (transit_days << 24);
/* CBID_CARGO_PROFIT_CALC = 0x39 = 57 */
uint16 callback = GetCargoCallback(CBID_CARGO_PROFIT_CALC, 0, var18, cs);
/* apply GB function to "callback" */
/* GB can be found https://github.com/OpenTTD/OpenTTD/blob/18ca3e8660f90737d672b6780301ff4b998df56f/src/core/bitmath_func.hpp */
/* GB (x, s, n) = (x << s) & ( 1U << n) - 1) where 1U << 1 = 1 = 00000001, 1U << 2 = 2 = 00000010 etc * /
if (callback != CALLBACK_FAILED) {
int result = GB(callback, 0, 14);
/* Simulate a 15 bit signed value */
/* if "callback" is max value for 14bits, lower it by 1, result = 16384-1 = 16383; this is max "result" */
if (HasBit(callback, 14)) result -= 0x4000;
/* "The result should be a signed multiplier that gets multiplied
* by the amount of cargo moved and the price factor, then gets
* divided by 8192." */
return result * num_pieces * cs->current_payment / 8192;
}
}
Re: FIRS cargo payment calculation
That code just implements a call to https://newgrf-specs.tt-wiki.net/wiki/C ... s_.2839.29 Stuff gets encoded in a single variable with some shifting and capping at the upper limit, and the result gets decoded again for the signed 14 bit number, which looks a bit weird, since C/C++ doesn't have native 14 bit numbers.
Otherwise, it just does what the description of the call says.
Otherwise, it just does what the description of the call says.
Being a retired OpenTTD developer does not mean I know what I am doing.
- andythenorth
- Tycoon
- Posts: 5705
- Joined: 31 Mar 2007 14:23
- Location: Lost in Music
Re: FIRS cargo payment calculation
I think you've got CB 39 there
https://newgrf-specs.tt-wiki.net/wiki/C ... s_.2839.29
AFAIK, FIRS doesn't use CB 39.
I am watching this with interest. I've got no useful information to add, but I'm not convinced that FIRS cargo payments are working as I want them to. They were set a long time ago, and there's been no attention to them since then.

AFAIK, FIRS doesn't use CB 39.
I am watching this with interest. I've got no useful information to add, but I'm not convinced that FIRS cargo payments are working as I want them to. They were set a long time ago, and there's been no attention to them since then.
FIRS Industry Replacement Set (released) | HEQS Heavy Equipment Set (trucks, industrial trams and more) (finished)
Unsinkable Sam (ships) (preview released) | CHIPS Has Improved Players' Stations (finished)
Iron Horse ((trains) (released) | Termite (tracks for Iron Horse) (released) | Busy Bee (game script) (released)
Road Hog (road vehicles and trams) (released)
Unsinkable Sam (ships) (preview released) | CHIPS Has Improved Players' Stations (finished)
Iron Horse ((trains) (released) | Termite (tracks for Iron Horse) (released) | Busy Bee (game script) (released)
Road Hog (road vehicles and trams) (released)
Re: FIRS cargo payment calculation
thanks for feedback guys 
later I'll try to convert the code to somewhat more user-friendly math formulas and I'll show you why the "callback approach" makes no sense to me

later I'll try to convert the code to somewhat more user-friendly math formulas and I'll show you why the "callback approach" makes no sense to me
Re: FIRS cargo payment calculation
ok guys I think I got this
actually, the whole thing is astonishingly simple. the correct formula is:
CARGO PRICE from the in-game graph /200 * AMOUNT * DISTANCE
where CARGO PRICE is calculated followingly:
FIRS pricefactor * timefactor scaled with 2,5days correction
^ FIRS pricefactor is price_factor value from https://hg.openttdcoop.org/firs/files/9 ... src/cargos. has to be divided by 200 because it's a payment for transporting 10t across 20 tiles
^ timefactor is calculated in exactly the same way as in base game (or in the code chunk above) ONLY the in-game days used for calculation must be divided by 2.5 (new grfs feature?)
example:
we transport 360,000 L of MILK (price_factor = 145, days1= 0, days2 = 16) across 131 tiles within 54 days (with loading/unloading)
^ effective days are 54/2.5 = 21.6 -> 22 (i'm not sure how the game handles rounding - I use mathematical rounding)
^ .. so the timefactor for 22 days is 255-(22-0)-(22-0-16)= 227
^ CARGO PRICE would be 145 (price_factor) * 227 (timefactor) / 255 = 129,08 GBP => this is the approximate payment rate you can read from in-game graph for transporting MILK within 22 days
^ 129.08 / 200 (10t across 20 tiles) * 360 (amount) * 131 (distance) = 30,437.06 GBP which is very close to real game payment
now, what part of code does this - I have no idea
actually, the whole thing is astonishingly simple. the correct formula is:
CARGO PRICE from the in-game graph /200 * AMOUNT * DISTANCE
where CARGO PRICE is calculated followingly:
FIRS pricefactor * timefactor scaled with 2,5days correction
^ FIRS pricefactor is price_factor value from https://hg.openttdcoop.org/firs/files/9 ... src/cargos. has to be divided by 200 because it's a payment for transporting 10t across 20 tiles
^ timefactor is calculated in exactly the same way as in base game (or in the code chunk above) ONLY the in-game days used for calculation must be divided by 2.5 (new grfs feature?)
example:
we transport 360,000 L of MILK (price_factor = 145, days1= 0, days2 = 16) across 131 tiles within 54 days (with loading/unloading)
^ effective days are 54/2.5 = 21.6 -> 22 (i'm not sure how the game handles rounding - I use mathematical rounding)
^ .. so the timefactor for 22 days is 255-(22-0)-(22-0-16)= 227
^ CARGO PRICE would be 145 (price_factor) * 227 (timefactor) / 255 = 129,08 GBP => this is the approximate payment rate you can read from in-game graph for transporting MILK within 22 days
^ 129.08 / 200 (10t across 20 tiles) * 360 (amount) * 131 (distance) = 30,437.06 GBP which is very close to real game payment
now, what part of code does this - I have no idea

Re: FIRS cargo payment calculation
for the travel time, this is always rounded down, as it is a counter that is increased by 1 in a regular interval. if the interval hasn't expired, there will be no counting updrsh1 wrote:(i'm not sure how the game handles rounding - I use mathematical rounding)
Who is online
Users browsing this forum: No registered users and 18 guests