XML-SDK question

RogerBacon

King
Joined
Nov 16, 2003
Messages
649
If I want to add a new entry to the XML schema is there any way to make it optional so that every entry doesn't have to have it? For example, if I add a new entry to the CIV4UnitSchema.xml called <MagicImmune> I would like to make it so I don't have to go back and edit every single unit entry to have that tag but only have to add it for the units that I want to have that characteristic. Is that possble?

Roger Bacon
 
It is absolutely possible. All you have to do is something like:
<element type="bRenderBelowWater" minOccurs="0"/> in the unit definition in the CIV4UnitSchema.xml file.
 
I recomend

<element type="bRenderBelowWater" minOccurs="0" maxOccurs="1"/>
 
Thank you.
I have added the entry and it works... sort of. I've added a python command getIsImmune() that returns a bool. However, it is always returning the value that is the default in CvInfos.cpp in the CvUnitInfo constructor.

In CvUnit::read I've added
pStream->Read(&m_bMagicImmune);

and in

CvUnit::write
pStream->Write(m_bMagicImmune);

Are those the places that the code reads from the XML file?

What else do I need to do? I've also made some changes in CyUnit and CyUnitInterface1.cpp but, looking back now, I don't think those should be necessary.

Roger Bacon
 
Look under the SomeInfo::read(XMLLoadUtility) functions, that reads from XML (the other 2 read and write save games). The functions their take the adress of the variable AND the name of the XML tag (how did you expect your previous code to know what XML tag was the right one?). A pXML->GetChildXmlValByName call is used to load up the value, and fortunatly when the element isn't found (which 99% of the time it wont be because of the way you did the Schema) the default values are retained. Also the lines your quoting are not from the Constructor, the constructor is CvTechInfo::CvTechInfo().
 
Impaler[WrG] said:
Look under the SomeInfo::read(XMLLoadUtility) functions, that reads from XML (the other 2 read and write save games). The functions their take the adress of the variable AND the name of the XML tag . A pXML->GetChildXmlValByName call is used to load up the value, and fortunatly when the element isn't found the default values are retained.

I had
pXML->GetChildXmlValByName(&m_bMagicImmune, "bMagicImmune");
in CvInfos.cpp under CvUnitInfo::read
In CvInfos.h I have
DllExport bool isMagicImmune() const;
I also added m_bMagicImmune to the same file.

Basically everywhere there was an entry for bAnimal or isAnimal I made one for my variable. However, it still doesn't work. Any further suggestions?

Roger Bacon
 
Can you show what you added to CIV4UnitInfos.xml (with the elements preceding and following your addition)?
 
PeteT said:
Can you show what you added to CIV4UnitInfos.xml (with the elements preceding and following your addition)?

I only added one line to the XML
<bAnimal>1</bAnimal>
<bMagicImmune>1</bMagicImmune> <!--RogerBacon -->
<bFood>0</bFood>

RogerBacon
 
Make sure you do all those things in the right places.
CvUnit.cpp has all the variables and functions that are attributes of each unit instance (and those are written to the savegame)

wereas CvInfos.cpp (UnitClassInfo) holds general UnitClass informations (the read write functions in CvInfo do not write to the savegame but only to the XML cache files)

Oh and try deleting that XML-comment within the unit block. That sometimes causes problems.
 
I would like to make it so I don't have to go back and edit every single unit entry to have that tag but only have to add it for the units that I want to have that characteristic.

I don't think you're going to be able to do this. Although it's syntactically acceptable to add a schema like:

Code:
<ElementType name="bAnimal" content="textOnly" dt:type="boolean"/ >
<ElementType name="bMagicImmune" content="textOnly" dt:type="boolean",[b] minOccurs="0"[/b] / >

I couldn't get it to work. I was working on this kind of stuff yesterday and am pretty well on top of it at the moment. Except for trying to have an optional boolean like that, it looks like you've done everything right, but here's a whole checklist anyway:

1) In CIV4UnitSchema.xml, add

Code:
<ElementType name="bAnimal" content="textOnly" dt:type="boolean"/ >
<ElementType name="bMagicImmune" content="textOnly" dt:type="boolean"/ >

2) Further down in CIV4UnitSchema.xml, add within the <ElementType name="UnitInfo" content="eltOnly">

Code:
<element type="bAnimal"/>
<element type="bMagicImmune"/>

3) In CvInfos.h, find the class CvUnitInfo, and add both the declaration:

Code:
DllExport bool isMagicImmune() const;

and the member:

Code:
bool m_bMagicImmune;

4) In CvInfos.cpp, add both the method

Code:
bool CvUnitInfo::isMagicImmune() const				
{
	return m_bMagicImmune;
}

and in the constructor CvUnitInfo::CvUnitInfo(), set

Code:
m_bMagicImmune(false)

5) Still in CvInfos.cpp, in the method bool CvUnitInfo::read(CvXMLLoadUtility* pXML):
add the lines:

Code:
	pXML->GetChildXmlValByName(&m_bMagicImmune, "bMagicImmune");

CvString szStr;
szStr.Format("\n read : m_bMagicImmune=%d\n", m_bMagicImmune) ;
gDLL->logMsg("xml.log",szStr);

To verify that it works, I've included some code to print out to xml.log. You need to have LoggingEnabled = 1 in your CivilizationIV.ini file to see this.

6) Finally, open CIV4UnitInfos.xml and add an element <bMagicImmune>0</bMagicImmune> (or "1") to each unit.

Somewhat tedious and finicky, but it worked fine for me.
 
PeteT said:
I don't think you're going to be able to do this. Although it's syntactically acceptable to add a schema like:

Code:
<ElementType name="bAnimal" content="textOnly" dt:type="boolean"/ >
<ElementType name="bMagicImmune" content="textOnly" dt:type="boolean",[b] minOccurs="0"[/b] / >

I couldn't get it to work. I was working on this kind of stuff yesterday and am pretty well on top of it at the moment.
You are adding the minOccurs="0" in the wrong place.

PeteT said:
2) Further down in CIV4UnitSchema.xml, add within the <ElementType name="UnitInfo" content="eltOnly">

Code:
<element type="bAnimal"/>
<element type="bMagicImmune"/>
THIS is where you add minOccurs="0". So it looks like:
Code:
<element type="bAnimal"/>
<element type="bMagicImmune" minOccurs="0"/>
 
Hi All,

PeteT,
I went down your checklist. I had already done everything there, except the logging. I added the logging and, sure enough, I have one entry that has m_bMagicImmune=1.
...
[16900.375] info type NONE not found, Current XML file is: Units/CIV4UnitInfos.xml
[16900.375] info type NONE not found, Current XML file is: Units/CIV4UnitInfos.xml
[16900.375] info type NONE not found, Current XML file is: Units/CIV4UnitInfos.xml
[16900.375]
read : m_bMagicImmune=1
[16900.375] info type NONE not found, Current XML file is: Units/CIV4UnitInfos.xml
[16900.375] info type NONE not found, Current XML file is: Units/CIV4UnitInfos.xml
...

I have some test code in python to tell me the value of bMagicImmune for any unit I put the mouse over and press a key. Unfortunately it always comes back 0. I've used this code many times so I'm 99% sure it is working but I'll post it here just in case that is the problem.

Code:
def onKbdEvent(self, argsList):
		eventType,key,mx,my,px,py = argsList
		#eventType,key,self.bCtrl,self.bShift,self.bAlt,mx,my,px,py = argsList
		if ( eventType == self.EventKeyDown ):
			theKey=int(key)
			CvCameraControls.g_CameraControls.handleInput( theKey )
			unit = CyMap().plot(px, py).getUnit(0)
			if(theKey == int(InputTypes.KB_M)):
				message0 = "Unit magic Immune: %s " %unit.isMagicImmune()		
				CyInterface().addImmediateMessage(message0,"")
				CvUtil.pyPrint(message0)

I'm using 0 for false and 1 for true but that should be ok, right?

I've also added code in some other places and maybe that is causing the problem. I added code in CvUnit.h and .cpp Is that not needed? It is basically a repeat of what is in CvInfos. I will comment it out and see if it makes a difference. Seems strange to add a tag to a unit and not have the code in CvUnit.cpp though.

Roger Bacon
 
Not sure on the Py code to do it, but you're calling isMagicImmune() on the unit, not the unit info. You've loaded the variable into CvUnitInfo, but try to retrieve it from CvUnit.

In the DLL I would call it:
pUnit->getUnitInfo()->isMagicImmune()

I had the same problem till I worked this out. :)

Dale

PS:
I setup this in CvUnit.cpp:
CvUnit::getDCMRanged() const
{
return getUnitInfo()->getDCMRanged();
}

And in CvUnitInfo.cpp:
CvUnitInfo::getDCMRanged() const
{
return m_bDCMRanged;
}

This means all I need to call is pUnit->getDCMRanged();
 
Dale, that did it! It works now.
My thanks to everyone who helped me in this thread.

I do have one more questiion though, since I want to clean up any unnecessary code I've added.
In CvUnit.cpp in CvUnit::reset I added m_bMagicImmune = false; Is that needed? It says the reset function is to initialize data members that are serialized.
Well, it's late and I'm just happy its working now. I'll look at it again tomorrow evening.

Thanks again everyone,

Roger Bacon :)
 
Okay, it depends how bMagicImmune is to work. If it NEVER changes during a game, then you can get rid of m_bMagicImmune from CvUnit as you repoint it to CvUnitInfo.

However:
If you want magic immunity to change for individual units (EG: Protection from Magic spell is cast on a unit) then you need to keep it.

Firstly, you need a way to set an individual units magic immunity. Thus a new funtion as such:
Code:
CvUnit.h:
void setMagicImmune(bool value);

CvUnit.cpp:
void CvUnit::setMagicImmune(bool value)
{
  m_bMagicImmune = value;
}

Now you CHANGE getMagicImmune() as such:
Code:
CvUnit.cpp:
bool CvUnit::getMagicImmune()
{
  return m_bMagicImmune;
}

So now you're returning that unit's magic immune, not the classes magic immune.

Now, when you setup a new unit you need to set the initial magic immunity:
Code:
CvUnit.cpp:
CvUnit::reset(..)
{
  ..
  ..
  setMagicImmune(getUnitInfo()->getMagicImmune());
  ..
}

We reference to the function you setup previously in CvUnitInfo.cpp.

Lastly, whenever you change the state of a unit's magic immunity you call:
Code:
pUnit->setMagicImmune(true/false);

That should be it.

NOTE: setting a unit's magic immunity only affect m_bMagicImmune in CvUnit. m_bMagicImmune in CvUnitInfo does not change.

Dale

BTW: I hope you've put both instances of m_bMagicImmune in protected!
 
Back
Top Bottom