Vanilla-Conquer
Vanilla-Conquer copied to clipboard
[TD] saving and loading causes bugs in game logic
Using the latest pre-build VanillaTD: vanilla-conquer-win-gcc-i686-85c834c.zip from 5-8-2021.
As usual testing covert operations mission 'infiltrated'. This mission seems to play fine without using the save system. But when loading saves things start to go weird. I did two play through attempts this way, which both came to a dead end because of the following:
- Harvester stuck unloading at refinery. (savegame.014)
- Harvester won't go to refinery, either automatically or manually. The triple green arrows cursor does not appear. (savegame.012)
- Minor: Enemy stealth tanks become visible near my units, but my units won't automatically fire on them. (savegame.012)
The two mentioned save files attached here. savegame.zip
EDIT: Testing some more. It seems these bugs come up in a very inconsistent manner. Loading the saves and watching things play out without issuing commands: the results vary.
EDIT2: Made a Win32 GCC 8.4.0 VanillaTD release build of current codebase 8d0d301. set(CMAKE_CXX_FLAGS_RELEASE "-O2"). Result: Same issues. Debug build: Same issues. I wrote regression in the title, but I suspect this is game-state data corruption in memory, that was already present months ago, but is becoming more noticable now.
Might be related to desync fix for harvesters.
I noticed several issues with the savegame while ago. Ion cannon cooldown being instant, airstrike disappearing from the sidebar, and even enemy turrets not shooting any of my units. I didn't bother opening a PR with this because these issues seems really random and hard to reproduce.
I test for this like every few months. Saving and loading is still a pretty sure way to get your units to ignore enemies in range, at least for a while. The other bugged unit behaviors, that I mentioned, I have not seen since.
Will change the title to better reflect the issue.

Whilst testing a recent build I came across the usual save-load oddities:
- Dino mission 4 has many reinforcements, but after a save-load they are mostly absent
- Loading a Skirmish save it gave the computer opponents instant-recharge ION cannon shots. All buildings on the map were levelled in 20 seconds.
Looking at saveload.cpp there is a whole debug dump procedure which mentions reinforcements like this:
fprintf(fp,"------------------ Reinforcements --------------------------\n");
fprintf(fp,"ActiveCount: %d\n",Reinforcements.ActiveCount);
for (i = 0; i < REINFORCEMENT_MAX; i++) {
fprintf(fp,"Entry %d: Active:%d \n",i,Reinforcements[i].IsActive);
}
fprintf(fp,"\n");
But the actually used save and load procedures don't mention reinforcements at all, or are they part of some other item there? Worth some investigation?
On second look, the more obvious save-load issues are the three SuperWeapons Ion/Nuke/Airstrike. AFAIK they are never saved+loaded properly.
Superweapon status is a "child" inside HouseClass. Two variables are key: RechargeTime and Control(time).
It should set for each of the SuperWeapons the "RechargeTime". This is not the remaining time but the total time for a recharge. It is not restored after save+load, and instead becomes zero/one or infinite. "RechargeTime" is a variable defined as private in SuperClass. Next the remaining time. This one is also not restored after save+load. This is "TCountDownTimerClass Control" declared private in SuperClass.
So there are several levels of classes nested in HouseClass, and only the parent HouseClass is saved+loaded properly here.
All RechargeTimes can easily be restored to their defaults when loading a game. But the "Control" remaining time cannot be easily restored somehow. One can add code to set them at the end of the loading procedure allright, but in practice some sort of re-initialization afterwards will then make Control = RechargeTime.