NIMBY Rails devblog 2020-12

NIMBY Rails Early Access is releasing on 26th January, 2021

The release date is finally revealed! NIMBY Rails Early Access will be released in Steam on 26th January, 2021. It’s been a little over 2 years since I started working on the game and it’s a huge relief to finally put it on sale. There’s still some areas that need major work (I can’t wait to start the final, more complex track model code), but I believe the EA build goes most of the way to my vision for NIMBY Rails. And it’s just the beginning!

City population is now a factor for destination demand

After some discussion in the Steam forum, I decided to prototype some of the demand code on top of city population. I was hesitant about this since this data is spotty in my database, plus I have very coarse geolocalization of city boundaries, so the matching of stations to cities can often be very wrong. But it does add some extra variable that makes demand more believable. After some testing it doesn’t look so bad.

Now 90% of new pax pick their destination based on a normal distribution over the reachable city destinations from a given station, sorted by descending population. The other 10% will make a random choice. The actual station within city is still random, to allow for interesting transfer scenarios. Additionally the total demand of any given pair of stations station is modulated by the population of both the origin and the destination when generating a new pax.

This introduces even more knobs into the demand simulation, which will need tuning later on as game testing advances.

Historical accounting for most objects

Detailed accounting was introduced in a previous update, and now said accounting is stored in historical series for different kinds of periods:

Pax statistics are also now being stored in the accounting data, not just cash. The data is also ready for graphing, but that will have to wait for a future version.

Accounting is also now being tracked for most kinds of cash or pax manipulating objects. Stations, trains, lines all have their own historical accounting, although the available period series is sometimes limited so the required storage does not explode in size (specially important in the context of multiplayer):

Loans

My original ideal for in-game financing is based on simulating public contracts, as it’s most often the case for real world train projects. But as long as the city database remains limited, and as long as there is no detailed population layer, I prefer to not attempt to implement such a system. For now I’ve implemented a loans system, which was always a required feature.

There’s no complex credit rating or similar filters. The game only allows to take 3 simultaneous loans, plus there is some hopefully sane limits on the amounts. After you take a loan the game pays for it monthly, and you can track your progress or pay it off early for an interest discount:

Optional OpenGL renderer

Back during the Steam Festival of June, some AMD users reported graphical corruption with the game demo. I was never able to reproduce it (apparently the AMD hardware I tried was either too old or too new), but I’ve been ever since improving the low level rendering code to deal better with possible error conditions. One of the new features for the EA build will be an optional OpenGL renderer, on the theory that maybe users who see errors with the default Direct3D 11 renderer may see some improvement by switching renderers. Additionally bringing up this renderer made me fix some issues with shaders that were not apparent under Direct3D.

New New York build for trailer EA cut

This month was leaner on programming work since I was focused on testing and polishing. A major task was to remake the fantasy New York subway network I did for the trailer, with the goal of using the new features the game has gained since, plus to find UI/UX bugs.

These big builds always result in small new features as I use some tools and find some thing repetitive or incomplete. For example in the screenshot you can also see the new visualization for stops on lines, which was very tiny in earlier versions. Now there are clear markers for said stops and they match the arrows locations in the lines editor. The next two new features are also a direct result of building this new map.

Improved AI for leaving/boarding trains

The test NY map has a very large of transfer stations, where 2 or more lines stop. This means most generated pax is going to change trains in their trips. When I started adding trains and looking at how pax flowed I realized they boarded trains in their first step, but then never left. They just remained forever inside the train, until they were kicked out by the “pax is lost” timer (and refunded and compensated, of course).

Analyzing the cause, I realized the problem was that with such an interconnected network, there are multiple paths to a single destination. And the pax AI, before deciding if to leave a train to transfer into a station, was asking itself, “if I stay in the train, can I still reach my destination (by changing in some future station in this line)?”. In this map, that answer is very often always yes, for all stops in a line. The pax rode the train forever.

What was missing was taking into account the cost (for some definition of cost) of the potential trip at each station, amending the question to “do I reach my destination faster if I stay in the train, or if I leave now and transfer into a different line?”. I fixed the AI so now it can consider the best possible trip to a given destination, not just if said destination is merely reachable.

Fixing this has also enabled some degree of support for express trains. Said trains are often running on lines that have many stops in common with other lines, but which skip them, and/or are running on faster engines. This way pax will be able to pick the fastest train and skip slower ones. With a big caveat: they cannot consider the waiting time in the station in this decision, so they may still pick wrongly in the end. This may be fixed in the future if/when fixed matrix timing is introduced, which would be a natural feature for said fast lines.

Adding this feature is now making it more important than ever that players correctly set up the desired leg timing between stops in lines. Otherwise the AI has no information to pick the correct trains and will degrade to merely picking based on connectivity alone.

Simple interval scheduling

Precising timing of long distance, long period trains will have to wait, but subways often run on interval schedules rather than fixed timetables. I realized it was relatively easy to add such a feature, so now it is possible to set a minimum interval time for line stops:

This minimum interval time is enforced by making the trains wait longer than the “min. wait” time if required. The game now keeps track of the last time a train visited a station platform for a given line, and will add extra time to the next train that visits it if the resulting interval would be under the selected minimum interval.

This feature makes it very easy to evenly space subway-like lines. Divide the total time required to travel the entire line (the game tells you automatically in the Stops panel, as long as you set up the leg times), the decided how many trains you want running in the line, and divide said time by the number of trains. That’s your interval timing, and the game is able to enforce it:

The big BUT of this feature, as it would be for any timing/scheduling feature, is the capability of the game to also enforce the leg timing. And this won’t be fully possible until the more complex track model is implemented, with signals and single track, to enable complex but efficient junctions and traffic flows. If there is not a lot of track sharing and branches are rarely used, this timing feature works very well. But on very busy tracks, like the last stations in the screenshot, it cannot keep up, since the trains are often forced to wait for too long during the trip to the station, outside of the control of this feature.