Duke176
Warlord
TITTLE SHOULD BE (pls change if possible) "HOW TO add unit Oil move cost, Oil Reserve counter and Oil produced each turn counter" - thx.
All right after my long studying and help recived I've reach a goal vs SDK and python difficoulties.
Here is a (for what I've understood) Tutorial about how I made it.
Let's start.
(to understand all the contents look at my project link in signature)
Files we are gonna change are:
XML:
Civ4UnitInfos.xml
Civ4UnitSchema.xml
GlobalDefines.xml
Civ4ImprovementInfos.xml
Civ4ImprovementSchema.xml
Python:
.../screens/CvMainInterface.py
SDK:
CvGameTextMgr.cpp
CvGameTextMgr.h
CvInfos.cpp
CvInfos.h
CvPlayer.cpp
CvPlayer.h
CvUnit.cpp
CvUnit.h
CyGameTextMgr.cpp
CyGameTextMgr.h
CyGameTextMgrInterface.cpp
CyInfoInterface1.cpp
CyInfoInterface2.cpp
CyPlayer.cpp
CyPlayer.h
CyPlayerInterface1.cpp
CyUnit.cpp
CyUnit.h
CyUnitInfoInterface.cpp
Bit long right?
You will see step by step won’t be so hard.
---------- PART I ------------
HOW TO ADD OIL CONSUMPTION FOR UNIT MOVEMENT
XML:
First we should start saying the Game how much unit will consume with their movements.
Civ4UnitInfos.xml
Each Unit have mainly the same Bold or Integer Infos so look for there lines and insert the new integer value you desire (I called it “iOilMoveCost”
Repeat it as many times you prefer, I mean for all the units you desire to have oil consumption.
Than we should tell the game what is this new tag it finds in XML files UnitInfos so get
Civ4UnitSchema.xml
Exactly in the same position (I don’t think it changes in another place but it’s to be sure)
Now the game knows it’s an integer value written with text symbols (so numbers of pad)
Now let’s start to interact with CPP to apply this modification.
SDK:
We start with CvInfos.cpp and CvInfos.h
In CvInfos.cpp look for “iMoves” – this way you will see how the programmers have implemented in this file the number of plot one unit can move.
Now let’s add our code and set our “iOilMoveCost” = 0 to defoult.
Look further and tell the game what will be the function that will recall the number taken from XML tag and stored here in the 1st part of this file code
As you see we tell the game that the function of the group “CvUnitInfo” – “getOilMoveCost()” will return the value of “m_iOilMoveCost”.
Now go on and look for streams data savers (dunno if in English is correct – but I’m not a programmer so sorry).
WHERE IS READ
WHERE IS WRITE
Now the most important part for this. Explain the game where he can find the tag we need to full the empty m_iOilMoveCost(0) with the value stored there and explain always the game how did you called that tag.
You see? GetChild-XML-Value-assigned to the tag that have name-(“iOilMoveCost”, we used in XML, and is related with m_iOilMoveCost, we decleared before in this file). I hope you understood ask me if not.
Pass to CvInfo.h
Dunno exacly the meaning of what we write here but remeber always that X.ccp is always realted with X.h (if both exists), so if you add something in X.cpp you will have to change also X.h most of the times.
Again look for “iMoves” you will find and add this – here we are saying to the game which functions are stored and used in X.CPP and which kind of functions are INT/BOOL/VOID:
Go on
So now the game knows what are the parts we added inside CvUnit.cpp.
now we will modify CvUnit.cpp and will tell the game how to use those finctions and members we decleared before in game.
Look for “int CvUnit::Move...” and add before:
All right core of our mod.
We want the game knows where to go to get the values token from XML assigning a value to iMoveOilCost each time we move a Unit.
Explain:
Int CvUnit:
ilMoveCost() cost
We create this function that we call “oilMoveCost()” in group of functions called “CvUnit” and we tell the game it will return a number “int”.
return GC.getUnitInfo(getUnitType()).getOilMoveCost();
All right “return” needed in INT functions – here we say to the game which will the number at the end of the function, return it’s always at the last row of the int functions.
Than we use structural functions of the game.
“GC.get” – go and get the function we need in another group of functions (so when we will compile the .cpp and .h files the game will look for that group in the big .dll file)
“.getUnitInfo” – the name of group of functions the game should look for
“(getUnitType())” – another game already existing function; here it becomes an argument of the GC.get... function and return the unit type that is selecet
“.getOilMoveCost();” – we tell the game which function should get from the group we directed it to. Now you see? “getOilMoveCost” is the one we created to recall the value m_iOilMoveCost in CvInfos.cpp.
Now the game knows which value is “iOilMoveCost” now we should use it.
We will sneak into CvUnit::Move(...) function the one ofter our “oilMoveCost()” and will insert a little part of code.
What we added?
“GET_PLAYER” – we say the game get Players who are playing this match (all AI too)
“(getOwnerINLINE())” – get the owner of that unit (“setXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true, (bShow && pPlot->isVisibleToWatchingHuman()));” i think is here where in MOVE function the game get the unit the player choosed but I could be wrong”
“.changeOilReserve(-(oilMoveCost()));” – here we complite and tell the game to get from the CvPlayer group of functions (with GET_PLAYER I think we recall all those functions) the function called “changeOilReserver(....)” and to subtract “(-(......))));” the value we get with our function (the one we creted before this one) “oilMoveCost()”.
ChangeOilReserve( int iChange) will be the function we will use to modify OIL RESERVE counter. You could change it with “ChangeGold” it does the same thing with gold. So oyu can check if your mod works by looking at Gold subtraction each move of unit.
Last part now.
We should also remember the game to check if the Reserve of OIL we have are enough to make the unit moving. So we will look further in this file and will look for
“bool CvUnit::canMove() const” and we will add this:
Here before the game checks if the unit has units left we should see if there’s enough OIL to move it. It’s a bool function because it returns YES or NO not a number.
So again:
“if (GET_PLAYER(getOwnerINLINE())” – again here we get the owner of unit, the functions of CvPlayer
“.getOilReserve() < oilMoveCost())” – now in spite of “ChangeOilReserve” we use “getOilReserve()” we will create if later and will return the Oil Reserves we have (you can change it with “getGold()” to see if it’s working) and look if your RESERVES are < (lower) than “oilMoveCost()” – the function we created and returns the value taken from XML.
Now one more step.
Pass to CvUnit.h
Now we decleare the functions we created in corrispondent CvUnit.cpp.
As before we decleare it near “CanMove”...
Now we pass to CyUnit.cpp
Dunno exactly what to do here but look for “Move” again and add:
Now we move to CyUnit.h
We decleare also here our new function.
Last move to CyUnitInterface1.cpp
Here we define what we made before, so we define our new function.
As done before we say to the game that our new funtion is an Integer.
Easy no?
Not truly.
Here it stops 1st part. Hope you understood, I’m not a programmer so I try to make ppl understand with not techincal speaking.
Sorry for mistakes and faces appearing.
Soon part TWO: HOW TO ADD OIL RESERVER COUNTER.
All right after my long studying and help recived I've reach a goal vs SDK and python difficoulties.
Here is a (for what I've understood) Tutorial about how I made it.
Let's start.
(to understand all the contents look at my project link in signature)
Files we are gonna change are:
XML:
Civ4UnitInfos.xml
Civ4UnitSchema.xml
GlobalDefines.xml
Civ4ImprovementInfos.xml
Civ4ImprovementSchema.xml
Python:
.../screens/CvMainInterface.py
SDK:
CvGameTextMgr.cpp
CvGameTextMgr.h
CvInfos.cpp
CvInfos.h
CvPlayer.cpp
CvPlayer.h
CvUnit.cpp
CvUnit.h
CyGameTextMgr.cpp
CyGameTextMgr.h
CyGameTextMgrInterface.cpp
CyInfoInterface1.cpp
CyInfoInterface2.cpp
CyPlayer.cpp
CyPlayer.h
CyPlayerInterface1.cpp
CyUnit.cpp
CyUnit.h
CyUnitInfoInterface.cpp
Bit long right?
You will see step by step won’t be so hard.
---------- PART I ------------
HOW TO ADD OIL CONSUMPTION FOR UNIT MOVEMENT
XML:
First we should start saying the Game how much unit will consume with their movements.
Civ4UnitInfos.xml
Each Unit have mainly the same Bold or Integer Infos so look for there lines and insert the new integer value you desire (I called it “iOilMoveCost”

Code:
<iMinAreaSize>-1</iMinAreaSize>
<iMoves>2</iMoves>
<!-- MIO OIL COST -->
<iOilMoveCost>1</iOilMoveCost>
<!-- end -->
<iAirRange>0</iAirRange>
<iNukeRange>-1</iNukeRange>
Than we should tell the game what is this new tag it finds in XML files UnitInfos so get
Civ4UnitSchema.xml
Exactly in the same position (I don’t think it changes in another place but it’s to be sure)
Code:
<ElementType name="iMinAreaSize" content="textOnly" dt:type="int"/>
<ElementType name="iMoves" content="textOnly" dt:type="int"/>
<!-- COSTO PER MOVE MOD -->
<ElementType name="iOilMoveCost" content="textOnly" dt:type="int"/>
<!-- end -->
<ElementType name="iAirRange" content="textOnly" dt:type="int"/>
<ElementType name="iNukeRange" content="textOnly" dt:type="int"/>
Now let’s start to interact with CPP to apply this modification.
SDK:
We start with CvInfos.cpp and CvInfos.h
In CvInfos.cpp look for “iMoves” – this way you will see how the programmers have implemented in this file the number of plot one unit can move.
Now let’s add our code and set our “iOilMoveCost” = 0 to defoult.
Code:
//======================================================================================================
// CvUnitInfo
//======================================================================================================
//------------------------------------------------------------------------------------------------------
//
// FUNCTION: CvUnitInfo()
//
// PURPOSE : Default constructor
//
//------------------------------------------------------------------------------------------------------
CvUnitInfo::CvUnitInfo() :
m_iAIWeight(0),
m_iProductionCost(0),
m_iHurryCostModifier(0),
m_iMinAreaSize(0),
m_iMoves(0),
//----------------------- MIO OIL COST ------------------
m_iOilMoveCost(0),
//-------------------------- end -------------------------------
m_iAirRange(0),
m_iNukeRange(0),
Look further and tell the game what will be the function that will recall the number taken from XML tag and stored here in the 1st part of this file code
Code:
int CvUnitInfo::getMoves() const
{
return m_iMoves;
}
//------------------------- MIO OIL COST ------------------------
int CvUnitInfo::getOilMoveCost() const
{
return m_iOilMoveCost;
}
//--------------------------- end --------------------------------------
int CvUnitInfo::getAirRange() const
{
return m_iAirRange;
}
Now go on and look for streams data savers (dunno if in English is correct – but I’m not a programmer so sorry).
WHERE IS READ
Code:
stream->Read(&m_iMinAreaSize);
stream->Read(&m_iMoves);
//--------------- MIO OIL COST -------------------------
stream->Read(&m_iOilMoveCost);
//--------------------- end ---------------------------------
stream->Read(&m_iAirRange);
stream->Read(&m_iNukeRange);
WHERE IS WRITE
Code:
stream->Write(m_iMinAreaSize);
stream->Write(m_iMoves);
//--------------------- MIO OIL COST -------------------------
stream->Write(m_iOilMoveCost);
//------------------------------ end -------------------------------
stream->Write(m_iAirRange);
stream->Write(m_iNukeRange);
Now the most important part for this. Explain the game where he can find the tag we need to full the empty m_iOilMoveCost(0) with the value stored there and explain always the game how did you called that tag.
Code:
pXML->GetChildXmlValByName(&m_iMinAreaSize, "iMinAreaSize");
pXML->GetChildXmlValByName(&m_iMoves, "iMoves");
//------------------------- MIO OIL COST -----------------------------------
pXML->GetChildXmlValByName(&m_iOilMoveCost, "iOilMoveCost");
//------------------------------------- end ---------------------------------------
pXML->GetChildXmlValByName(&m_iAirRange, "iAirRange");
pXML->GetChildXmlValByName(&m_iNukeRange, "iNukeRange");
Pass to CvInfo.h
Dunno exacly the meaning of what we write here but remeber always that X.ccp is always realted with X.h (if both exists), so if you add something in X.cpp you will have to change also X.h most of the times.
Again look for “iMoves” you will find and add this – here we are saying to the game which functions are stored and used in X.CPP and which kind of functions are INT/BOOL/VOID:
Code:
DllExport int getMinAreaSize() const; // Exposed to Python
DllExport int getMoves() const; // Exposed to Python
//---------------- MIO OIL COST -------------------------
DllExport int getOilMoveCost() const; // Exposed to Python
//--------------------- end -------------------------------------
DllExport int getAirRange() const; // Exposed to Python
DllExport int getNukeRange() const; // Exposed to Python
Go on
Code:
int m_iMinAreaSize;
int m_iMoves;
//--------------- MIO OIL COST --------------------
int m_iOilMoveCost;
//-------------------- end ------------------------------
int m_iAirRange;
int m_iNukeRange;
So now the game knows what are the parts we added inside CvUnit.cpp.
now we will modify CvUnit.cpp and will tell the game how to use those finctions and members we decleared before in game.
Look for “int CvUnit::Move...” and add before:
Code:
void CvUnit::attack(CvPlot* pPlot, bool bQuick)
{
FAssert(canMoveInto(pPlot, true));
FAssert(getCombatTimer() == 0);
setAttackPlot(pPlot);
updateCombat(bQuick);
}
//---------------------------------- MIO OIL COST ------------------------------------ I get this here to decleare the function that recalls the row after
int CvUnit::oilMoveCost() const
{
return GC.getUnitInfo(getUnitType()).getOilMoveCost();
}
//------------------------------------------- end -----------------------------
void CvUnit::move(CvPlot* pPlot, bool bShow)
{
FeatureTypes eFeature;
EffectTypes eEffect;
All right core of our mod.
We want the game knows where to go to get the values token from XML assigning a value to iMoveOilCost each time we move a Unit.
Explain:
Int CvUnit:

We create this function that we call “oilMoveCost()” in group of functions called “CvUnit” and we tell the game it will return a number “int”.
return GC.getUnitInfo(getUnitType()).getOilMoveCost();
All right “return” needed in INT functions – here we say to the game which will the number at the end of the function, return it’s always at the last row of the int functions.
Than we use structural functions of the game.
“GC.get” – go and get the function we need in another group of functions (so when we will compile the .cpp and .h files the game will look for that group in the big .dll file)
“.getUnitInfo” – the name of group of functions the game should look for
“(getUnitType())” – another game already existing function; here it becomes an argument of the GC.get... function and return the unit type that is selecet
“.getOilMoveCost();” – we tell the game which function should get from the group we directed it to. Now you see? “getOilMoveCost” is the one we created to recall the value m_iOilMoveCost in CvInfos.cpp.
Now the game knows which value is “iOilMoveCost” now we should use it.
We will sneak into CvUnit::Move(...) function the one ofter our “oilMoveCost()” and will insert a little part of code.
Code:
void CvUnit::move(CvPlot* pPlot, bool bShow)
{
FeatureTypes eFeature;
EffectTypes eEffect;
FAssert(canMoveOrAttackInto(pPlot) || isMadeAttack());
changeMoves(pPlot->movementCost(this, plot()));
setXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true, (bShow && pPlot->isVisibleToWatchingHuman()));
if (getOwnerINLINE() == GC.getGameINLINE().getActivePlayer())
{
if (!(pPlot->isOwned()))
{
//spawn birds if trees present - JW
eFeature = pPlot->getFeatureType();
if (eFeature != NO_FEATURE)
{
if (GC.getASyncRand().get(100) < GC.getFeatureInfo(eFeature).getEffectProbability())
{
eEffect = (EffectTypes)GC.getInfoTypeForString(GC.getFeatureInfo(eFeature).getEffectType());
gDLL->getEngineIFace()->TriggerEffect(eEffect, pPlot->getPoint(), (float)(GC.getASyncRand().get(360)));
gDLL->getInterfaceIFace()->playGeneralSound("AS3D_UN_BIRDS_SCATTER", pPlot->getPoint());
}
}
}
}
gDLL->getEventReporterIFace()->unitMove(pPlot, this);
//------------------------------- MIO OIL COST ------------------------------
GET_PLAYER(getOwnerINLINE()).changeOilReserve(-(oilMoveCost()));
//------------------------------------- end ----------------------------------------
}
What we added?
“GET_PLAYER” – we say the game get Players who are playing this match (all AI too)
“(getOwnerINLINE())” – get the owner of that unit (“setXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true, (bShow && pPlot->isVisibleToWatchingHuman()));” i think is here where in MOVE function the game get the unit the player choosed but I could be wrong”

“.changeOilReserve(-(oilMoveCost()));” – here we complite and tell the game to get from the CvPlayer group of functions (with GET_PLAYER I think we recall all those functions) the function called “changeOilReserver(....)” and to subtract “(-(......))));” the value we get with our function (the one we creted before this one) “oilMoveCost()”.
ChangeOilReserve( int iChange) will be the function we will use to modify OIL RESERVE counter. You could change it with “ChangeGold” it does the same thing with gold. So oyu can check if your mod works by looking at Gold subtraction each move of unit.
Last part now.
We should also remember the game to check if the Reserve of OIL we have are enough to make the unit moving. So we will look further in this file and will look for
“bool CvUnit::canMove() const” and we will add this:
Code:
int CvUnit::movesLeft() const
{
return max(0, (maxMoves() - getMoves()));
}
bool CvUnit::canMove() const
{
//----------------------------- MIO OIL COST --------------------------------- look if the cost of movement in oil ammount is higher than total ammount of OIL
if (GET_PLAYER(getOwnerINLINE()).getOilReserve() < oilMoveCost())
{
return false;
}
//------------------------------------------------- end ------------------------------
return (getMoves() < maxMoves());
}
bool CvUnit::hasMoved() const
{
return (getMoves() > 0);
}
Here before the game checks if the unit has units left we should see if there’s enough OIL to move it. It’s a bool function because it returns YES or NO not a number.
So again:
“if (GET_PLAYER(getOwnerINLINE())” – again here we get the owner of unit, the functions of CvPlayer
“.getOilReserve() < oilMoveCost())” – now in spite of “ChangeOilReserve” we use “getOilReserve()” we will create if later and will return the Oil Reserves we have (you can change it with “getGold()” to see if it’s working) and look if your RESERVES are < (lower) than “oilMoveCost()” – the function we created and returns the value taken from XML.
Now one more step.
Pass to CvUnit.h
Now we decleare the functions we created in corrispondent CvUnit.cpp.
As before we decleare it near “CanMove”...
Code:
DllExport int movesLeft() const; // Exposed to Python
DllExport bool canMove() const; // Exposed to Python
DllExport bool hasMoved() const; // Exposed to Python
//----------------------------------- MIO OIL COST -----------------------------------
DllExport int oilMoveCost() const;
// Exposed to Python
//--------------------------------------end-------------------------------------------------
DllExport int airRange() const; // Exposed to Python
DllExport int nukeRange() const;
Now we pass to CyUnit.cpp
Dunno exactly what to do here but look for “Move” again and add:
Code:
bool CyUnit::hasMoved()
{
return m_pUnit ? m_pUnit->hasMoved() : false;
}
//---------------------------------- MIO OIL COST ---------------------------------
int CyUnit::oilMoveCost()
{
return m_pUnit ? m_pUnit->oilMoveCost() : -1;
}
//------------------------------------- end ----------------------------------------------
int CyUnit::airRange()
{
return m_pUnit ? m_pUnit->airRange() : -1;
}
Now we move to CyUnit.h
We decleare also here our new function.
Code:
bool canMove();
bool hasMoved();
//------------------------------ MIO OIL COST -----------------------
int oilMoveCost();
//------------------------------------- end -------------------------------
int airRange();
int nukeRange();
Last move to CyUnitInterface1.cpp
Here we define what we made before, so we define our new function.
Code:
.def("canMove", &CyUnit::canMove, "bool ()")
.def("hasMoved", &CyUnit::hasMoved, "bool ()")
//------------------------------------- MIO OIL COST --------------------------------------------------
.def("oilMoveCost", &CyUnit::oilMoveCost, "int ()")
//--------------------------------------------- end ----------------------------------------------------------
.def("airRange", &CyUnit::airRange, "int ()")
.def("nukeRange", &CyUnit::nukeRange, "int ()")
As done before we say to the game that our new funtion is an Integer.
Easy no?
Not truly.
Here it stops 1st part. Hope you understood, I’m not a programmer so I try to make ppl understand with not techincal speaking.
Sorry for mistakes and faces appearing.
Soon part TWO: HOW TO ADD OIL RESERVER COUNTER.