NIMBY Rails devblog 2022-09

1.5 first beta phase is done

Version 1.5 is ready to go into the default branch. During this month long beta phase a huge amount of work was devoted to making the new order system more usable and complete, and to fix many issues with it. After 1.5 is made default, a new 1.5 beta series will start to implement the remaining 1.5 features.


Orders are the user facing interface for timetables, and as such their core concepts didn’t change during 1.5 first beta. But their initial implementation was very much a MVP, so they gained new features during the 1.5 beta:

Toggle for single run or repeating

Before this change, all orders always generated as many runs as possible their duration. When only a single run was needed it was required to very carefully time the new order start. With this new toggle the order always generates a single run and just pads any extra time on the pad wait stop.

“Arrive no later than”

This new start event was added to orders, to allow to express the concept of “the arrival time is not important, just get there ASAP”. This is very useful for depot line orders, and combined with 1x run mode, makes depot orders much easier.

Multi day orders

Orders now have a day mask, allowing to enable or disable them for each day of the week. This cuts down on a lot of repetition and copy pasting, while making it possible to have any changes to a single order apply automatically to a whole week and a whole group of trains, when combined with train groups. This combination makes the 1.5 order system much easier, faster and usable than 1.4 ever was.

This feature is also an example on how intense the 1.5 beta development was. Prior to this, a new order mode was introduced: single day orders, which replicated a single day orders to the whole week. Just a couple days later this mode was removed and replaced with multi day orders.

Enter / exit stops

An often requested feature was to allow to pick the starting stop for train orders. This was implemented, plus also allowing to pick the exit stop. Advanced players are using this feature to for example start a line at different points during the morning, with several train groups stopping for the night at different depots.

Auto skip stop on matching destination

This train AI feature allows to “glue” together runs without forcing the train to make a path between them. When the last stop of a run matches with the first stop of the next one (on either the main platform or any secondary platform), the train AI will just skip that stop and initiate the departure wait of the next one. With some effort this allows to build meta lines out of smaller lines (or sections of lines). The train and pax AI will improve in the future to better support this gameplay.

Train groups

Finally, in order to make manual orders gameplay as smooth as auto run lines, train groups were implemented. When a train is set to auto copy another train orders, it becomes part of its parent train group. As such its timetable shift time can be auto managed by the game, just like an auto run line. “Clone as copier” and a migration tool for auto run trains were also added to make the transition from auto run lines to train groups easier.

Auto line duration

This is not an order system feature, but it is related to it. Lines can now have a duration auto calculated so they fit exact periods of time, like days, weeks, or a day service hours period input by the player. This is very important to avoid pad stops before a run changes into the next order. The default setting for new lines and imported 1.4 games is auto duration, week period, all stops wait, which results in perfectly fitting line durations with any extra stop wait evenly distributed in the line.

Depot gameplay

The proposed pattern for depot gameplay from the previous blog has been made the official one in 1.5. The core concept is that a “depot” is a train order on a certain configured line, not a physical place on the map. Keeping depots as physical places is very limiting for 1.5 gameplay. It was one of those things I implemented back 1.1 because other train games did it that way, unquestioning why. In reality any station can serve as a depot, and this often happens in real life. Train downtime is a state of the train, and such it is modelled in 1.5 with a line setting: technical maneuvers. Lines in that mode are ignored by pax. And since they are lines, they can visit and stop at any station, they can have orders set to run them, and they are never suddenly scheduled without regard for the timetable.

To make this idea more playable and to match 1.4, a new setting was added to technical lines, to make trains able to go into a black hole in the sky when they reach a stop. This means any station can serve as a depot with unlimited capacity if desired, without interfering with regular train lines, making 1.5 depots more usable and friendly than 1.4 ones. The final touch was adding a button to the line editor to create depot lines in two clicks.

Stale runs and interventions

Timetables are fixed, static objects as far as train AI and pax AI knows. And they should be. Imagine a real life train whose timetable changed unpredictably, multiple times per day, while it was full of pax, between stations? But by allowing players to edit orders at any point, this is exactly what is happening in the game. So the concept of stale runs was introduced. Trains whose orders have changed and thus invalidated their current timetabled line run will now very visibly warn the user of their state.

To fix that state an intervention is required, but it gets tedious (and expensive) fast. For this reason trains now receive an auto intervention when they finish a stale run. It’s a good compromise between doing nothing, which results in very delayed trains, or immediately teleporting trains on every order or line change. Teleporting trains might sound like a unrealistic option, but I ask, isn’t changing a train timetable multiple times a day while servicing pax also unrealistic? So after testing the most realistic option given the circumstances (do nothing), I picked a more usable option without going full cheat mode.

Explicit loop handling in pax pathfinding

A bug of times past, pax deciding to stay in trains for a set of legs which return them to their boarding station, was back. The issue in the 1.5 world is that for two paths with exact same duration, the train path is preferred, due to station waits having a hard limit of 3h compared to train ride time which is in practice unlimited. Even with that preference this should not happen, but the pax pathfinder uses an optimization, equivalent to jump point search, but adapted to the very much non uniform graph nature of this game. Since the pax pathfinder advances in “jumps” rather than in single train legs, it was not able to know when it was jumping over an already visited station, and it could pick that path if its time was exactly the same as not picking it, given the previous rule.

To fix this the pax pathfinder was made aware of the concept of looping and of going over again the same departed station. And not just for the same run, but also for any number of runs the explored train is making. This fixed the bug and it will also be important in the future when the current pax PF limit of one future run is lifted.

First dynamic train pathfinding case is now in the game

1.5 line stops can have secondary platforms, to allow trains to stop in more than one platform for a single stop. This is accomplished by having the train check the platform occupancy from a designated signal, which is a safe spot to stop the train if desired. It should also have been a safe spot to change the train destination when the available platform does not match the original one, but it turned out this was buggy. The path and reservation changed correctly, but that new path was often very strange. The reason is that the train always assumes its next step will never change, so in the case of a branching track, any new looked up path was forced to start with the same first step as the original one. This restriction has been lifted in 1.5 for this specific case, which was equivalent to performing a path search with multiple start points and filtering based on the signal position, a very complex search setup compared to the normal train pathfind. It looks successful, so this capability might get used in more places in the future.

Dominating trip explorer

And finally, to not finish this post without an screenshot, this is the dominating trip view in the station window. This view was added during the 1.5 beta and it displays the best path between two stations, for every second of the day. This kind of advanced visualization was impossible in 1.4 and earlier. And it’s not just for the UI: this is what pax reason about, and they pick these exact paths at the corresponding times of the day.