[HELP] Cloning ImprovementYieldChanges from Civic Infos to Trait Infos

Cybah

Emperor
Joined
Jun 22, 2007
Messages
1,481
Cloning integers like iWorkerSpeedModifier to Trait Infos is easy, but ImprovementYieldChanges look highly complicated.

Here is what I got so far:

CvGameTextMgr.cpp:

PHP:
void CvGameTextMgr::parseTraits(CvWStringBuffer &szHelpString, TraitTypes eTrait, CivilizationTypes eCivilization, bool bDawnOfMan)
...
		for (iI = 0; iI < NUM_YIELD_TYPES; ++iI)
		{
			for (iJ = 0; iJ < GC.getNumImprovementInfos(); iJ++)
			{
				if (GC.getTraitInfo(eTrait).getImprovementYieldChanges(iJ, iI) != 0)
				{
					szHelpString.append(gDLL->getText("TXT_KEY_CIVIC_IMPROVEMENT_YIELD_CHANGE", GC.getTraitInfo(eTrait).getImprovementYieldChanges(iJ, iI), GC.getYieldInfo((YieldTypes)iI).getChar()).c_str());
				}
			}
		}



CvInfos.cpp:


PHP:
CvTraitInfo::CvTraitInfo() :
...
m_ppiImprovementYieldChanges(NULL),


PHP:
CvTraitInfo::~CvTraitInfo()
...
int CvTraitInfo::getImprovementYieldChanges(int i, int j) const
{
	return m_ppiImprovementYieldChanges[i][j];
}


PHP:
bool CvTraitInfo::read(CvXMLLoadUtility* pXML)
...
	int j;
	int iNumSibs=0;				// the number of siblings the current xml node has
	int iIndex;
	pXML->Init2DIntList(&m_ppiImprovementYieldChanges, GC.getNumImprovementInfos(), NUM_YIELD_TYPES);
	if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"ImprovementYieldChanges"))
	{
		if (pXML->SkipToNextVal())
		{
			iNumSibs = gDLL->getXMLIFace()->GetNumChildren(pXML->GetXML());
			if (gDLL->getXMLIFace()->SetToChild(pXML->GetXML()))
			{
				if (0 < iNumSibs)
				{
					for (j=0;j<iNumSibs;j++)
					{
						pXML->GetChildXmlValByName(szTextVal, "ImprovementType");
						iIndex = pXML->FindInInfoClass(szTextVal);

						if (iIndex > -1)
						{
							// delete the array since it will be reallocated
							SAFE_DELETE_ARRAY(m_ppiImprovementYieldChanges[iIndex]);
							// if we can set the current xml node to it's next sibling
							if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"ImprovementYields"))
							{
								// call the function that sets the yield change variable
								pXML->SetYields(&m_ppiImprovementYieldChanges[iIndex]);
								gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
							}
							else
							{
								pXML->InitList(&m_ppiImprovementYieldChanges[iIndex], NUM_YIELD_TYPES);
							}
						}

						if (!gDLL->getXMLIFace()->NextSibling(pXML->GetXML()))
						{
							break;
						}
					}
				}

				gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
			}
		}

		gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
	}


CvInfos.h:

PHP:
class CvTraitInfo :
...
	int getImprovementYieldChanges(int i, int j) const;				// Exposed to Python



CvPlayer.cpp:

PHP:
void CvPlayer::init(PlayerTypes eID)
...
				for (iI = 0; iI < GC.getNumImprovementInfos(); iI++)
				{
					for (iJ = 0; iJ < NUM_YIELD_TYPES; iJ++)
					{
						changeImprovementYieldChange(((ImprovementTypes)iI), ((YieldTypes)iJ), (GC.getTraitInfo((TraitTypes)iI).getImprovementYieldChanges(iI, iJ)));
					}
				}


CIV4CivilizationsSchema.xml:

PHP:
	<ElementType name="ImprovementType" content="textOnly"/>
	<ElementType name="ImprovementYields" content="eltOnly">
		<element type="iYield" minOccurs="0" maxOccurs="*"/>
	</ElementType>
	<ElementType name="ImprovementYieldChange" content="eltOnly">
		<element type="ImprovementType"/>
		<element type="ImprovementYields"/>
	</ElementType>
	<ElementType name="ImprovementYieldChanges" content="eltOnly">
		<element type="ImprovementYieldChange" minOccurs="0" maxOccurs="*"/>
	</ElementType>

...

	<ElementType name="TraitInfo" content="eltOnly">
...
		<element type="ImprovementYieldChanges" minOccurs="0"/>


I could compile the DLL, but I get multiple xml load errors like these:

Error loading/calling Civ4TraitInfos.xml

and



I guess it has something to do with my long part in CvInfos.cpp. This is 99% copied from another entry without any knowledge from me. :blush:

Can you help me on this? What's wrong/missing?
 
That error you got means that the array is empty, I think. If you look at the CvXMLLoadUtilitySet.cpp LoadPreMenuGlobals() the order which the files are loaded shows that TraitInfos is loaded way before ImprovementInfos. One option is to move ImprovementInfos loading before the TraitInfos loading, but this can cause problems if your ImprovementInfos file refers to other xml values. The other option is to create a ReadPass2 or 3. I don't remember which but not sure if it even matters.
 
Well, as far as I know you need to add a ReadPass3 function to CvTraitInfo and then call it from CvXMLLoadUtilitySet LoadPreMenuGlobals for every trait:
Code:
	for (int i=0; i < GC.getNumTraitInfos(); ++i)
	{
		GC.getTraitInfo((TraitTypes)i).readPass3();
	}
But I don't know how the ReadPass3 should work. :dunno: Mayby someone has more knowledge.
 
Perhaps this is not widely known. The pass2 and pass3 functions exist because the xml is processed file by file, and line by line. The order of files is given in CvXMLLoadUtilitySet.cpp and should not be changed unless you really understand all the relationships between the xml.

If you want one xml object to refer to another object in the same file, you must use readpass2. For example, one tech often lists another tech as a prereq. It could be that the tech appears in the file before the prereq tech, so referring to the prereq tech name would result in a "name not defined" error.

If you want one xml object in one file, to refer to another object in another file which appears earlier in the CvXMLLoadUtilitySet.cpp source file, you do not need to do anything. But, if you want to refer to an object which appears later in the source file, you must add a readpass3.

In general you want to define your xml additions to avoid the need for a readpass3; but there can be circular references where file A needs some object from B, and B needs some other object from A. To avoid this, you may want to invert the reference in your xml additions. For example, if you want to add something to xml object A which refers to something in a later xml object B, it may be possible to put your new data onto object B instead. That way the order of xml parsing is preserved and no readpass3 is needed.
 
Or, to be more specific, instead of adding an "ImprovementYieldChanges" to the trait info, you could add a "TraitYieldChanges" to the improvement info.
 
Top Bottom