News:

Simutrans Wiki Manual
The official on-line manual for Simutrans. Read and contribute.

Convoy operating staff cost

Started by Ranran(retired), July 02, 2019, 09:33:19 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

ACarlotti

Ranran: This suggestion completely ignores the fact that staff don't work 24/7. They have a limited amount of working time, and within this working time they will usually have shorter breaks. For a large company this might average out to about the right value (due to the current number of staff not varying as much proportionately), but for a company just starting out it could have a massive impact. For example, consider a company that uses a single truck to deliver goods from a producer to a consumer, where the truck remains idle three quarters of the time. If you charge for staff according to the maximum usage, then you miss the fact that you only need one hired member of staff to drive this vehicle (ignoring sickness/holiday cover), not four.

Ranran(retired)

QuoteThis suggestion completely ignores the fact that staff don't work 24/7.
It should be noted that there is no real time change in simutrans.
There is no difference between rush-hour and off-peak and midnight, and convoy (worker) always works.
The actual number of staff involved can adjust the salary.
We consider 18 hours as a two-shift work system and double the required personnel for convoy staff.
Assuming a 2 day break out of 7 days, multiply the required staffs (salary) by 7/5.
Also, the lowest class staff may be able to lower their salary because they are not full time.


QuoteFor a large company this might average out to about the right value (due to the current number of staff not varying as much proportionately), but for a company just starting out it could have a massive impact.
Even in the real world, small companies often use human resources inefficiently.

Imagine a rural line that runs two convoys in the morning rush and the evening rush.
When averaged it may be taken as one convoy going back and forth, but in reality it is not.
That is, two drivers and two conductors are needed.
Convoy is not working at off-peak hours, but they will be working differently.
Because they also have a life, there will be no one who applies for the job if company do not pay proper salary.
And it should also be noted that players have the option of leaving them free.
Fuel cost will increase if you increase flights because they are free. So the company may choose to spare them more than that.

And as company gets bigger, this kind of error gets smaller rather than larger.

On the other hand, setting all convoys to depart at the beginning of the month may require the most staffs... (´・ω・`)
Yeah, this may be a bad idea.  ::'(
I thought that seeing the number of employees could be an indicator of the size of a company, a reference for improving management. :)





When paying a salary by the running cost method, the correct salary can not be calculated because this depends on the moving tile and not on the working time.

Is it better way to pay the staff salary for the travel time between stations for each station at the same time the convoy get the fare?
(I think it is currently calculating the traveling time between stations.)
ひめしという日本人が開発者達の助言を無視して自分好みの機能をextendedに"強引に"実装し、
コードをぐちゃぐちゃにしてメンテナンスを困難にし(とりわけ道路と建物関連)、
挙句にバグを大量に埋め込み、それを知らんぷりして放置し(隠居するなどと言って)別のところに逃げ隠れて自分のフォーク(OTRP)は開発を続けている
その事実と彼の無責任さに日本人プレイヤーは目を向けるべき。らんらんはそれでやる気をなくした(´・ω・`)
他人の振り見て我が振り直せ。ひめしのようにならないために、らんらんが生み出したバグや問題は自分で修正しなくちゃね(´・ω・`)

ACarlotti

Quote from: Ranran on August 01, 2019, 10:43:30 AMWhen paying a salary by the running cost method, the correct salary can not be calculated because this depends on the moving tile and not on the working time.

Is it better way to pay the staff salary for the travel time between stations for each station at the same time the convoy get the fare?
(I think it is currently calculating the traveling time between stations.)
I think it would be sensible to charge for the time spent travelling, plus a proportion of time spent waiting at stations (beyond which we can perhaps assume that the workers are taking a scheduled break, or there is a gap between shifts, or the workers are switching to a different convoy).

jamespetts

There are some complex issues raised here. First of all, for vehicles, the plan is to use the layover function in the vehicle maintenance feature-set to simulate times when those vehicles/convoys do not need staff. This requires, as noted above, quite precise time calculation of when these vehicles do and do not require staff. If we only sample the number of staff that they are using once a month, then all the changes between a laid over state and a non-laid over state within that month would be ignored (imagine sampling a 60hz frequency cycle once a second).

Buildings are another matter again. Currently, buildings simply have a single flat monthly cost, which takes into account the average total costs of that building, including the staff who work there regularly, services (coal/electricity/gas/water/telephone) and building maintenance (which is mostly also staff cost, but non-regular staff). Rent is not accounted for as the player is assumed to own the land (and charged accordingly in the construction costs). This is workable for buildings, since they are fixed and do not time slice their staff in the way that vehicles need to be able to do (with the layover feature). If one were to change the way in which the costs for buildings work so that one specifies a number of staff, however, one would then have to calculate the cost for that staff differently to the way in which one would calculate the cost for staff for a vehicle with exactly the same data, as, as A. Carlotti points out, staff do not work all day and all night. One might, however, imagine shift workers and calibrate the numbers on the basis of the average number of staff needed to operate the building at any given time; but would we then need to add a layover concept for a building? I suspect not given that we do not yet have any regular cycles of varying demand with time, so we might be able to use the simple system for buildings.

But we still need a way of recording times for vehicles. One additional complexity that has come to mind is this: in the planned future system, when convoy re-combination is introduced, it will be possible for one convoy to have vehicles from multiple different players, as in this real life example from Oxford in 1939:



Thus, storing the staff cost in the convoy will not work. It either needs to be stored per vehicle, or alternatively stored per player in the way that way maintenance is stored. The latter may have much to recommend it so long as only single threaded parts of the code will ever need to change this.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Ranran(retired)

Quotethe plan is to use the layover function in the vehicle maintenance feature-set to simulate times when those vehicles/convoys do not need staff. This requires, as noted above, quite precise time calculation of when these vehicles do and do not require staff.
Staff should be working while convoy travels between stations.
The travel time between stations is currently recorded (as can be seen in the Times history dialog).
The time until the convoy leaves the station when it arrives at the station is calculated.
If convoy goes directly to the next station, the staff will continue to work.
So, player pays the salary by adding the calculated loading time to the travel time between stations.
That way, every time convoy arrives at a station or depot, it pays a salary for the staff according to the uptime.

If the schedule is set to "wait for time" or "minimum load", the crew can rest for the time waiting at the station.

In the case of reversing, it will fall into several patterns.
1) If the convoy only changes the direction of travel, as in EMU, the crew can rest until the departure time. In many cases, they will be chnaged to another staffs. Therefore, the salary of the staff is not paid while the convoy stops at the station.
2) If the convoy needs shunting, the driver has to work in the meantime. The staff for the passenger service will be able to take a break.


Some staff may be optional if there is no load in "no load" mode. There is a problem in how to distinguish it. A conductor may be unnecessary, but a brake man seems to be necessary.


QuoteI think it would be sensible to charge for the time spent travelling, plus a proportion of time spent waiting at stations (beyond which we can perhaps assume that the workers are taking a scheduled break, or there is a gap between shifts, or the workers are switching to a different convoy).
I think that the staff waiting time suggested by ACarltti may be simulated by adding a certain margin to the salary.
For example, assume that two hours out of nine hours of restraint are spent at such time.
In the real world, the train driver does not drive the train for eight hours out of eight working hours. Usually about half. Therefore, the number of staff required may be large.
But truck drivers will drive a lot of their working hours.
I think that part can be dealt with by setting a high salary (class). For example, class higher than the bus driver.
This may differ from country to country, and to some extent it would be adjustable by class settings.

I think that the relationship between class and salary can be set as the pakset creator thinks.
Quotebut would we then need to add a layover concept for a building? I suspect not given that we do not yet have any regular cycles of varying demand with time, so we might be able to use the simple system for buildings.
Yes, I think the building is good with a simple salary calculation method. The lowest class is considered part-timer, and lower working hours are set as low salary.
It would also be useful to display worker information in the station (detail) information as suggested in another thread.



QuoteBut we still need a way of recording times for vehicles.
I think we are recording the travel time between stations in Times history.



QuoteThus, storing the staff cost in the convoy will not work. It either needs to be stored per vehicle, or alternatively stored per player in the way that way maintenance is stored. The latter may have much to recommend it so long as only single threaded parts of the code will ever need to change this.
I think this applies to many other things.
The charts that convoy currently has, these data are almost meaningless for convoy with variable formations.

The resolution of the problem James pointed out seems to have to be done together with these.
However, dividing the data that convoy currently has into individual vehicles will consume more memory.


Quoteit will be possible for one convoy to have vehicles from multiple different players
This issue is not limited to the staff cost issue.
After two train with locomotives join, only one locomotive is often used. That is, one locomotive is left behind.
If the owner of the locomotive is different from the owner of the coach, the owner of the locomotive will pay much of the operating cost of the convoy.
However, on the other hand, because the locomotive does not carry anything, will it not earn any income?
ひめしという日本人が開発者達の助言を無視して自分好みの機能をextendedに"強引に"実装し、
コードをぐちゃぐちゃにしてメンテナンスを困難にし(とりわけ道路と建物関連)、
挙句にバグを大量に埋め込み、それを知らんぷりして放置し(隠居するなどと言って)別のところに逃げ隠れて自分のフォーク(OTRP)は開発を続けている
その事実と彼の無責任さに日本人プレイヤーは目を向けるべき。らんらんはそれでやる気をなくした(´・ω・`)
他人の振り見て我が振り直せ。ひめしのようにならないために、らんらんが生み出したバグや問題は自分で修正しなくちゃね(´・ω・`)

jamespetts

This raises a large number of highly complex issues.

First of all, I do not think that the idea of assuming that staff only work when a vehicle is in motion (or when a vehicle is in motion plus a fixed margin) is workable. It is likely significantly to underestimate staff times. Even if there is a fixed margin, whenever a vehicle comes to a stop for slightly longer than that margin, the staff would be assumed to be having an unpaid break for a very short fragment of time. In reality, times between shifts are never tiny fragments of time. Also, if a vehicle is unattended by staff, one cannot have passengers aboard the vehicle, and shunting operations cannot take place. This is why the layover concept was described; can I check whether you (and A. Carlotti, as well as any other contributors to this discussion) have read about and understood the layover concept in the other thread regarding schedule features? It is of some importance in this discussion.

As to convoy metrics, this is an interesting point that I had not considered fully, especially the GUI aspect. In terms of actually charging the player running cost, the current code for that is this:


/**
* convoi add their running cost for travelling one tile
* @author Hj. Malthaner
*/
void convoi_t::add_running_cost(sint64 cost, const weg_t *weg)
{
jahresgewinn += cost;

if(weg && weg->get_owner() != get_owner() && weg->get_owner() != NULL && (!welt->get_settings().get_toll_free_public_roads() || (weg->get_waytype() != road_wt || weg->get_player_nr() != 1)))
{
// running on non-public way costs toll (since running costs are positive => invert)
sint32 toll = -(cost * welt->get_settings().get_way_toll_runningcost_percentage()) / 100l;
if(welt->get_settings().get_way_toll_waycost_percentage())
{
if(weg->is_electrified() && needs_electrification())
{
// toll for using electricity
grund_t *gr = welt->lookup(weg->get_pos());
for(  int i=1;  i<gr->get_top();  i++  ) {
obj_t *d=gr->obj_bei(i);
if(  wayobj_t const* const wo = obj_cast<wayobj_t>(d)  )  {
if(  wo->get_waytype()==weg->get_waytype()  ) {
toll += (wo->get_desc()->get_maintenance()*welt->get_settings().get_way_toll_waycost_percentage())/100l;
break;
}
}
}
}
// now add normal way toll be maintenance
toll += (weg->get_desc()->get_maintenance() * welt->get_settings().get_way_toll_waycost_percentage()) / 100l;
}
weg->get_owner()->book_toll_received( toll, get_schedule()->get_waytype() );
get_owner()->book_toll_paid(         -toll, get_schedule()->get_waytype() );
// book( -toll, CONVOI_WAYTOLL);
book( -toll, CONVOI_PROFIT);
}

get_owner()->book_running_costs( cost, get_schedule()->get_waytype());
book( cost, CONVOI_OPERATIONS );
book( cost, CONVOI_PROFIT );
}


This code is called once per tile. We have a concept of the convoy itself having an owner, which is used for the way toll. This will need to continue, and this is in any event how real railways worked: the company controlling the train was traditionally considered to be the company which owned the locomotive hauling the train. Thus, whichever player owns the first powered vehicle in the convoy in its non-reversed direction should be considered to be the owner of the convoy. This then would determine whether a way toll should be paid.

As to the actual running costs, this method is called as follows from this code in convoi_t::increment_odometer(uint32 steps)


sint32 running_cost = 0;
bool must_add = false;
for(uint8 i= 0; i < vehicle_count; i++)
{
const vehicle_t& v = *vehicle[i];
if (v.get_pos() != pos)
{
if (must_add)
{
add_running_cost(running_cost, weg);
}
pos = v.get_pos();
weg = v.get_weg();
running_cost = 0;
}
must_add = true;
running_cost -= v.get_desc()->get_running_cost(welt);
}

if (waytype == air_wt)
{
// Halve the running cost if we are circling or taxiing.
air_vehicle_t* aircraft = (air_vehicle_t*)front();
if (!aircraft->is_using_full_power())
{
running_cost /= 2;
}
}

if (must_add)
{
add_running_cost(running_cost, weg);
}
}


We would therefore need to create a system in which we pass a vector to add_running_cost of cost values per player, and these are booked accordingly. The most complex issue, however, is how to deal with the statistics and GUI. If anyone has any thoughts on how to deal with this, this would be much appreciated, as this is a potentially very complex issue.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Ranran(retired)

#41
QuoteIt is likely significantly to underestimate staff times. Even if there is a fixed margin, whenever a vehicle comes to a stop for slightly longer than that margin, the staff would be assumed to be having an unpaid break for a very short fragment of time
The idea I described in the previous post shows two cases where convoy's stop time may or may not be added to working time.

1) loading time (If stop time at the station = loading time, staff will be considered as working continuously)
2) Of the reversing times, the time spent on shunting. - *
During the above time, the convoy staff will continue to work even if convoy is stopped. (At the time of shunting it only looks like it is stopped.)
The stop time is currently calculated when convoy stops at the station. Therefore, add that time to the inter-station travel time.
The time they are loading and unloading passengers at the station they are still on the train and will continue to work and their salary will definitely be paid.
Is your "overlay" different from this?


QuoteIf the schedule is set to "wait for time" or "minimum load", the crew can rest for the time waiting at the station
If the time staffs have to work these way has not been decided, they will be released.
The staff will work continuously rather than fragmented, except in these case and in the case where EMU changes direction at the terminal station.
However, pay will be made every time convoy arrive at the station or depot.

(If the schedule changes, is it correct to be liquidated immediately?)
(And will waypoint be considered as a station?)

The margin is an addition to that (traveling time + loading time + shunting time).
Therefore, the margin will not be shorter than the stop time (which the staff may need to continue).
In the case of Japanese railways, the time when the crew is on the moving vehicle is about half of the working time.
In other words, it requires twice as many people as the train is moving.
Replace this with double salary. (This is the content that is properly adjusted by each pakset.)


*The head shunting needs one driver (per locomotive group), but the three-part shunting seems to require two drivers (e.g. move brake van to rear), but I think that distinction is possible.
Other necessary staff are often thought to be staff working at the station, but it may not be simulated correctly in the current specification.
Because the station does not judge whether the head shunting is possible or not. Even if that station doesn't have a shunting loop, you can do head shunting. We also do not need to build a turntable to turn the locomotive. That is, the cost of necessary facility is ignored.
I think that there are many contradictions of this kind today and will continue to do so. So I think that's not a big issue.


Quotethe company controlling the train was traditionally considered to be the company which owned the locomotive hauling the train. Thus, whichever player owns the first powered vehicle in the convoy in its non-reversed direction should be considered to be the owner of the convoy. This then would determine whether a way toll should be paid.
If the convoy includes other owner's vehicles, I think paying the rental fee for the vehicle is the correct behavior.
The track owner and the rental vehicle owner may be different. Payment of tolls will not help.
In the Japanese example, it is customary to equalize the number of vehicles or the total distance traveled to offset the rental charges as much as possible.
However, it is necessary to set an appropriate vehicle rental fee because it is considered that many cases will occur in the game.
ひめしという日本人が開発者達の助言を無視して自分好みの機能をextendedに"強引に"実装し、
コードをぐちゃぐちゃにしてメンテナンスを困難にし(とりわけ道路と建物関連)、
挙句にバグを大量に埋め込み、それを知らんぷりして放置し(隠居するなどと言って)別のところに逃げ隠れて自分のフォーク(OTRP)は開発を続けている
その事実と彼の無責任さに日本人プレイヤーは目を向けるべき。らんらんはそれでやる気をなくした(´・ω・`)
他人の振り見て我が振り直せ。ひめしのようにならないために、らんらんが生み出したバグや問題は自分で修正しなくちゃね(´・ω・`)

Ves

Hi all! Hope you had a good summer so far! :)
I was sitting and thinking about this and came up with this strategy. Im not sure if you talked about this approach before and I dont know how resource demanding it might be.

I was thinking that for each class of employers there is a value. These values fills up and down automatically by the player vehicles and buildings. For instance, when a vehicle goes out of layover into normal operation, it checks the vehicle_desc for what classes the employers are and then add the appropriate amount of employers to the respective class value,
When a vehicle goes into layover, it subtrakts the amount of employers it holds from the class values.
If all goes well, those values should never go below 0!

Now the tricky part which might be too consuming:
In simuconf.tab there should be a setting called employer_salaries_per_month. This value is a fractal of a month and should be as high as possible for better accuracy, but could be set to a lower value for better performance or pakset design. As far as I can think of, the highest value possible would be the number of ticks per month.

How it would work then is that whenever the time specified above has passed, the game looks at the current number of employes in the different working classes and then pay their salary. The formula would look like this:
monthly_salary_class[ X ] / employer_salaries_per_month * number_of_employes_class_[ X ]
.. and that would be done for each class of employers.



As to determine wether a vehicle needs an employe or not to run is more complex and it migh be quite difficult to get it fail proof. I have not yet thought out a princip that I think would work fail proof, but it should be possible I think.

jamespetts

Thank you both for your responses.

First of all, as to layovers, I suggest looking at this topic, which discusses them. This should give a clear description of what is intended.

Secondly, there is some merit to Ves's idea (which is very similar to the way in which infrastructure maintenance works, and I believe similar to what I suggest above), but it would make keeping track of metrics for convoys and lines very difficult. It also has the potential to be fragile in the sense that any place in the code where these data are added or not added incorrectly would lead to the number being incorrect for an extended period of time, and each error would compound the existing incorrect state; moreover, there are many different places where these data would have to be adjusted, and there is no easy way of making sure that nothing that requires adjustment can happen without this adjustment taking place, so it will be extremely easy to miss the line of code calling for an adjustment in one of the many dozens of places where it will need to be added (and it will be even harder to make sure that this be not missed when the code is modified). If we can think of some way of adding an abstraction layer so that there is some automatic link between the types of things that require adjustment of this figure and the actual code calling for the adjustment, that would make the code far more robust, but I cannot immediately think of such a mechanism that is compatible with the Simutrans codebase.

As Ves has correctly identified, sampling time is the real complexity with this. The only way of doing it that would not cause errors is to compute the staff cost every time that staff costs are added or subtracted (and probably also at the ends of months): any less frequent sampling would inevitably lose data and produce inaccurate results, and any more frequent calculation would have no benefit. This would not be too computationally intensive, as it would require only a few arithmetical operations and would require only a total of six 64-bit integers per player (one for each class of staff, if this sort of class be used, plus one representing the time when the calculation was last performed). However, where things get extremely complex is the interaction between this and rounding errors: if the recalculation occurs too frequently, the values may well be low enough to be a fraction of a simucent, which would then be truncated; but if there are tens of thousands of truncations per month, it is theoretically possible to truncate tens of thousands of fractions of simucents, which might add up to hundreds or thousands of simucents per month.

The only lossless way of doing this of which I can think is to record actual start and end points using the 64-bit integer representing current game time. It should be possible to do this per player rather than per convoy, and then compute the charges on the basis of this once per month: this would then ensure that any precision loss is a once a month event (and therefore trivial in amount) and not affected by the number of actual changes of staff requirements per player per month. This would take more memory than the more basic system suggested by Ves, requiring a 64-bit integer to be stored per player once every change. Assuming that each of 14 players has 1,000 convoys each (by way of comparison, there are circa 6,000 convoys on the current Bridgewater-Brunel server), and that each of those convoys change configuration on average 100 times per month, this would require 100 x 1,000 x 14 x 8 bytes of memory by the end of the month, being 1,814 bytes (just over 1 megabyte), which is not very significant in the grand scheme of things, and that is assuming a server even more heavily developed than the current Bridgewater-Brunel server.

As to Ranran's suggestions, one or two questions of clarification.

Quote from: RanranThe idea I described in the previous post shows two cases where convoy's stop time may or may not be added to working time.

1) loading time (If stop time at the station = loading time, staff will be considered as working continuously)
2) Of the reversing times, the time spent on shunting. - *
During the above time, the convoy staff will continue to work even if convoy is stopped. (At the time of shunting it only looks like it is stopped.)
The stop time is currently calculated when convoy stops at the station. Therefore, add that time to the inter-station travel time.
The time they are loading and unloading passengers at the station they are still on the train and will continue to work and their salary will definitely be paid.

Imagine that a train arrives at a station at 0:00. Its loading time is 0:15, but its schedule requires it to wait until 0:30. Assuming no shunting, would the staff be paid for the time between 0:15 and 0:30 in this situation in your proposed algorithm?

More generally, do I understand correctly that your proposed algorithm is one which, at the most fundamental level, computes staff time just spent in fixed blocks rather than assessing a monthly cost and then working out a fraction of that cost based on when the staff would be working?

So, for instance, to simplify what I imagine your algorithm might be for the sake of illustration, suppose that we have a train travelling between points A and B. Its dwell time at point A is 0:30, its travel time between points A and B is 1:00 and its dwell time at point B is 0:30; one could simply at 0:30 of staff time on departing point A, 1:00 of staff time on arriving at point B, and 0:30 of staff time on departing point B. Is this, at a very simple level, the sort of thing that you had in mind? This is potentially workable, but has a possible issue with precision loss: if we have a 'bus travelling from point A to point B, and the dwell time at point A is 0:00:10 and the journey time between points A and B is 0:00:45, then we could well end up needing to add a staff cost that is signifciantly less than 0.01 SimuCents (the currency being stored in a 64-bit integer representing 0.01 SimuCents). This would lead to 0 staff cost being recorded for that convoy at all.

Forgive me if this is not what you had in mind and I have misunderstood your proposed algorithm: perhaps you could clarify if that is so?

Quote
If the convoy includes other owner's vehicles, I think paying the rental fee for the vehicle is the correct behavior.
The track owner and the rental vehicle owner may be different. Payment of tolls will not help.
In the Japanese example, it is customary to equalize the number of vehicles or the total distance traveled to offset the rental charges as much as possible.
However, it is necessary to set an appropriate vehicle rental fee because it is considered that many cases will occur in the game.

My apologies: I have not fully understood this. It would help if you could explain what you imagine should happen in each of the following examples.

Suppose that the toll is 10 SimuCents per km. What would you imagine the toll to player A to be for the following convoys travelling over player A's ways:

(1) a train with a locomotive owned by player A, 2 carriages owned by player A and 2 carriages owned by player B;
(2) a train with a locomotive owned by player A and 4 carriages owned by player B;
(3) a train with a locomotive owned by player B, 2 carriages owned by player A and 2 carriages owned by player B; and
(4) a train with a locomotive owned by player B and 4 carriages owned by player A.

Remember, the current toll system in Extended is based on a proportion of the revenue generated (which is based on how the Railway Clearing House worked), so it would also help to understand how you imagine this system interacting with your suggestions as to the toll.

For reference, what is currently planned is for the player which owns the convoy to take all the revenue for the journey but to have to pay all the variable maintenance costs and be liable in full for the tolls to other players (including if that other player owns some or most of the revenue earning vehicles, e.g. passenger carriages, in that convoy). No payment to other players for the use of their vehicles is envisaged (as in Railway Clearing House practice). This would incentivise players to send though trains onto other players' networks, but to change locomotives near the boundaries of the networks - exactly as tended to happen in reality.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

jamespetts

#44
Given that implementation work on the schedule and related features is about to recommence, some further consideration of the issues discussed here is now merited.

What I intend to do here is set out a provisional design for some elements of what has been discussed here, based in part on Ranran's suggestions, so that we can move toward refining and then implementing this design.

Staff vs. fixed maintenance costs

It is probably better to have staff cost separated from the existing fixed maintenance cost. Although nobody has been able to find any data on fixed maintenance costs that are not staff costs, it would not take much additional work to implement this separately, and, given the staff specific code set out below that will be needed for staffing costs, it is probably better to have them separate. There is nothing to stop pakset authors from simply not using the fixed vehicle maintenance.


Different staff

It is definitely necessary to have a system to simulate the different cost of different staff and the ability to have inflation affecting the cost of different staff differently. I had wondered whether Ranran's suggestion above of using classes might work for this, but this might be problematic for paksets that do not define passenger classes, or define only a few of them. It would also be too inflexible as it would not allow enough differentiations: an airline pilot is paid more than a flight engineer, who in turn is paid more than a train driver, who in turn is paid more than a 'bus driver, who in turn is paid more than a minibus or van driver, who in turn is paid more than a 'bus conductor, who in turn is paid more than a shunter. The number of classes in a pakset do not allow for this number of strata.

I therefore suggest the following system: each pakset, in a staff.tab file, will define categories of staff and their monthly salary at various points in time, using the same format as the speedbonus.tab file (thus allowing code re-use). The speedbonus.tab file looks like this:


track=1750,8,1825,10,1830,15,1835,17,1840,33,1850,40,1865,52,1880,60,1895,65,1910,67,1920,72,1930,78,1940,82,1950,84,1960,87,1970,100,1985,120,2000,150,2030,175

road=1750,8,1825,10,1830,15,1835,17,1840,33,1850,40,1865,52,1880,60,1895,65,1910,67,1920,72,1930,78,1940,82,1950,84,1960,87,1970,100,1985,120,2000,150,2030,175

monorail_track=1750,8,1825,10,1830,15,1835,17,1840,33,1850,40,1865,52,1880,60,1895,65,1910,67,1920,72,1930,78,1940,82,1950,84,1960,87,1970,100,1985,120,2000,150,2030,175

tram_track=1750,8,1825,10,1830,15,1835,17,1840,33,1850,40,1865,52,1880,60,1895,65,1910,67,1920,72,1930,78,1940,82,1950,84,1960,87,1970,100,1985,120,2000,150,2030,175

narrowgauge_track=1750,8,1825,10,1830,15,1835,17,1840,33,1850,40,1865,52,1880,60,1895,65,1910,67,1920,72,1930,78,1940,82,1950,84,1960,87,1970,100,1985,120,2000,150,2030,175

maglev_track=1750,8,1825,10,1830,15,1835,17,1840,33,1850,40,1865,52,1880,60,1895,65,1910,67,1920,72,1930,78,1940,82,1950,84,1960,87,1970,100,1985,120,2000,150,2030,175

water=1750,8,1933,13,1955,16,1972,18,2010,20,2025,25

air=1906,67,1920,72,1930,78,1940,82,1950,84,1960,87,1970,100,1985,120,2000,150,2030,175


A staff.tab could look like this:


airline_pilot=1920,150,1930,160,1950,200,1955,250,1960,275,1970,375,1980,500,1990,550,2000,600,2020,620
cabin_crew=1920,20,1930,22,1950,40,1955,45,1960,50,1970,55,1980,65,1990,70,2000,72,2020,75

train_driver=1750,10,1800,11,1820,12,1850,15,1890,17,1900,20,1910,25,1920,30,1935,32,1940,35,1950,45,1960,75,1970,90,1980,100,1990,120,2000,130,2020,150


One might then define the staff in a vehicle's .dat file as follows:


staff[airline_pilot]=2
staff[cabin_crew]=3


I am not sure how easy that it would be to implement the system of using text strings to define the individual type of staff: the only reason that text strings can be used in speedbonus.tab is that they are the names with a hard-coded association with an enum. Since this will not directly affect users, only pakset maintainers, it may be implemented simply using numbers instead of names, in a similar way to the way in which signalbox groupings are implemented. Thus, the above would instead look like this:


# ** Aircraft **
# Airline pilot
1=1920,150,1930,160,1950,200,1955,250,1960,275,1970,375,1980,500,1990,550,2000,600,2020,620
# Cabin crew
2=1920,20,1930,22,1950,40,1955,45,1960,50,1970,55,1980,65,1990,70,2000,72,2020,75

# ** Trains **
# Train driver
3=1750,10,1800,11,1820,12,1850,15,1890,17,1900,20,1910,25,1920,30,1935,32,1940,35,1950,45,1960,75,1970,90,1980,100,1990,120,2000,130,2020,150



# Airline pilot
driver[1]=2
# Cabin crew
staff[2]=3


This would then make it much easier to maintain the paksets, as there would be no need to change each individual vehicle if one wanted to change the staff cost of, for example, airline pilots, nor any need to normalise the values of staff in each individual vehicle to a standard point in time for inflation purposes when adding each entry. Instead, the inflation computation would be built into the basic system for assigning staff costs.


Variable staff operating cost, including multiple working

Ranran's original analysis of this is very helpful, and it is necessary to take into account the issues that he raises. The suggested design and the statistics for staff costs on Japanese railways, trams and 'buses as of 2007 are especially helpful.

I think that a modified version of Ranran's algorithm is the best implementation for this. I adopt Ranran's tripartide distinction between drivers, conductors and other staff. However, instead of having flags for vehicles that do or do not need these, one would simply specify, for each vehicle, how many of each is needed.

For example, a diesel locomotive might have:


# Train driver
driver[3]=1


whereas a steam locomotive might have:


# Train driver
driver[3]=1
# Fireman
driver[4]=1


In reality, multiple working requires compatible equipment. For example, two BR Class 50 locomotives can work in multiple with one another, but not with anything else. A BR Class 47, however, can work in multiple with a range of other types of locomotives (e.g. the BR Class 37) and driving trailer types (e.g. the BR Mk. 2 DBSO).

Thus, we need to be able to specify a multiple working type. This can be done simply with a numerical value thus:


multiple_working=5


(multiple_working=0 would denote no multiple working capability).

Thus, the algorithm for drivers would be simple: ignore the driver staff cost of each vehicle in the convoy which comes later (in the present orientation) than each vehicle with the same non-zero multiple working type defined which has already had its driver staff cost counted. In reality, most sensible paksets will define the train driver costs to be the same, and thus it will not matter which vehicle is first, but there needs to be some algorithm for dealing with the theoretical possibility of differing values here.

For conductors (apt to cover 'bus conductors and train guards), the algorithm could be even simpler: for each convoy, count only the conductor cost of whichever vehicle is nearest to the rear of the convoy and has a conductor cost defined. However, I note that Ranran proposes a system to provide for multiple conductors dependant on train length. I am not sure how important that this will be to simulate; but, if simulated, it is likely to need to be customised at the individual vehicle level rather than the pakset level, and then have a system for dealing with what happens when vehicles with different settings mix in the same train. It is not immediately obvious quite how this should be done.

For all other staff, the staff cost would be counted in all instances, no matter the formation of the train. This other staff parameter could be used for train guards/brakespeople in trains without continuous braking, to simulate the fact that each brake carriage on such a train would need a guard no matter the formation of the train, as each brake carriage would need somebody manually to apply the brakes when the driver gave the appropraite whistle code. They would simply be defined, e.g.:


# Buffet staff
staff[5]=2


Thus, trains or 'buses without conductors or drivers would not need a "driverless" or "conductorless" flag: they would simply be composed entirely of vehicles without any driver or conductor staff defined.

Computing time based maintenance costs

This needs to avoid both rounding errors and excessive memory consumption. The easiest way of doing this, I think, is for each player to have a vector of staff cost for each pay grade of staff, as defined in staff.tab. That vector will store data in ticks (the internal measurement of time).

Based in part on Freddy's suggestion in another thread, each time that a convoy departs from a stop or arrives at a stop, and each new month, the number of ticks since its last departure or the last month can be computed and that number of ticks, multiplied by the number of staff of each type, added to the player's vector for each different staff pay grade. At the end of the month, the number of ticks would be multiplied by the current prevailing salary for that grade of staff and then dividided by the number of ticks per month and a figure for staff cost for that player in that month would thus be computed. Rounding errors would therefore be minimised and would be incapble of being compounded, and memory usage would be minimal.


Mixed player convoys and costs

This has the potential, as can be seen from above, to become extremely complex, so I would suggest the simpler version that I set out in my last post on this topic above: each convoy willl be regarded as having an owner, which would be determined by the owner of the first powered vehicle in the convoy's non-reversed state (based, as stated above, on Railway Clearing House practice). The owner of the convoy will pay all of the staff operating cost for the whole convoy. The owner of the individual vehicles will continue to pay the running (per km) and maintenance (per month) cost for those individual vehicles.


Convoy recombination and statistics

This is complex and challenging. In one sense, it is a less critical issue, as it does not directly affect gameplay, but it has the potential to mislead players.

The simplest solution would be to erase the data and start again whenever it becomes invalidated: this would at least prevent players from being given inaccurate or misleading data.

If anyone can think of a better alternative that does not take an infeasible amount of coding effort, that would be very helpful; but, otherwise, I think that I shall have to implement the erasure system.

Catering

Ranran makes the point that catering vehicles sometimes did not have through gangways, so that a dining car on a train could only service passengers in that particular carriage. This should be dealt with by a new .dat file setting,


self_contained_catering=1


which, when set, will mean that the catering revenue and comfort boost will apply only to the individual vehicle rather than to the whole convoy.



Edit: Added catering
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Vladki

Regarding the multiple_working=X feature. This (if implemented) should affect also the functionality of "can_lead_from_rear" or "has_rear_cab". If the last vehicle has rear cab, but zero power, then look for a powered vehicle with the same multiple_working value. If such vehicle is not found, then it should be treated as if it does not have a rear_cab for reversal purposes. For even more realistic function - all vehicles in between them, should have the same multiple_working value - even if having no cab and no power - just to show that they have the necessary cables.

Regarding conductor costs. It would be nice to allow fractional numbers. Let's say that the railway rules say there must be one conductor for every 4 cars. So one could specify staff[train_conductor]=0.25. This value would be rounded up, so a 5-car train would have 2 conductors.  This would also solve the problem of two or more multiple units connected together, where it is not possible to pass from one unit to the other, and thus each requires it's own conductor.

jamespetts

Quote from: Vladki on December 28, 2020, 10:16:03 AM
Regarding the multiple_working=X feature. This (if implemented) should affect also the functionality of "can_lead_from_rear" or "has_rear_cab". If the last vehicle has rear cab, but zero power, then look for a powered vehicle with the same multiple_working value. If such vehicle is not found, then it should be treated as if it does not have a rear_cab for reversal purposes. For even more realistic function - all vehicles in between them, should have the same multiple_working value - even if having no cab and no power - just to show that they have the necessary cables.

This is an interesting idea. I wonder whether this can be communicated clearly to the player? It should not be difficult in principle to write the logic for this.

Quote
Regarding conductor costs. It would be nice to allow fractional numbers. Let's say that the railway rules say there must be one conductor for every 4 cars. So one could specify staff[train_conductor]=0.25. This value would be rounded up, so a 5-car train would have 2 conductors.  This would also solve the problem of two or more multiple units connected together, where it is not possible to pass from one unit to the other, and thus each requires it's own conductor.

I am still unsure about this feature, and in particular quite what the algorithm would be for this.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Vladki

Quote from: jamespetts on December 28, 2020, 11:24:00 AM
This is an interesting idea. I wonder whether this can be communicated clearly to the player? It should not be difficult in principle to write the logic for this.
Perhaps similar to showing the constraints - have a "translation" for each multiple working type, and show it next to constraints:
Supported multiple working type: WTB (wire train bus)
or
Supported multiple working type: Electrostar (classes 375, 376, 378 and 387)

Quote
I am still unsure about this feature, and in particular quite what the algorithm would be for this.
Each passenger car would have staff[train_conductor]=1/x, where x is the max number of cars served by one conductor. (or the number of cars in multiple unit). Then these numbers would be summed up for all vehicles in the convoy, and rounded up to nearest integer. The result would be the number of conductors needed for that train, and used further to calculate the wages.

jamespetts

Quote from: Vladki on December 28, 2020, 11:44:12 AM
Perhaps similar to showing the constraints - have a "translation" for each multiple working type, and show it next to constraints:
Supported multiple working type: WTB (wire train bus)
or
Supported multiple working type: Electrostar (classes 375, 376, 378 and 387)

That could possibly work. I should be interested in Ranran's views on this.

QuoteEach passenger car would have staff[train_conductor]=1/x, where x is the max number of cars served by one conductor. (or the number of cars in multiple unit). Then these numbers would be summed up for all vehicles in the convoy, and rounded up to nearest integer. The result would be the number of conductors needed for that train, and used further to calculate the wages.

There is no existing algorithm for parsing mathematical symbols in strings to be read, so there would be a very large amount of work required to add this as opposed to a basic system involving reading only numbers.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Vladki

Quote
There is no existing algorithm for parsing mathematical symbols in strings to be read, so there would be a very large amount of work required to add this as opposed to a basic system involving reading only numbers.
Of course you would not enter 1/4 but 0.25. Just the system would have to support fractional numbers for staff[...], and have the special logic if x is train_conductor, just as it would have special logic for train_driver.
Alternatively one could specify that staff[train_conductor]=x and the 1/x calculation would be done internally, but I think that would be confusing to pak designers, and lead to errors.

EDIT: maybe there would not be any need for special treatment of conductors. Any staff (except drivers) could be treated this way. (i.e sum over all vehicles using float, and round up the sum).

jamespetts

I do not think that the existing algorithm can even deal with floating point numbers; I think that it works only with integers, although I have not looked into this in detail.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.