OpenLoco v25.09 is out!

This is a major milestone of a release. We have finally implemented every single function from the original game. This means that, apart from graphics and sound assets, OpenLoco is now a complete reimplementation of the game! Talking of graphics assets, this release also contains a whole bunch of new OpenGraphics objects as well.

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

Changes and Features

Rotate Company Headquarters

@LeftOfZen was testing some refactoring to company headquarter ghosts, and noticed that you couldn’t rotate them from the UI. It’s a simple change, but adds to the consistency of the UI.

Improve Zoom to Cursor

Zoom to cursor was implemented many years ago, originally by @AaronVanGeffen on the OpenRCT2 project. Recently, on the OpenRCT2 project, @mixiate vastly simplified and improved the accuracy of the function. Aaron has now backported the improvements to the OpenLoco engine. It’s nice when we can share some code between the projects as the two engines are very very similar.

Disable Currency Selection in Title Screen

@LeeSpork found it odd that you could change the currency on the title screen. It didn’t do anything, but it was odd. Now it’s been disabled. It’s not too surprising this occurred; the title screen is basically displaying a save game like everywhere else. We should really get round to making our own title screen, like we have done for OpenRCT2.

Reimplementation

Implement Create/Remove Road Mod Game Command

These game commands are mostly useless as they’re only used to remove/add the catenary wires on tram tracks. I’m not sure why you would want to remove these wires, as trams require them to run. Either way, the commands existed in the base game so we have also implemented them. There is a huge amount of code for these commands, as they require iterating all connected tram tracks to remove/add the wires. One of the reasons to implement these commands is that their iteration code might be useful for other future features.

Implement Remaining Vehicle Update Functions

There weren’t many vehicle update functions left, but some of them were complex. The most complex were the road vehicle update. In particular was the function that calculated whether the vehicle should try overtake another vehicle. It does this by looking ahead for a slower/stopped vehicle and then lays out a chain of routings to change lane, overtake, then merge back. It did help finally resolve a bunch of unknowns I had with how the routings system worked. Other vehicle functions were the place down vehicle function, which is surprisingly similar to the overtake function, involving looking ahead for a clear section of road/rail to place, then laying out a chain of routings.

At some point I should really write a big blog post on how the routing system works, as it is complex at first sight, but easy enough to understand once you get stuck in.

Implement Update Traffic Handedness

I had left this function to the very, end as it did a bunch of moving about of memory that I didn’t want to implement. Instead, we can just duplicate the memory and reference the correct one based on traffic handedness. But I could only do that when all vehicle update functions were implemented. At the same time, I fixed an original bug where when road vehicles calculate lane occupancy if they are overtaking it would access invalid memory (company AI memory, to be exact). This could cause the check to return unexpected results. I’ve fixed this by ignoring overtaking, but I’m not 100% sure that that is correct. It is at least deterministic now. When overtaking, we should perhaps just say all lanes are occupied. Either way, perhaps something people should test and let us know if its a bit wonky.

Remove All Hooks

With all the functions implemented it was time to finally remove all the hooks into the original game. We are now free to modify interfaces to our hearts content, giving us lots of flexibility for new features. We aren’t fully standalone from the original game yet, as we still share some memory addresses, but it wont take long to change those.

With all the hooks gone we can also start getting x64 builds working, and perhaps even ARM builds.

OpenGraphics

We’ve forgotten to continue posting about OpenGraphics updates but they have been happening over the last few months; there are 24 new objects since we last posted in March about this, and they’re all by just 2 contributors, @shusaura85 and @glenjimen! Here’s a short summary:

Vehicles

@glenjimen figured out how to set up a modern Blender workflow and started generated some gorgeous vehicles, which all have twice the rotation frames as the vanilla objects so the look extra smooth in-game. I’ve highlighted the new vehicles/sprites in red in the below image. Starting at the bottom, we have OG_GRAINHP2.dat replacing GRAINHP2.dat, then OG_GRAINPH1.dat replacing GRAINHP2.dat and finally in the top right, we have OG_GOODS1.dat replacing GOODS1.dat:

Red carriages show the new OG sprites

Road Stations

@shusaura85 replaced all of the vanilla road stations as well as the bus stop with OG versions:

New road station New road station New road station New road station New road station New road station New road station

Tunnels

@shusaura85 replaced TUNNEL1.dat and TUNNEL2.dat with OG_TUNNEL1.dat and OG_TUNNEL2.dat, respectively. Vanilla shown on the left, OG on the right:

tunnels

Hill Shapes

The hill shapes object, HS1.dat, which controls how the vanilla terrain generation works, was replaced with OG_HS1.dat by @shusaura85. The new file has many more terrain shapes and much more natural shapes at that, generating some very nice terrain with vanilla generator. Vanilla is shown on top here, and the OG replacement on the bottom:

hillshapes

Streetlights

@shusaura85 replaced SLIGHT1.dat was replaced with OG_SLIGHT1.dat:

streetlights

Land

@shusaura85 replaced all of the land types with OG versions:

land comparison

Cliffs

Land objects have associated cliff objects, so these were also replaced by @shusaura85:

cliffs

Snow

@shusaura85 replaced SNOW.dat with OG_SNOW.dat:

snow

Water

@shusaura85 replaced ` WATER1.dat with OG_WATER1.dat`:

water

Updated: