Don't implement any new features until you fully reimplement original game or at least big part of it such as geoscape.
That is the plan. Any improvements I introduce in the mean-time are purely because of how simple/handy they are.
Create separate programs for geoscape and battlescape. Use the same file format as original X-COM. This will let you replace one of the programs with original program running inside DOSBox. Share source files between these programs. Don't create shared libraries, just compile them from overlapping sets of source files.
That is a very bad idea:
- Having a program split into pieces like that is just asking for trouble. Sure back in the day you needed to save extra byte of memory you could, but you have to manage information between programs yourself which is bothersome and error-prone, there's no proper way to handle one of the parts failing (when the X-Com Battlescape died, the Geoscape wouldn't notice and just use the last available mission results), and it just restricts the parts needlessly (you couldn't quit or load saves from the Battlescape because the Geoscape had to do that). Who knows if I won't later extend the game to a point that the Geoscape and Battlescape should be tied together.
- The community still hasn't fully reverse-engineered the game's file formats, so a lot of them still remain a mystery and it'd force me to have to wait around until I could use them. Plus the old file formats also bring a lot of old bugs and limitations with them like the "proximity mine bug", the various engine limits, and in the end it'd just restrict me from extending them and taking full advantage of a new engine.
I get that in a perfect world this would mean that I could write a new Geoscape and you'd plug it in with the old Battlescape and pretty much have a full game in half the time wouldn't that be awesome!!!!!, but I don't even want to imagine the trouble of getting both to cooperate without issue, specially if you mixed platforms. In any case the point of OpenXcom isn't to reverse-engineer the original and replace/patch it (there's already plenty of hacks trying to do that), but to provide a new clean codebase based on the original but relying on modern standards and practices, to not be bogged down on all the old needless restrictions, file formats and so on.
Use less abstractions.
For example, you have "Soldier" class. Most of it's methods just get and set private fields. There is only one place in code that modify soldier's names, it can handle everything that is related to renaming so you don't really need "setName" function. And nothing is calculated when you get name so you don't need "getName" method. Just make "name" field public.
Well this is mostly me sticking to OOP best practices and keeping the code consistent. Never having classes with public fields, always use get/set methods, etc.
I know this can get kinda painful since inevitably a lot of classes in a game are just gonna be a bunch of numbers. Hell, looking at the Soldier class as is now, why don't I just replace it all with one line like:
struct Soldier { int _tu, _stamina, _health, _bravery, _reactions, _firing, _throwing, _strength, _psiStrength, _psiSkill, _melee; }
Now that's a whole lot simpler with virtually the same functionality! Man all the time and lines I could've saved.
But then the code starts getting kinda ugly. You get stuff mixed like "save.funds -= base.getTotalMaintenance()". Then you don't know if some class uses a getNameOrSomething() or do I access the field directly. What if I suddenly decide I wanna append something to the end of soldier's names? Or start validating user input?
I know this is all exaggerating and you're probably right that a name will always be just a name and so on, but I like sticking to these kind of standards as it teaches me to be consistent and not get carried away and be lazy. It's a slippery slope, I'm very prone to being lazy and next thing you know the code is all condensed in a few lines with no comments or anything and you'll have a real adventure trying to modify it.
Also you have XcomRuleset that is based on Ruleset. You don't really need more than one ruleset in one game, just create one "Ruleset" class and everyone will be able to modify it if they want to change rules of the game.
Ruleset is probably a bit of a misnomer. In fact I still haven't set in stone what it really does, but there probably won't be many actual "rules" in there since an X-Com engine is an X-Com engine and there probably isn't a whole lot you wanna change without becoming a different game entirely. It probably won't contain gameplay features like whether
For now it's just a nice place to keep all the typically hardcoded numbers like craft stats, facility stats, item stats, weapon stats, research tree, etc. For example, as far as the engine is concerned, a craft is a craft and it has various properties and can contain weapons and soldiers and it can fly around intercepting stuff and going on missions. It's the ruleset that tells it there's a craft type X with acceleration Y and crew capacity Z and so on. Whether you call it a Skyranger or a Triton the engine will treat it just the same.
In any case, the reason there's support for "multiple rulesets" is people will probably wanna play around with these stats a lot, so I need to keep them fairly separate from the engine. The XcomRuleset has all the original game stats, but some people would probably prefer improved tanks and weapons like in XcomUtil. You might only have one ruleset in use by one game at a time, but the player might have a wide selection to choose from when they start a new game (kinda like mods). Hell, maybe they're a picky bunch and decide they want the "improved tanks" but not the "improved weapons", so you need to split the rulesets into bits so the player can pick multiple ones that get combined for them. That is the reason there's an abstract Ruleset, planning for the future.
If you want others to be able to modify game engine, don't try to create bulletproof abstractions and don't add scripting engines. Abstractions don't let you fully modify game until you understand code behind them. Scripting engines are even more limited.
There is already nearly 8k lines of code (and 15k if you count blank lines and comments). This number can be greatly reduced by removing most of such abstractions.
I am just afraid I would not be able to modify code when you finish implementing bigger part of it.
I don't really see what point you're trying to make. What do you mean by "bulletproof abstractions"? I'm not writing some generic game engine, as you pointed out, but an X-Com engine. There are Crafts, Soldiers, Bases, etc. Obviously if someone wants to use the engine for something else they'll have to rip that stuff apart and it'll be a lot of work, but that's their own fault for not using a proper generic game engine.
There is a whole bunch of stuff that could probably apply to any game, yes, like a state machine, interface, graphics, sounds, etc. And a lot of it could be clustered together, but there's really no need. That's not really trying to abstract away the whole system, but keeping things tidy and organized and in their place. I used to have all the resource loading in the Game class until I decided it was getting kinda bulky and moved it all out to its own class. As you code a lot you find more and more stuff that would fit better elsewhere and makes it easier to work. You can see this in the SVN history, the game grew from a little bunch of clustered files to a ton more cleaner files, and it's much easier to work with this way. You said it yourself, half the code is just commenting, spacing and other stuff to make it more pleasant to read and work on.
But it's still all designed to load X-Com formats, use 8bpp palette graphics, etc, and you'd probably have a hard time getting the engine to do something else.