Nightingale's idea of trying to have a somewhat modular DLL code base is a good one if it can be done - ie use "ifdef Col2071" in a few sections where exceptions to the base M:C code is needed. If the need for this can be kept to only a few sections, it could enable easy updates or merges when needed and also greatly help out anyone else who might want to use this DLL as a base for modding.
It's actually a fairly common approach in open source programming except it's done to support multiple OSes. Download the source from some game or app, which supports a great number of platforms. Chances are that there is a directory called OS with windows.cpp, unix.cpp, macosx.cpp etc. and the compiler will compile ONE of them. Each off them then has the same function names meaning the rest of the code can call "draw this on the screen" without considering which platform it's on and those specialized files will make sure it happens.
We want to do the opposite, which is to make two "applications" for a single OS. However that approach has proven reliable and we should see if we can use it.
I came up with this approach. We make Yields.h and move all yield related into it (may need Yield.cpp too)
static inline bool YieldIsMetalArmor(YieldTypes eYield)
{
return eYield == YIELD_SCALE_ARMOR || eYield == YIELD_MAIL_ARMOR || eYield == YIELD_PLATE_ARMOR;
}
static inline bool YieldIsArmor(YieldTypes eYield)
{
return eEquipment == YIELD_LEATHER_ARMOR || YieldIsMetalArmor(eYield);
}
This mean we get the same result (even same speed) if we write this in the code
if (YieldIsArmor(eEquipment))
if (eEquipment == YIELD_LEATHER_ARMOR || eEquipment == YIELD_SCALE_ARMOR || eEquipment == YIELD_MAIL_ARMOR || eEquipment == YIELD_PLATE_ARMOR)
if (YieldIsMetalArmor(eEquipment))
if (eEquipment == YIELD_SCALE_ARMOR || eEquipment == YIELD_MAIL_ARMOR || eEquipment == YIELD_PLATE_ARMOR)
Now we define that is armor in a single location meaning adding more will be easier. Also we eliminated the risk that one of the checks forgets to check for YIELD_PLATE_ARMOR.
Another important factor here is that 2071 could have different functions for the check. Say we don't want to use the code for metal armors we can just write
static inline bool YieldIsMetalArmor(YieldTypes eYield)
{
return false;
}
With a few well defined function checks for yield group we should be able to remove the majority of hardcoded yields from the general code. We can then define whatever we like for 2071.
A few yields will still stay hardcoded, such as YIELD_FOOD. That's not a major concern as those special functions are likely needed for both MODS. Luxury food might be an issue, but I think that's the only one, which might be an issue.
The new combat system features with glancing blows etc are really good and have great generalizable use for modding, but the specific hardcoding as PLATE_ARMOR, MAIL, etc is what makes it hard for other mods. The proposal to expose these features to xml where possible (ie <glancingblowchance> in promotionsinfos) is a good one that would make these awesome for modding.
Ideally we define everything in XML. If we don't, then we should change the code to do so. If speed force us to hardcode something, then we should do as I just wrote about with yields.
The question now is how to proceed now? Should we make a fork on github to provide XML/python files for 2071 to work on? Such a fork shouldn't bother with the DLL code as it should use M:C DLLs, including the M:C DLL updates. This mean working on col2071 means cloning "Colonization_2071" (or whatever we call the project) into MODS, play with that one, edit XML and commit those, but ignore the source code there. The source code comes from M:C meaning you will also have to clone M:C, set Makefile.settings to compile for 2071 and set YOURMOD to the path to MODS/Col2071 (or whatever it ends up being named). That way you open VC++ in M:C, compile and the DLL ends up inside col2071, ready for you to play with.
Now that I think about it, we don't have to fork anything. I already did that. I made a branch called colonization2071. Now we aren't going to modify the source like originally planned, which mean we don't need that branch. We might as well use it to keep track of col2071 XML files.
Now that I'm aware of at least two enums, which needs to be the same as XML I'm going to write some code to assert if XML doesn't live up to the DLL expectations. Also I will check if there are more like that. If we need XML and DLL to match, then at least check if that is the case instead of crash without any human readable error message.