More realistic convoy loading & p****enger behavior
New poster, old player (well, couple years). I've been spending my holiday with Simutrans (102, pak64 and pak128) and while my preference may be different to others, I wish for more realism on some things where it can be achieved with little effort. I'm coder myself so I should have reasonably good idea on the amount or work needed, and gotta admit I'm slightly tempted at coding them myself. But let's see what people think first.
#1 More realistic convoy loading. I'm well aware that this has popped up before on forums and I chose to write a clarified new thread rather than necroing an old one.
Current behavior: Load nearest first. In route A->B->C->D, at A we first load everything that's heading for B, then if there's more room, everything for C and so on. Works fine on most cases and thread http://forum.simutrans.com/index.php?topic=886.0 has had lengthy discussion about it, including the suggestion of what is in my opinion both by far most realistic and also best for gameplay point of view. That thread was about a different suggestion (bad one imo) so here's the correct one in its very own thread hoping for a response.
Preferred behavior: Load even portion to each destination. In route A->B->C->D, at A we load some for B, C and D. How much? Put into a formula: amount heading to B loaded = B / (B+C+D) * convoy capacity.
Example: Train fits 350 p****engers. Station A has 1100 p****engers waiting, 400 to B, 200 to C and 500 to D.
B / (B+C+D) * convoy capacity = 400 / 1100 * 350 = 127
C / (B+C+D) * convoy capacity = 64
D / (B+C+D) * convoy capacity = 159
Total loaded: 127 p****engers heading to B, 64 p****engers heading to C and 159 p****engers heading to D.
As a comparison, current loading system would pick up 350 p****engers to B, 0 to C and 0 to D.
Since I did mention realism, how does this fit into that? In reality, you'd either sell seats to your train beforehand and thus load train with FIFO, or people would just rush into the arriving train randomly. FIFO takes too much resources to keep up in the game so it's obviously out, but ****uming even speed of p****enger generation between given B, C and D, the first 350 people in that FIFO list would be very close 127 to B, 64 to C and 159 to D, just like the suggested method produces. Considering the case of 1100 people rushing into the train and lucky 350 getting in, we'd still end up with 127 to B, 64 to C and 159 to D.
Now, implementation for even balance is easy and couple multiplications & divisions isn't too heavy. Certainly nothing like FIFO would be, and since people have already agreed FIFO would give best results but it's out of the question because of memory usage, I don't really see any reason not to use the suggested method that creates same end result as FIFO without the m****ive memory cost.
Problems: Express train A->D. With current implementation p****engers heading to D are ignored by the A->B->C->D train most of the time so express train straight to D has plenty to pick. With even load such express train wouldn't work as well (it still would to some extent since likely A->D has lots of p****engers to pick from). Now, people going for slower local train instead of the faster express train can be explained with two things: 1) they might still get to D earlier with local train than express, if express isn't due for a while, or 2) they're just too stupid to choose what's better for them (this IS a problem and should be fixed). Either way, loading to all destinations equally isn't breaking express trains: they're already broken, current 'nearest first' loading system just happens to band-aid express trains to being somewhat viable. But as I said, problem is elsewhere and belongs to another thread.
Possible problems with implementation: Considering division is used, the shares for each destination aren't integers but need to be rounded. As a result, in given example it's not guaranteed that shares of B, C and D end up with total of 350 due to rounding errors. Flooring the values and filling the possible last empty spot in convoy with whatever p****engers would probably work fine, but it'd be annoyingly messy code. Instead, I'd consider this:
Example: convoy with room for 130 p****engers, divided among 3 destinations with previous formula gives values
rB = 33.333, rC = 43.333, rD = 53.333
Flooring or rounding will both end up with 129 p****engers, roofing would go to 132. Both bad. So, instead:
B = round(rB) = 33
C = round(rB+rC) - B = round(76.666) - 33 = 44
D = round(rB+rC+rD) - B - C = round(129.999) - 33 - 44 = 53
End result 130 sharp. In pseudo,
double rsum=0.0;
int isum=0;
foreach (next, destinations) {
rsum += next.rval;
next.ival = round(rsum) - isum;
isum += next.ival;
}