Ray's Tutorials: "How to add simple XML tags" for DLL and Python [FINISHED]

raystuttgart

Civ4Col Modder
Joined
Jan 24, 2011
Messages
9,638
Location
Stuttgart, Germany
Ok guys, I am going to post screenshots here in this thread.
I will try to teach you how to add a simple XML tag that can later be used in DLL and Python.

To try this tutorial yourself get:

1. Our Source Code and Project Setup (coming with the download)
2. A good editor like Notepad++ and a good Development IDE like Visual Studio

I am not going to explain how to setup these because @Nightinggale already did.

----------

This is the content of the tuorial:
(Special Rules for Storage Capacity considering Food, Lumber and Stone)

----------

Objectives / Goals:

A) Remove hardcoded Yield Logic for Food, Lumber and Stone by making it XML configurable.
B) Visualizing the Special Rules for Storage Capacity considering Food, Lumber and Stone in Colopedia

----------

Most Important Steps:

1. XML attribute (CvYieldInfos.xml): bIgnoredIForStorageCapacity
(Do not forget to adjust the Schema accordingly: CIV4TerrainSchema.xml)

2. DLL method: CvYieldInfo:: isIgnoredForStorageCapacity()

Use it in the internal logic that currently hardcodes Food, Lumber and Stone for Storage Capacity.
(Just search for "YIELD_STONE" to find it.)

3. Making it accessible for Python (CyInfoPythonInterface3)
.def("isIgnoredForStorageCapacity", &CvYieldInfo::isIgnoredForStorageCapacity, "bool ()")

4. Using that Logic in Pedia Screen of Yields
(Well of course you also need a TXT_KEY in XML to display the message.)
 
Last edited:
Ok, let us get started with the XML configuration:
1. XML attribute (CvYieldInfos.xml): bIgnoredIForStorageCapacity
(Do not forget to adjust the Schema accordingly: CIV4TerrainSchema.xml)

1) Go into the ...\<YourMod>\Assets\XML\Terrain


2) Open the Schema: Civ4TerrainSchema.xml

Question: How do we know that we have to open this Schema and not another one?
Answer: It is the only Schemal in this folder. Thus it needs to be the one used for Civ4YieldInfos.xml as well.

3) Make these 2 adjustments to the Schmema

The Type Definition: Boolean (that is why it should also start with "b" according to naming convention)


The Structure Definition: Sub-Element of YieldInfo
(we will make it optional: minOccurs=0)


4) Open the actual XML: Civ4YieldInfos.xml

Question: How do we know that we have to open this XML and not another one?
Answer: Well, we are configuring a rule for a Yield and this XML is called "YieldInfos".

5) Configure the XML tag at Food, Lumber and Stone.

Pay attention to the structure you have built in the Schema ! It must be put below "bCargo".
(But again it is optional, we only put it at the Yields we really want it.)

At "YIELD_FOOD":


At "YIELD_LUMBER":


At "YIELD_STONE":
 

Attachments

  • Screenshot_XMLs.JPG
    Screenshot_XMLs.JPG
    107.9 KB · Views: 219
  • New_Attribute_bIgnoredIForStorageCapacity_1.JPG
    New_Attribute_bIgnoredIForStorageCapacity_1.JPG
    84.2 KB · Views: 218
  • New_Attribute_bIgnoredIForStorageCapacity_2.JPG
    New_Attribute_bIgnoredIForStorageCapacity_2.JPG
    51.8 KB · Views: 217
  • YIELD_FOOD.JPG
    YIELD_FOOD.JPG
    36.1 KB · Views: 220
  • YIELD_LUMBER.JPG
    YIELD_LUMBER.JPG
    37.2 KB · Views: 213
  • YIELD_STONE.JPG
    YIELD_STONE.JPG
    36.6 KB · Views: 208
Last edited:
So now we are done with the pure configuration in XML.

The DLL (actual game logic) however does not know yet what it should do with it.
And Python (UI logic) also does not use it because it needs to get that information from DLL.

So nothing - absolutely nothing is going to happen.
We have just started.
 
Last edited:
So ok, let us teach DLL.
2. DLL method: CvYieldInfo:: isIgnoredForStorageCapacity()
Use it in the internal logic that currently hardcodes Food, Lumber and Stone for Storage Capacity.
(Just search for "YIELD_STONE" to find it.)

Advice:

As a beginner it is a good advice to search a similar attribute / method as "BluePrint" to copy the pattern.
(Later you will not need this anymore because you will know these patterns by heart.)

e.g. in this case, why not use "bCargo" / "CvYieldInfo::isCargo()" as our BluePrint. ;)
So we will search for these and make our adjustments for "bIgnoredIForStorageCapacity" / "CvYieldInfo::isIgnoredForStorageCapacity()" at (almost) the same places.

Only major exception the actual game logic we will use our new attribute will of course be different.

Question: How do we find relevat places with "bCargo" or "isCargo()" ?
Answer: We do a stupid file search in VisualStudio for "bCargo" or "isCargo()"





 

Attachments

  • Search_Bar.JPG
    Search_Bar.JPG
    103.7 KB · Views: 207
  • Search_Results_1.JPG
    Search_Results_1.JPG
    42.7 KB · Views: 201
  • Search_Results_2.JPG
    Search_Results_2.JPG
    132.7 KB · Views: 203
Last edited:
Changes for Reading the XML tag in DLL:

Explanations for non-programmers:
  • m_bIgnoredIForStorageCapacity: This is the internal DLL variable which we use to read and store XML tag bIgnoredIForStorageCapacity.
  • isIgnoredForStorageCapacity(): This is the method that will return m_bIgnoredIForStorageCapacity to other logic in the DLL.
Comment for non-programmers:

Do not worry about "Visual Studio" warnings in steps 1 to 3, they will all disappear once you are at step 4.







 

Attachments

  • 1.JPG
    1.JPG
    54.6 KB · Views: 209
  • 2.JPG
    2.JPG
    64.2 KB · Views: 209
  • 3.JPG
    3.JPG
    93 KB · Views: 206
  • 4.JPG
    4.JPG
    66.3 KB · Views: 211
Last edited:
Changes to allow Python to access that DLL method.

3. Making it accessible for Python (CyInfoPythonInterface3)
.def("isIgnoredForStorageCapacity", &CvYieldInfo::isIgnoredForStorageCapacity, "bool ()")

 

Attachments

  • Final_Correction_Of_Python_Def.JPG
    Final_Correction_Of_Python_Def.JPG
    184.4 KB · Views: 198
Last edited:
Now, let us actually adjust the gameplay logic for YIELD_FOOD, YIELD_LUMBER, YIELD_STONE

To find potential places in code to adjust, we simply search for "YIELD_STONE".
But sadly there are a lot. (In the past I had been hardcoding a bit much.) :mischief:




-----

But the good news is:
The relevant places I need to adjust are not that many.
 

Attachments

  • YIELD_STONE_HARDCODED.JPG
    YIELD_STONE_HARDCODED.JPG
    261.2 KB · Views: 183
Last edited:
Here are the places in the DLL source code I had to adjust for this game logic:
(Ignore them for the general tutorial if you like - they are very specific to this logic.)

It is mostly just the 2 lines (one commented out and one new) below this comment:
// ray, making special storage capacity rules for Yields XML configurable

Spoiler :
















 

Attachments

  • 1.JPG
    1.JPG
    28 KB · Views: 206
  • 2.JPG
    2.JPG
    33 KB · Views: 211
  • 3.JPG
    3.JPG
    42.4 KB · Views: 217
  • 4.JPG
    4.JPG
    48.4 KB · Views: 206
  • 5.JPG
    5.JPG
    65.7 KB · Views: 200
  • 6.JPG
    6.JPG
    71.1 KB · Views: 202
  • 7.JPG
    7.JPG
    69.8 KB · Views: 207
  • 8.JPG
    8.JPG
    47.2 KB · Views: 205
Last edited:
So ok now that the DLL can tell Python that a Yield is ignored in Storage System, let us contine from there. :)
First let us set up the message text in the XML for texts.

I will put my message text in: Civ4GameText_WTP_utf8.xml
(Could have put it in another file, but it seems to fit. Maybe the text should also be used in Mouse Over)


This is the actual text message I added:
(For now only English and German. Gave it a Bullet Icon and some colour as well.)

 

Attachments

  • Text_XMLs.JPG
    Text_XMLs.JPG
    190.6 KB · Views: 219
  • New_XML_TEXT_Message.JPG
    New_XML_TEXT_Message.JPG
    38.8 KB · Views: 216
Last edited:
So ok, we now have the text to display as well.
Let us do so in Python. :)
(In this case the Pedia Screen for Yields.)



 

Attachments

  • Python_for_Pedia_Screens.JPG
    Python_for_Pedia_Screens.JPG
    172 KB · Views: 212
  • Python_Code.JPG
    Python_Code.JPG
    45.7 KB · Views: 197
Last edited:
So ok, now we are done and can test it ingame (Colopedia).

Woohoo !!! :woohoo:
It is working. :thumbsup:

We did our first small tutorial together.:hug:
Congratulations, you are now a programmer and can program all the great features you want !!!:badcomp:

 

Attachments

  • Civ4ScreenShot0006.JPG
    Civ4ScreenShot0006.JPG
    191.7 KB · Views: 202
Last edited:
Great example :thumbsup:, now we can finally get rid of the hard-coding concerning those yields. It's neat that you also give an example on how to expose the method to Python because we need to remove a hard-coded check in CvMainInterface.py as well:

Code:
if (iStored > pCity.getMaxYieldCapacity() and i != int(YieldTypes.YIELD_FOOD) and i != int(YieldTypes.YIELD_LUMBER) and i != int(YieldTypes.YIELD_STONE)): # WTP, ray, fix for unnecessary red colour of more Stone or Lumber stored than total Storage

Maybe an aspiring modder feels like taking care of that ? :mischief:
 
Last edited:
So ok guys. :)
Our first tutorial is done.

Now you got a small overview of XML, DLL and Python.
This is what we modders do.

Have fun becoming a modder yourself. :thumbsup:
 
@devolution

In my original commit I had forgotten to commit these removals of Hardcoding for Stone, Lumber and Food from Screens CvDomesticAdvisor.py and CvMainInterface.py
(Simply working in too many workspaces and need to clean this up at some point.)

So here is the rest commited as well. :thumbsup:
(Just in case you want to merge that stuff to your personal development branch.)
 
Here's another suggestion for removal of hard-coding: Add a (Free)Route attribute (or similar) to BuildingInfo:

Spoiler CvCity::processBuilding :
[
Code:
//RWL Railroads and Trainstations
if (GC.getBuildingInfo(eBuilding).getSpecialBuildingType() == 26) // easiest way to identify Trainstation
{
//WTP fixing small bugs in City Founding an Roads
CvPlot* pPlot = plot();
if (pPlot->getRouteType() < 2)
{
pPlot->setRouteType((RouteTypes)2);
}
}
//RWL END Railroads and Trainstations
// R&R, ray, Plastered Road
if (GC.getBuildingInfo(eBuilding).getAICitySize() == 4) // easiest way to identify Townhall
{
//WTP fixing small bugs in City Founding an Roads
CvPlot* pPlot = plot();
if (pPlot->getRouteType() < 1)
{
pPlot->setRouteType((RouteTypes)1);
}
}
// R&R, ray, Plastered Road -END
/SPOILER]
 
But let us not put it in this thread for the "Tutorial". ;)

Please create a new thread for it. :thumbsup:
(e.g. "Removal of Hardcoding in Logic" or whatever you want to call it.)
 
Top Bottom