OpenLoco v24.09 is out! In this release we have made a few little tweaks to the landscape generation and implemented various vehicle functions.

For a complete summary of changes, please find the OpenLoco changelog on GitHub.

We’d also like to draw your attention to the new Object Editor release, v3.0.0! It adds the option to browse custom objects from an online directory, so be sure to check it out!

Implement Update Track / Road Motion (#2174, #2588)

Vehicles travel along tracks and road in much the same way. There are fixed lanes that they can travel, with all positions along the lane precomputed. When a road vehicle needs to overtake, it enters/leaves an overtake lane. Moving along a lane is controlled by the UpdateMotion family of functions. With these functions, a speed is converted into a distance travelled in a single update tick. It then iteratively looks up the new positions in the precomputed lane data (sub position data).

In OpenRCT2, these functions were very complex and handled a lot of special case situations. For this reason, we had been putting off doing them for some time. Recently, I had taken a look at a bug tangentially related to the function, and realised they were really quite simple for Locomotion. Although very simple, these functions are called a huge amount of times, so they represent a huge amount of the code that was still running vanilla.

With both of these implemented, it takes us another small step towards being able to add new track or road pieces.

Implement Paint Road (#2580)

Much like the track paint functions from v24.02, the road paint functions represent a huge chunk ~3% of the vanilla game. Like the track paint functions, they are repetitive and probably were automatically generated by some sort of code generator. Annoyingly, they don’t share enough to use the same code as we did for track paint, but we could use the same technique (TestPaint) to generate our C++ version.

With them implemented, it’s another big jump in percentage completed, and another step towards being able to add new road pieces.

Implement Create Airport Game Command (#2585, #2568, #2598, #2603)

In the implementing game commands project this month, we start with finishing the airport creation command. Airport creation is a simple function that is very similar to the other building related game commands (Industry, Building, Docks). However, it identified a slew of small mistakes we had made in previously merged code. Issues:

  1. Sounds generated using the wrong random number generator. Turned out that there is one random number generator used only for sounds and ui and another for game logic. We had accidentally been using the game logic one for sounds. It doesn’t really change anything but it would have caused issues when it came to multiplayer.
  2. Large square stations couldn’t be created. We had known for a few releases that our code for finding nearby stations wasn’t quite correct and would prevent 16x16 square stations. It wasn’t until Create Airport, though, that we had to solve that issue as it was causing a very minor desync.
  3. Road vehicles may use the wrong track type when reversing. This is actually a vanilla mistake, which we accidentally duplicated. It’s unlikely to cause any real difference, as it appears this was only being looked at for working out max speeds on turns. However, it is possible that this might cause a crash. Either way, it’s now corrected. It might seem odd that we found this whilst doing an airport function. However, it’s because in the process of resolving the nearby station issue I implemented another function that was also used by road station placement, which surfaced this bug.

Implement Track Removal Game Command (#2571)

Also on game command front, @AaronVanGeffen implemented the track removal game command this month. Much more straight forward compared to track creation, but still complex in its own ways.

With this one implemented we now have only 14/84 commands left to implement. Four of these are road versions of track commands, and four that look to be AI-only functions. The rest seem to be related to the old two-player game implementation. We might be able to omit these, as our multiplayer mode is planned to work in a different way.

Implement Map Generator Terrain In Random Areas (#2594)

Another two functions from @AaronVanGeffen that finished off the last of the map generator! We now have complete control over map generation and @AaronVanGeffen has been using these new powers to start adding new features to the map generator…

Add Riverbeds To Map Generator (#2597)

With the map generator no longer depending on any vanilla routines, we can now extend it to our hearts’ content. This month, we’ve added functionality to automatically add rivers to your maps! This works by carving out riverbeds throughout the landscape, then filling these with water as specified by the regular ‘sea level’ parameter.

To make these rivers a bit more dynamic, you can customise several parameters. These include the river width, the meander rate (curvature), and the riverbank width. This last parameter smoothens the landscape along the river, such that the river actually looks like it’s carved out the landscape.

Rivers

Implement Scenario Preview Generation (#2608)

Whenever you browse the scenario list, a preview map appears on the right of the window. This map is actually already prerendered in the scenario file, so the game doesn’t have to worry about figuring out what tile goes where on the map. As it turns out, we actually hadn’t reimplemented this render step in C++ yet, though. That, too, has now been taken care of!

Implement Misc. Company Manager Functions (#2573, #2606)

Last week I thought I had implemented all of the functions that used the object index, but I keep finding one or two more misc. functions that still use it. This month, it was the automatic company face selection that happens when you start a game, or when an Ai is spawned. It’s not a complex function in C++, but in assembly it is very long and winding due to the complexity of the object index. It’s great to have it completed, and hopefully this time it’s all of the functions that use the object index!

Updated: