View Full Version : Sample SDK Code (basic)


Kael
Apr 13, 2006, 09:35 AM
This thread is to post simple working SDK changes to help begining programmers get an idea of how they can use the SDK without having to get into deep in depth programming.

Please don't use this thread to ask questions on things that aren't working or post non-working code. Start new threads in the creation and customization forum for that.

1. So that the promotion prereq’s are AND reqs instead of OR reqs

CvUnit.cpp CvUnit::canAcquirePromotion:

Original:

if (GC.getPromotionInfo(ePromotion).getPrereqOrPromot ion1() != NO_PROMOTION)
{
if (!isHasPromotion((PromotionTypes)(GC.getPromotionI nfo(ePromotion).getPrereqOrPromotion1())))
{
if ((GC.getPromotionInfo(ePromotion).getPrereqOrPromo tion2() == NO_PROMOTION) || !isHasPromotion((PromotionTypes)(GC.getPromotionIn fo(ePromotion).getPrereqOrPromotion2())))
{
return false;
}
}
}

Changed to:

if (GC.getPromotionInfo(ePromotion).getPrereqOrPromot ion1() != NO_PROMOTION)
{
if (!isHasPromotion((PromotionTypes)(GC.getPromotionI nfo(ePromotion).getPrereqOrPromotion1())))
{
return false;
}
}

if (GC.getPromotionInfo(ePromotion).getPrereqOrPromot ion2() != NO_PROMOTION)
{
if (!isHasPromotion((PromotionTypes)(GC.getPromotionI nfo(ePromotion).getPrereqOrPromotion2())))
{
return false;
}
}


2. So that player owned animals act like normal units

CvUnit.cpp CvUnit::canMoveInto():

Origional:

if (isAnimal())
{
if (pPlot->isOwned())
{
return false;
}

Changed to:

if (isAnimal() && isBarbarian())
{
if (pPlot->isOwned())
{
return false;
}


3. So that animals don’t disappear when barbarians appear

CvGame.cpp CvGame::createBarbarianUnits():

Commented out the following lines:

// CvUnit* pLoopUnit;

// for (pLoopUnit = GET_PLAYER(BARBARIAN_PLAYER).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(BARBARIAN_PLAYER).nextUnit(&iLoop))
// {
// if (pLoopUnit->isAnimal())
// {
// pLoopUnit->kill(false);
// break;
// }
// }

4. So that civs with the Scorched Earth trait auto-raze cities

CvPlayer.cpp CvPlayer::acquireCity()

Original:

if (bConquest)
{
if (((pOldCity->getHighestPopulation() == 1) && !(GC.getGameINLINE().isOption(GAMEOPTION_NO_CITY_R AZING))) ||
((GC.getGameINLINE().getMaxCityElimination() > 0) && !(GC.getGameINLINE().isOption(GAMEOPTION_NO_CITY_R AZING))) ||
(GC.getGameINLINE().isOption(GAMEOPTION_ONE_CITY_C HALLENGE) && isHuman()))
{

Changed to:

if (bConquest)
{
if (((pOldCity->getHighestPopulation() == 1) && !(GC.getGameINLINE().isOption(GAMEOPTION_NO_CITY_R AZING))) ||
((GC.getGameINLINE().getMaxCityElimination() > 0) && !(GC.getGameINLINE().isOption(GAMEOPTION_NO_CITY_R AZING))) ||
(GC.getGameINLINE().isOption(GAMEOPTION_ONE_CITY_C HALLENGE) && isHuman()) ||
(hasTrait((TraitTypes)GC.getInfoTypeForString("TRAIT_SCORCHED_EARTH"))))
{


5. So that civs with the Agnostic trait can’t adopt a state religion

CvPlayer.cpp CvPlayer::canConvert()

Added:

if (hasTrait((TraitTypes)GC.getInfoTypeForString("TRAIT_AGNOSTIC")))
{
return false;
}

Thasis
Apr 13, 2006, 12:07 PM
This is cool man. Getting me started on the SDK which is going to be rad.

HP_Ganesha
Apr 13, 2006, 01:18 PM
hun... what language SDK use??? (I not downloading yet..) this codes remember Java...

Kael
Apr 13, 2006, 01:49 PM
hun... what language SDK use??? (I not downloading yet..) this codes remember Java...

It uses C++

IrishDragon
Apr 13, 2006, 03:35 PM
cant wait to see what can be done in a few weeks

AndyTerry
Apr 14, 2006, 06:36 AM
Well, and what should we do to make it work?

Kael
Apr 14, 2006, 06:39 AM
Well, and what should we do to make it work?

Check here if you would like help getting the SDK to the point where you can compile your own CvCoreGameDLL.dll: http://forums.civfanatics.com/showthread.php?t=166933

Thorn
Apr 14, 2006, 11:32 AM
Thanks! I'm trying a compile right now. Is there any documentation or references for this stuff? I know most of the variables are fairly easy to follow but it would be nice to have a reference doc describing what is done in each file. Otherwise I guess it'll be a lot of trial and error.
Now if there was an EASY way (and free!) to change the graphics and animations...

Kael
Apr 14, 2006, 11:34 AM
Thanks! I'm trying a compile right now. Is there any documentation or references for this stuff? I know most of the variables are fairly easy to follow but it would be nice to have a reference doc describing what is done in each file. Otherwise I guess it'll be a lot of trial and error.

Yeah, I would love to see someone as detailed as Locotus go through an detail the files and the functions with their purposes.

Now if there was an EASY way (and free!) to change the graphics and animations...

No doubt.

Thorn
Apr 14, 2006, 11:40 AM
It compiled fine and I replaced CvGameCoreDLL.dll with the one I made. I started the game and everything seemed to work great!
I did notice that my CvGameCoreDLL was about 1.5M larger than the original one. Is that normal?
Now, what to do next. :p

talchas
Apr 14, 2006, 12:05 PM
My dlls are generally around 4800 kb.

Dianthus
Apr 14, 2006, 12:15 PM
@Thorn/talchas, are you using codeblocks, or VS2003? I'm using VS2003 and my dll is compiling to 3752Kb. That's slightly larger than standard, but my dll's got lots of extra stuff in it ;). If I turn off VS2003's linker optimization it comes out at 4956Kb.

talchas
Apr 14, 2006, 12:24 PM
I'm using codeblocks. My compiler switches that could make a difference seem to be /O2 /GR /EHsc and for the linker switches, /debug /INCREMENTAL:NO

The compiler is just the 2003 compiler, so the difference should only be due to different switches.

Thorn
Apr 14, 2006, 01:04 PM
I'm also using codeblocks. I suppose it is the compiler options that make the difference. My test build was 4.66 megs.

Aussie_Lurker
Apr 14, 2006, 08:51 PM
I should start by saying that I am NO programmer, just someone who fiddles around the edges-as it were-so forgive my ignorance. Kael, you said the Code is written in C++ (and I do believe you), but then why does it read so much like Python?

Dumb question, but one I need to ask!

Aussie_Lurker.

Grey Fox
Apr 14, 2006, 09:32 PM
I should start by saying that I am NO programmer, just someone who fiddles around the edges-as it were-so forgive my ignorance. Kael, you said the Code is written in C++ (and I do believe you), but then why does it read so much like Python?

Dumb question, but one I need to ask!

Aussie_Lurker.


Modern programming languages often Copy syntax from C/C++. *I think* that C or C++ was the first object-oriented language aswell, which another reason its copied. The first being its probably one of the most popular programming languages.

PeteT
Apr 14, 2006, 10:16 PM
It's not really the syntax, it's more the way Boost Python has been used to expose the underlying C++ functions.

For example, there is a C++ method declared in CvPlayer.h:


DllExport bool isHuman(); // Exposed to Python


This is 'wrapped ' in CyPlayer, the Python wrapper class for CvPlayer:


bool CyPlayer::isHuman()
{
return m_pPlayer ? m_pPlayer->isHuman() : false;
}


(IIRC, this 'wrapping' is an error protection technique.) Next, this method is exposed to Python in CyPlayerInterface1.cpp:


void CyPlayerPythonInterface1(python::class_<CyPlayer>& x)
{
...
.def("isHuman", &CyPlayer::isHuman, "bool ()")


Now when you call "isHuman" in a Python script it goes through this &CyPlayer::isHuman to ultimately call CvPlayer::isHuman().

That's how so much of the stuff that you see in Python is actually defined in CvGameCoreDLL.

LDiCesare
Apr 15, 2006, 02:42 AM
Modern programming languages often Copy syntax from C/C++. *I think* that C or C++ was the first object-oriented language aswell, which another reason its copied. The first being its probably one of the most popular programming languages.
No. C is not object oriented at all (well, you have structs, so you can program OO if you like to), but it is immensely popular.
C++ is not the first OO language either (that'd be Smalltalk) but it is(was) totally compatible with C, thus became very popular. ObjectiveC was a C dialect that was OO too but it didn't get as popular as C++. Looking at C code, C++ and Obejctive C, C++ looks like C the most, thus I think it won because of its greater familiarity and compatibility with C.
Apart from that, indeed, the functions are mostly the same between C++ and python apis, thus they look somewhat similar. But count the lines to do the same stuff in C++ and in python, and you will see the difference...

Grey Fox
Apr 15, 2006, 09:41 AM
No. C is not object oriented at all (well, you have structs, so you can program OO if you like to), but it is immensely popular.
C++ is not the first OO language either (that'd be Smalltalk) but it is(was) totally compatible with C, thus became very popular. ObjectiveC was a C dialect that was OO too but it didn't get as popular as C++. Looking at C code, C++ and Obejctive C, C++ looks like C the most, thus I think it won because of its greater familiarity and compatibility with C.
Apart from that, indeed, the functions are mostly the same between C++ and python apis, thus they look somewhat similar. But count the lines to do the same stuff in C++ and in python, and you will see the difference...

Kinda knew C wasnt OO. And thanks for correcting my *I think* part. Wasnt sure about that. :goodjob:

Kael
Apr 15, 2006, 01:49 PM
Just a simple example of a change that can be made in CvUnit::maxCombatStr(). This applies a combat modifier based on the existence of the "Elf" promotion on the defender and the "Elf Slaying" promotion on the attacker. maxCombatStr is called from the perspective of the defender and I have the 2 checks in so that the bonus is applied on attack and defense.

Changes are in bold.

CvUnit::maxCombatStr()

if (getUnitCombatType() != NO_UNITCOMBAT)
{
iModifier -= pAttacker->unitCombatModifier(getUnitCombatType());
if (pCombatDetails != NULL)
{
pCombatDetails->iCombatModifierT = -(pAttacker->unitCombatModifier(getUnitCombatType()));
}
}

if (isHasPromotion((PromotionTypes)GC.getInfoTypeForS tring("PROMOTION_ELF")))
{
if (pAttacker->isHasPromotion((PromotionTypes)GC.getInfoTypeForSt ring("PROMOTION_ELF_SLAYING")))
{
iModifier = iModifier - 40;
}
}
if (isHasPromotion((PromotionTypes)GC.getInfoTypeForS tring("PROMOTION_ELF_SLAYING")))
{
if (pAttacker->isHasPromotion((PromotionTypes)GC.getInfoTypeForSt ring("PROMOTION_ELF")))
{
iModifier = iModifier + 40;
}
}

iModifier += domainModifier(pAttacker->getDomainType());
if (pCombatDetails != NULL)
{
pCombatDetails->iDomainModifierA = domainModifier(pAttacker->getDomainType());
}

Why use this? It provides the ability to specify anti-unit combat bonuses without having to make new unit combats or declare specific unitclasses. Also since its easy to add and remove promotions as you play it can allow you to create pretty dynamic bonuses.

Outside of that just being familiar with the effect of changing maxCombatStr can be very helpful to anyone who wants to effect the combat odds. Changes made here are reflect both in the actual combat odds as well as the display.

Grey Fox
Apr 15, 2006, 09:30 PM
Uhm, I dont understand really what you did there. Why not just add the +40% or whatever to the promotion rather then in the battle code? Im confused.

Kael
Apr 16, 2006, 04:51 AM
Uhm, I dont understand really what you did there. Why not just add the +40% or whatever to the promotion rather then in the battle code? Im confused.

If you added +40% to the promotion it would be +40% vs everything. Applying the modifier in this function lets a modmaker be more granular about when the bonus is gained. Want a unit to have a bonus when it is attacking into forests or when the defending unit is French/fatigued/republican/hindu/etc etc? Then you may want to modify the maxCombatStr code.

Grey Fox
Apr 16, 2006, 09:54 AM
If you added +40% to the promotion it would be +40% vs everything. Applying the modifier in this function lets a modmaker be more granular about when the bonus is gained. Want a unit to have a bonus when it is attacking into forests or when the defending unit is French/fatigued/republican/hindu/etc etc? Then you may want to modify the maxCombatStr code.

Ok, im getting what you are saying now.

But cant you just make some units be classed Elf. And then the promotion give +40% vs Elf like the ones in the game does vs melee etc. Or do you want your elfs to still be melee and also elf? Isnt it easier to make a super class then that you give all units that defines their race? And a promotion can be against Unit Superclass, class and type (like the Grenadiers +vs Riflemen.).

Or am I still confused?

Kael
Apr 16, 2006, 10:28 AM
Ok, im getting what you are saying now.

But cant you just make some units be classed Elf. And then the promotion give +40% vs Elf like the ones in the game does vs melee etc. Or do you want your elfs to still be melee and also elf? Isnt it easier to make a super class then that you give all units that defines their race? And a promotion can be against Unit Superclass, class and type (like the Grenadiers +vs Riflemen.).

Or am I still confused?

Nope, you are absolutly correct. In fact thats exactly how I did it in phase 1. But in phase 2 of my mod I wanted the units to be archers and elves, or melee and elves or whatever. Also the system is a lot more flexible than the unitcombat system is since promotions can be added and removed on the fly.

Lord Olleus
Apr 17, 2006, 03:45 PM
But why do this in C++ Kael?
Why not just create an event which is called at the same time as combat and do that in python? It would be a much neater way of doing it.

Dianthus
Apr 17, 2006, 04:29 PM
But why do this in C++ Kael?

One reason I can think of is it makes a good example for how to use the SDK in the absence of documentation from Firaxis. Good work Kael :goodjob:.

Kael
Apr 17, 2006, 04:30 PM
But why do this in C++ Kael?
Why not just create an event which is called at the same time as combat and do that in python? It would be a much neater way of doing it.

There is a time to use python and a time to use C++. You may be right, this may be a better time for a python routine. In all honesty I did it this way because it was very easy. I haven't added any python events called from the SDK yet. There are a few I would love to see but I don't know how to do them yet.

Most notably I would love to see a pre-combat python event, a cannotAttack python event and plot.doTurn() python event. Though that last one may be expensive.

I dont think I have ever seen a python event that passes data back to c++ as we would need to do if you wanted a python event that allow you to modify the odds.

snarko
Apr 17, 2006, 04:43 PM
I dont think I have ever seen a python event that passes data back to c++ as we would need to do if you wanted a python event that allow you to modify the odds.
What about CvGameUtils.py? Those functions return values to the c++ part don't they?

edit: from canTrain in CvCity.cpp
long lResult=0;
gDLL->getPythonIFace()->callFunction(PYGameModule, "canTrain", argsList.makeFunctionArgs(), &lResult);
delete pyCity; // python fxn must not hold on to this pointer
if (lResult == 1)
{
return true;
}

Kael
Apr 17, 2006, 04:59 PM
What about CvGameUtils.py? Those functions return values to the c++ part don't they?

edit: from canTrain in CvCity.cpp
long lResult=0;
gDLL->getPythonIFace()->callFunction(PYGameModule, "canTrain", argsList.makeFunctionArgs(), &lResult);
delete pyCity; // python fxn must not hold on to this pointer
if (lResult == 1)
{
return true;
}


Your absolutly right, good call!

Vehem
Apr 22, 2006, 09:41 AM
...Want a unit to have a bonus when it is attacking into forests ...

This is the similar to the bonus I'm trying to implement - "Attackers with Woodsman2 (soon to be Woodsman3) gain a bonus when attacking into Forests equal to the current iDefense of the Forest feature. Also, the Defender does not receive the bonus."

The only part of this I've managed to get working is that I can reverse the terrain bonuses indiscriminantly, though the way I've done that seems messy from a coding point of view.

The problems I have are
identifying forests specifically (as they're Enumerated into FeatureTypes after loading the XML - the best I've got so far is along the lines of [ GC.getFeatureInfo(pPlot->getFeatureType()).getTextKey() == "FEATURE_FOREST" ]
Displaying a "[UNIT1] has been ambushed by [UNIT2]" message - struggling with the syntax for "gDLL->getInterfaceIFace()->addMessage"


If you were planning on adding any further functional example code to this thread - I'd request the above :D

Kael
Apr 22, 2006, 09:58 AM
This thread is only for samples of completed working code. Please start new threads for asking questions. That said I added a few recomendations.

This is the similar to the bonus I'm trying to implement - "Attackers with Woodsman2 (soon to be Woodsman3) gain a bonus when attacking into Forests equal to the current iDefense of the Forest feature. Also, the Defender does not receive the bonus."

The only part of this I've managed to get working is that I can reverse the terrain bonuses indiscriminantly, though the way I've done that seems messy from a coding point of view.

The problems I have are
identifying forests specifically (as they're Enumerated into FeatureTypes after loading the XML - the best I've got so far is along the lines of [ GC.getFeatureInfo(pPlot->getFeatureType()).getTextKey() == "FEATURE_FOREST" ]

You can search for enumerated data types by adding the (TYPE) to the getinfotype as in the following:

if (pPlot->getFeatureType() == (FeatureTypes)GC.getInfoTypeForString("FEATURE_FOREST"))

Sorry I havent messed with displaying text yet so I dont know about the 2nd question.

NP300
Apr 23, 2006, 07:11 PM
Any idea where is the code that controls whether invisible units are visible or not?

I'm trying to make the sighting of submarines more random:

http://forums.civfanatics.com/showthread.php?t=164133

Kael
May 02, 2006, 04:52 PM
Adding a python cannotAttack check

This was actually pretty easy, I assumed it would be harder. In the CvUnit.cpp I added the following section to make the call:

void CvUnit::updateCombat(bool bQuick)


//FfH: Added by Kael 05/02/2006

CyUnit* pyUnit = new CyUnit(this);
CyUnit* pyUnit2 = new CyUnit(pDefender);
CyArgsList argsList; // XXX
long lResult=0;
argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit)); // pass in unit class
argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit2)); // pass in unit class
gDLL->getPythonIFace()->callFunction(PYGameModule, "cannotAttack", argsList.makeFunctionArgs(), &lResult);
delete pyUnit; // python fxn must not hold on to this pointer
delete pyUnit2; // python fxn must not hold on to this pointer
if (lResult == 1)
{
bFinish = true;
}

//FfH: End Add


This passes the Attacker (CvUnit which is "this" in the function) and the Defender (pDefender) to the cannotAttack python function. And if the python fucntion returns a 1 (true) then it cancels combat.

To create the python function add the following function to the CvGameInterface.py file:


def cannotAttack(argsList):
pAttacker = argsList[0]
pDefender = argsList[1]

if pAttacker.isHasPromotion(gc.getInfoTypeForString(' PROMOTION_CHARMED')):
return True

if pDefender.isHasPromotion(gc.getInfoTypeForString(' PROMOTION_FEAR')):
if pDefender.maxCombatStr(pDefender.plot(), pAttacker) > pAttacker.maxCombatStr(pDefender.plot(), pDefender):
return True

return False


And thats it. You can see that I check for a few things in the python routine. If the defender has the fear promotion and has higher strength than the attacker a false is returned (the attacker is unable to attack). Also if the attacker is charmed he is unable to attack.

I hope you guys find it handy. It allows you do make significant changes with very minor changes with the SDK and keeping your more complex programming in Python.

Major
May 12, 2006, 01:31 PM
To add a python event, you have to do almost exactly the same thing described as above by Kael, but instead of using
gDLL->getPythonIFace()->callFunction(PYGameModule, "cannotAttack", argsList.makeFunctionArgs(), &lResult);

you should use:

gDLL->getEventReporterIFace()->genericEvent("yourevent", argsList.makeFunctionArgs());


And in your python event manager, just add your new event in the self.EventHandlerMap, let's say 'yourevent' : 'onYourEvent', create you onYourEvent function and that's it !

Kael
May 30, 2006, 12:36 PM
I wanted to allow more than one religion to spread to a city naturally. As is only one will spread and then you need to use a missionary or other method to get more religions to the city.

When I went to look at the code to do this I found a bit of a surprise, Firaxis had already programmed it to work this way and changed it later. Note that in the origional code there is a commented out line that divies the chance of the religion spreading by the amount of religions that already exist in the city. Also notice the if (!isHasReligion((ReligionTypes)iI)) line, which is completly unnessesary if you have already verified that the city has no religions as is done a few lines before.

So this is an extremly easy tweak, remove the if (getReligionCount() == 0) block and put the disor for multiple religions back in place and we are done.

I have attach the CvCoreGameDLL.dll for those that just want to use this change and haven't played with the SDK kit (I've had a few people request this change).

Game Effect: More than one religion can spread "naturally" (without missionarys) to a city. Although theoretically this could allow an unlimited amount of religions the chance of the religion spreading is divided by the amount of religions that already exist +1 so there is a practical limit.

CvCity.cpp

Original code:
void CvCity::doReligion()
{
CvCity* pLoopCity;
int iRandThreshold;
int iSpread;
int iLoop;
int iI, iJ;

CyCity* pyCity = new CyCity(this);
CyArgsList argsList;
argsList.add(gDLL->getPythonIFace()->makePythonObject(pyCity)); // pass in city class
long lResult=0;
gDLL->getPythonIFace()->callFunction(PYGameModule, "doReligion", argsList.makeFunctionArgs(), &lResult);
delete pyCity; // python fxn must not hold on to this pointer
if (lResult == 1)
{
return;
}

if (getReligionCount() == 0)
{
for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
{
if (!isHasReligion((ReligionTypes)iI))
{
if ((iI == GET_PLAYER(getOwnerINLINE()).getStateReligion()) || !(GET_PLAYER(getOwnerINLINE()).isNoNonStateReligio nSpread()))
{
iRandThreshold = 0;

for (iJ = 0; iJ < MAX_PLAYERS; iJ++)
{
if (GET_PLAYER((PlayerTypes)iJ).isAlive())
{
for (pLoopCity = GET_PLAYER((PlayerTypes)iJ).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iJ).nextCity(&iLoop))
{
if (pLoopCity->isConnectedTo(this))
{
iSpread = pLoopCity->getReligionInfluence((ReligionTypes)iI);

iSpread *= GC.getReligionInfo((ReligionTypes)iI).getSpreadFac tor();

if (iSpread > 0)
{
iSpread /= max(1, (((GC.getDefineINT("RELIGION_SPREAD_DISTANCE_DIVISOR") * plotDistance(getX_INLINE(), getY_INLINE(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE())) / GC.getMapINLINE().maxPlotDistance()) - 5));

//iSpread /= (getReligionCount() + 1);

iRandThreshold = max(iRandThreshold, iSpread);
}
}
}
}
}

if (GC.getGameINLINE().getSorenRandNum(GC.getDefineIN T("RELIGION_SPREAD_RAND"), "Religion Spread") < iRandThreshold)
{
setHasReligion(((ReligionTypes)iI), true, true);
break;
}
}
}
}
}
}

Here is the changed code, the only changes made were to comment out 3 lines (basically the if statement that blocks if the city has more than 0 religions and its 2 { } lines).

Modified code:
void CvCity::doReligion()
{
CvCity* pLoopCity;
int iRandThreshold;
int iSpread;
int iLoop;
int iI, iJ;

CyCity* pyCity = new CyCity(this);
CyArgsList argsList;
argsList.add(gDLL->getPythonIFace()->makePythonObject(pyCity)); // pass in city class
long lResult=0;
gDLL->getPythonIFace()->callFunction(PYGameModule, "doReligion", argsList.makeFunctionArgs(), &lResult);
delete pyCity; // python fxn must not hold on to this pointer
if (lResult == 1)
{
return;
}

// if (getReligionCount() == 0)
// {
for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
{
if (!isHasReligion((ReligionTypes)iI))
{
if ((iI == GET_PLAYER(getOwnerINLINE()).getStateReligion()) || !(GET_PLAYER(getOwnerINLINE()).isNoNonStateReligio nSpread()))
{
iRandThreshold = 0;

for (iJ = 0; iJ < MAX_PLAYERS; iJ++)
{
if (GET_PLAYER((PlayerTypes)iJ).isAlive())
{
for (pLoopCity = GET_PLAYER((PlayerTypes)iJ).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iJ).nextCity(&iLoop))
{
if (pLoopCity->isConnectedTo(this))
{
iSpread = pLoopCity->getReligionInfluence((ReligionTypes)iI);

iSpread *= GC.getReligionInfo((ReligionTypes)iI).getSpreadFac tor();

if (iSpread > 0)
{
iSpread /= max(1, (((GC.getDefineINT("RELIGION_SPREAD_DISTANCE_DIVISOR") * plotDistance(getX_INLINE(), getY_INLINE(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE())) / GC.getMapINLINE().maxPlotDistance()) - 5));

iSpread /= (getReligionCount() + 1);

iRandThreshold = max(iRandThreshold, iSpread);
}
}
}
}
}

if (GC.getGameINLINE().getSorenRandNum(GC.getDefineIN T("RELIGION_SPREAD_RAND"), "Religion Spread") < iRandThreshold)
{
setHasReligion(((ReligionTypes)iI), true, true);
break;
}
}
}
}
// }
}

If you want this change without changing the SDK youself here is the modified CvGameCoreDLL with only this change: CvGameCoreDLL.dll (http://kael.civfanatics.net/files/CvGameCoreDLL.dll)

onedreamer
May 31, 2006, 06:34 AM
superb help Kael, thanks !

BomberEscort
Jun 01, 2006, 07:15 AM
I want the Carrier unit to increase its strength by a certain percentage of the air unit strength whenever a fighter is on it and another percentage whenever a Jet is on it. I want these effects to be cumulative, but only for defense and only when they are on the intercept mission. Do I need the SDK to do this?

Lord Olleus
Jun 02, 2006, 11:41 AM
no you can do that it python. I made a script which transfered promotions from a unit, to its carrier. All you have to do is give fighters/jets a promotion, and the carrier then gets that promotion. I'll see if I can dig it up.

Shqype
Jun 02, 2006, 09:50 PM
Kael, you might want to update post 35 to let people know that modification is done in CvCity.cpp :)

Just a simple example of a change that can be made in CvUnit::maxCombatStr(). This applies a combat modifier based on the existence of the "Elf" promotion on the defender and the "Elf Slaying" promotion on the attacker. maxCombatStr is called from the perspective of the defender and I have the 2 checks in so that the bonus is applied on attack and defense.

Changes are in bold.

CvUnit::maxCombatStr()

if (getUnitCombatType() != NO_UNITCOMBAT)
{
iModifier -= pAttacker->unitCombatModifier(getUnitCombatType());
if (pCombatDetails != NULL)
{
pCombatDetails->iCombatModifierT = -(pAttacker->unitCombatModifier(getUnitCombatType()));
}
}

if (isHasPromotion((PromotionTypes)GC.getInfoTypeForS tring("PROMOTION_ELF")))
{
if (pAttacker->isHasPromotion((PromotionTypes)GC.getInfoTypeForSt ring("PROMOTION_ELF_SLAYING")))
{
iModifier = iModifier - 40;
}
}
if (isHasPromotion((PromotionTypes)GC.getInfoTypeForS tring("PROMOTION_ELF_SLAYING")))
{
if (pAttacker->isHasPromotion((PromotionTypes)GC.getInfoTypeForSt ring("PROMOTION_ELF")))
{
iModifier = iModifier + 40;
}
}

iModifier += domainModifier(pAttacker->getDomainType());
if (pCombatDetails != NULL)
{
pCombatDetails->iDomainModifierA = domainModifier(pAttacker->getDomainType());
}

Why use this? It provides the ability to specify anti-unit combat bonuses without having to make new unit combats or declare specific unitclasses. Also since its easy to add and remove promotions as you play it can allow you to create pretty dynamic bonuses.

Outside of that just being familiar with the effect of changing maxCombatStr can be very helpful to anyone who wants to effect the combat odds. Changes made here are reflect both in the actual combat odds as well as the display.
How difficult is it to add a new tag in CIV4PromotionInfos.xml that is coded with a more generic code so as to allow modders to add their own anti-promotion promotions without setting the specifics for it all in the SDK?

Kael
Jun 02, 2006, 10:10 PM
Kael, you might want to update post 35 to let people know that modification is done in CvCity.cpp :)


How difficult is it to add a new tag in CIV4PromotionInfos.xml that is coded with a more generic code so as to allow modders to add their own anti-promotion promotions without setting the specifics for it all in the SDK?

More difficult than what I have done but not impossible (and a better solution overall). Chalid is working on something along those lines and hopefully we will be able to get him to share the results if it is relativly consise.

Shqype
Jun 02, 2006, 11:00 PM
Sounds good to me, hopefully he is successful!

jenks
Jun 16, 2006, 07:54 AM
Just a simple example of a change that can be made in CvUnit::maxCombatStr(). This applies a combat modifier based on the existence of the "Elf" promotion on the defender and the "Elf Slaying" promotion on the attacker. maxCombatStr is called from the perspective of the defender and I have the 2 checks in so that the bonus is applied on attack and defense.

Changes are in bold.

CvUnit::maxCombatStr()

if (getUnitCombatType() != NO_UNITCOMBAT)
{
iModifier -= pAttacker->unitCombatModifier(getUnitCombatType());
if (pCombatDetails != NULL)
{
pCombatDetails->iCombatModifierT = -(pAttacker->unitCombatModifier(getUnitCombatType()));
}
}

if (isHasPromotion((PromotionTypes)GC.getInfoTypeForS tring("PROMOTION_ELF")))
{
if (pAttacker->isHasPromotion((PromotionTypes)GC.getInfoTypeForSt ring("PROMOTION_ELF_SLAYING")))
{
iModifier = iModifier - 40;
}
}
if (isHasPromotion((PromotionTypes)GC.getInfoTypeForS tring("PROMOTION_ELF_SLAYING")))
{
if (pAttacker->isHasPromotion((PromotionTypes)GC.getInfoTypeForSt ring("PROMOTION_ELF")))
{
iModifier = iModifier + 40;
}
}

iModifier += domainModifier(pAttacker->getDomainType());
if (pCombatDetails != NULL)
{
pCombatDetails->iDomainModifierA = domainModifier(pAttacker->getDomainType());
}

Why use this? It provides the ability to specify anti-unit combat bonuses without having to make new unit combats or declare specific unitclasses. Also since its easy to add and remove promotions as you play it can allow you to create pretty dynamic bonuses.

Outside of that just being familiar with the effect of changing maxCombatStr can be very helpful to anyone who wants to effect the combat odds. Changes made here are reflect both in the actual combat odds as well as the display.

I know these will seem like very basic questions, but i only started with XML this week and im in at the deep end :confused:

1 - Im not sure where the file is that this set of instructions needs to be added to, anyone? (i did a search for .cpp files on my HD but couldnt find a single one, and browsing around the vanilla files as well as a few mods i can only see .py files)

2 - Anyone know where i can download a FREE c++ editor/compiler to load and edit the .cpp file? (when i find it) :)

3 - Can I just copy the code into the place shown in the example, with my own promotions replacing PROMOTION_ELF (to PROMOTION_BORG) and PROMOTION_ELFSLAYING (PROMOTION_RUSE1), or do i need to declare the variables somewhere else?

Kael
Jun 16, 2006, 07:59 AM
I know these will seem like very basic questions, but i only started with XML this week and im in at the deep end :confused:

1 - Im not sure where the file is that this set of instructions needs to be added to, anyone? (i did a search for .cpp files on my HD but couldnt find a single one, and browsing around the vanilla files as well as a few mods i can only see .py files)

Its in the CvUnit.cpp file in the SDK.

2 - Anyone know where i can download a FREE c++ editor/compiler to load and edit the .cpp file? (when i find it) :)

The instructions for a free editor are here: http://forums.civfanatics.com/showthread.php?t=166933

3 - Can I just copy the code into the place shown in the example, with my own promotions replacing PROMOTION_ELF (to PROMOTION_BORG) and PROMOTION_ELFSLAYING (PROMOTION_RUSE1), or do i need to declare the variables somewhere else?

You can just replace them with your promotion names. Check out my post here though for other options: http://forums.civfanatics.com/showthread.php?t=174455

Gerikes
Jun 17, 2006, 03:10 PM
Ok, yes, all the problems I ran into were Civcraft: SC related. So, this should work for Civ4, although I haven't really tested it in a normal Civ4 environment.

Under Civ4, any unit can be upgraded to any other unit if there exists a "path" of upgrades. Thus, a warrior can in one turn upgrade to a Mech Infantry, because there exists a path...

Warrior->Spearman->Pikeman->Rifleman->Infantry->Mech Inf.

Typically, the disadvantage to this is that it costs a ton of money. But perhaps you want to make it even tougher, by forcing the player to only be able to upgrade a few rungs up the ladder at a time.


bool CvUnit::upgradeAvailable(UnitTypes eFromUnit, UnitClassTypes eToUnitClass, int iCount) const
{
UnitTypes eLoopUnit;
int iI;

/* Modifed by Gerikes to disable recursive upgrade*/
//if (iCount > GC.getNumUnitClassInfos())
if (iCount > 0)
/* End Modifed by Gerikes to disable recursive upgrade*/
{
return false;
}

if (GC.getUnitInfo(eFromUnit).getUpgradeUnitClass(eTo UnitClass))
{
return true;
}

for (iI = 0; iI < GC.getNumUnitClassInfos(); iI++)
{
if (GC.getUnitInfo(eFromUnit).getUpgradeUnitClass(iI) )
{
eLoopUnit = ((UnitTypes)(GC.getCivilizationInfo(getCivilizatio nType()).getCivilizationUnits(iI)));

if (eLoopUnit != NO_UNIT)
{
if (upgradeAvailable(eLoopUnit, eToUnitClass, (iCount + 1))) // Recursive call
{
return true;
}
}
}
}

return false;
}


This function is a recursive function. That means that during the course of running through the code, the function will actually call itself. This is important to realize for what we're doing.

When the function is first called, the eFromUnit value (say, UNIT_WARRIOR) and the eToUnitClass value (say, UNITCLASS_SAM_INFANTRY) are passed in, along with the number for iCount (by default, 0). In the first run, there is a check to see if the unit can upgrade to the unitclass only by checking it's upgrades. This would return true if eToUnitClass were, say, a Spearman or Axeman. But it's not, so it's false.

What happens next is that big for-loop mess will check every single unitclass that the warrior CAN upgrade to all by itself. It will then, for each one, call the function upgradeAvailable AGAIN, only this time using the new eFromUnit (say, a Spearman), the same eToUnitClass, and an incremented count.

If you're not familar with recursive functions, the next sentence may not make sense, but trust me on it. For every "hop" on the upgrade path the unit has to make to get to it's destination, iCount will increase. Thus, by checking what iCount is at the beginning of each function, you can control how far you're willing to search the "path" of upgrades.

By changing that first if-block, I'm changing how far I'm allowing the recursive function to dive. In this case, where I check iCount for 0, it will allow through the first pass, checking all of the Warriors "direct" upgrades. But, during the recursive calls, while trying to check all the upgrades from the spearman, axeman, etc., iCount will be incremented to one, which is greater than zero, so it will fail, and return false.

The moral of this story, is that you can control the depth of how far you can "search" the tree to upgrade. Rather than making it a magic number, you can make it a define:


/* Modifed by Gerikes to change recursive upgrade max depth*/
//if (iCount > GC.getNumUnitClassInfos())
if (iCount >= GC.getDefineINT("MAX_UPGRADE_DEPTH"))
/* End Modifed by Gerikes to change recursive upgrade max depth*/


Now, you can set a variable in the XML to define how far an upgrade can go. Note I changed the ">" to a ">=". Now, a value of 0 will disable upgrades, a value of 1 will allow upgrades of depth 1, a value of 5 will allow upgrades up to depth 5.

ocedius
Aug 03, 2006, 08:08 PM
Could youall continue posting such snipplets? They're mighty helpful for us stemmies.

Kael
Aug 03, 2006, 09:08 PM
K, here is a pretty easy one:

So that Players can be queried to see if they have certain bonuses in any of their cities
version: 0.15

CvPlayer.cpp


//FfH: Added by Kael 07/19/2006

bool CvPlayer::hasBonus(BonusTypes eIndex)
{
CvCity* pLoopCity;

int iLoop;
for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
{
if (pLoopCity->hasBonus(eIndex))
{
return true;
}
}
return false;
}

//FfH: End Add


CvPlayer.h


//FfH: Added by Kael 07/19/2006

bool hasBonus(BonusTypes eIndex);

//FfH: End Add


Basically I wanted a new function I could call from other places in the SDK that would tell me if the player had a resource available in any of his cities. The code is faily simple, just a new function tacked on to the bottom of the CvPlayer.cpp file and defined in the CvPlayer.h file.

Once its in I can do a:

if (pPlayer.hasBonus(eBonus))

and get a true or false if the player has it anywhere or not. As it is it is only available in the SDK, although its not that hard to extend this function to python.

Why am I doing this in the SDk instead of in Python? Mostly because the function that are going to be using it are in the SDK so its similiar to have the function there. Its also faster to parse through the players cities in complied code instead of a scripted language like Python.

Specifically I added the ability to have promotions require resources. You can have your mages learn fire spells unless you have access to fire mana in some of your cities. Since the canAcquirePromotion function is a SDK function I wanted the new hasBonus to be as close to it as possible.

LittleRedPoint
Aug 05, 2006, 10:38 AM
How to make civics to suport negative religion hapiness?

For example I want to make theocracy to give +3 happy with state religion and 3 unhappy with non state religion. If I insert -3 in xml the game gives me value of 246583. I saw this suport in several mods. Kael you did it in your mod too. How to do this?

Kael
Aug 05, 2006, 07:55 PM
How to make civics to suport negative religion hapiness?

For example I want to make theocracy to give +3 happy with state religion and 3 unhappy with non state religion. If I insert -3 in xml the game gives me value of 246583. I saw this suport in several mods. Kael you did it in your mod too. How to do this?

Replyed in PM.

ocedius
Aug 05, 2006, 09:46 PM
Thanks for the city-has-bonus SDK implementation. And yes, python scripted functions do have a disadvantage over C++ due to the whole compiled-vs-interpreted coding.

I was looking over Ffh and liked the whole sprawling vs non-sprawling 3 vs. 2 city radius you all did. Could you post how. Or maybe I should ask this on the Ffh thread. Same with the negative civics. XML changes don't quite seem to work.

Also, have you tried a recursive SDK implemented search through of units in the whole has promotion vs. does have promotions. Python gets the job done, but searching through 200+ units can cause lag time that aren't pretty :lol:

Edit: Nevermind. I think I figuered it out.

Kael
Aug 08, 2006, 12:32 PM
So Lifesparks heal units in their stack that are about to die during combat
version 0.15

CvUnit.cpp
void CvUnit::updateCombat(bool bQuick)


//FfH: Added by Kael 08/08/2006

if ((pDefender->getDamage() + iDamage) >= pDefender->maxHitPoints())
{
CvUnit* pLoopUnit;
int iLoop;
for (iLoop=0; iLoop <= pPlot->getNumUnits(); iLoop++)
{
pLoopUnit = pPlot->getUnit(iLoop);
if (pLoopUnit != NULL && pLoopUnit->getUnitClassType() == (UnitClassTypes)GC.getInfoTypeForString("UNITCLASS_LIFESPARK"))
{
pDefender->changeDamage(-40);
szBuffer = gDLL->getText("TXT_KEY_MESSAGE_LIFESPARK_USED", pDefender->getNameKey());
gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()). getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
pLoopUnit->kill(false);
break;
}
}
}

//FfH: End Add


What it does: Inserted in the updateCombat function (specifically in the section where the attacker wins the roll just before the attackers damage is applied to the defender) this code checks the defenders stack to see if their is a unit it it with the unit class of "UNITCLASS_LIFESPARK". If there is it heals the defender 40% and kills the lifespark.

I wanted to add some defensive magic to the game. In this case a creature that could be summoned that helps guard the stack it is in. Since their is no real interface here (if the unit is about to die it performs the heal) the AI doesn't have to know more than to include it in stacks to be good at it, and players don't have to manage anything except keep it around.

Why? I admit this specific implementation is a very FfH concept. But it can easily be converted into anything you would like to do during the combat step. If you want to have a unit heal when it does damage to an opponent, add it here. If you want to give a chance to break combat everytime the defender hits when he is inside a fort, this is the place to do it. Have archery units in the defenders stack apply some damage to attackers on each combat turn. Have defending helicopters flee if they get to low on damage. Have the defending unit have a chance to turn into the Hulk everytime he is hurt and start destroying everyone.

ocedius
Aug 17, 2006, 08:27 AM
Why do you torture us with sniplets like this and then disappear without revealing any more?

You're eebell, vewy vewy ebell :p

seady
Sep 21, 2006, 01:05 PM
Modern programming languages often Copy syntax from C/C++. *I think* that C or C++ was the first object-oriented language aswell, which another reason its copied. The first being its probably one of the most popular programming languages.

"Object-oriented programming (http://en.wikipedia.org/wiki/Object-oriented) developed as the dominant programming methodology during the mid-1980s, largely due to the influence of C++, an extension of the C programming language."

I did computer science (badly) many years ago, and i could sort of understand C, but was lost when we hit C++ partly because of the whole OO bit which never really became clear to my feeble brain. :blush:

Pascal, on the other hand... whatever happened to pascal? It was fun :crazyeye:

talchas
Sep 21, 2006, 04:29 PM
C is not OO, C++ is not the first OO, smalltalk is often assigned as being the thing that is pure OO (there are very different ways to do OO, but in C++/Java/Python/Ruby + most others you don't care). C++ may well have been what made OO popular.

An object holds state and has methods which manipulate or do work based on that state. They are VERY useful for many problems - in Civ4, see CvUnit - it contains just about all the game information for one unit, and has methods to do stuff with or to a unit.

Ket
Sep 23, 2006, 09:19 AM
Replyed in PM.

Could you share?

Kael
Oct 20, 2006, 09:05 PM
To allow for a Fatigued promotion that lasts until the unit rests (spends a turn without taking an action).

CvUnit.cpp
void CvUnit::doTurn()


if (hasMoved())
{
if (isAlwaysHeal())
{
doHeal();
}
}
else
{
if (isHurt())
{
doHeal();
}

changeFortifyTurns(1);

//FfH: Added by Kael 10/05/2006
if (isHasPromotion((PromotionTypes)GC.getInfoTypeForS tring("PROMOTION_FATIGUED")))
{
setHasPromotion((PromotionTypes)GC.getInfoTypeForS tring("PROMOTION_FATIGUED"), false);
}
//FfH: End Add

}


What it does: This is pretty minor. Just an additional routine that kicks off if the unit hasMoved() is false that removes the promotion.

Why? You can have the promotion do whatever you'd like, I think I ours gives -10% to the units combat strength and is applied to the unit when they use the Sprint ability to boost their movement. Fatigue could be applied if units move through hazardous terrain, withdrawal from combat, or maybe spend x amount of turns otuside of their civilizations zone of control.

Aussie_Lurker
Oct 21, 2006, 01:36 AM
Hey Kael, this could prove useful to people like myself and Dom Pedro in the future. What I am wondering, though, is what would you replace the if (hasmoved()) line with if you wanted to represent units being 'out of supply'. I am guessing it would probably have to be some kind of if (isPlot()) routine, am I right?

Aussie_Lurker.

Kael
Oct 21, 2006, 07:24 AM
Hey Kael, this could prove useful to people like myself and Dom Pedro in the future. What I am wondering, though, is what would you replace the if (hasmoved()) line with if you wanted to represent units being 'out of supply'. I am guessing it would probably have to be some kind of if (isPlot()) routine, am I right?

Aussie_Lurker.

What exactly would you want the effect of being "out of supply" to be?

Aussie_Lurker
Oct 21, 2006, 08:57 AM
Well its effects would be identical to the Fatigue function you describe. The only difference is that, rather than being based on whether the unit moved, it would be based on how far the plot said unit is on is from a friendly/home plot.
Does that make sense?

Aussie_Lurker.

Kael
Oct 21, 2006, 09:41 AM
Well its effects would be identical to the Fatigue function you describe. The only difference is that, rather than being based on whether the unit moved, it would be based on how far the plot said unit is on is from a friendly/home plot.
Does that make sense?

Aussie_Lurker.

If you don't want to have it effected by the units movement you probably want to keep it in CvUnit.cpp doTurn() but outside of the hasMoved section I displayed. That way its just a check on each unit each turn.

You could also do the same from python in the begin player turn function. Just cycling through the units and applying or removing fatgiue based on whatever criteria you setup.

Aussie_Lurker
Oct 21, 2006, 11:49 PM
Well, I do try and avoid python where I can, as I have had the greatest success with SDK. So if I can do it in SDK, that will always be my preferred option.

Aussie_Lurker.

Rod
Nov 02, 2006, 05:25 AM
Replyed in PM.

please always post every single bit of code on the forum, it is all veeery interesting you are an awesome developer !! If the solution is in python rather than in C++ then maybe open another Python-Topic ? ....

Kael
Nov 03, 2006, 09:22 AM
please always post every single bit of code on the forum, it is all veeery interesting you are an awesome developer !! If the solution is in python rather than in C++ then maybe open another Python-Topic ? ....

It wasnt code we just chatted about what he was seeing and why (as I recall).

As for example code here is a fairly minor change:

To keep buildings from listing units they are required to train that the civilization doesn't have access to

CvGameTextMgr.cpp
void CvGameTextMgr::setBuildingHelp(CvWString &szBuffer, BuildingTypes eBuilding, bool bCivilopediaText, bool bStrategyText, bool bTechChooserText, CvCity* pCity)


//FfH: Modified by Kael 11/02/2006
// for (iI = 0; iI < GC.getNumUnitInfos(); iI++)
// {
// if (GC.getUnitInfo((UnitTypes)iI).getPrereqBuilding() == eBuilding)
// {
// swprintf(szFirstBuffer, L"%s%s", NEWLINE, gDLL->getText("TXT_KEY_BUILDING_REQUIRED_TO_TRAIN").c_str());
// swprintf(szTempBuffer, SETCOLR L"<link=literal>%s</link>" ENDCOLR , TEXT_COLOR("COLOR_UNIT_TEXT"), GC.getUnitInfo((UnitTypes)iI).getDescription());
// setListHelp(szBuffer, szFirstBuffer, szTempBuffer, L", ", bFirst);
// bFirst = false;
// }
// }
UnitTypes eLoopUnit;
for (iI = 0; iI < GC.getNumUnitClassInfos(); iI++)
{
if (GC.getGameINLINE().getActivePlayer() != NO_PLAYER)
{
eLoopUnit = (UnitTypes)GC.getCivilizationInfo(GC.getGameINLINE ().getActiveCivilizationType()).getCivilizationUni ts(iI);
}
else
{
eLoopUnit = (UnitTypes)GC.getUnitClassInfo((UnitClassTypes)iI) .getDefaultUnitIndex();
}
if (eLoopUnit != NO_UNIT)
{
if (GC.getUnitInfo(eLoopUnit).getPrereqBuilding() == eBuilding)
{
swprintf(szFirstBuffer, L"%s%s", NEWLINE, gDLL->getText("TXT_KEY_BUILDING_REQUIRED_TO_TRAIN").c_str());
swprintf(szTempBuffer, SETCOLR L"<link=literal>%s</link>" ENDCOLR , TEXT_COLOR("COLOR_UNIT_TEXT"), GC.getUnitInfo(eLoopUnit).getDescription());
setListHelp(szBuffer, szFirstBuffer, szTempBuffer, L", ", bFirst);
bFirst = false;
}
}
}
//FfH: End Modify


What it does: All of the commented out code at the top (the lines preceeded with a "//") are the origional code. As you can tell it used to read through all of the available units and add every unit to the list that requires that building. The new code reads through the unit classes instead and only lists the units appropriate for that civ.

Why? Vanilla doesn't have many (or any?) building requirements for units so it isn't an issue. But if you were to require that Musketmen and Musketeer's both required the 'Musket Crafter' building you would see that the building is 'Required to train Musketmen and Musketeers' for every civ. With this change the French would see 'Required to train Musketeers' and all the other civs would see 'Required to train Musketmen'.

This became even more important if you have set a large amount of UU's as we have in FfH. In some cases there can be 10 different versions of a unit for different civs so these lists got very long.

Special Bonus Feature (no charge, limited time only, not valid in Mississippi): The entire source code for Fall from Heaven 2 (http://forums.civfanatics.com/showthread.php?t=171398) is online and available at: http://forums.civfanatics.com/showthread.php?t=171398. Modders are welcome to use it as a base for their mods, or just dig into it for bits and pieces they can use, I just ask that you please credit the programmer if you use his code.

Galeocerdo
Jun 29, 2007, 08:56 PM
I was wondering if anyone could explain the flow of how the SDK and Python files interact. My understanding on this is very fuzzy at best. To be more specific:

1. how does a .py file reference say a function from the SDK (if they actually can)?

2. how are the .cpp files with Cv prefixes related to the .cpp files with Cy prefixes?

3. what exactly is a wrapper?

4. how does a .cpp file get data from a .py class (is this somehow related to the wrappers?)?

I greatly appreciate any input on these. I have been playing around with the files and sometimes think I understand what is going on, but other times end up confused.

Thanks

Kael
Jun 29, 2007, 09:15 PM
1. how does a .py file reference say a function from the SDK (if they actually can)?

The function has to be exposed to python in the SDK. If that is the case python can call the function on an object. For example pUnit.getDamage() is calling the SDK call getDamage on the pUnit object.

2. how are the .cpp files with Cv prefixes related to the .cpp files with Cy prefixes?

Cv are SDK functions, Cy are the SDK functions that are "exposed" to python.

3. what exactly is a wrapper?

Wrapper is a python class that creates a list of python functions that can be used on a unit. Modders find them handy to make an easy way to reference common functions.

4. how does a .cpp file get data from a .py class (is this somehow related to the wrappers?)?

It doesn't. Python makes calls into the SDK. The SDK doesn't get data from python. You can make a python call into the SDK that passes data (for example: pUnit.setDamage(10)). But you wouldn't write an SDK function that requested info from python.

Python never directly calls XML either. the SDk calls XML, and python requests the info from the SDK.

Galeocerdo
Jun 30, 2007, 01:51 PM
The function has to be exposed to python in the SDK. If that is the case python can call the function on an object. For example pUnit.getDamage() is calling the SDK call getDamage on the pUnit object.



Cv are SDK functions, Cy are the SDK functions that are "exposed" to python.



Wrapper is a python class that creates a list of python functions that can be used on a unit. Modders find them handy to make an easy way to reference common functions.



It doesn't. Python makes calls into the SDK. The SDK doesn't get data from python. You can make a python call into the SDK that passes data (for example: pUnit.setDamage(10)). But you wouldn't write an SDK function that requested info from python.

Python never directly calls XML either. the SDk calls XML, and python requests the info from the SDK.


Thank you, this clears things up greatly.

Shqype
Mar 05, 2008, 02:57 PM
Bump :) :)

Gaius Octavius
Mar 05, 2008, 07:30 PM
Here's a little bit of code that I wrote for Ambreville and Jeckel in the "OIL vs. MOVE" thread. (I just converted what Jeckel did in Python to C++.)


// Oil movement restriction - Gaius Octavius
if (m_pUnitInfo->isMechUnit())
{
if (GET_PLAYER(getOwnerINLINE()).getNumAvailableBonus es((BonusTypes)GC.getInfoTypeForString("BONUS_OIL")) < 1)
{
return false;
}
}


This goes in CvUnit.cpp under the CvUnit::canMove() function. It checks to see whether a civilization has oil, and if it does not, then all mechanized units (tanks, planes, modern ships...) cannot move.

This is far from perfect code, since there are so many little things you'd need to take into account, like the fact that ships can use oil OR uranium - this currently would keep them from moving with no oil even if you have uranium. But I think people will get some use out of it. :)

Dom Pedro II
Mar 05, 2008, 08:48 PM
Actually, I don't think you want to use the numavailablebonuses function. use the "hasbonus" function because I think the other one is used for trading to find out if you have resources available to trade.

Gaius Octavius
Mar 05, 2008, 09:00 PM
Actually, I don't think you want to use the numavailablebonuses function. use the "hasbonus" function because I think the other one is used for trading to find out if you have resources available to trade.

I think that's what he wanted. You see, if you use "hasbonus" and you only have one supply, and you trade it away, then numavailable returns zero. At least, that was my experience. It worked when only one oil source was connected, and if it used only the tradeable resources, then it would not have worked.

mod freak
Mar 24, 2008, 08:05 AM
Sorry, but how do you edit the files on the SDK? I'm new at this and need help.:confused::sad::confused:

Gaius Octavius
Mar 24, 2008, 11:51 AM
Sorry, but how do you edit the files on the SDK? I'm new at this and need help.:confused::sad::confused:

It is in this thread. http://forums.civfanatics.com/showthread.php?t=166933