NIMBY Rails devblog 2022-10

Wrapping up 1.5

2/3rds of October were devoted to the second beta series of v1.5, which will end very soon. I kept the beta branch going for longer than I anticipated since there are a couple of pax behaviors which don’t look very good, namely the late train behavior and the matching on line+stop, and I wanted to see how players worked around it with the current version. In the end I’ve decided I won’t apply anymore changes to these two behaviors being so late in the 1.5 development since applying any changes would open up other problems for sure. Better a known defect and how to work around it than having an endless beta series.

But these three weeks of the final 1.5 betas proved productive, with even some medium size features being implemented which better fit in the 1.5 theme than future releases.

Custom leg timing

Ancient 1.1 builds supported manually inputting leg times for a total of a few weeks, and players endlessly reminded me of it, asking why “it had been removed”, like just on a whim on my part. Well, it was removed because it never worked, it was just as well a placebo input. In these times it was clear the whole line timing concept was broken and that it needed a real train simulation to calculate leg times, and so, even from these ancient 1.1 times, line times have been based on simulating an actual train on the tracks. This is why the only customization available for leg timing was speed: you cannot directly tell the train how long it must take to reach somewhere, that’s not how the train simulation works.

In 1.5 line timing became much more important than before, so having an extra capability for changing line times was important. It has always been possible to change leg times by editing the cruise speed, but it order to exactly match a desired leg time, it required tedious trial and error. The 1.5 beta now automates the process, allowing the direct input of a leg time and then trying to find the perfect cruise speed to match it. This is accomplished by an optimization process which tries to find the exact speed with progressively smaller changes, going over and under the desired leg time on each iteration.

Better late train estimation

In 1.5 trains always have a fixed arrival time for their destination, and so being aware of being late is important, to allow the train to speed up to arrive on time. The previous late estimation was too basic, with just checking the current time versus the arrival time. Often when the train realized it was late, it was too late to speed up. 1.5 beta now has a new lateness estimation system which warns the train much earlier in its leg path of being late, even from the initial stop.

Rather than tracing a full path, this system is using a simple heuristic over the remaining distance and the cruise speed. Despite this simplicity it is very good at the job of telling the train to speed up only when needed.

Stop conflict display in platform table

The station window platform tab is now capable of highlighting line stops which overlap with another stop on the same platform:

The info tooltip was also updated to show all the affected stops, to make it easier to fix scheduling conflicts between lines.

Line services

An often repeated pattern for 1.5 scheduling is to have multiple versions of a line with some changes only for a subset of trains. Often due to wanting to skip stops, or change a leg timing, for example. This was possible by cloning a line and editing it, but doing so made them two different lines, requiring to manually duplicate editing when changing the original line. This pattern is now has better support with the introduction of line services:

A line service is a restricted clone of a line, which is always kept up to date with the original line. Unlike a normal line, line services are not allowed to create, delete or reorder stops, and they can only change main and secondary platforms from within the original station. But thanks to these restrictions they are automatically kept up to date with their parent line, and it is possible to change all duration, leg and stop timings, and to disable stops. This meets most of the uses cases for cloning lines in the context of 1.5 scheduling.

Manual track transforms in bulk editor

This feature probably belonged better in 1.6 than in 1.5, but it was simple and had zero impact on game systems, so it was added at the end of the 1.5 beta. The bulk editor panel now has extra options for moving and rotating tracks, with manually input for the exact values:

Starting 1.6 with new track concepts

The second half of October was devoted to initial 1.6 development. I didn’t want to start the big items for 1.6, so I tackled a medium sized task: introducing custom track curve weights, and using them to introduce track split, track taping and station taping.

Custom curve weight between track nodes

The NIMBY Rails track geometry is composed exclusively of circle arcs and line segments. There are no splines of any kind. Basically the user inputs a polyline of track nodes, and then the game tries to fit the largest possible circles in each corner of the polyline, cuts them into arcs at the tangent points, and uses line segments to connect the tangent points.

To “fairly” maximize the curve arcs, the ideal tangent points are chosen so they are always halfway between track nodes:

Let’s call this idea the “curve weight”, and say it is hardcoded to 0.5. This has served well for the past two years of game development. But now I wanted to implement track split while preserving the track shape, and realized this system made it impossible. As long as 0.5 remains the hardcoded weight, it is only possible to split a track at the exact middle point of its circle arc. So before I implemented track split, I lifted the hardcoded 0.5 weight, and made it customizable:

In 1.6 it will be possible to change track curve weights like shown in the video while in the track editor selection mode. Moving the middle point now changes the weight from 0 to 1, and changes the sibling track node so it changes in the opposite way. These middle points are not new track nodes and do not support selection of any kind. They are just the existing middle points, marked with the same little whiskers as ever, but now you can drag them up and down along the polyline to give more or less curvature to your tracks.

Track splitting

Custom weights made it finally possible to implement track splitting. This feature allows to pick a point in a track segment and automatically split the track in two new segments, with their middle point in the exact spot of the click:

It always tries to keep the previous shape of the track and it usually manages to with a good degree of accuracy, but it is not 100% perfect, since it works with the already stroked track. But for the current state of 1.6 it is precise enough.

Track tape tool

Track curve weights enabled track splitting, and track splitting enables a new track editor tool: track tape. Track tape is just the concept of picking two points in a track segment and inserting a new track segment exactly between these two points, possibly with a different layer and track kind:

Building viaducts and tunnels will be a much easier and fun activity in 1.6! The name is “track tape” for how the UI will look, but actually nothing is being taped over anything. The inserted track is a normal track, and it is actually linked to two new tracks which represent the previous and next segments of the original track, while making use of track curve weights to approximate the original track curve. This saves a lot of editing for the player.

Station tape tool

And finally, the composition of all these layers of new features and tools, the station tape tool:

This tool is just like the track tape tool, but it instead creates two track segments, and automatically sets them up as a station platform. So inline station creation will be possible in 1.6, while preserving the track curve shape.