Orthogonal Income Patch

Forum for technical discussions regarding development. If you have a general suggestion, problem or comment, please use one of the other forums.

Moderator: OpenTTD Developers

User avatar
SquireJames
Tycoon
Tycoon
Posts: 1863
Joined: 07 Aug 2004 11:56
Skype: squirejames5
Location: Stoke-on-Trent
Contact:

Re: Orthogonal Income Patch

Post by SquireJames »

This will still result in the age old "nothing competes with Airlines" especially in Multiplayer.
Image
Wahazar
Tycoon
Tycoon
Posts: 1451
Joined: 18 Jan 2014 18:10

Re: Orthogonal Income Patch

Post by Wahazar »

SquireJames wrote:This will still result in the age old "nothing competes with Airlines" especially in Multiplayer.
Yes. But it is not my fault, that game is addicted to airplanes. I have some ideas, how to balance it, but this thread is not about.

I need little advice, how to query available to everyone, already introduced and not expired engine.
I tried to use

Code: Select all

FOR_ALL_ENGINES(e)    if (e->flags & ENGINE_AVAILABLE)

but seems that it returns all engines available for certain climate, not only those available for current date.
Is it any easy way to query engines which can be purchased by any company?
Formerly known as: McZapkie
Projects: Reproducible Map Generation patch, NewGRFs: Manpower industries, PolTrams, Polroad, 600mm narrow gauge, wired, ECS industry extension, V4 CEE train set, HotHut.
Another favorite games: freeciv longturn, OHOL/2HOL.
User avatar
planetmaker
OpenTTD Developer
OpenTTD Developer
Posts: 9432
Joined: 07 Nov 2007 22:44
Location: Sol d

Re: Orthogonal Income Patch

Post by planetmaker »

McZapkie wrote:
SquireJames wrote:This will still result in the age old "nothing competes with Airlines" especially in Multiplayer.
Yes. But it is not my fault, that game is addicted to airplanes. I have some ideas, how to balance it, but this thread is not about.

I need little advice, how to query available to everyone, already introduced and not expired engine.
I tried to use

Code: Select all

FOR_ALL_ENGINES(e)    if (e->flags & ENGINE_AVAILABLE)

but seems that it returns all engines available for certain climate, not only those available for current date.
Is it any easy way to query engines which can be purchased by any company?
The build vehicle code must obviously know, so look there: (build_vehicle_gui.cpp:1120). This will build the actual list of available engines. It's a method of the build vehicle window (similar exist for other vehicle types):

Code: Select all

	void GenerateBuildRoadVehList()
	{
		EngineID sel_id = INVALID_ENGINE;

		this->eng_list.Clear();

		const Engine *e;
		FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
			EngineID eid = e->index;
			if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
			if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue;
			*this->eng_list.Append() = eid;

			if (eid == this->sel_engine) sel_id = eid;
		}
		this->sel_engine = sel_id;
	}
It seems to use IsEngineBuildable (engine.cpp:1046). This checks availability for each engine:

Code: Select all

bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Don't re-implement that routine.
(I didn't know by heart either. Usage of the xterms and editor's grep function quickly gives the answer. Make use of it :) I simply started to grep the whole source for 'purchase' :) )
Wahazar
Tycoon
Tycoon
Posts: 1451
Joined: 18 Jan 2014 18:10

Re: Orthogonal Income Patch

Post by Wahazar »

planetmaker wrote:
McZapkie wrote: Is it any easy way to query engines which can be purchased by any company?
It seems to use IsEngineBuildable (engine.cpp:1046). This checks availability for each engine:

Code: Select all

bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
I know about this routine, but it need to put CompanyID.
I need to know every engines potentially available for any company, even if no company is established.
Should I use OWNER_DEITY?
Formerly known as: McZapkie
Projects: Reproducible Map Generation patch, NewGRFs: Manpower industries, PolTrams, Polroad, 600mm narrow gauge, wired, ECS industry extension, V4 CEE train set, HotHut.
Another favorite games: freeciv longturn, OHOL/2HOL.
User avatar
planetmaker
OpenTTD Developer
OpenTTD Developer
Posts: 9432
Joined: 07 Nov 2007 22:44
Location: Sol d

Re: Orthogonal Income Patch

Post by planetmaker »

McZapkie wrote:
planetmaker wrote:
McZapkie wrote: Is it any easy way to query engines which can be purchased by any company?
It seems to use IsEngineBuildable (engine.cpp:1046). This checks availability for each engine:

Code: Select all

bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
I know about this routine, but it need to put CompanyID.
I need to know every engines potentially available for any company, even if no company is established.
Should I use OWNER_DEITY?
Availability *does* differ between companies. The preview is given only to one company. And that can build that vehicle one or two earlier than anyone else.

Also: if you're interested in existing and possibly existing vehicles, availability does not necessarily cut it: vehicles may be not available anymore - but they might still roam the tracks, road, air and oceans.
Wahazar
Tycoon
Tycoon
Posts: 1451
Joined: 18 Jan 2014 18:10

Re: Orthogonal Income Patch

Post by Wahazar »

planetmaker wrote: Availability *does* differ between companies. The preview is given only to one company.
I know, but need "standard" availability, without all those "preview" bonuses.
I want to take into account all vehicles available to purchase in a given time without previews
and without those old, declined from purchase list.
I build such query:

Code: Select all

	FOR_ALL_CARGOSPECS(update_cargo) {
		engine_count = 1; 			
		roll_avg = 0;
		FOR_ALL_ENGINES(e) {
			eid = e->index;
			if (IsEngineBuildable(eid, VEH_TRAIN, OWNER_DEITY)) {
				maxs = e->GetDisplayMaxSpeed();
				if  (maxs > 0) {
					uint32 refit_mask = GetUnionOfArticulatedRefitMasks(eid, true); // & _standard_cargo_mask;
					if (HasBit(refit_mask, update_cargo->Index()))  {
						engine_count++;
						roll_avg += maxs;
						}
//...
		update_cargo->average_max_speed = roll_avg / engine_count;
but I observe strange numbers for maxs variable and resultant average_max_speed.
It works fine with VEH_SHIP and VEH_ROAD, but not with VEH_TRAIN.
Of course, to avoid "0" fot wagons, I changed table/engines.h and defined max speed for all wagons: 265 for standard, 336 for monorail, 640 for maglev.
If I start in 1950, average_max_speed for all is 413 km/h -?
In 2040, average_max_speed are even lower - 394, except oil which is still 413. Note, that only VEH_TRAIN are taken into account,
in fact only train cars, no locomotives.

Any advise, what is messed up?
Formerly known as: McZapkie
Projects: Reproducible Map Generation patch, NewGRFs: Manpower industries, PolTrams, Polroad, 600mm narrow gauge, wired, ECS industry extension, V4 CEE train set, HotHut.
Another favorite games: freeciv longturn, OHOL/2HOL.
Eddi
Tycoon
Tycoon
Posts: 8272
Joined: 17 Jan 2007 00:14

Re: Orthogonal Income Patch

Post by Eddi »

obviously, changing table/engines.h is the wrong way, because NewGRFs may still give you 0 speed vehicles. also, you need to take wagonspeedlimits setting into account.

why do you initialize engine count with 1 instead of 0?

also, a matter of style:
use

Code: Select all

if (!condition) continue;
to avoid nesting ifs

and eid and maxs should be declared as local variables to the block.
User avatar
adf88
Chief Executive
Chief Executive
Posts: 644
Joined: 14 Jan 2008 15:51
Location: PL

Re: Orthogonal Income Patch

Post by adf88 »

I did my own research and came to conclusion that present formula for calculating cargo income is really OK. It has really nice properties. The bump on the "income vs distance" plot is OK too: lengthening a route increases profit but at some point the profit begin to decrease because cargo is getting too old on such long routes. Fine for me.

Perhaps one thing may be corrected - the bump could be more slight. It can be achieved by altering the "time vs income" formula (known as "cargo payment rates"). When the factor reaches the magic limit 32, decaying should start slowing down and slightly evaporate in the end. Something like this:
Income_vs_time.png
Income_vs_time.png (9.94 KiB) Viewed 2170 times
(compare to http://wiki.openttd.org/Cargo_income, first plot)

I also investigated the new McZapkie's formula (the one from the patch) and I must say it's really bad. See:
cargo_income.png
(25.51 KiB) Downloaded 4 times
There are many issues.

McZapkie, perhaps you didn't test your formula very well, probably because you are using Excel which is not good for the task. I advise you to use some mathematical tool like Matlab/Octave. I did my plots in Octave. The script is short and clear:
cargo_income.m.zip
(1.07 KiB) Downloaded 62 times
:] don't worry, be happy and checkout my patches
Wahazar
Tycoon
Tycoon
Posts: 1451
Joined: 18 Jan 2014 18:10

Re: Orthogonal Income Patch

Post by Wahazar »

adf88 wrote:present formula for calculating cargo income is really OK
In my opinion it is not OK, especially if you play at large maps with low density of resources, or if start date is in at beginning of XIX century
(generally early start date need large and sparse map to bring proper scale for city size in later stages of the game).
It is problematic to make profitable long routes with ships and horse carriages (especially if infrastructure costs are on).
It is OK in 1950, but not in a dilligence era.
I can set running/maintenance costs low enough, but it will result in later unlimited growth of income - well known issue related to openttd economy.

Present formula is also not OK, because is not monotonic: in case of slow transport, you gain large profit for very short AND very long distances, and drop at medium distance.
Additionally there is issue with cargodist long distance hopping, mentioned elsewhere by KeldorKatarn.
adf88 wrote: I also investigated the new McZapkie's formula (the one from the patch) and I must say it's really bad. See:
cargo_income.png
Thank you for testing. If you mean payment vs time graph, it is valid only for original formula which rely on time and distance only.
My new older formula was using velocity, thus standard graph produces strange values
(velocity was very low for 20 tiles and 200 days).
Instead of this, income from 1 piece across 200 tiles would give more reliable values.

The real issue was predicted by Eddi - using exponential function without floats is overcomplicated,
with to many magic constants to play around.

-------------------------------------------------

Now I'm working on better and more compact model with payment calculations consist of two parts:
distant/velocity dependent part and time difference penalty part.

What we need for payment function is:

1. limited growth of payment vs distance
2. penalty, if delivery time is much longer then expected
3. payment ratio adapted to vehicle epoch.


My proposal is, for point 1, to make following formula income depend on distance d and cargo time in transit t
Image
- instead of substracting, use dividing.
(for readability I skipped amount and base constant)

Such formula is represented by olive-green below.
It is typical payment curve, it is compatible with old curve and is scalable with velocity.

For point 2 and 3, my proposal is to use old subtracting formula, however instead of cargo in transit time, use difference between
carried and expected transit time
:
Image
Expected transit time is calculated as manhattan distance between source and target, divided by rolling average speed specific for given cargo.
Rolling average speed will be updated every year as weighted average of available for such cargo vehicles and previous year average.
Weight of previous year average should be enough to accumulate changes over several years, instead of abrupt change when new fast model appear in purchase menu.

Resultant income is an multiplier of I(t,d) - growth curve 1. and possible penalty 2, where penalty P(t,d,v_cargo_avg)
depend on existing vehicle set.

Now, imagine 2-horse carriage in 1800. Instead of original orange line, you have superposition of growth curve 1 (olive-green line)
and penalty 2.
Image
You have eGRVTS set and Sailing Ships set, average speed for passengers is about 21 km/h.
Therefore, you can safely use 2-horse carriage (20 kmph) up to 500 tiles distance, see dotted light green line,
but of course you would be penalised if effective speed is low because horse is very old, or tired due to lack of sheds maintenance.
(however 4-horse carriage would be safer for long distances, because its maximal speed 26 kmph guarantee shorter trip then expected travel time, even in case of failures and other obstacles).
If your long/medium distance link is served correctly, nobody should complain if you are using horse power, if no-one invented steam train yet.
In a middle of XX century, if expected average speed is about 160 km/h, horse carriage can still be used only at low distances, as in original game (see solid light green line).

Please note, that calculating penalty as difference between expected and performed transit time, instead of plain transit time,
give you opportunities to design more sophisticated transport networks, for example if freight locomotive is faster then average coal speed,
saved time can be used to prioritising passenger trains (which must conquer with airplanes) prior to the freight trains.
(original game Cargodays1 parameter is very low to be significant for old payment model).
lengthening a route increases profit but at some point the profit begin to decrease because cargo is getting too old on such long routes
It is a common arguments - cargo is perishable, thus penalty must be proportional to the transit time.
Such arguing is not valid in a century long time scale, because "perishability" term is not fixed.
Nowadays we pay for fresh food delivered by airplanes. Because we have opportunity to do that.
Our ancestors paid for canned food delivered by ships and trains.
Their ancestors paid for grain, delivered by horse carriage and sail ships from Ukraine to Sweden, and salted herrings delivered in opposite way.

In my model payment adapt to the used vehicle set. I think this is better idea then infamous inflation.
Even if average cargo speed is elevated by airplanes/maglevs etc, you can still use slower means of transport, but in limited range.
Increase of "needs for speeds" ;) is not directly date-related, but newgrf set related.
If you have an unrealistic vehicle set with (for some reason) very slow futuristic vehicles, it should work fine ;)

PS: spreadsheet with new2 model is here:
https://docs.google.com/spreadsheet/ccc ... sp=sharing
PS2. I'm using google spreadsheets because they are easy to share. Personally I'm using Matlab and Origin, but not for www sharing.

=============================
Eddi wrote:obviously, changing table/engines.h is the wrong way, because NewGRFs may still give you 0 speed vehicles. also, you need to take wagonspeedlimits setting into account.
Of course, I done it just for testing purposes. I want to take wagon speed limits into account, pity that there is possibility to define 0 speed in newgrf. Both options are overlapping.
The best would be take locomotives (all) and powered units (refit matched) if wagon speed limits are off,
and wagons speeds, if on. But additional option of unlimited speed hardcoded in newgrf need to take locomotives into account
even if wagon limits are on.
Not a really big issue, it is an average speed including also other means of transport.
Formerly known as: McZapkie
Projects: Reproducible Map Generation patch, NewGRFs: Manpower industries, PolTrams, Polroad, 600mm narrow gauge, wired, ECS industry extension, V4 CEE train set, HotHut.
Another favorite games: freeciv longturn, OHOL/2HOL.
TadeuszD
Transport Coordinator
Transport Coordinator
Posts: 329
Joined: 07 Nov 2011 19:32
Location: PL

Re: Orthogonal Income Patch

Post by TadeuszD »

I discussed with McZapkie about the new income model on polish OTTD forum.

In my opinion the current income algorithm is not bad, but it realy needs some extensions for largest maps.
The simplest way to achieve interesting effects is slowing down the cargo ageing process for maps greater than 512 tiles. This solution is easy for implementation and effects will be easily predictable - no dependencies to vehicle parameters or limits... :idea:

BTW - this strange constant value 32 in current incoming rate algorithm should be changed to 0 (zero), because of abnormal high incomes generated on extremelly long distances... ;)
Image
Wahazar
Tycoon
Tycoon
Posts: 1451
Joined: 18 Jan 2014 18:10

Re: Orthogonal Income Patch

Post by Wahazar »

Eddi wrote:why do you initialize engine count with 1 instead of 0?
Because it is rolling average and previous value is taken into account (in future, there will be a weight parameter instead of 1).

But I encountered strange problem during wagons query.
If have following check (forgive my pascalish style, I will fix it later):

Code: Select all

FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
	eid = e->index;
	if (IsEngineBuildable(eid,  VEH_TRAIN, OWNER_DEITY)) {
		maxs = e->GetDisplayMaxSpeed();
		if  (maxs > 0) {
			int pe = Engine::Get(eid)->GetPower();
			uint32 refit_mask = GetUnionOfArticulatedRefitMasks(eid, true) & _standard_cargo_mask; 
					bool iscargo = HasBit(refit_mask, update_cargo->Index());
					if (_settings_game.vehicle.wagon_speed_limits) {   //count only vehicles refittable to cargo
						if (iscargo) {
							engine_count++;
							roll_avg += maxs;
						}
					}
					else if  ( ( (pe!=0) && !(e->CanCarryCargo()) ) || ((pe!=0) && iscargo ) ) {  //count lok || refittable dmu/emu
							engine_count++;   //locomotives counts instead of wagons
							roll_avg += maxs;
//....end of loops
If wagon_speed_limits is off, second part is take into account and works well - if I check engine_count, there is 3 for temperate, 1 for arctic etc.
In case of enabled wagon_speed_limits, engine_count should be 1 (there is one wagon for each cargo at the beginning),
but for passengers I got two, and for other cargo - three!
Where are hidden wagons?
Filtering in purchase menu shows predicted 1 type for each cargo.
Formerly known as: McZapkie
Projects: Reproducible Map Generation patch, NewGRFs: Manpower industries, PolTrams, Polroad, 600mm narrow gauge, wired, ECS industry extension, V4 CEE train set, HotHut.
Another favorite games: freeciv longturn, OHOL/2HOL.
Alberth
OpenTTD Developer
OpenTTD Developer
Posts: 4763
Joined: 09 Sep 2007 05:03
Location: home

Re: Orthogonal Income Patch

Post by Alberth »

TadeuszD wrote:In my opinion the current income algorithm is not bad, but it realy needs some extensions for largest maps.
Not perticularly aimed at you TadeuszD, but can anyone explain to me why you need longer routes in a bigger world?

I fail to understand the apparently assumed(?) 1-to-1 connection between big world and longer routes. Isn't a very viable alternative to simply have more short routes on a bigger world?
Just let the payment drop to 0 after say 256 or 512 tiles or so.


Even today in our fast real world, there are very few points in the world where all cargo of some type originates from or it brought to.
lugo
Engineer
Engineer
Posts: 100
Joined: 12 Oct 2010 13:55

Re: Orthogonal Income Patch

Post by lugo »

Alberth wrote:I fail to understand the apparently assumed(?) 1-to-1 connection between big world and longer routes. Isn't a very viable alternative to simply have more short routes on a bigger world?
Just let the payment drop to 0 after say 256 or 512 tiles or so.
Assuming CargoDist ist turned on and you're building your rail routes as a network. Why would passengers travelling >512(>256) tiles pay less?
TadeuszD
Transport Coordinator
Transport Coordinator
Posts: 329
Joined: 07 Nov 2011 19:32
Location: PL

Re: Orthogonal Income Patch

Post by TadeuszD »

Alberth wrote:I fail to understand the apparently assumed(?) 1-to-1 connection between big world and longer routes. Isn't a very viable alternative to simply have more short routes on a bigger world?
The answer is simple. In small world all industries are located in small distances. In bigger world, necessary industries (i.e. coal mine and power station) can be located at a greater distance. If you can not find industries located close enough to each other, you business will fall down due to no incomes.

So, the income algorithm should be scaled to map size. Of course, the scaling mechanism need not be linear. For example, if map size grows 2x, the income algorithm can be scaled 1,5x or 1,41x.
Image
Wahazar
Tycoon
Tycoon
Posts: 1451
Joined: 18 Jan 2014 18:10

Re: Orthogonal Income Patch

Post by Wahazar »

Alberth wrote:Isn't a very viable alternative to simply have more short routes on a bigger world?
First of all, please define "small/big world" and "short/long route".

For example, which map is bigger,
this:
Image

or this:
Image
?
Alberth wrote: Even today in our fast real world, there are very few points in the world where all cargo of some type originates from or it brought to.
Even yesterday in our slow real world, there were many points in the world where all cargo of some type originates from or it brought to,
for example silk, tea, latex, spices etc :)
Formerly known as: McZapkie
Projects: Reproducible Map Generation patch, NewGRFs: Manpower industries, PolTrams, Polroad, 600mm narrow gauge, wired, ECS industry extension, V4 CEE train set, HotHut.
Another favorite games: freeciv longturn, OHOL/2HOL.
Eddi
Tycoon
Tycoon
Posts: 8272
Joined: 17 Jan 2007 00:14

Re: Orthogonal Income Patch

Post by Eddi »

it's not just about size of the world, also about density.

for a long time now i wanted to introduce "scale factors" into the game, where certain aspects of the game are increased or decreased.
e.g.
  • daylength
  • industry/town production
  • cargo age for payment
  • distance for payment
  • vehicle (airplane) ranges
  • ...
but this is a really really tricky thing to do, as can be seen by the various daylength patches out there (which partly try to adress some of the other things as well). people generally have different opinion on what should be affected and what not. and not all combinations result in even remotely balanced gameplay.

(this is totally independent from which function you use to calculate the payment)
Wahazar
Tycoon
Tycoon
Posts: 1451
Joined: 18 Jan 2014 18:10

Re: Orthogonal Income Patch

Post by Wahazar »

I encountered strange problem during wagons query. In case of enabled wagon_speed_limits, engine_count should be 1 (there is one wagon for each cargo at the beginning),
but I got three, because all wagons are initialised with same game start date, thus

Code: Select all

IsEngineBuildable(eid,  VEH_TRAIN, OWNER_DEITY)
returns three wagons in 1950.
Mono and Maglevs wagons are not available directly for user at the beginning, because tracks are not available.
How to filter out these wagons? May I perform query across all companies?
Formerly known as: McZapkie
Projects: Reproducible Map Generation patch, NewGRFs: Manpower industries, PolTrams, Polroad, 600mm narrow gauge, wired, ECS industry extension, V4 CEE train set, HotHut.
Another favorite games: freeciv longturn, OHOL/2HOL.
Post Reply

Return to “OpenTTD Development”

Who is online

Users browsing this forum: No registered users and 38 guests