Modder's Guide to Utilizing C2C Game Option Edits

Thunderbrd

C2C War Dog
Joined
Jan 2, 2010
Messages
29,959
Location
Las Vegas
Modder's Guide to Utilizing C2C Game Option Edits​


This is a project I've been working on for a bit here in the background. After an initial attempt to implement the Combat Mod was met with a blend of extreme approval and disapproval in equal amounts, it became clear that to legitimately implement the Combat Mod, I'd need to unlock the ability to enable Game Options to actually change the values of existing game objects.

By Game Object, I mean any entry in a given class. For example: a particular Unit, Promotion, Civic, Tech, Trait etc...

Up until now, our only ability to conditionally edit an existing game object has been via modules. This in and of itself has been a very powerful tool for the mod team. But it tends to confuse new players to the mod who wish to turn off or turn on specific modules. The MLF methods employed there require forethought to edit before beginning a game, and can be intimidating to do so for those who have not learned any modding skills. And its just kinda a pain so if a modder really wants his edits to game options to be optional but for that option to be easily toggled for players, this is not the BEST answer.

Unfortunately, this modular method has been our ONLY answer... until now.

What the functionality I call Game Option Edits accomplishes is the ability to write, directly into the core info files a given game object, an entry that will completely replace another indicated entry in the SAME file IF an indicated Game Option is in use.

Basically, this means that if we wish to have a different definition for a Trait under a Complex Traits game option, we can. Or perhaps we want a different Scout unit definition to be in use if Raging Barbarians is on... we could do that too. Or perhaps under a new religious option, the religion's Temples should be redefined to include the use of a tag they don't normally use - we can do that too.

Although at the moment this new functionality in our dll only applies to Traits, it should eventually be added to all the most core game classes over the course of the next version or two.


Now, this does not just assist me and my goals to implement portions of the Combat Mod in various Game Options so that nobody is forced to play any particular new way, it also helps us all with other matters that have long been at hand.

For example, an upcoming project that utilizes this method could be changing the Alternative Timeline projects into a Game Option or a set of Game Options. This would make it much nicer for those players who can't understand why we've currently made those on by default while maintaining the approval of those who are quite happy to play with Alternative Timelines. As a game option, they will be very easily determined on or off when setting up the game.

At this point, all the rest of the team will need to know is how to use this system and some of you have expressed a desire to know how it was setup. I may be able to get some feedback here too on little ways to improve the structure as well.

But I'm pretty sure we'll all find that the only processing time impact this method will have is at loadup the game will simply have more content to process in, the usual price to pay for additional content - and it pays it faster this way than it does in a modular format! In game, there would be NO additional processing time added from this method, and those who will understand the coding section here will see why.

Memory requirements may increase some through this method. @Koshling/AIAndy... shouldn't be too bad there should it?


Anyhow, without further introduction, let's discuss:

HOW to utilize Game Option Edits (for the XML modder)

Let me simply show you upfront how a Game Option Edit entry would look in the XML:
Spoiler :
Code:
		<TraitInfo>
			<Type>TRAIT_OPTIONEDIT_COMPLEX_TRAITS_PHILOSOPHICAL</Type>
			<Description>TXT_KEY_TRAIT_PHILOSOPHICAL</Description>
			<ShortDescription>TXT_KEY_TRAIT_PHILOSOPHICAL_SHORT</ShortDescription>
			<Button>ART/Buttons/Traits/TraitPhilosophical.dds</Button>
			<ForGameOption>GAMEOPTION_COMPLEX_TRAITS</ForGameOption>
			<EditedTrait>TRAIT_PHILOSOPHICAL</EditedTrait>
			<OnGameOption>GAMEOPTION_COMPLEX_TRAITS</OnGameOption>
			<NotOnGameOption/>
			<PromotionLine>PROMOTIONLINE_PHILOSOPHICAL</PromotionLine>
			<iLinePriority>0</iLinePriority>
			<bNegativeTrait>0</bNegativeTrait>
			<bImpurePromotions>0</bImpurePromotions>
			<bImpurePropertyManipulators>0</bImpurePropertyManipulators>
			<Flavors>
				<Flavor>
					<FlavorType>FLAVOR_PRODUCTION</FlavorType>
					<iFlavor>1</iFlavor>
				</Flavor>
				<Flavor>
					<FlavorType>FLAVOR_GOLD</FlavorType>
					<iFlavor>2</iFlavor>
				</Flavor>
				<Flavor>
					<FlavorType>FLAVOR_RELIGION</FlavorType>
					<iFlavor>1</iFlavor>
				</Flavor>
				<Flavor>
					<FlavorType>FLAVOR_SCIENCE</FlavorType>
					<iFlavor>3</iFlavor>
				</Flavor>
				<Flavor>
					<FlavorType>FLAVOR_CULTURE</FlavorType>
					<iFlavor>4</iFlavor>
				</Flavor>
				<Flavor>
					<FlavorType>FLAVOR_ESPIONAGE</FlavorType>
					<iFlavor>1</iFlavor>
				</Flavor>
				<Flavor>
					<FlavorType>FLAVOR_MILITARY</FlavorType>
					<iFlavor>-2</iFlavor>
				</Flavor>
			</Flavors>
			<iHealth>10</iHealth>
			<iHappiness>0</iHappiness>
			<iMaxAnarchy>-1</iMaxAnarchy>
			<iUpkeepModifier>0</iUpkeepModifier>
			<iLevelExperienceModifier>0</iLevelExperienceModifier>
			<iGreatPeopleRateModifier>0</iGreatPeopleRateModifier>
			<iGreatGeneralRateModifier>0</iGreatGeneralRateModifier>
			<iDomesticGreatGeneralRateModifier>0</iDomesticGreatGeneralRateModifier>
			<iMaxGlobalBuildingProductionModifier>0</iMaxGlobalBuildingProductionModifier>
			<iMaxTeamBuildingProductionModifier>0</iMaxTeamBuildingProductionModifier>
			<iMaxPlayerBuildingProductionModifier>0</iMaxPlayerBuildingProductionModifier>
			<!-- Revolution Trait Effects Begin -->
			<iRevIdxLocal>0</iRevIdxLocal>
			<iRevIdxNational>0</iRevIdxNational>
			<iRevIdxDistanceModifier>0</iRevIdxDistanceModifier>
			<iRevIdxHolyCityGood>0</iRevIdxHolyCityGood>
			<iRevIdxHolyCityBad>0</iRevIdxHolyCityBad>
			<fRevIdxNationalityMod>0</fRevIdxNationalityMod>
			<fRevIdxBadReligionMod>0.0</fRevIdxBadReligionMod>
			<fRevIdxGoodReligionMod>0.0</fRevIdxGoodReligionMod>
			<bNonStateReligionCommerce>0</bNonStateReligionCommerce>
			<bUpgradeAnywhere>0</bUpgradeAnywhere>
			<!-- Revolution Trait Effects End -->
			<ExtraYieldThresholds/>
			<BonusHappinessChanges>
				<BonusHappinessChange>
					<BonusType>BONUS_FUR</BonusType>
					<iHappinessChange>-1</iHappinessChange>
				</BonusHappinessChange>
			</BonusHappinessChanges>
			<TradeYieldModifiers/>
			<CommerceChanges/>
			<CommerceModifiers/>
			<SpecialistCommerceChanges>
				<SpecialistCommerceChange>
					<SpecialistType>SPECIALIST_SCIENTIST</SpecialistType>
					<CommerceChanges>
						<iCommerce>0</iCommerce>
						<iCommerce>0</iCommerce>
						<iCommerce>1</iCommerce>
					</CommerceChanges>
				</SpecialistCommerceChange>	
			</SpecialistCommerceChanges>
			<iWarWearinessAccumulationModifier>20</iWarWearinessAccumulationModifier>
			<iCivicAnarchyTimeModifier>20</iCivicAnarchyTimeModifier>
		</TraitInfo>
This is actually IN the TraitInfo file NOW. If you want to prove it works, go ahead and edit the GameOptionsInfos.xml file to make it possible to use the Complex Traits option I added for eventual use (I currently have it invisible and off by default) and make sure that option is on when you start the game. Take a look at the Philosophical trait... it will be according to the definitions given in that Game Option Edit entry rather than the definitions given in the original Philosophical Trait entry.

So the first thing to really be clear about is: Yes, this is an entry IN the TraitsInfo.xml file.

You'll notice that the <Type> tag is not named the same as the game object we want to edit under the Complex Traits option. Instead, its tagline is given a name under a naming convention: TRAIT_OPTIONEDIT_COMPLEX_TRAITS_PHILOSOPHICAL.

As with any Trait, they <Type> tag begins with TRAIT_ and very well should as sometimes in python or code, this might be an assumed aspect of this label to indicate its class type. Then we add OPTIONEDIT_ to indicate what we're making this entry for. Then we add COMPLEX_TRAITS_ to indicate the Option this will function under (this is not what controls it... just a naming convention to help all of us quickly 'get the point'). Then we indicate PHILOSOPHICAL to denote the trait being edited under the aforementioned option.


Now, although Description through Button tags are present, they are the only tags that do NOT function to replace the edited trait (yet... I'm hoping I can yet figure out how to get that to work so we can redefine the Description text(s) and the Button if needbe.)


Then pretty much any other tag that CAN exist on the original is up for redefinition here. Just keep in mind this redefinition entry must be absolutely complete. Anything you leave out is equivalently left out of the redefined trait stats. Thus, if I were to want to take an original iHealth value of 1 and turn it into 0, I could either define it here as 0 or even just leave it off.

This whole Trait entry completely replaces the Trait that's indicated when the option is ON and leaves the original definition in use whenever the indicated option is OFF.


There are a few new tags to use for setting this up though. You'll notice these tags just under the Button tag:
Spoiler :
Code:
			<ForGameOption>GAMEOPTION_COMPLEX_TRAITS</ForGameOption>
			<EditedTrait>TRAIT_PHILOSOPHICAL</EditedTrait>
			<OnGameOption>GAMEOPTION_COMPLEX_TRAITS</OnGameOption>
			<NotOnGameOption/>
<ForGameOption> sets the option that will cause this trait to replace whatever trait is indicated in <EditedTrait> whenever that option is ON.

<OnGameOption> is critical to use here as well to make sure this trait doesn't show up independently as a valid trait of its own whenever the option isn't in use. It's also used on its own to restrict any additional trait definitions that aren't intended for use whenever the option isn't on BUT is also not an edit of a previous trait.

Thus if I want to create EXTRA traits for a given option, I'd define them as normal and utilize the OnGameOption tag to make sure those extra traits are only on for that Game Option.

But FOR game option is only part of an Option Edit setup. As is <EditedTrait> (which won't work unless a ForGameOption is specified.)

One can also use the new <NotOnGameOption> tag to indicate that a trait that would normally appear simply does NOT appear if the indicated option is used. Don't set both OnGameOption and NotOnGameOption to the same thing... results would be somewhat unpredictable as it would be completely illogical to do so.


And that's it! It's really that simple. Might not seem like it in a written out explanation but hopefully the example helps! All you need is an option to work with and you can edit any other Trait's details under that option's use. (And soon... so much more!)


How it works in the SDK code
Since there's only a few of us here who even want to see this, I'll put this in a whole spoiler block. The rest may ignore ;)
Spoiler :

The trick to this method has been to manipulate the return on each tag in the traits class. But that required a loop check SO it ALSO caches this result whenever a GAME (not THE game but A game) is initiated or loaded so that the time spent to process out what the modified return should be is spent only once on starting or loading up a game.

Here's a basic example. The rest you can find in CvInfo.cpp under CvTrait:
Code:
int CvTraitInfo::getHealth() const									
{
	if (isOptionEditsIndexCached() && getOptionEditsIndex() != -1)
	{
		return GC.getTraitInfo((TraitTypes)getOptionEditsIndex()).getHealth();
	}

	if (GC.getGameINLINE().isOption(GAMEOPTION_PURE_TRAITS))
	{
		if (isNegativeTrait() && m_iHealth > 0)
		{
				return 0;
		}
		else if (!isNegativeTrait() && m_iHealth < 0)
		{
			return 0;
		}
	}
	return m_iHealth;
}
There's a few things going on here that I should mention. The traits mechanism also has the Pure Traits option to work with here so not all of the tweaks you see here from what the original was:
Code:
int CvTraitInfo::getHealth() const									
{
	return m_iHealth;
}
applies specifically to this Option Edit method.

Really, its all encapsulated in this simple statement:
Code:
	if (isOptionEditsIndexCached() && getOptionEditsIndex() != -1)
	{
		return GC.getTraitInfo((TraitTypes)getOptionEditsIndex()).getHealth();
	}

See... what happens is at game load you have the following new functions called(in CvGame):
Code:
void CvGame::setOptionEdits()
{
	int iI;

	//Traits
	for (iI = 0; iI < GC.getNumTraitInfos(); iI++)
	{
		GC.getTraitInfo((TraitTypes)iI).setOptionEditsIndex();
	}
}

void CvGame::resetOptionEdits()
{
	int iI;

	//Traits
	for (iI = 0; iI < GC.getNumTraitInfos(); iI++)
	{
		GC.getTraitInfo((TraitTypes)iI).setOptionEditsIndexUncached();
	}
}

You can find them to see if these are being called everywhere they should be but testing has shown it to be completely successful from starting a game, or loading a game, or even loading in a game without the same options as the game currently being played.

It cycles through and sends every trait entry through .setOptionEditsIndex(). This reads (from CvInfos.cpp):
Code:
void CvTraitInfo::setOptionEditsIndex()
{
	int iI;
	for (iI = 0; iI < GC.getNumTraitInfos(); iI++)
	{
		TraitTypes eTOE = ((TraitTypes)iI);
		if ((TraitTypes)GC.getTraitInfo(eTOE).getEditedTrait() == (TraitTypes)GC.getInfoTypeForString(getType()))
		{
			if (GC.getGameINLINE().isOption(GC.getTraitInfo(eTOE).getForGameOption()))
			{
				m_iOptionEditsIndex = iI;
				m_bOptionEditsIndexCached = true;
				break;
			}
		}
	}
}
Honestly, "== (TraitTypes)GC.getInfoTypeForString(getType())" is the part I think could be done better here. I wasn't sure about the best way to refer to 'self' and had struggled with it a bit (though this works I think there's a faster processing method, isn't there?)

Anyhow, this goes through and establishes that for this trait, we've identified an existing qualified Option Edit entry(or have identified that there are none), stored the first one found and ignored any others that may be applicable to that trait(so as to keep from there being any further conflicts).

It also stores, in boolean form, that this trait has a defined option edit and that option edit's info will now be used to replace the values in any given tag call for this trait.


All modders should, however, take note that it is possible to string edits if needbe. Thus I can option edit Philosophical under the Complex Traits game option, then option edit the option edit of Philosophical under the Complex Traits game option under another option entirely. Thus if BOTH options are selected, we get a whole THIRD type of definition that overrides both previous ones! Hopefully we won't find too many need for that but it I figured I should point out that its very possible to do!


Anyhow, I'll leave this lengthy explanation there for now. Any further questions? I'm excited to get working on adding this fairly simply programmed method to other Game Object Classes! But I need the review of the team before I'd feel right moving past this basic prototype. So... comments anyone?
 
Ok I have some questions. Note that I am not nearly as familiar with all the coding stuff as most of you so please bear with me.

1. So it can change stuff even after the game has loaded? Meaning pre-game setting could be changed after?

2. How will this effect the max compatibility of C2C where when you load up a game you can click to update your game with any new changes.

3. How will this interact with "force override" mod code which will "lock" code in place above all other mods.

4. Will mod order still matter? Or are they independent of this?
 
The problem I have with this is that we already have something that does this.

Lets look at an example. Currently ClockPunk is a module that can be turned off using the Modular Loading Facility (MLF) where you edit the file MLF_CIV4ModularLoadingControls.XML in the parent folder to turn it on or off. There is also an entry in the Technologies XML file which shows a Clockpunk tech even if turn off the module. This could easily be fixed but we haven't by adding the following WoC (World of Civilization XML Standard) to the technology XML entry for Clockpunk.

Code:
			<AndDependencyTypes>
             	<DependencyType>BONUS_CLOCKPUNK</DependencyType>
 			</AndDependencyTypes>

The AndDependencyTypes is used for consistency between modules so that if I build something that may require or act differently if another module is there or not I can account for it.

If instead of using MLF we use a game option then all we need do is use the RoMAND tag PrereqGameOption (or similar since there are others like it) on each element.
 
1) When initializing a game or loading a game, not the mod itself, is when the edit goes into effect. Thus, yes, I think, is the appropriate answer to your question if I understand it correctly.

2) No impact on that whatsoever. Completely compatible. However, if you have a gameobject like, for example, a Scout, that suddenly becomes edited under the game options you're currently running, after you load the game and recalculate, you'll notice the Scout's base values have been altered.

3) Force Override is overridden by this method since the option edit will take full priority regardless. Force Override is not utilized in determining whether to replace or not. If playing under the option, the edit set becomes the new definition.

4) OPTION order matters as the FIRST qualified option edit found is the one that will be used and will ignore further unless the option edit itself has an option edit replacing IT as well based on the options used. But modules aren't necessary to utilize here and thus load order of modules makes no difference. Again... these option edits may be safely placed inside the core info files. But they CAN be modularly included as well just as if you were adding in any other new class entry.

I'm sure my horrible wording confuses the situation further potentially but let me know if it has helped.
 
The problem I have with this is that we already have something that does this.

Lets look at an example. Currently ClockPunk is a module that can be turned off using the Modular Loading Facility (MLF) where you edit the file MLF_CIV4ModularLoadingControls.XML in the parent folder to turn it on or off.
And the problem with this is that one has to manipulate the MLF file to change things. This way a gameoption selection can turn the edit on or off instead. Most new players won't dare to tweak with MLF files and it gets exhausting repeatedly explaining how to do so doesn't it?

There is also an entry in the Technologies XML file which shows a Clockpunk tech even if turn off the module. This could easily be fixed but we haven't by adding the following WoC (World of Civilization XML Standard) to the technology XML entry for Clockpunk.

Code:
			<AndDependencyTypes>
             	<DependencyType>BONUS_CLOCKPUNK</DependencyType>
 			</AndDependencyTypes>

The AndDependencyTypes is used for consistency between modules so that if I build something that may require or act differently if another module is there or not I can account for it.
Great functionality, yes... and it does show that we shouldn't have to always utilize option edits for everything. But this is, I believe, a method that would be more convenient for players.

If instead of using MLF we use a game option then all we need do is use the RoMAND tag PrereqGameOption (or similar since there are others like it) on each element.
Which is pretty much the same as OnGameOption which did not exist in the Traits tag selections. Where it exists, I probably won't need to establish an OnGameOption tag. But the ForGameOption tag would still be necessary to establish that this entry is going to REPLACE another, which is something that PrereqGameOption cannot achieve.

I'm not saying y'all HAVE to use this method. It doesn't replace nor obsolete the modular methods you are comfortable with. It just gives us another way to go about it that is much better for the common player than having to go in and toggle the MLF entries. Even I am reluctant to do so because its just a pain in the arse. Particularly due to trying to keep my mod file in harmony with the SVN without having to make sure I'm being vigilant to avoid accidentally updating or overwriting an MLF I've adjusted.
 
Purely implementation (and XML syntax) comments:

  1. I don't like the reliance on the naming convention for the optional trait type to find the replaced trait type (things like a spelling mistake would cause issue that might not be obvious). I would far prefer to see a 'ReplacesType' tag that simply specifies the type being replaced (when the option is in force), which would then make the name of the overriding type semantically unimportant

I can confirm that memory penalty should be minor unless replacement types really start to proliferate wildly.
 
Purely implementation (and XML syntax) comments:

  1. I don't like the reliance on the naming convention for the optional trait type to find the replaced trait type (things like a spelling mistake would cause issue that might not be obvious). I would far prefer to see a 'ReplacesType' tag that simply specifies the type being replaced (when the option is in force), which would then make the name of the overriding type semantically unimportant

I can confirm that memory penalty should be minor unless replacement types really start to proliferate wildly.

I agree with you on this, that would be much better for avoiding dumb XML mistakes. As for memory issues, this will eventually add a new entry for every unit (Combat Mod will be the option, normal units will remain in the core) and two new sets for every trait.

Also l would strongly encourage that all new sets of anything be in separate files, preferably in a module.
 
Purely implementation (and XML syntax) comments:

  1. I don't like the reliance on the naming convention for the optional trait type to find the replaced trait type (things like a spelling mistake would cause issue that might not be obvious). I would far prefer to see a 'ReplacesType' tag that simply specifies the type being replaced (when the option is in force), which would then make the name of the overriding type semantically unimportant

I can confirm that memory penalty should be minor unless replacement types really start to proliferate wildly.
You may have misunderstood what I was trying to say there. The naming convention mention was just established so we can keep things straight for us modders. The actual programming is not reliant on it at all. The method very much does rely on a 'ReplacesType' tag, although the tag is called <EditedTrait>. In other classes this would be renamed to <Edited(whatever class we're working in)>. The programming for the switch works directly off that tag and the naming convention is actually meaningless for the syntax.

However, if you can indicate a better way to refer to the trait in this line:
Code:
if ((TraitTypes)GC.getTraitInfo(eTOE).getEditedTrait() == (TraitTypes)GC.getInfoTypeForString(getType()))
I'm listening! Because something didn't feel right about this. It seemed to me there should've been an easier way to refer to the trait than getInfoTypeForString! (I know this runs through a bit more processing than should be necessary here... but I simply couldn't figure out the correct syntax to run that call so for now I went with what I could figure out simply worked.)

I agree with you on this, that would be much better for avoiding dumb XML mistakes.
Good. As mentioned above, I agreed as well when setting things up ;)
As for memory issues, this will eventually add a new entry for every unit (Combat Mod will be the option, normal units will remain in the core) and two new sets for every trait.
You may recall me saying this would be best used somewhat sparingly. We can handle that with traits since there's not a whole lot of entries there. And in the combat mod, I hope to be able to work things out largely in a variety of methods to minimize the amount of OptionEdits for this very reason.

Most of the combat mod options can be a matter of turning on or off certain tags themselves. Thus for most of the units, it can be built onto the existing unit definitions - put the tags in place under those units and if the option(s) that enable them is in use we have those tags functional and if not, we maintain the original design.

ONLY when a unit would have to be truly restructured to fit a combat mod option would an OptionEdit be necessary. Since most of the Combat Mod intends to simply build on top of existing design, not all units would need this treatment. There are some that would, thus necessitating the design of this method, but I'm not looking to redefine ALL units under the Combat Mod. That would, I agree, be too heavy in terms of additional content.

Also l would strongly encourage that all new sets of anything be in separate files, preferably in a module.
I don't really feel this way. I believe you should be able to safely re-order what entries are in the core files to aid in keeping things tidy in there (aka: keep all option edits grouped by option and at the end of the file) and one of the strengths of this method is whatever is in the core will load faster than what is in modules. We see big improvements in load times in general when we take heavy modules and port them into the core.

Not to say I don't see some of the reasons why you'd suggest that so this is just one opinion from my outlook. I feel we have WAY too many modules as is and 90% of it if not all of it should be moved to the core for improved load time and ease of manipulating things when sweeping changes are called for.

And it's a pain for we modders to have things so scattered about. Going through and changing out all references to BONUS_IRON to BONUS_WARE_IRON and so on throughout ALL unit files in our mod was a great practice in seeing why it's SO much more convenient if everything's simply in the one unit file.

The main benefit I'm seeing, however, aside from enabling the use of the MLF switches, which even I am reluctant to ever use, is that the modules allow us to tag and take credit for our work independently. OK, fine, so at least we should have ONE unit file in our own mods, ONE building file etc... rather than the 30 or so building files, each one for a different building, that you might see in some of our modules - unless we feel its truly important to enable one such item to be isolated off by a player who would go so far out of his way to do so with the MLF switch. Some of the groupings I see in there, like DH's religious files, make sense. But on the whole, there's so much data, scattered about in so many places, that its gone beyond ridiculous! (Just my opinion... I know I'm not persuading anyone here ;) )

All that rant aside though, I do plan the Combat Mod as a module so that it CAN be turned off as a potential or even eliminated from the file set if players find they aren't using it and its causing them longer than necessary load times. But the alternative traits sets don't seem to be necessary to do this with imo. I dunno... maybe it would be best.

What are some reasons you see to suggest this that I might be overlooking here?
 
<snip>

All that rant aside though, I do plan the Combat Mod as a module so that it CAN be turned off as a potential or even eliminated from the file set if players find they aren't using it and its causing them longer than necessary load times. But the alternative traits sets don't seem to be necessary to do this with imo. I dunno... maybe it would be best.

What are some reasons you see to suggest this that I might be overlooking here?

Load times aren't very concerning, even for something as huge as the UnitInfos file, once it is serialized it takes about a second or two to load. I'm thinking that for organizational purposes it would be nice to have different files for things. That way I know that my traits are in /modules/ls612/traits, and the main ones are in the core, adn yours are in /modules/thunderbrd/whereever. This will minimize mistakes about whose XML is which, which could happen if we are in a hurry and don't read everything thoroughly.

As for the Combat Mod, I've pointed out before why we'd need two sets of unitinfos for every unit changed by it. Let's say that an Axeman gets 4 puncture in the Combat mod, and 1 without it (once the split is started I intend to take full responsibility for Core unit balancing and let you handle Combat Mod unit balancing), and a spearman has 6 puncture with the combat mod and 3 without it. And the Combat mod has Equipment while the core will not. Without changing stats and such just deleting extra tags here will have deleterious effects on balance, and since it isn't immediately obvious what changes with and without the mod that could lead to unintended consequences. If it doesn't use too much memory (if it does then we can look at eliminating extra memory usage) then it would be much safer and easier to keep track of if the Combat mod XML went in modules/Thunderbrd/CombatMod or something and the Core XML is what you get when the Combat Mod is disabled.
 
Load times aren't very concerning, even for something as huge as the UnitInfos file, once it is serialized it takes about a second or two to load. I'm thinking that for organizational purposes it would be nice to have different files for things. That way I know that my traits are in /modules/ls612/traits, and the main ones are in the core, adn yours are in /modules/thunderbrd/whereever. This will minimize mistakes about whose XML is which, which could happen if we are in a hurry and don't read everything thoroughly.

As for the Combat Mod, I've pointed out before why we'd need two sets of unitinfos for every unit changed by it. Let's say that an Axeman gets 4 puncture in the Combat mod, and 1 without it (once the split is started I intend to take full responsibility for Core unit balancing and let you handle Combat Mod unit balancing), and a spearman has 6 puncture with the combat mod and 3 without it. And the Combat mod has Equipment while the core will not. Without changing stats and such just deleting extra tags here will have deleterious effects on balance, and since it isn't immediately obvious what changes with and without the mod that could lead to unintended consequences. If it doesn't use too much memory (if it does then we can look at eliminating extra memory usage) then it would be much safer and easier to keep track of if the Combat mod XML went in modules/Thunderbrd/CombatMod or something and the Core XML is what you get when the Combat Mod is disabled.

So it's about being able to point at the right person to blame easier huh? :lol: Personally I feel we're a team and all responsible for helping each other where an error exists and blame is only important in extreme cases. Taking CREDIT is another issue entirely and one that for the sake of ease of access should not be held above making things easier for each other. But again... just opinions. I may seem like an ego hound and recognition certainly does matter to me too but I don't need to sign everything on the backend. Just my name on the team roster.

As for the Combat Mod, as I said, for purposes of the mass of content, I agree it should be a module. And I suppose if you're going to be using a lot of the tags it brought to the table where I may end up manipulating them differently, I can see how yeah, many units may well get the optionedit treatment. Hopefully that won't hurt download and load times toooo much.

once the split is started I intend to take full responsibility for Core unit balancing and let you handle Combat Mod unit balancing
My thoughts exactly. We're like two states of a union on these projects, you and I. One may establish a better practice in one area while the other in another and perhaps by seeing both visions clearly in the process of being able to experience them both individually, we might be able to eventually figure out a way to blend in our ideas into something better than both were alone.
 
So it's about being able to point at the right person to blame easier huh? :lol: Personally I feel we're a team and all responsible for helping each other where an error exists and blame is only important in extreme cases. Taking CREDIT is another issue entirely and one that for the sake of ease of access should not be held above making things easier for each other. But again... just opinions. I may seem like an ego hound and recognition certainly does matter to me too but I don't need to sign everything on the backend. Just my name on the team roster.

More like I want to keep things organized. More than once I've done the wrong thing to the wrong unit in the XML because I was tired and not reading too well. That will be far more easy to do if the XML is so similar as it will be for some of these options. Splitting it up will be more organized and help reduce bugs.
 
Well... that makes sense. Just keep in mind that someone who goes through and MLF's off the file you're using in a gameoption edit will end up creating a confusing situation for themselves.

My point is this: If you have all the optionedits in a Modular Loading Format and that module gets turned off, the option is still going to appear on the game option list, but if selected, simply won't DO anything (except set the game up for a big recalc change if the MLF gets changed back!)
 
While this solution works, it has the significant disadvantage that any loop over all traits will get longer because all your edited traits have a trait id as well (not that bad for traits but it will be for units).
I would suggest reading the game option specific edits into a separate vector/map during the XML reading process and then on game start/load move it into the standard vector (which is a vector of pointers) if the game option is selected while moving the standard one to backup vector/map.
 
Well... that makes sense. Just keep in mind that someone who goes through and MLF's off the file you're using in a gameoption edit will end up creating a confusing situation for themselves.

My point is this: If you have all the optionedits in a Modular Loading Format and that module gets turned off, the option is still going to appear on the game option list, but if selected, simply won't DO anything (except set the game up for a big recalc change if the MLF gets changed back!)

The only people who will use the MLFs are you and myself, and others who know what they are doing, so I don't envision that being a problem.
 
To make frequent use of statements like :

Code:
if ((TraitTypes)GC.getTraitInfo(eTOE).getEditedTrait() == (TraitTypes)GC.getInfoTypeForString(getType()))

efficient I think you should make a small change to CvInfoBase, and add an m_iID member there. Initialize it to -1 in the constructor, add a getID() method that looks like this:

Code:
int CvInfoBase::getID()
{
    if ( m_iID == -1 )
    {
        m_ID = GC.getInfoTypeForString(getType());
    }

    return m_iID;
}

then at the point of use in your code the first section above becomes:

Code:
if ((TraitTypes)GC.getTraitInfo(eTOE).getEditedTrait() == (TraitTypes)getID())

which is much less expensive
 
To make frequent use of statements like :

Code:
if ((TraitTypes)GC.getTraitInfo(eTOE).getEditedTrait() == (TraitTypes)GC.getInfoTypeForString(getType()))

efficient I think you should make a small change to CvInfoBase, and add an m_iID member there. Initialize it to -1 in the constructor, add a getID() method that looks like this:

Code:
int CvInfoBase::getID()
{
    if ( m_iID == -1 )
    {
        m_ID = GC.getInfoTypeForString(getType());
    }

    return m_iID;
}

then at the point of use in your code the first section above becomes:

Code:
if ((TraitTypes)GC.getTraitInfo(eTOE).getEditedTrait() == (TraitTypes)getID())

which is much less expensive
Unfortunately that is not possible. You cannot add anything to CvInfoBase because the exe expects it to be exactly the size that it is now.
 
While this solution works, it has the significant disadvantage that any loop over all traits will get longer because all your edited traits have a trait id as well (not that bad for traits but it will be for units).
I would suggest reading the game option specific edits into a separate vector/map during the XML reading process and then on game start/load move it into the standard vector (which is a vector of pointers) if the game option is selected while moving the standard one to backup vector/map.
While I'm not sure I can envision the method you're suggesting and it would help to see a code example of what you're saying there, I get the issue you're pointing at. I had originally intended for GameOptionEdits to be new classes in parallel to the ones they were setup to edit but I saw that to be a fairly huge pain when I began to put it into test practice. So it sounds like you have a way to generate a best of both worlds situation but unfortunately I'm not so good with conceiving of how the method you suggest would look in code.


The only people who will use the MLFs are you and myself, and others who know what they are doing, so I don't envision that being a problem.
Yeah, alright. You've made good points here. I've no further objection.


To make frequent use of statements like :

Code:
if ((TraitTypes)GC.getTraitInfo(eTOE).getEditedTrait() == (TraitTypes)GC.getInfoTypeForString(getType()))

efficient I think you should make a small change to CvInfoBase, and add an m_iID member there. Initialize it to -1 in the constructor, add a getID() method that looks like this:

Code:
int CvInfoBase::getID()
{
    if ( m_iID == -1 )
    {
        m_ID = GC.getInfoTypeForString(getType());
    }

    return m_iID;
}

then at the point of use in your code the first section above becomes:

Code:
if ((TraitTypes)GC.getTraitInfo(eTOE).getEditedTrait() == (TraitTypes)getID())

which is much less expensive

Unfortunately that is not possible. You cannot add anything to CvInfoBase because the exe expects it to be exactly the size that it is now.

Efficiency isn't too greatly important in this case since it only ever runs through those at the load or start of a given game once. I just thought that surely there'd be a better way to reference the same 'id' so to speak, than 'getInfoTypeforString', particularly since we're simply trying to refer to the self object. So there's really no other way there to say, get my own index #?
 
They are... but I may need to do something to fix a problem I can't remember if I fixed or not... if that makes any sense. I'll take a look at it this week and although it may create an interesting effect its nothing to stop you from beginning your XML development now since I won't need to change anything about the tags or xml structure.

I AM hoping that AIAndy will return and give me a little more guidance on his great coding suggestion. Unfortunately, without some further help on that I'm not sure I'd be able to implement his suggestion with my skillset.
 
@ls612:
AIAndy apparently has a fairly involved concept as to how to improve this setup so that it won't create any possible drag on any loops through the class objects, which this would potentially have.

According to his last message to me on the subject, the XML may well be able to remain the same though so if you want to work on things, this is effectively ready for it and could perhaps only require the slightest of after adjustments.

It might even help to have your developments on the method in XML to aid in testing the coding conversion project he's got in mind. It's not that this mechanism doesn't work and as he said, wouldn't be a problem for traits. But it needs some improvement at his level of programming to be valid for units and promos and such.

You also might want to utilize the new GameOption tag(s) I implemented for designating Incompatible and Prerequisite Gameoptions.
 
Back
Top Bottom