A project to decompile SMAC/X to C++ with the long term goal of creating a full open source clone.
Source tested and compiled as an x86 DLL with Visual Studio 2019 using Visual C++ with default settings.
Tested with CodeBlocks 20.03 using GCC 8.1.0 compiler. Project file (cbp) courtesy of induktio.
The patcher script found under tools is compatible with the latest GOG version as well as the most recent version of my unofficial patch. Cursory testing shows it is compatible with PRACX.
You can follow development progress, discuss ideas or issues here:
https://alphacentauri2.info/index.php?board=23.0
v0.2.3
- Lots of additional analysis, clean up, refactoring, and optimization of the existing code base.
- Fixed four bugs within OpenSMACX code.
- Created new probe related source files (two net new functions, shifted one existing).
- Implemented one of the probe related fixes from my unofficial patch.
- Additional work on Path class (almost complete, 3 functions left).
- 55 net new functions across multiple areas.
- Cumulative decompiled and redirected function count: 420
Bug Fixes:
- Fixed a bug with OpenSMACX where a small change to how the Random class was reseeded from the default behavior caused rivers globally to shift. This happened whenever a Borehole or Condenser was built by any faction. I'm still unsure as to why. Something to review again in the future when more of the world code is decompiled.
- Fixed a bug with OpenSMACX where after selecting a random faction for a game, afterward on game start the game would throw a faction parsing error related to JENN282. This was due to the JENN282 code not being implemented in read_factions(). Originally, it looked like this was left over debug code so it was skipped. As it turns out, JENN282 is the internal faction identifier that SMACX uses for a random faction. Thankfully, this was the only place in the project where code wasn't implemented like this (excluding obvious optimizations). Multiple improvements to the code's performance and fixes for fringe cases were applied to this parsing code.
- Fixed an issue with OpenSMACX where two functions (tech_ai, rnd) weren't having rand() reseeded properly. This was caused by my_srand() only having the old built-in version of srand(). Both need to be initialized while the project straddles new and old code base.
- Fixed a preference parsing bug with OpenSMACX where "Time Controls" default value could have been set as "0" rather than "1". This was due to an oversight in how the return value was processed by prefs_get(LPCSTR, int, BOOL) when the useDefault parameter was set to true. This code is part of some of the earliest decompiled functions prior to my including comprehensive regression tests into the decompile process.
- Fixed a bug inside success_rates() where a probe wouldn't receive a penalty to its survival rate when it targeted a faction that has the Hunter-Seeker Algorithm secret project. Instead, its success rate would be given an erroneous 2nd penalty. This issue was somewhat masked because the 2nd penalty happened after the success rate had already been written for display by the UI. This bug caused a lower success rate and increased survival rate of probes targeting an HSA faction.
- Fixed various issues related to the Scenario Editor undo/redo mechanic. Undo auto-saves weren't properly saved outside of the 1st one because auto_undo() didn't include the ".SAV" extension to process previous auto-saves. Undo auto-saves weren't properly removed because wipe_undo() didn't include the ".SAV" extension. Added in logic to prevent being able to attempt a redo before an undo has taken place. Fixed a map redraw issue after loading an undo or redo where units and tiles wouldn't be properly redrawn.
v0.2.2
- Lots of clean up and optimization of the existing code base.
- Initial work on the Path class.
- Added some Council related functions.
- 50 new functions across almost every game related area with a focus on Map and Technology.
- Decompiled and redirected function count: 365
Bug Fixes:
- Fixed a bug under certain conditions that the end game function to determine whether a faction is nearing a diplomatic win (Supreme Leader) would return incorrect results. The function aah_ooga() is called with the 2nd parameter set to -1 in certain instances. The original code would then attempt to use this value to check the pact status within the player_data structure of the 1st faction parameter. In these instances, it would actually be trying to do the diplomacy check against last_turn_new_base value. There was a check to skip the pact check if the 2nd parameter was 0. The fix now accepts -1 or 0 to skip the pact check.
v0.2.1
- Some additional map functions to get ready for working on Path class.
- Miscellaneous clean up.
- Fixed an issue with the patcher script incorrectly patching best_specialist() and base_making().
- Decompiled and redirected function count: 315
Bug Fixes:
- Factions with the FREEPROTO flag (Spartans) will gain free retooling in their bases as long as the production switch is within the same category (unit to unit, base facility to base facility) and they've discovered the necessary tech for Skunkworks (default is "Advanced Subatomic Theory"). This is to resolve the issue with FREEPROTO factions never being able to gain the undocumented retooling ability of a Skunkworks found in base_making(). There is good indication this was likely an oversight and that the FREEPROTO flag should be the equivalent to a free Skunkworks for the faction's bases.
v0.2
- Veh, Map and Base related code that sets the groundwork to break down more complex functions.
- Engine classes: Font, Spot, Time.
- Decompiled and redirected function count: 308
Bug Fixes:
- Added an additional check to facility_avail() that prevents the Caretakers from being given the ability of selecting the secret project "Ascent to Transcendence". This goes against their core philosophy and would cause them to declare war on themselves if initiated.
- Sealurks no longer receive a movement penalty when moving through Sea Fungus. They are now treated the same as an "Isle of the Deep" as intended. This was likely an oversight to add the specific check to hex_cost().
- Added a new check inside facility_avail() that prevents building Paradise Garden if you have Punishment Sphere built or in queue. There is a check to prevent Punishment Sphere from being constructed if you have Paradise Garden but not vise versa. Paradise Garden and Punishment Sphere are antithetical facilities where you can build either one in any given base, but you were never suppose to be able to build both.
- Fixed a bug in DirectPlay multiplayer that likely caused a performance hit when moving units due to a faulty coordinate check. Whenever the stack_fix() function was called by moving a unit or other actions, it would cause every stack of units on the map to be sorted in a certain way (at least temporarily) as well as redundantly sorting the same stack once for every unit on the map.
- Removed an extra space displayed for certain prototype statistics (Ex. Transport Foil) shown in the Military Command Nexus via say_stats() function.
- Fixed logic inside offense_proto() and armor_proto() where under certain conditions the game would try to compare an arbitrary memory value against the Spore Launcher basic unit id. If they matched, non-PSI units would display incorrect offense and defense values. This happened any time you clicked on a non-PSI unit when calculating its offensive value. It was just incredibly rare the memory address value would match the Spore Launcher id. While it was unlikely this would be triggered by armor_proto() due to logic flow, added in a preventative bound check anyway.
- Fixed a bug in Time::pulse(void(__cdecl *)(int), int, uint32_t, uint32_t) where the Timer event could have persisted and executed continuously when it should have executed only once. It seems affected code branch was never used by the original game.
- Miscellaneous additional error handling or bound checks to various functions (see source).
Enhancement:
- Added the ability to set a reactor value (1-4) for #UNITS inside alpha/x.txt. To do so, add a comma after the Abil field with the value of the reactor you want for the unit. If no value or a value of 0 is set, it defaults to 1 (Fission Plant) like the original code. For SMACX only, there are two exceptions where the default isn't 1 but 2 (Battle Ogre MK2) and 3 (Battle Ogre MK3). The Ogre defaults can still be overridden. Ex. "Colony Pod,..., 00000000000000000000000000,4" will give Colony Pods a Singularity Engine.
- Added some basic randomization for sea base name order. This mostly affects Pirates since the randomization method isn't great for small lists. Base name count increases once all names inside faction files and basename.txt are exhausted rather than stopping.
v0.1
- Parsing in alpha/x.txt and faction text files complete
Bug fixes:
- Fixed crash if BaseButton::set_name(LPCSTR input) parameter was NULL.
- Fixed bug with TextIndex having carriage return at end of "HEADER\r" breaking compare. This could have had significant performance increases back in 1999. Not so much in the time of cheap SSDs.
- Fixed bug if Heap::get() realloc ended up shifting memory to a different location (unlikely).
- Fixed crash in proto_cost() found via fuzzing/testing. Could be triggered by mods.
- Fixed Retool strictness in alpha/x.txt to accept a value of 3 (never free).
- Fixed setting alpha/x.txt probe teams can steal technologies now only to accept 0 or 1.
- Fixed setting alpha/x.txt humans always contact in net games now only to accept 0 or 1.
- Fixed setting alpha/x.txt humans always contact in hotseat/email games now only to accept 0 or 1.
- Fixed setting alpha/x.txt obliterating a base counts as an atrocity now only to accept 0 or 1.
- Fixed soc_ideology_effect overriding faction text files with -1, disabling AI faction "Emphasis".
- Fixed reactor power value being ignored when parsing. Game still won't use this value until more code is decompiled since hardcoded values are being used throughout.
Changes:
Improved how Random::reseed sets new seed value.- Improved performance of proto_cost() without changes to original logic.
Removed debug code related to non-existent faction JENN282. Nothing of value. SMACX binary only.- Various optimizations without changes to original logic.
Enhancement:
-
The original code explicitly sets facility freetech value to disabled (-2) overriding alpha/x.txt.
It states in #FACILITIES alpha/x.txt: "Free = No longer supported". This mechanic could have been removed for balance reasons or dropped due to time constraints. There is code that checks this value and sets the free facility only for new bases built after discovering the tech. It looks like existing bases do not get it. This will have to be reviewed more. For now, this mechanic is included as is. You can revert to vanilla behavior by modifying the four entries below in alpha/x.txt #FACILITIES with free tech parameter set to "Disabled".Recycling Tanks, 4, 0, Biogen, EcoEng2, > free with "Adv.Ecological Engineering" Recreation Commons, 4, 1, Psych, SentEco, > free with "Sentient Econometrics" Energy Bank, 8, 1, IndEcon, QuanMac, > free with "Quantum Machinery" Network Node, 8, 1, InfNet, HAL9000, > free with "Self - Aware Machines"