The International Simutrans Forum

 

Author Topic: How are cargo revenues calculated  (Read 3925 times)

0 Members and 1 Guest are viewing this topic.

Offline DrSuperGood

  • Dev Team
  • Devotee
  • *
  • Posts: 2727
  • Languages: EN
How are cargo revenues calculated
« on: December 15, 2015, 07:20:44 AM »
Quote
There is an even stranger division later on. The formula you presented is not the whole thing.
Possibly, although the results seemed pretty accurate. Lets enlighten ourselves about how the algorithm works together just to be sure.

For this demonstration let us assume pak64 coal. We all love coal and it makes far too much money.

Let us look at how coal is declared. It uses the name "Kohle" because it must have been declared when Simutrans was still using German as its main language.
Quote
obj=good
name=Kohle
MapColor=128
metric=tonnen
catg=2
value=210
speed_bonus=2
weight_per_unit=1000
This translates into the following in game in the goods list when shipped at speedbonus speed (0% setting).
Quote
Revenue: 0.70
% Bonus: = 2%
Weight: 1000kg
One can immediately notice something is strange with this. Although the percent bonus and weight translates directly in game, the "value" does not. This means there is some value scaling going on. Let us work this constant out just for piece of mind.
Code: [Select]
(Revenue) * x = (value)
0.70 * x = 210
x = 210 / 0.70
x = 300
So if we divide value by 300 we should be getting the in game value. A quick test with Passengers and Mail shows this to be the case.

The scaling is done with...
Code: [Select]
waren[i]->value = (uint16)((long_base_value*multiplier)/1000l);
Where multiplier is usually defined as 1000, with exception of if beginner mode is used. This means that the value is the same as provided in the pakset at this stage, which is 300 times bigger than the final value.

The calculation starts with...
Code: [Select]
const sint32 kmh_base = (100 * speedkmh) / ref_kmh - 100;
The multiply by 100 here is clearly some scaling factor. Without it the integer division will produce nonsense results. Why 100 was chosen instead of some binary value (which should be faster) is unclear and probably down to not knowing about fixed point numbers in computers.

Given a case of 0 speed, speedbonus speed and 2 * speedbonus speed we get the following out...
Quote
0 : -100 -> -1
1 : 0 -> 0
2 : 100 -> 1

Next the following is used...
Code: [Select]
const sint32 grundwert_bonus = 1000+kmh_base*besch->get_speed_bonus();      // speed bonus factor
We now multiply the previous value by speed bonus.
Quote
0 : -200 -> -2
1 : 0 -> 0
2 : 200 -> 2
It is then added to 1000. This clearly represents the logical value of 1 since we are adding a bonus to a multiplier. Since our previous ones used a scaling of 100, their logical values can be divided by 10 when viewed like this (where the magic 10 constant comes from).
Quote
0 : 800 -> 0.8
1 : 1000 -> 1.0
2 : 1200 -> 1.2

Next up...
Code: [Select]
return besch->get_preis() * (grundwert128 > grundwert_bonus ? grundwert128 : grundwert_bonus);
Firstly this clamps the previous result to a minimum. This minimum comes from game settings so can be largely ignored.

Here it is for people to see...
Quote
# lowest possible income with speedbonus (1000=1) default 125
bonus_basefactor = 125
So applying the clamp gives us...
Quote
0 : 800 -> 0.8
1 : 1000 -> 1.0
2 : 1200 -> 1.2
It only affects cargo with a % bonus larger than 10 it seems...

Ok now to multiply by coal to get the currency. I am writing the actual currency output for clarity.
Quote
0 : 168000 -> 0.56
1 : 210000 -> 0.70
2 : 252000 -> 0.84

This value is then used by convoys to work out revenue for all their cargo.
Code: [Select]
// calculate freight revenue incl. speed-bonus
if (ware.get_besch() != last_freight) {
freight_revenue = ware_t::calc_revenue(ware.get_besch(), get_besch()->get_waytype(), cnv_kmh);
last_freight = ware.get_besch();
}
const sint64 price = freight_revenue * (sint64)dist * (sint64)ware.menge;

// sum up new price
value += price;

Then finally it is transformed into something else...
Code: [Select]
// Hajo: Rounded value, in cents
return (value+1500ll)/3000ll;
Pushing our values through this
Quote
0 : 56 -> 0.56
1 : 70 -> 0.70
2 : 84 -> 0.84
Behold, the value out is simucents! So the value declared in files is in 1/3 simucent units. On top of this the revenue is computed with an extra 1000 scaling for computational accuracy.

Why something like Q.10 was not used and why cargo values are in 1/3 of a simucent I do not know.

As such speed bonus currently is defined as the % increase in revenue for a 10% increase in average maximum speed realitive to speedbonus speed.

Offline Frank

  • Inactive/Retired
  • *
  • Posts: 1431
  • Languages: DE
Re: How are cargo revenues calculated
« Reply #1 on: December 15, 2015, 04:07:04 PM »
please split the thread

Offline Ters

  • Coder/patcher
  • Devotee
  • *
  • Posts: 5542
  • Languages: EN, NO
Re: How are cargo revenues calculated
« Reply #2 on: December 15, 2015, 04:48:16 PM »
Code: [Select]
const sint32 kmh_base = (100 * speedkmh) / ref_kmh - 100;
The multiply by 100 here is clearly some scaling factor. Without it the integer division will produce nonsense results. Why 100 was chosen instead of some binary value (which should be faster) is unclear and probably down to not knowing about fixed point numbers in computers.
It's percent, plain and simple. If speedkmh is 101 and ref_kmh is 100, kmh_base is 1. Which means speed is 1% above the reference speed. Simutrans can't store it as 0.01, as it's doing integer math only at these depths.

[...]why cargo values are in 1/3 of a simucent I do not know.
There used to be a comment, by prissi I think, which also asked that question. Maybe it was easier to balance something by doing a division in the code, rather than change all the dat files? Now, it's just a relic, just like how we use a 12-based counting system for angles and time, and perhaps also other lingering old units of measurements.

Offline DrSuperGood

  • Dev Team
  • Devotee
  • *
  • Posts: 2727
  • Languages: EN
Re: How are cargo revenues calculated
« Reply #3 on: December 16, 2015, 04:36:25 AM »
Quote
It's percent, plain and simple. If speedkmh is 101 and ref_kmh is 100, kmh_base is 1. Which means speed is 1% above the reference speed. Simutrans can't store it as 0.01, as it's doing integer math only at these depths.
However it could have been a fixed point. Potentially more precision and retains its fractional value (from a human understanding point of view) so in theory should be more readable.

That still does not change that the % bonus for cargo is the % increase in revenue for a 10% increase in average maximum speed relative to speedbonus speed. This should probably be mentioned in the game help.

Quote from:
Should be?
% Bonus: The percent change in cargo revenue per 10% of current speedbonus speed change to convoy average maximum speed.
« Last Edit: December 16, 2015, 04:53:22 AM by DrSuperGood »

Offline Ters

  • Coder/patcher
  • Devotee
  • *
  • Posts: 5542
  • Languages: EN, NO
Re: How are cargo revenues calculated
« Reply #4 on: December 16, 2015, 06:59:06 AM »
However it could have been a fixed point. Potentially more precision and retains its fractional value (from a human understanding point of view) so in theory should be more readable.

I disagree. Having 100 in there what was made be understand what was going on, because it made the formula recognizable. Of course, one could compensate by actually documenting how this works. As you mention next, it's not even explained what the basic premise is.