FIRS cargo payment calculation

OpenTTD is a fully open-sourced reimplementation of TTD, written in C++, boasting improved gameplay and many new features.

Moderator: OpenTTD Developers

Post Reply
drsh1
Engineer
Engineer
Posts: 7
Joined: 04 Mar 2019 12:10

FIRS cargo payment calculation

Post by drsh1 »

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!
Eddi
Tycoon
Tycoon
Posts: 8258
Joined: 17 Jan 2007 00:14

Re: FIRS cargo payment calculation

Post by Eddi »

income calculation for NewGRF cargos can be found here: https://newgrf-specs.tt-wiki.net/wiki/A ... 11.2C12.29
drsh1
Engineer
Engineer
Posts: 7
Joined: 04 Mar 2019 12:10

Re: FIRS cargo payment calculation

Post by drsh1 »

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?
Eddi
Tycoon
Tycoon
Posts: 8258
Joined: 17 Jan 2007 00:14

Re: FIRS cargo payment calculation

Post by Eddi »

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.
drsh1
Engineer
Engineer
Posts: 7
Joined: 04 Mar 2019 12:10

Re: FIRS cargo payment calculation

Post by drsh1 »

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
Eddi
Tycoon
Tycoon
Posts: 8258
Joined: 17 Jan 2007 00:14

Re: FIRS cargo payment calculation

Post by Eddi »

drsh1 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
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
here, in firs, the error is more of a factor of 100x than 2x
it could be that firs hides some factor elsewhere in its code... have you tried other industry GRFs?
drsh1
Engineer
Engineer
Posts: 7
Joined: 04 Mar 2019 12:10

Re: FIRS cargo payment calculation

Post by drsh1 »

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
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.

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;
		}
	}
	
I'm not really skilled in C++ so I may be making some mistakes here, I can elaborate if someone's willing to check me up with this
Alberth
OpenTTD Developer
OpenTTD Developer
Posts: 4763
Joined: 09 Sep 2007 05:03
Location: home

Re: FIRS cargo payment calculation

Post by Alberth »

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.
Being a retired OpenTTD developer does not mean I know what I am doing.
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5656
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: FIRS cargo payment calculation

Post by andythenorth »

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.
drsh1
Engineer
Engineer
Posts: 7
Joined: 04 Mar 2019 12:10

Re: FIRS cargo payment calculation

Post by drsh1 »

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
drsh1
Engineer
Engineer
Posts: 7
Joined: 04 Mar 2019 12:10

Re: FIRS cargo payment calculation

Post by drsh1 »

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 :)
Eddi
Tycoon
Tycoon
Posts: 8258
Joined: 17 Jan 2007 00:14

Re: FIRS cargo payment calculation

Post by Eddi »

drsh1 wrote:(i'm not sure how the game handles rounding - I use mathematical rounding)
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 up
Post Reply

Return to “General OpenTTD”

Who is online

Users browsing this forum: No registered users and 4 guests