VOGONS


Reply 40 of 44, by Fujoshi-hime

User metadata
Rank Member
Rank
Member

In a world where people are pooping out AI slopped 'decompiles' of games, with no care for accuracy or dealing with bugs and walking off into the sunset declaring 'Mission Accomplished' after spending 2hrs with an LLM and making a YouTube video about it, I just want to say I appreciate the attention to detail you're making here. This really could be the best way to play RRT once completed.

Reply 41 of 44, by gerry

User metadata
Rank l33t
Rank
l33t
Fujoshi-hime wrote on 2026-10-02, 18:55:

In a world where people are pooping out AI slopped 'decompiles' of games, with no care for accuracy or dealing with bugs and walking off into the sunset declaring 'Mission Accomplished' after spending 2hrs with an LLM and making a YouTube video about it, I just want to say I appreciate the attention to detail you're making here. This really could be the best way to play RRT once completed.

that's made me think about all this, i'll post about it

Reply 42 of 44, by Wilczek_h

User metadata
Rank Newbie
Rank
Newbie

Dear Vogons,

@Fujoshi-hime: thank you so much for the kind words and for all the support. 😀

This is going to be a short post. I'm soooo happy to report that I managed to implement track and station building in the port! I even added the bridge building animations to it.

Check out this VIDEO!

I will share some technical details later and oh man, there are a lot of things to share. The track and station building in the original is quite buggy, but I fixed those bugs in the port. Some parts I had to reimplement from scratch as the original logic was so bad (I'm looking at you "bridge building logic"). I also eliminated the 32-station limit 😀 and increased it to 127. (Only 1 byte fits in the original structure that links a station structure to an extra station info structure. The high bit of the index is taken, so technically the limit could be 128, but index 127 is special, so the range is 0..126 giving 127 slots). I'm not sure how this will affect train routing though as in the port I cannot add stops to train schedules yet.

Anyway, I'm not releasing this version now as union station building is not yet implemented, it needs further testing AND I want the next release to be playable! So, what's next for me? Implement building a union station, collect the ASM code that is needed to add stops to train schedules and the ASM code that builds new trains. Then analyze and port those code fragments of course. If (and this is a huge if) everything goes well a playable version will be out in December.

Best regards,
Zoltan Farkas (Wilczek/FzSoftware)

Reply 43 of 44, by Fujoshi-hime

User metadata
Rank Member
Rank
Member
Wilczek_h wrote on 2026-10-13, 17:26:

Check out this VIDEO!

That's great. It's really nice seeing this proceed.

If you get time, I do have one track laying and general input request. In DOS, RRT could only do smooth curves or diagonals with commands from the 7, 9, 1 and 3 keys. Basically with the number pad treated as an 8 day DPad. I was trying on in DOS on my Steam Deck and you can't really make this input with an analog stick because they are often only four digital ways. Their diagonals are done by software seeing say both 'Up' and 'Left' at the same time as 'Go Up-Left/North-East' basically. RRT can't do that, it just quickly makes a track go up and another right with a sharp turn between them. This can also be an issue on modern 'Ten Keyless' keyboards that omit the numpad entirely.

Would it be possible to, come release, accommodate a combination of two directions as being a 'diagonal'?

Reply 44 of 44, by Wilczek_h

User metadata
Rank Newbie
Rank
Newbie

Dear Vogons,

I am super happy to let you know that I managed to implement the track, station and train building functions as well as all functions of the train report screen. This means I'm releasing a long awaited PLAYABLE VERSION to the public! 😀
Download the PLAYABLE VERSION HERE.

So, what's new in this release?
- The train report screen is now fully functional; you can add or change scheduled stops and use all the features of the screen. I also added mouse support for the "Change Station" screen (but only to this one).
- Building tracks, including tunnels, ferries and bridges (complete code!). Transcontinental bonus determination and related stuff is also implemented!
- Building signal towers and stations, including union stations and stations taking part in rate wars (complete code!)
- Building trains (complete code!)
- I implemented/enabled the animations for train wrecks (even though the displayed engines in the animation are incorrect. This is known, the logic to replace the engine assets in the animation is not yet implemented).
- Bridge building animations are implemented (however, the wooden trestle animation artifacts here and there, but no major issues are present),
- I also fixed a lot of bugs that were present in the original and the port is free from them. I will talk about some of those below.
- I increased the original's station limit in the port from 32 to 126!!! Now you can have tons of stations. (Note: there are 100 cities, so 126 stations should do 😀)
- I increased the original's train limit in the port from 32 to 126!!! Now you can run a lot of trains on your network.
- The original can build 64 junctions only. This limit is also increased in the port. The maximum is 126 now.
- The original can misbehave if you build a really-really large network as it starts overwriting other memory areas holding important stuff. The port allocates enough memory (because we are not limited by the base memory amount) to build tracks on all cells.
I also included 2 empty test maps in case you want to start building a totally new network in the port.

Some words about limits: while it was super fun to build stations and trains freely due to increased limits I realized that I stopped really thinking about the network, like selecting cities carefully or managing train stops. Since I can have 126 trains now, I just started to run a single train between every 2 stations. Less impressive cities were also added to the network as "ah, I still have free station slots, so why not". On the other hand, I built into many resource rich areas to pick up cargo (coal, grapes, etc.) as the 32 station limit is lifted. Again, this was super fun that I could build freely. BUT, the management aspect of the game got a little bit less focus. Therefore, I added the option to switch on the original limits to the Advanced Settings on the start screen, if you want to play like that. The default is off, so by default the port will use the increased limits. Let me know what you think about this.

The attachment FRRT_OptionToChangeLimits.png is no longer available

We need to talk about some important stuff, like how to build tracks in the port. Many of today's keyboards have no numeric pads. Therefore, in the port I had to come up with a solution. Here is how you can build tracks in the port today:
Hold down the Shift key and press any of the arrow keys or home, end, page up or page down. This works nicely on regular keyboards and on laptops that have no numeric pads. (This did not work on my surface pro 2 keyboard though, I will have to look into it).
If you have and prefer the numpad, you can still use it. Switch off num lock, press shift and use the numpad keys.
I'm considering adding other keyboard shortcuts for a more convenient building experience on limited keyboards, but for now the above methods would work on most keyboards.

@Fujoshi-hime: I tried to implement what you asked for, but the first results are not yet convincing. I have some ideas to get this right, but I need more time. If the ideas turn out to work then what you suggested will be implemented in the next release.

Here is a long gameplay video as a teaser:

And here is a short one if you have less time:

Now, let me write about the original game's bugs and design flaws I found in the collected ASM code after carefully analyzing it.
Let's start with track building:
The port is faithful to the original, yet its track‑building logic works quite differently.
Let's assume you want to build tracks: what the original does is that it runs some basic checks and builds. However, if a decision is needed things get complicated. A case where the original track building logic is flawed is bridge building. So, the original builds track on the 2 sides of the river, then, when needed, asks the user and continues building. The port doesn't do this, but more on this later.

Here are some cases where the original logic's flaw really comes through. Let's assume you start building tracks from London and the next cell is a river cell. The original builds a piece of track on the bottom part of the starting cell, on the other side of the river and then asks the player what kind of bridge should be built. However, if you choose cancel, things go haywire. The original needs to undo the built tracks on both sides of the river and well, it just does a very bad job. Some of the tracks are not removed, some cash is lost and an inconsistent state is left in memory preventing you to build tracks anywhere, even though you have no tracks visible on the screen.
Here is a video of this bug in the original.
Here is the video of the port fixing the above mentioned issue.

Another consequence of the original's build logic of "build-ask-build or revert" is the following.
Let's say you have a river flowing horizontally and below the river there is a horizontal track already existing. If you want to cross the river from above with new tracks then the original builds the first segment, tries to build the segment on the other side of the river, but it realizes that it cannot be done, so it displays "illegal track configuration". When the message is dismissed it happily asks you what kind of bridge you want to build. You select one and again you have an inconsistent state in memory.
Proof: (collected ASM code with my comments):

02BB:3B88  FF76E4              push word [bp-1C]           ss:[FF08]=002C // target cellY
02BB:3B8B FF76E6 push word [bp-1A] ss:[FF0A]=0046 // target cellX
02BB:3B8E E8A2F4 call 00003033_GetCellType ($-b5e)
02BB:3B91 83C404 add sp,0004 // AX=0003 FootHills
02BB:3B94 3D1800 cmp ax,0018 // check if river
02BB:3B97 7414 je 00003BAD ($+14) (no jmp) // if river, jump
// not river>>
02BB:3B99 FF76E4 push word [bp-1C] ss:[FF08]=002C // target cellY
02BB:3B9C FF76E6 push word [bp-1A] ss:[FF0A]=0046 // target cellX
02BB:3B9F E891F4 call 00003033_GetCellType ($-b6f)
02BB:3BA2 83C404 add sp,0004 // AX=0003 FootHills
02BB:3BA5 3D1000 cmp ax,0010 // check if Landing
02BB:3BA8 7403 je 00003BAD ($+3) (no jmp) // not landing, continue with the river code
02BB:3BAA E98D00 jmp 00003C3A ($+8d) (down) // not river and not landing -> jump
// river or landing>>
02BB:3BAD FF7608 push word [bp+08] // direction
02BB:3BB0 FF76E4 push word [bp-1C] // target cellY
02BB:3BB3 FF76E6 push word [bp-1A] // target cellX
02BB:3BB6 E846F9 call 000034FF_BuildTrackFromCellToDirection ($-6ba) // recursive call to the same function!
02BB:3BB9 83C406 add sp,0006 // AX: 0=track not built, 1=track built
02BB:3BBC FF76E4 push word [bp-1C] // targetCellY
02BB:3BBF FF76E6 push word [bp-1A] // targetCellX
02BB:3BC2 CD3F int 3F
FOR THE BRIDGE BUILDING TEST THE EMPTY ENGLAND MAP WAS USED (1828, Tycoon)>>
// INLINING IT HERE>> BUILD BRIDGE DECESION NEEDED + BRIDGE BUILDING CODE>> params cellX, cellY
1199:0228 55 push bp
1199:0229 8BEC mov bp,sp
1199:022B 83EC04 sub sp,0004
…
// END_INLINING<<
02BB:3BC7 83C404 add sp,0004
02BB:3BCA 0BC0 or ax,ax // check if bridge is built
02BB:3BCC 756C jne 00003C3A ($+6c) (down) // if the bridge is built, then jump
// OTHERWISE THE BRIDGE IS NOT BUILT>>
.. revert code here
//

Can you spot the issue at 02BB:3BBC? There are no checks, the original does not check the return value. The invoked function might display "Illegal track configuration", but execution continues and asks the user for the bridge type.

Undoing tracks while building is a huge amount code with overlay calls and half way through when collecting the ASM code I just stopped and decided that it is better to write my own track building version, using the ported checks and track building fragments as building blocks. So, how does the port build tracks. First of all, in the port there is a game state, game state update code and render loop. The game state update code cannot draw or update the UI and the render loop cannot touch the game state. I wrote about this earlier why this is so important.
Anyway, the port first just TRIES to build the track and if no blocker happens, it does build the track. When the player needs to decide what should happen (like build track or build tunnel if elevation is large enough or what type of bridge should be built) the logic simply returns that track building failed as a decision needs to be made by the player. No track is built!
Excerpt from the port:

//////// CUSTOM CODE TO FIX MANY BRIDGE BUILDING BUGS OF THE ORIGINAL>>
if ((this->function_02BB_3033_GetCellType(connectToCellX/*bp-1A*/, connectToCellY/*bp-1C*/) == 0x18/*river*/) ||
// 02BB:3B99-02BB:3BAA:
(this->function_02BB_3033_GetCellType(connectToCellX/*bp-1A*/, connectToCellY/*bp-1C*/) == 0x10/*landing*/)) {
const auto result = this->CheckBridgeCanBeBuilt(connectToCellX + this->cellXOffsetTable[direction], connectToCellY + this->cellYOffsetTable[direction], direction);
if (result.Failed) return result;

if (!decision)
return TrackBuildingResult(true, "Type of bridge?", std::shared_ptr<TrackBuildingNeededDecision>(new TrackBuildingNeededDecision(TrackBuildingNeededDecision::SelectBridgeType)));
}
//////// CUSTOM CODE TO FIX MANY BRIDGE BUILDING BUGS OF THE ORIGINAL<<

// 02BB:3AAD-02BB:3AB9:
this->function_02BB_3D50_BuildTrackInCellWithLayout(trackLayout/*bp-18*/, cellX, cellY, buildTrackVars);

Then the game updates the UI state and the render loop renders the UI.
Excerpt from the port:

const auto buildingResult = this->configuration.BuildTrackFromCellToDirection(this->configuration.focusedCellX,
this->configuration.focusedCellY,
static_cast<uint8_t>(direction),
decision);
if (buildingResult.Failed) {
this->CloseActiveMenu();

if (buildingResult.DecisionNeeded) {
switch (*buildingResult.DecisionNeeded) {
…
case GameConfiguration::TrackBuildingNeededDecision::SelectBridgeType:
this->activeMenu = this->CreateBridgeTypeSelectorMenu(buildingResult.Message);
this->activeMenu->SetActionHandler(std::bind<bool>(&GameContent::BridgeTypeSelectorMenuEventHandler, this, std::placeholders::_1));

this->guiManager->AddGUI(this->activeMenu);

break;
…

When the player makes a decision the track building is repeated, but the decision is passed as a parameter to the track builder function, so it can move on.
Excerpt from the port:

bool GameContent::BridgeTypeSelectorMenuEventHandler(const GLGUI::GLGUIBase::gui_id_t id) {
if (!lastDirection) return false;

const auto lastDir = *lastDirection;

switch (static_cast<BridgeTypeSelectorMenuItemIDs>(id)) {
case BridgeTypeSelectorMenuItemIDs::WoodenBridge:
case BridgeTypeSelectorMenuItemIDs::StoneBridge:
case BridgeTypeSelectorMenuItemIDs::IronBridge:
this->function_02BB_348A_BuildOrRemoveTrack(*(this->lastDirection), std::shared_ptr<GameConfiguration::TrackBuildingDecision>(new GameConfiguration::TrackBuildingDecision(
static_cast<GameConfiguration::TrackBuildingDecision>(
id - static_cast<GLGUI::GLGUIBase::gui_id_t>(BridgeTypeSelectorMenuItemIDs::WoodenBridge) + static_cast<GLGUI::GLGUIBase::gui_id_t>(GameConfiguration::TrackBuildingDecision::WoodenBridge)
)
)));

When all checks are passed and all decisions are made, only then the track is built. This way the port never has to revert any tack building, no inconsistent state will occur, no money will be lost if the user changes his/her mind and actually, no revert code needs to be written. This way the 2nd bridge building issue is also partially handled automatically, the remaining part is handled by an extra check. When building a bridge checks run, so we know whether building in the start cell and over the river is possible. Here the port simply does another (partial) check to see whether building from the river position (assuming that the river is the starting cell) to the other side of the river is possible. If not, the story ends, the error message is displayed (like "Illegal track configuration") and that's it. Nothing was built, so no revert is needed. If all the checks passed, the track building function still returns a failure, but with the code that a decision is needed. The bridge type selector menu is displayed and the user chooses an option. If the user selects "Cancel", then the port has to do nothing as no tracks are to be reverted. If a bridge type is selected then the build track function is invoked again, but now with the decision (chosen bridge type) and the bridge and the 2 sides of the bridge are built at once. This is simple to understand and sounds obvious, but it is easier said than done. I also eliminated the use of global variables in the port, so failed track building attempts can be repeated. Anyway, you will be able to enjoy a better track building experience in the port than in the original.

Now let's talk about building stations: this is just very buggy in the original. The original developers got lucky that the game didn't crash back in the days. There are corner cuttings, under indexing issues resulting in reading garbage memory, missing checks, etc. I'm not going to list all the issues I found and fixed, but here are some hilarious and some serious ones.

Let's start with the under indexing the station array (17ED:AFF0) issue:
When you build your first station (depot, station or terminal) the original calls a function that determines the index of the closest station to the spot where the new station is to be built. However, the original does NOT check the returned index, which is -1 when you are building your first station. Then it reads garbage before the array and works with garbage data to run checks, etc.. Fortunately, all the bytes are zeros before the array, but this does not mean you cannot trigger the bug.
Proof: the collected ASM code with my comments:

// ELSE >>
02BB:F016 FF36DC0B push word [0BDC] ds:[0BDC]=002C // cellY
02BB:F01A FF36DA0B push word [0BDA] ds:[0BDA]=0045 // cellX
02BB:F01E E8E6A8 call 00009907_GetClosestStationIndex ($-571a)
02BB:F021 83C404 add sp,0004 // AX=FFFF, no station nearby
02BB:F024 8946F8 mov [bp-08],ax ss:[FF12]=FFFF // closest station index
02BB:F027 B81800 mov ax,0018 // each station is described by 24 bytes
02BB:F02A F76EF8 imul word [bp-08] ss:[FF12]=FFFF // index to closest station, FFFF=INVALID!
02BB:F02D 8BF0 mov si,ax // rel. ptr. to closest station
02BB:F02F 8B84F0AF mov ax,[si-5010] ds:[AFD8]=0000 // READING BEFORE THE ARRAY, INVALID!!! Fortunately memory before the station array is full of 0s...; NORMALLY: Offset=0, &7 gives the station type
02BB:F033 250700 and ax,0007 // get the current station type from the flags
02BB:F036 0346FA add ax,[bp-06] ss:[FF14]=0002 // old station type + selected station type, so AX=0000+0002=>station
02BB:F039 8946F4 mov [bp-0C],ax ss:[FF0E]=0002 // new station type as a result
02BB:F03C 837EFA00 cmp word [bp-06],0000 ss:[FF14]=0002 // check if the selected station type is a signal tower
02BB:F040 7459 je 0000F09B ($+59) (no jmp) // if signal tower->jump
// otherwise check if the covered area by the station does not overlap with another's station area>>
02BB:F042 A1DA0B mov ax,[0BDA] ds:[0BDA]=0045 // focusCellX
02BB:F045 2B84F2AF sub ax,[si-500E] ds:[AFDA]=0000 // INVALID WHEN BUILDING THE FIRST STATION!; Normally: offset=2, station Y

So, since all the bytes are 0s that means the original believes that there is a signal tower at location 0,0 that is treated as a station!
Let's test the theory: let's build a station in cell 1, 1, aaaaaand yep', the bug is triggered:

The attachment RRT_UnderIndexingBugInTheOriginal.png is no longer available

In the port this bug is fixed. By the way, the original does NOT update the cash until the map is redrawn. The port always displays the actual cash amount, even if you build tracks while the time is frozen.
By the way, the port draws the area types nicer. If it does not fit on the screen then it won't draw the words on top of each other, but moves the text to the bottom part of the rectangles. A little bit of a nice touch 😀.

The attachment FRRT_NoIssueInThePort.png is no longer available

Now let's take a look at a hilarious one:
You can build stations on the tracks of the opponent! 😀 The problem is that the original only checks if there is a suitable track in the cell where you want to build your station. The ownership is not checked. Nice 😀
Here is a video of this issue in the original.
Here is a video about how the port behaves in the same situation.

Destroying and rebuilding stations: if the first station is destroyed (or downgraded to a signal tower) and there are other stations then the newly built station will get an engine shop as the first station slot became free earlier. This is just annoying that you might have an engine shop in another station and you are forced to pay 100k for an engine shop, just because the original only checks if the slot index is 0.
The port does the following: it loops through the existing stations and checks if some of the existing stations already have an engine shop. If yes, then the port only builds the station without the engine shop.

The "take money for nothing" bug: When the station limit is exceeded in the original the message is displayed, but the price of the station is taken! This bug was easy to fix, in the port I only subtract the price of the station when it is actually built 😀. Fair enough I guess…

The "bookkeeping bug": when you build your first station an engine shop is automatically built. However, the developers did some corner cutting here:

02BB:F378  C784DCE40100        mov  word [si-1B24],0001    ds:[E4DC]=0001 // offset=80, builtImprovements=0-->1 engine shop
02BB:F37E 832EAA9564 sub word [95AA],0064 ds:[95AA]=0374 // current cash -= 100, the price of the engine shop
// THIS IS INCORRECT, THE ENGINE SHOP WILL NOT BE COUNTED AS FACILITY PROFIT!!!

In other words there will be a 100k LOSS on the balance sheet. Normally, when you build an improvement your cash amount is decreased, but the facility value increases.
The port calls the proper function, which does the bookkeeping :

this->BuildStationImprovement(stationIndex/*bp-0C*/, StationExtraInfo::Buildings::EngineShop);

Another annoying bug in the original: when upgrading a station: the price is subtracted even if the same station type is selected (station upgraded to a station). The port checks if there is no upgrade and no downgrade.

So, you might have wondered whether the original's 32 station limit can be somehow lifted? Here is what I found in the ASM code, actually, you can have 33 stations, but there is a caveat! Anyway, here is how to do this: when connecting tracks to an opponent station and the opponent is bought by the player, but station limit is exceeded: it displays the message that a union station is built in the city, but only a signal tower is built (due to the limit). Removing the signal tower and trying again will build a new station successfully and the original will go over the limit by under indexing the array and overwriting memory areas.
Video of the bug in the original.
Obviously the port fixes this when reaching the limit or the extended limit (depending on the settings). Since the port does not build anything without checking if the track segment or segments can be built, no issues happen. The original runs some basic checks, builds and if it finds itself in an "uh-oh" situation it tries to revert, quite unsuccessfully.

Another "taking money for nothing" issue: when connecting tracks to an opponent station the track attributes are changed and the station price is taken, even if the station is not built due to exceeding the station limit.

The "serious corner cutting that backfires twice" case:
When a union station is built the original shows the image of a station, but the station is immediately converted to a terminal after the screen. Pressing "I" on the union station will show a terminal. This is because the code by default builds a station and only then it checks if the opponent is bought by the player. The corner cutting here is that the original just modifies the flag of the station to be a terminal. A one liner fix, right? Well, this is first of all misleading. The game shows a station and after that you see a terminal on the map. BUT the worse thing is that due to this some cargo might not be produced correctly. Let's assume you have 2 vineyards around the city that would only be considered if you built a terminal. The original first builds a station then calls the produce cargo at station. Anything that is within the area of a station would produce the cargos. Then the game flips a flag and you have a terminal and now 2 vineyards could produce grapes. But the original misses these and no grapes cars will be produced initially. Even the "supplied cargos" list would be incorrect.
Here is the corner cutting code:

02BB:3A6C  808CF0AF01          or   byte [si-5010],01      ds:[B290]=4002->4003 // flags of union station->so making a terminal from a station by adding 1!

The port correctly shows a terminal and the supplied/demanded cargos as it builds the station with the correct type by checking whether the opponent was bought:

stationBuildingResult.reset(new StationBuildingResult(this->function_02BB_F27D_CreateStationAt(connectToCellX/*bp-1A*/, connectToCellY/*bp-1C*/, 
companyOwnedByPlayer ? StationInfo::StationType::Terminal : StationInfo::StationType::Station,
nullptr))); // force not to sell stocks to city leaders

Video of this bug in the original.
The port handles this correctly: video

Another serious bug in the original (which is fixed in the port):
When connecting to a union station from the other direction the original rebuilds the terminal as a simple station, takes the money, renames the station (for example Berlin -> Berlin Hills) then converts it to a terminal (by flipping a flag) and renames it back to Berlin.
This is wrong, the station is destroyed (with the already available cargos), rebuilt and the player looses money, and then cargos could be incorrectly produced (mentioned above).
The port fixes this by checking if the player already has a station at the location (not just checking if the cell contains a station owned by an opponent). If the player's station exists then it just connects the 2 sides of the tracks, handles the signals and calls it a day.
Video of the bug in the original.
This is how the port handles this case: video

The case which the original developers could not solve due to the track building design flaw (no way to revert properly):
Precondition: building a bridge over the river and the next cell is an opponent RR station: first the station will be built(!!!), rate war is declared then the bridge type will be asked, but selecting the CANCEL option will pop up the menu again and again. The player is forced to build a bridge now that the station is already built.
I think this is fundamentally wrong. If I, as a player, want to build over a river then the game should ask me what type of bridge I want. I could still press cancel. If I go ahead only then should the station be built on the other side of the river.
Video of this bug in the original.
The port fixes this as it builds track differently. The port will ask the player first about the bridge type and if the player presses cancel then everything is good. If the player goes ahead then first the bridge is built and then the station. Video

Last, but not least, the original's schedule handler code is also buggy:
Here is how to trigger the bug:
1. build 2 stations
2. build a train
3. destroy all stations
4. then rebuild stations
5. add the 2 stations back to the schedule(!)
6. when the train arrives it displays this, even though the schedule is correct:

The attachment RRT_ScheduleHandlingBugInTheOriginal.png is no longer available

The reason of this issue is that the destinationStationIndex at offset 0x91 is not updated by the original! In fact, if the scheduled station is changed, then the destinationStationIndex is not updated, the schedule shows the new station, but the train will go to a different station!
I fixed this issue in the port the following way: if the scheduled stop is changing -> update destination station index, if no station at scheduled stop then go to the priority station if no priority station exists then go to the first stop if exists, otherwise no change and showing impossible route.

I hope you will enjoy the port and the fixes and will see value in the port 😀.

I also need to mention a tiny quirk in the port:
On the change train schedule screen the red arrow (representing the train's position and heading) might be very much off the lines. This is something I will resolve later, either by projecting the point of the train's position to the track line or reimplementing the original's network drawing logic with a custom one. How is the network drawn? The stations (depot, station, terminal) cell coordinates are mapped to screen coordinates as well as the junctions' cell coordinates. These mapped points are then simply connected with straight lines. If the real track lines seriously deviate from the straight lines between stations then the red arrow (representing the train's position and heading on the screen) can be very much off in the port. This issue is also present in the original, but there the issue is less pronounced as the original uses a 320x200 resolution. However, in the port the "slightly off" can be "way off" as the network is scaled accordingly to the window size. Any "errors" are also scaled. This does not alter the usage or functionality of the port, it is just an aesthetic issue. I'm considering changing the original logic and drawing the real network, but I will play with this idea when no other features are missing from the port.

What's next for me now?
I will implement track (and station) destruction and converting a piece of double track to single track. I have already collected the necessary ASM code and sort of analyzed it, but I need to go through it again. Some stuff is already fishy, but I don't want to jump to early conclusions. Then I will implement the "build industry" feature.
After that I will investigate the computer player logic of the original. I'm not really keen on it; I very much enjoyed a stress-free building experience in the port 😀, but the computer player logic needs to be added in the end. However, I will give you a "Play Alone" option to switch off computer players 😀 if you want to play without computer players.

Until then, enjoy the PLAYABLE PORT. As always if you find bugs or issues in the port (because I'm sure I also introduced a couple of them) then please let me know. Thank you for reading and giving the playable version a chance.

Take care and best regards,
Zoltan Farkas (Wilczek/FzSoftware)