C2C Modder's Guide to XML

Thunderbrd

C2C War Dog
Joined
Jan 2, 2010
Messages
29,813
Location
Las Vegas
There's a few of us here looking to expand their ability to mod C2C in the XML files.

Numerous questions have come up about 'what tags can do what', 'what's the proper way to code for that' etc...

I figured I'd start a thread to go over some things that will make these questions much more possible to answer for yourselves as the information often is available if you only know how to read it.

Most of those answers lie within the Schema files. Schemas probably look like Greek when you first take a look at one. I know it did for me. I only managed to garner a greater understanding of how it can be used to derive important XML modding information when learning what I would have to do to manipulate it to add new tags. So it's understandable how this information is not so obvious to those who've not taken the step of trying to learn to code new tags.

But ignoring the schema will leave you in the dark, only able to program with tags you can see examples of on other buildings, open to making grievous errors in the order of the tags you utilize on a given object and possibly missing out on understanding some of the options you have available to you.

There's two parts to understanding the Schema. The first is how to read it and apply that knowledge. The second is how to garner a basic understanding of a tag by understanding some basic naming conventions. I'll cover both here.

So let's say we want to add a unit to the game. The schema is too big to post here so you'll have to open it yourself - I'd suggest doing so in Notepad++.

You'll find there are a number of lines like the following:
Code:
<ElementType name="BonusType" content="textOnly"/>
    <ElementType name="PrereqTech" content="textOnly"/>
    <ElementType name="Description" content="textOnly"/>
These are declarations of tags. To have a tag included in an info.xml file attached to this schema the tag must be declared somewhere in the schema. This is not, however, an automatic indicator that these tags are included in your particular info file. Any tag that is declared like this MAY be, without error, used in your info file, but without further programming in the dll, it probably won't work.

Thus we include a list of the tags that ARE programmed for a given Info file in an 'application' line.

Declaration lines are easily spotted by the way they begin: <ElementType name=

Application lines are also easily spotted by the way THEY begin: <element type=

You'll see Declaration lines that don't close, such as the following:
<ElementType name="UnitInfo" content="eltOnly">
These almost always end with content="eltOnly"> and they then go on to have Application lines listing off underneath them, wrapping up the full statement with a final close line:
</ElementType>

In this example, what we're seeing here is the list of all tags used in UnitInfos.xml. You'll see IN the unit info file the way the file begins:
Code:
<Civ4UnitInfos xmlns="x-schema:C2C_CIV4UnitSchema.xml">
    <UnitInfos>
        <UnitInfo>
The first line indicates what this file is and what schema this file is going to use as a control file. The second line you'd actually find inside the schema. It reads:
Code:
    <ElementType name="UnitInfos" content="eltOnly">
        <element type="UnitInfo" maxOccurs="*"/>
    </ElementType>
Which is saying, Within <UnitInfos> you'll find any number of uses of the <UnitInfo> tag.

Note: I'm not entirely sure what maxOccurs="*' means still but the application of <element type="UnitInfo" within the nested UnitInfos declaration is where I'm able to derive the above noted meaning.

Then I can search for the term UnitInfo and find the Declaration for UnitInfo and I find my example above:
<ElementType name="UnitInfo" content="eltOnly">

Then there are nested applications of tags within UnitInfo. These tags, applied with <element type=, are declared elsewhere in the schema. Where is not important so long as it is not within any other declaration and that it is only declared once - even though once declared, a tag may be applied in multiple places, nested within other multi-tag (eltOnly) declarations.

If that above paragraph is too confusing, take away from it the following:
1) A tag must only be declared once in the schema.
2) A tag may, however, be applied in many places.

So under <ElementType name="UnitInfo" content="eltOnly"> we start listing off the tags that can be used for a given Unit definition. Here's a sample of the first ones listed there:
Code:
        <element type="Class" minOccurs="0"/>
        <element type="Type" minOccurs="0"/>
<!-- XMLCOPY                02/20/2008            MRGENIE        -->
        <element type="bTypeDependency" minOccurs="0"/>       
        <element type="bForceOverwrite" minOccurs="0"/>
        <element type="AndDependencyTypes" minOccurs="0"/>
        <element type="OrDependencyTypes" minOccurs="0"/>
<!-- XMLCOPY                END                    MRGENIE        -->
        <element type="UniqueNames" minOccurs="0"/>
        <element type="Special" minOccurs="0"/>
        <element type="Capture" minOccurs="0"/>
        <element type="Combat" minOccurs="0"/>
        <!--TB SubCombat Mod begin-->
        <element type="SubCombatTypes" minOccurs="0"/>
        <!--TB SubCombat Mod end-->
        <element type="Domain" minOccurs="0"/>
        <element type="DefaultUnitAI" minOccurs="0"/>
        <element type="Invisible" minOccurs="0"/>
        <element type="SeeInvisible" minOccurs="0"/>
        <element type="Description" minOccurs="0"/>
        <element type="Civilopedia" minOccurs="0"/>
        <element type="Strategy" minOccurs="0"/>
        <element type="Help" minOccurs="0"/>
        <element type="Advisor" minOccurs="0"/>
        <element type="bAnimal" minOccurs="0"/>
        <element type="bFood" minOccurs="0"/>
        <element type="bNoBadGoodies" minOccurs="0"/>
        <element type="bOnlyDefensive" minOccurs="0"/>
        <element type="bNoCapture" minOccurs="0"/>
        <element type="bQuickCombat" minOccurs="0"/>
        <element type="bRivalTerritory" minOccurs="0"/>
        <element type="bMilitaryHappiness" minOccurs="0"/>
        <element type="bMilitarySupport" minOccurs="0"/>
        <element type="bMilitaryProduction" minOccurs="0"/>
        <element type="bPillage" minOccurs="0"/>
        <element type="bSpy" minOccurs="0"/>
        <element type="bSabotage" minOccurs="0"/>
        <element type="bDestroy" minOccurs="0"/>
        <element type="bStealPlans" minOccurs="0"/>
        <element type="bInvestigate" minOccurs="0"/>
        <element type="bCounterSpy" minOccurs="0"/>
        <element type="bFound" minOccurs="0"/>
        <element type="bGoldenAge" minOccurs="0"/>
        <element type="bInvisible" minOccurs="0"/>
        <element type="bFirstStrikeImmune" minOccurs="0"/>
        <element type="bNoDefensiveBonus" minOccurs="0"/>
And it goes on for quite a few more tags than that.

Now, when you are programming the xml, you must keep these tags in order on a given UnitInfo. Thus you would find that this beginning sample example of a UnitInfo entry adheres to the above listed order of tags:
EDIT: Update - the order of tags no longer matter in C2C due to a new way to load tags that was added by our master programmers. You can now put them in whatever order you wish in the XML entry.

Code:
<UnitInfo>
            <Class>UNITCLASS_AARDVARK</Class>
            <Type>UNIT_AARDVARK</Type>
            <UniqueNames/>
            <Special>NONE</Special>
            <Capture>NONE</Capture>
            <Combat>UNITCOMBAT_ANIMAL</Combat>
            <Domain>DOMAIN_LAND</Domain>
            <DefaultUnitAI>UNITAI_ANIMAL</DefaultUnitAI>
            <Invisible>NONE</Invisible>
            <SeeInvisible>NONE</SeeInvisible>
            <Description>TXT_KEY_UNIT_AARDVARK</Description>
            <Civilopedia>TXT_KEY_CONCEPT_ANIMALS_PEDIA</Civilopedia>
            <Strategy>TXT_KEY_UNIT_ANIMAL_STRATEGY</Strategy>
            <Advisor>NONE</Advisor>
Some may be missing - that's not only ok, that's advisable. If a tag is not used, it really shouldn't be included in the definition of that UnitInfo at all. (EDIT: Sometimes there are design reasons you may want to include a tag with a default value so that you or others to come may see the specific intention to use default.)

In otherwords, it would usually be better to have the <Advisor> tag line in the above example simply not be there at all. However, some tags are not optimally programmed and thus not including them causes a default that is not exactly what you'd think so be on the lookout for those.

Nevertheless, even if a tag is missing from a UnitInfo (we'll begin calling that an 'object definition' from here on out) as long as the tags that ARE included are in the order established by the schema, we're OK.

So what we've learned so far is how to find a FULL list of tags that can be used in any object definition and the proper syntax use for those tags.

Now if you see a tag in use in an info file and it isn't given an application line in the schema, this is fine... as I said above, it COULD possibly work and it won't error out. Tags that are just declared but not applied can be used ANYWHERE in the xml. An example of such a tag is <ConstructCondition> in the Buildings Schema. You can go on to use ConstructCondition anywhere in any building file and the way AIAndy has programmed it it'll work just fine to apply to the object definition its used in. It is not, however, given an application line on any Info type in the Building Schema. Don't let this throw you if you're looking for where you should be putting that tag in any given order.

Generally the rule of thumb here is if a tag has NO application lines anywhere, its a generic tag that can be used in all of the object definitions that apply to that schema.

Otherwise, if you search for and FIND an application line on a tag but you don't find it within the particular Info type you're wanting to apply that tag to, you're probably looking at a situation where the tag isn't setup to work with that particular Info type.

Thus, if I have a TechPrereq tag and I want to use it on my FeaturesInfo but in the Terrain schema you find TechPrereq has been declared, and applied to some of the Info types within that schema, like BuildsInfo for example, but NOT applied under FeaturesInfo, you have a tag that probably isn't setup to work with FeaturesInfo even though you could use the tag there without error but without it having any effect.

Ok, I'll move on to the next post to explain more.
 
Last edited:
Tag Types

Naming convention is how the tag programmer begins the process of guiding you in how to utilize a tag.

There are 3 basic 'types' to understand:

1) Integers - just that, a non-decimalized numeric value.

2) Booleans - 1 or 0 is all that would go here, 1 for true, 0 for false.

3) Type tags - indicates where you'd refer to another info type object with its Type tag (its primary key).

4) Multi-tag


Integers are denoted on a tag that begins its name with i. Booleans begin with b. Multi-tags start with neither.

To program an integer, you simply place the integer value within the open and close statements as this example:
<iXPValueAttack>6</iXPValueAttack>

To program a boolean, you simply place '1' or '0' within the open and close statements as this example:
<bAnimal>1</bAnimal>

Note: booleans are the biggest ones to watch out for having problematic defaults if the tag isn't included in the info entry.

To program a Type tag, place the Type name inside the opening and closing statements, such as:
<UnitAIType>UNITAI_ANIMAL</UnitAIType>
This particular tag is then referring to the animal unit AI definition.

To program a Multi-tag is where things get interesting.

You'll notice this works exactly like an Info entry itself, as a nested statement. You start the tag with the opener on its own line.
Code:
			<UnitAIs>
Then underneath, tab over one more time (not that white space is critical in xml so much as doing the whitespace correctly is a courtesy to the xml modders to follow - makes it easier to read.) There, add the first tag nested within the Multi-Tag, such as this:
Code:
			<UnitAIs>
				<UnitAI>
Often, such as in this example, you are working with another multi-tag immediately within the first multi-tag. UnitAI is another multi-tag itself. Thus we continue with another new line and a further tab over THEN apply the next tag, such as:
Code:
			<UnitAIs>
				<UnitAI>
					<UnitAIType>UNITAI_ANIMAL</UnitAIType>

And if there are more tags to include within the nesting we're working in, we continue to apply them. This is working just exactly like it does to enter the UnitInfo tags themselves.
Code:
			<UnitAIs>
				<UnitAI>
					<UnitAIType>UNITAI_ANIMAL</UnitAIType>
					<bUnitAI>1</bUnitAI>

Then, once the tags we're going to use within the nested statement is finished, we wrap up the multi-tag with a closing statement on the next line but at the same tab mark as where the opening statement lie:
Code:
			<UnitAIs>
				<UnitAI>
					<UnitAIType>UNITAI_ANIMAL</UnitAIType>
					<bUnitAI>1</bUnitAI>
				</UnitAI>
You can see we've only closed off the first multi-tag within our starting multi-tag so far. Here we could open up another occurence of that multi-tag again, such as:
Code:
			<UnitAIs>
				<UnitAI>
					<UnitAIType>UNITAI_ANIMAL</UnitAIType>
					<bUnitAI>1</bUnitAI>
				</UnitAI>
				<UnitAI>
					<UnitAIType>UNITAI_PROPHET</UnitAIType>
					<bUnitAI>1</bUnitAI>
				</UnitAI>
and only close it off when we're actually done:
Code:
			<UnitAIs>
				<UnitAI>
					<UnitAIType>UNITAI_ANIMAL</UnitAIType>
					<bUnitAI>1</bUnitAI>
				</UnitAI>
				<UnitAI>
					<UnitAIType>UNITAI_PROPHET</UnitAIType>
					<bUnitAI>1</bUnitAI>
				</UnitAI>
			</UnitAIs>


But how do I know how to find the tags that are supposed to be used WITHIN a multi-tag? This seems to be the biggest question that lies within even some of our more experienced modders here. How do I program the syntax for a Multi-tag?

First, do a search for the tag name itself. In the above example, go into the unitschema and search for 'UnitAIs'. In Notepad++ you have the option to search for all occurrences and I often use it when doing this.

Find the line where your multi-tag is Declared (not applied - we already know its applied under UnitInfos).

Remember, this line will start with <ElementType name= and will end with content="eltOnly"> (note the missing / before the last > which means its an opening statement that is not closing here and will then be listing off nested tag application lines.) Thus we KNOW the proper Declaration line here will look exactly like <ElementType name="UnitAIs" content="eltOnly">

Finding that, we see the following:
Code:
	<ElementType name="UnitAIs" content="eltOnly">
		<element type="UnitAI" minOccurs="0" maxOccurs="*"/>
	</ElementType>
Ok, so now we see why we immediately had another multi-tag, because UnitAI is what's listed within UnitAIs.

Note: minOccurs="0" means the use of this tag within UnitAIs is NOT mandatory. This is why we CAN express the following in code:
Code:
			<UnitAIs>
			</UnitAIs>
But if minOccurs wasn't set to "0" then you'd HAVE to include UnitAI within the UnitAIs tag or you'd get a problem with your info file. Again, however, better yet to simply not include the UnitAIs tag at all rather than having a null tag use. This is even more important to observe with multi-tags as that's where we've seen some problems emerge with null value tags.

So now where do we go? That's right... we search for UnitAI rather than UnitAIs so we can find the Declaration line (and the nested tags beneath it) for THAT tag.

Searching for UnitAI we find:
Code:
	<ElementType name="UnitAI" content="eltOnly">
		<element type="UnitAIType"/>
		<element type="bUnitAI"/>
	</ElementType>
So this tells us that within any use of UnitAI, we MUST (note there's no minOccurs="0" statement in these application lines) include the tags UnitAIType AND bUnitAI.

Now, we could look for the declaration on those two tags but we can already derive what they are from the names.

We know from the ending of the first tag, 'Type', that it's going to be declared as an integer (types are actually string coded integers as the list of types is enumerated in the code - thus our Aardvark is actually 'unit 0' - the count always starts at 0.) And we know that being a Type tag it will take a Type entry and it states that its type IS UnitAI so we should be pretty clear what's supposed to go in that tag.

And we know from the beginning of the second tag, bUnitAI, that its a boolean so it's going to take a 1 or a 0. This turns on or off that given UnitAIType entry. It's totally unnecessary to program tags to require this boolean and its very memory heavy to do so but it was a standard that was established by the original Firaxis programmers.

Our newer tags won't ever utilize this boolean activation method at all thus you often have one multi-tag and may list off many types without segmenting them each into their own multi-tag as this example does. Thus you'd have the following sort of 'list' approach:
Code:
			<MayDamageAttackingUnitCombatTypes>
				<UnitCombatType>UNITCOMBAT_MELEE</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_THROWING</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_ARCHER</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_GUN</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_MOUNTED</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_WHEELED</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_SIEGE</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_HOVERCRAFT</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_TRACKED</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_DREADNOUGHT</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_ASSAULT_MECH</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_ROBOT</UnitCombatType>
				<UnitCombatType>UNITCOMBAT_HITECH</UnitCombatType>
			</MayDamageAttackingUnitCombatTypes>
Notice there's no <MayDamageAttackingUnitCombatType> tag, only the <MayDamageAttackingUnitCombatTypes> and if you looked at the building schema in this case, you'd see only <UnitCombatType> applied within the <MayDamageAttackingUnitCombatTypes> multi-tag declaration:
Code:
	<ElementType name="MayDamageAttackingUnitCombatTypes" content="eltOnly">
		<element type="UnitCombatType" minOccurs="0" maxOccurs="*"/>
	</ElementType>

Ok, so that pretty much explains how to determine the proper syntax for a tag. Let me know if you have further questions or if I've lost you anywhere here.

Soon, I'll cover some more basic naming conventions that will be helpful in guiding you to understand the meaning of a tag that will help to suggest exactly how the tag WORKS in the game. It's surprising how much can be inferred by the name alone and knowing these tips will help you to figure out if you have a tag that does exactly what you want it to. Unfortunately, not all naming conventions have been well adhered to by all the many programmers that have worked on tags up to this point and additional naming conventions that SHOULD have been used have not begun being used until recently. But I can at least give you tips to understand the tag on the name alone. So that's coming up next.
 
That is certainly helpful there ls!


I figured I should share this in this thread to help those who try to use it in times to come:
Thanks TB, I really learnd something in your tutorial (I think :p) So lets se if I can get the code for my question...

Code:
<UnitCombatProdModifiers>
     <UnitCombatProdModifier>
          <UnitCombatProd>UnitCombatClass_MELEE</UnitCombatProd>
          <iUnitCombatProdModifier>10</iUnitCombatProdModifier>
     </UnitCombatProdModifier>
     <UnitCombatProdModifier>
          <UnitCombatProd>UnitCombatClass_ARCHER</UnitCombatProd>
          <iUnitCombatProdModifier>20</iUnitCombatProdModifier>
     </UnitCombatProdModifier>
</UnitCombatProdModifiers>

Would this make all Melee trained 10% faster and all Archers 20%?
Why does the <UnitCombatProd> not say "type"?
Well... to answer your question its because I did not have the insight I have now when I built that tag. lol... as stated, naming conventions have not been fully adhered to throughout the whole schema. But you 'got' the point and did a great job.

However there is one flaw. Remember that in a Type tag reference, which you are correct that this is, you must use the same label as you'd find in the Type tag for the game object you are referring to.

So if we open up the UnitCombatInfos.xml file (located in the Basic Infos file operating under the schema there since it was not intended originally to be such a used class of its own) and search for MELEE we'll the Melee entry expressed as such:
Code:
		<UnitCombatInfo>
			<Type>UNITCOMBAT_MELEE</Type>
			<Description>TXT_KEY_UNITCOMBAT_MELEE</Description>
			<Button>,Art/Interface/Buttons/Promotions/Shock.dds,Art/Interface/Buttons/Promotions_Atlas.dds,4,5</Button>
		</UnitCombatInfo>
So the <Type> tag label for the Melee CC is UNITCOMBAT_MELEE and that should go in your code so that it looks like this:
Code:
<UnitCombatProdModifiers>
     <UnitCombatProdModifier>
          <UnitCombatProd>UNITCOMBAT_MELEE</UnitCombatProd>
          <iUnitCombatProdModifier>10</iUnitCombatProdModifier>
     </UnitCombatProdModifier>
     <UnitCombatProdModifier>
          <UnitCombatProd>UNITCOMBAT_MELEE</UnitCombatProd>
          <iUnitCombatProdModifier>20</iUnitCombatProdModifier>
     </UnitCombatProdModifier>
</UnitCombatProdModifiers>
Then this would work out perfectly. You did learn a lot to get here though :D Well done!
 
Top Bottom