Case Study: Adding new XML attributes and using them in the SDK

Edit:

The problem really lies in displaying text because attitude change works properly as soon as I meet another civ. Those who must be pleasant are pleasant and those who must be cautious are cautious etc. etc. Also I can see texts for years of peace etc. now. I will try to look into that textmngr file again probably I'll find some clue.
 
How do I add XML tags that are linked? Example:

Code:
			<FeatureModify>
				<FeatureType>
					<Feature>FEATURE_FOREST</Feature>
					<iMovement>1</iMovement>
					<bImpassible>0</bImpassible>
				</FeatureType>
				<FeatureType>
					<Feature>FEATURE_ICE</Feature>
					<iMovement>1</iMovement>
					<bImpassible>0</bImpassible>
				</FeatureType>
			</FeatureModify>

and

Code:
			<CivRequire>
				<Civilization>CIVILIZATION_KLINGON</Civilization>
				<Civilization>CIVILIZATION_ROMULAN</Civilization>
			</CivRequire>
 
Bump. This is useful, so it should be added to woodelf's Tutorial Thread Index.
 
Kael:

Would it be possible for you to update this excellent tutorial with a section on exposing newly created tags to Python? It would be very helpful :)
 
Ok, I'm having some trouble here.

I'm adding some tags so that a building can add happiness per each of a certain kind of improvement in the city radius. The xml structure is exactly the same as the tag <ImprovementFreeSpecialists> that is used by the National Park building. Here is an example:

Code:
<ImprovementHappinessTypes>
        <ImprovementHappiness>
                <ImprovementType>IMPROVEMENT_VILLAGE</ImprovementType>
                <iHappinessCount>1</iHappinessCount>
        </ImprovementHappiness>
        <ImprovementHappiness>
                <ImprovementType>IMPROVEMENT_TOWN</ImprovementType>
                <iHappinessCount>1</iHappinessCount>
        </ImprovementHappiness>
</ImprovementHappinessTypes>

I want one happiness in each town and village, maybe someday 2 per each whatever.

Here are the relevant Schema entries:
Code:
	<ElementType name="iHappinessCount" content="textOnly" dt:type="int"/>
	<ElementType name="ImprovementHappiness" content="eltOnly">
		<element type="ImprovementType"/>
		<element type="iHappinessCount"/>
	</ElementType>

Then I use this to read in the XML:
Code:
pXML->SetVariableListTagPair(&m_piImprovementHappiness, "ImprovementHappinessTypes", sizeof(GC.getImprovementInfo((ImprovementTypes)0)), GC.getNumImprovementInfos());

The XML loads fine and everything compiles fine in the SDK, but when I try to access the data with this function:
Code:
int CvBuildingInfo::getImprovementHappiness(int i) const
{
	FAssertMsg(i < GC.getNumImprovementInfos(), "Index out of bounds");
	FAssertMsg(i > -1, "Index out of bounds");
	return m_piImprovementHappiness ? m_piImprovementHappiness[i] : -1;
}

Instead of 0 or 1 I'm getting garbage values like 84672934. All these functions and variables are set up like the <ImprovementFreeSpecialists> tag. I'm in a little over my head with the XML reading functions. I'd like to try skipping the helper function SetVariableListTagPair and read it in long hand, but I'm not sure how the whole scheme works.
 
I did some more testing and it looks like my XML is in fact loading in correctly. Things go haywire in between the XML reading and my access to the data.

That's pretty scary...
Goodbye weekend...
 
Don't you need to have something like this (just picked a random line from CvInfos.XML):

Code:
pXML->GetChildXmlValByName(&m_iImprovementUpgradeRateModifier, "iImprovementUpgradeRateModifier");
 
Don't you need to have something like this (just picked a random line from CvInfos.XML):

Code:
pXML->GetChildXmlValByName(&m_iImprovementUpgradeRateModifier, "iImprovementUpgradeRateModifier");

The example I posted above is working. My mistake was elsewhere.
 
So..let's say I wanted to add a new tag to Civ4UnitsInfo.xml.

1) Add the tag to the Schema
2) Add the tag to all entries in the file
3) Enter Sid Meier's Civilization 4/Beyond the Sword/CvGameCoreDLL/CvUnit.cpp?

I think understand what to do from there, but I'm unsure as to which files to enter..

Edit: in the schema, what does "eltOnly" and "textOnly" mean?
 
eltOnly means that it contains sub-elements, and won't have any data to itself. TextOnly means it will have data, but won't have any sub-elements.


You have to modify quite a few locations in the DLL to get new tags to work I am afraid.
 
First off... thanks for an awesome tutorial, it helped me a great deal.

I'm working on a mod that (for right now) alters the way Values ("Religions") work in the Final Frontier mod. So far I have everything working except that the actual Diplomacy value doesn't print out after the diplomacy text:

It says "We admire your values."
When it's suppose to say "+2: We admire your values."

Code:
// TRACHMYR - FFValuesMod - Display new values attitudes in diplomacy
		iAttitudeChange = GET_PLAYER(ePlayer).AI_getKnowledgeValueAttitude(eTargetPlayer);
		if ((iPass == 0) ? (iAttitudeChange > 0) : (iAttitudeChange < 0))
		{
			szTempBuffer.Format(SETCOLR L"%s" ENDCOLR, TEXT_COLOR((iAttitudeChange > 0) ? "COLOR_POSITIVE_TEXT" : "COLOR_NEGATIVE_TEXT"), gDLL->getText(((iAttitudeChange > 0) ? "TXT_KEY_MISC_ATTITUDE_VALUE_GOOD" : "TXT_KEY_MISC_ATTITUDE_VALUE_BAD"), iAttitudeChange).GetCString());
			szBuffer.append(NEWLINE);
			szBuffer.append(szTempBuffer);
		}

		iAttitudeChange = GET_PLAYER(ePlayer).AI_getPleasureValueAttitude(eTargetPlayer);
		if ((iPass == 0) ? (iAttitudeChange > 0) : (iAttitudeChange < 0))
		{
			szTempBuffer.Format(SETCOLR L"%s" ENDCOLR, TEXT_COLOR((iAttitudeChange > 0) ? "COLOR_POSITIVE_TEXT" : "COLOR_NEGATIVE_TEXT"), gDLL->getText(((iAttitudeChange > 0) ? "TXT_KEY_MISC_ATTITUDE_VALUE_GOOD" : "TXT_KEY_MISC_ATTITUDE_VALUE_BAD"), iAttitudeChange).GetCString());
			szBuffer.append(NEWLINE);
			szBuffer.append(szTempBuffer);
		}

		iAttitudeChange = GET_PLAYER(ePlayer).AI_getPowerValueAttitude(eTargetPlayer);
		if ((iPass == 0) ? (iAttitudeChange > 0) : (iAttitudeChange < 0))
		{
			szTempBuffer.Format(SETCOLR L"%s" ENDCOLR, TEXT_COLOR((iAttitudeChange > 0) ? "COLOR_POSITIVE_TEXT" : "COLOR_NEGATIVE_TEXT"), gDLL->getText(((iAttitudeChange > 0) ? "TXT_KEY_MISC_ATTITUDE_VALUE_GOOD" : "TXT_KEY_MISC_ATTITUDE_VALUE_BAD"), iAttitudeChange).GetCString());
			szBuffer.append(NEWLINE);
			szBuffer.append(szTempBuffer);
		}

		iAttitudeChange = GET_PLAYER(ePlayer).AI_getReligionValueAttitude(eTargetPlayer);
		if ((iPass == 0) ? (iAttitudeChange > 0) : (iAttitudeChange < 0))
		{
			szTempBuffer.Format(SETCOLR L"%s" ENDCOLR, TEXT_COLOR((iAttitudeChange > 0) ? "COLOR_POSITIVE_TEXT" : "COLOR_NEGATIVE_TEXT"), gDLL->getText(((iAttitudeChange > 0) ? "TXT_KEY_MISC_ATTITUDE_VALUE_GOOD" : "TXT_KEY_MISC_ATTITUDE_VALUE_BAD"), iAttitudeChange).GetCString());
			szBuffer.append(NEWLINE);
			szBuffer.append(szTempBuffer);
		}

		iAttitudeChange = GET_PLAYER(ePlayer).AI_getSurvivalValueAttitude(eTargetPlayer);
		if ((iPass == 0) ? (iAttitudeChange > 0) : (iAttitudeChange < 0))
		{
			szTempBuffer.Format(SETCOLR L"%s" ENDCOLR, TEXT_COLOR((iAttitudeChange > 0) ? "COLOR_POSITIVE_TEXT" : "COLOR_NEGATIVE_TEXT"), gDLL->getText(((iAttitudeChange > 0) ? "TXT_KEY_MISC_ATTITUDE_VALUE_GOOD" : "TXT_KEY_MISC_ATTITUDE_VALUE_BAD"), iAttitudeChange).GetCString());
			szBuffer.append(NEWLINE);
			szBuffer.append(szTempBuffer);
		}

		iAttitudeChange = GET_PLAYER(ePlayer).AI_getWealthValueAttitude(eTargetPlayer);
		if ((iPass == 0) ? (iAttitudeChange > 0) : (iAttitudeChange < 0))
		{
			szTempBuffer.Format(SETCOLR L"%s" ENDCOLR, TEXT_COLOR((iAttitudeChange > 0) ? "COLOR_POSITIVE_TEXT" : "COLOR_NEGATIVE_TEXT"), gDLL->getText(((iAttitudeChange > 0) ? "TXT_KEY_MISC_ATTITUDE_VALUE_GOOD" : "TXT_KEY_MISC_ATTITUDE_VALUE_BAD"), iAttitudeChange).GetCString());
			szBuffer.append(NEWLINE);
			szBuffer.append(szTempBuffer);
		}

		iAttitudeChange = GET_PLAYER(ePlayer).AI_getNoValueAttitude(eTargetPlayer);
		if ((iPass == 0) ? (iAttitudeChange > 0) : (iAttitudeChange < 0))
		{
			szTempBuffer.Format(SETCOLR L"%s" ENDCOLR, TEXT_COLOR((iAttitudeChange > 0) ? "COLOR_POSITIVE_TEXT" : "COLOR_NEGATIVE_TEXT"), gDLL->getText(((iAttitudeChange > 0) ? "TXT_KEY_MISC_ATTITUDE_NO_VALUE_GOOD" : "TXT_KEY_MISC_ATTITUDE_NO_VALUE_BAD"), iAttitudeChange).GetCString());
			szBuffer.append(NEWLINE);
			szBuffer.append(szTempBuffer);
		}
		// END

However the game properly recognizes when there is an attitude change, applies it correctly, and prints the text correctly.

Code:
<TEXT>
		<Tag>TXT_KEY_MISC_ATTITUDE_VALUE_GOOD</Tag>
		<English>"We admire your values."</English>
		<French>"We admire your values."</French>
		<German>"We admire your values."</German>
		<Italian>"We admire your values."</Italian>
		<Spanish>"We admire your values."</Spanish>
	</TEXT>
	<TEXT>
		<Tag>TXT_KEY_MISC_ATTITUDE_VALUE_BAD</Tag>
		<English>"We oppose your values."</English>
		<French>"We oppose your values."</French>
		<German>"We oppose your values."</German>
		<Italian>"We oppose your values."</Italian>
		<Spanish>"We oppose your values."</Spanish>
	</TEXT>
	<TEXT>
		<Tag>TXT_KEY_MISC_ATTITUDE_NO_VALUE_GOOD</Tag>
		<English>"We appreciate that you are open to all values."</English>
		<French>"We appreciate that you are open to all values."</French>
		<German>"We appreciate that you are open to all values."</German>
		<Italian>"We appreciate that you are open to all values."</Italian>
		<Spanish>"We appreciate that you are open to all values."</Spanish>
	</TEXT>
	<TEXT>
		<Tag>TXT_KEY_MISC_ATTITUDE_NO_VALUE_BAD</Tag>
		<English>"We are concerned that you do not adhere to any value."</English>
		<French>"We are concerned that you do not adhere to any value."</French>
		<German>"We are concerned that you do not adhere to any value."</German>
		<Italian>"We are concerned that you do not adhere to any value."</Italian>
		<Spanish>"We are concerned that you do not adhere to any value."</Spanish>
	</TEXT>

Any ideas?

Thanks again.
 
Oops, it should be %D1, you need the integer to specify WHICH of the items provided to the text key to use. Forgot about that bit.

You are also allowed to leave yourself/others a little "note" about what the item should be by using an Underscore and then unspaced text, ie:

%D1_AttitudeValue
 
Where does the "%D1" type notation get defined? I can see that it draws the penalty/bonus and and prints it along with the appropriate of + or -, but I can seem to figure out where that is done in python or C++. Another .xml example from CIV4GameTextInfos:

Code:
    <TEXT>
        <Tag>INTERFACE_PANE_UNIT_NAME</Tag>
        <English>[COLOR_UNIT_TEXT]%s1[COLOR_REVERT]</English>
        <French>[COLOR_UNIT_TEXT]%s1[COLOR_REVERT]</French>
        <German>[COLOR_UNIT_TEXT]%s1[COLOR_REVERT]</German>
        <Italian>[COLOR_UNIT_TEXT]%s1[COLOR_REVERT]</Italian>
        <Spanish>[COLOR_UNIT_TEXT]%s1[COLOR_REVERT]</Spanish>
    </TEXT>
    <TEXT>
        <Tag>INTERFACE_PANE_UNIT_NAME_HOT_KEY</Tag>
        <English>[COLOR_UNIT_TEXT]#%d1 - %s2[COLOR_REVERT]</English>
        <French>[COLOR_UNIT_TEXT]#%d1 - %s2[COLOR_REVERT]</French>
        <German>[COLOR_UNIT_TEXT]#%d1 - %s2[COLOR_REVERT]</German>
        <Italian>[COLOR_UNIT_TEXT]#%d1 - %s2[COLOR_REVERT]</Italian>
        <Spanish>[COLOR_UNIT_TEXT]#%d1 - %s2[COLOR_REVERT]</Spanish>
    </TEXT>

I would like to be able to change that + or - to a x or ÷.
 
Back
Top Bottom