Modders Guide to FfH2

I started another thread a while back but got no responses, so I'm going to re-ask my question again here since it is the thread with the most people with programming experience, and in case Kael missed it from his vacation. (Please hit me over the head if this suggestion has already been implemented in the latest release, I won't be able to download things for a while yet)

In all the python event check the code has the gc.getInfoTypeForString() plastered all over the place. Would it not be faster to define all the getInfoTypeForString() variables as global variables earlier, such as on game start?

i.e. (the spacing is messed up for the spoiler, but the idea is still there)
Spoiler :
if unit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ELEMENTAL')):
if pPlayer.getNumBuilding(gc.getInfoTypeForString('BUILDING_TOWER_OF_THE_ELEMENTS')) > 0:
unit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_STRONG'), True)

if unit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_UNDEAD')):
if pPlayer.getNumBuilding(gc.getInfoTypeForString('BUILDING_TOWER_OF_NECROMANCY')) > 0:
unit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_STRONG'), True)


would turn into this:
Spoiler :
if unit.isHasPromotion(PROMOTION_ELEMENTAL):
if pPlayer.getNumBuilding(BUILDING_TOWER_OF_THE_ELEMENTS) > 0:
unit.setHasPromotion(PROMOTION_STRONG, True)

if unit.isHasPromotion(PROMOTION_UNDEAD):
if pPlayer.getNumBuilding(BUILDING_TOWER_OF_NECROMANCY) > 0:
unit.setHasPromotion(PROMOTION_STRONG, True)

plus in the onGameStart() and onGameLoad()

global PROMOTION_ELEMENTAL
PROMOTION_ELEMENTAL = gc.getInfoTypeForString('PROMOTION_ELEMENTAL')

etc


Or would that just use up more memory resources? Also it would allow the code to be optimized in a few places by changing some of the code to reduce the number of checks in some places by nesting some of the variables in a tuple and doing an if in check to check if it should even start further processing?

found an example

Spoiler :
if pUnit.getOwner() == gc.getBARBARIAN_PLAYER():
pPlot = pUnit.plot()
if pPlot.getImprovementType() == gc.getInfoTypeForString('IMPROVEMENT_BARROW') or pPlot.getImprovementType() == gc.getInfoTypeForString('IMPROVEMENT_RUINS') or pPlot.getImprovementType() == gc.getInfoTypeForString('IMPROVEMENT_HELLFIRE') or pPlot.getImprovementType() == gc.getInfoTypeForString('IMPROVEMENT_BEAR_DEN') or pPlot.getImprovementType() == gc.getInfoTypeForString('IMPROVEMENT_LION_DEN'):
if pPlot.getNumUnits() == 1:
return 1

to

if pUnit.getOwner() == gc.getBARBARIAN_PLAYER():
pPlot = pUnit.plot()
if pPlot.getImprovementType() in SOMEVAR:
if pPlot.getNumUnits() == 1:
return 1
and

global IMPROVEMENT_BARROW
IMPROVEMENT_BARROW = gc.getInfoTypeForString('IMPROVEMENT_BARROW')
. . .
global SOMEVAR
SOMEVAR = [IMPROVEMENT_BARROW, IMPROVEMENT_RUINS, IMPROVEMENT_HELLFIRE, IMPROVEMENT_BEAR_DEN, IMPROVEMENT_LION_DEN]



Or if I am wrong, just let me know before I try to mess with my game when I get a copy of the latest version.
 
I'm not sure if you can use gc when declaring globals. (But possibly as self.variableName)

I tried defining all my variables in another file (CvHelpers.py) which I import like this:
from CvHelpers import *

But it wouldn't load the variables correctly.

I think you have to declare them before, but set the value in onGameStart (possibly also in onLoadGame)

@Kael: Will the source for patch E be uploaded any time soon?
 
I'm not sure if you can use gc when declaring globals. (But possibly as self.variableName)

I tried defining all my variables in another file (CvHelpers.py) which I import like this:
from CvHelpers import *

But it wouldn't load the variables correctly.

I think you have to declare them before, but set the value in onGameStart (possibly also in onLoadGame)

@Kael: Will the source for patch E be uploaded any time soon?
I did it for my modcomp and it seems to work fine (http://forums.civfanatics.com/showthread.php?t=267783). I had to declare the variables in the same class as where they are called. I also had to add some calls to a new function in the class that triggered onGameLoad() and onGameStart(). So I guess the global variables are setup for that particular class.

Actually it was necessary for my Promotion modcomp because the iterations of checking each unit for each promotion on each plot type became too much overhead.

Example of the big variable in my modcomp:

Spoiler :

# The next list set defines what promotions can be given out to units in a stack. Each list (group of items within a bracket)
# must contain four variables contained within quotemarks. In the same order they denote:
# ["PROMOTIONGIVEN", "UNITNAME", "TILERESTRICTIONS", "TILETYPE", "ALLOWEDUNITS"]
# All variables are mandatory and case sensitive!
#
#
# "PROMOTIONGIVEN" is the promotion which is given to allowed units, it is in the <Type></Type> tags in CIV4PromotionInfos.XML
# ******WARNING any promotion in any one of these fields will always disappear from units, only use custom promotions
#
# gc.getInfoTypeForString("UNITNAME" is the unit which provides the promotion, it is in the <Type></Type> tags (gc.getInfoTypeForString(gc.getInfoTypeForString("UNIT_DRUID")) in CIV4UnitInfos.XML
# multiple unit names can be given, they all must be within the brackets
#
# "TILERESTRICTIONS" is any one plot restriction which affects where the promotion can be given out. The options are:
# --"ANY", "CITY", any feature tag (gc.getInfoTypeForString("FEATURE_JUNGLE")), improvement tag (gc.getInfoTypeForString("IMPROVEMENT_CAMP")), or terrain tag (gc.getInfoTypeForString("TERRAIN_PLAINS"))
# multiple tile restrictions can be given, they all must be within the brackets
#
# "TILETYPE" is used to determine what type of tile restriction was used, unless TILERESTRICTIONS was CITY or ANY in which case
# you should put "ANY" within this slot. Otherwise you need to put the tag type from tile restrictions. The options are:
# --"FEATURE", "IMPROVEMENT", "TERRAIN", "ANY"
#
# "ALLOWEDUNITS" defines which units can receive the promotion. The options are:
# --"ALL", "SELF", or any unitclass found within the <Combat></Combat> tags (gc.getInfoTypeForString("UNITCOMBAT_RECON")) in CIV4UnitInfos.XML

# exempt units. These units will neither be able to receive promotions, nor trigger the plot update function, thereby saving
# CPU cycles since the check is earlier than the more intensive plot checks. Comes from the <Class></Class> tags

global promotionList
promotionList = [[gc.getInfoTypeForString("PROMOTION_LED"), [gc.getInfoTypeForString("UNIT_FIELD_COMMANDER")], ["ANY"], "ANY", "ALL"],
[gc.getInfoTypeForString("PROMOTION_HAWK_FRIEND"), [gc.getInfoTypeForString("UNIT_HAWK")], ["ANY"], "ANY", gc.getInfoTypeForString("UNITCOMBAT_RECON")],
[gc.getInfoTypeForString("PROMOTION_FOREST_INVISIBILITY"), [gc.getInfoTypeForString("UNIT_RANGER"), gc.getInfoTypeForString("UNIT_DRUID"), gc.getInfoTypeForString("UNIT_SATYR")], [gc.getInfoTypeForString("FEATURE_FOREST"), gc.getInfoTypeForString("FEATURE_FOREST_ANCIENT"), gc.getInfoTypeForString("FEATURE_JUNGLE")], "FEATURE", "SELF"],
[gc.getInfoTypeForString("PROMOTION_TUTOR"), [gc.getInfoTypeForString("UNIT_ARCHMAGE")], ["ANY"], "ANY", gc.getInfoTypeForString("UNITCOMBAT_ADEPT")],
[gc.getInfoTypeForString("PROMOTION_WOLF_FRIEND"), [gc.getInfoTypeForString("UNIT_WOLF")], [gc.getInfoTypeForString("IMPROVEMENT_NONE")], "IMPROVEMENT", gc.getInfoTypeForString("UNITCOMBAT_RECON")],
[gc.getInfoTypeForString("PROMOTION_INSPIRED"), [gc.getInfoTypeForString("UNIT_ACHERON"), gc.getInfoTypeForString("UNIT_GOVANNON"), gc.getInfoTypeForString("UNIT_LOKI"), gc.getInfoTypeForString("UNIT_DONAL"), gc.getInfoTypeForString("UNIT_LOSHA"), gc.getInfoTypeForString("UNIT_RANTINE"), gc.getInfoTypeForString("UNIT_WAR_MACHINE"), gc.getInfoTypeForString("UNIT_CORLINDALE"), gc.getInfoTypeForString("UNIT_MAGNADINE"), gc.getInfoTypeForString("UNIT_WILBOMAN"), gc.getInfoTypeForString("UNIT_HYBOREM"), gc.getInfoTypeForString("UNIT_MAROS"), gc.getInfoTypeForString("UNIT_EURABATRES"), gc.getInfoTypeForString("UNIT_GUYBRUSH"), gc.getInfoTypeForString("UNIT_GILDEN"), gc.getInfoTypeForString("UNIT_BARNAXUS"), gc.getInfoTypeForString("UNIT_TEUTRIX"), gc.getInfoTypeForString("UNIT_BASIUM"), gc.getInfoTypeForString("UNIT_ABASHI"), gc.getInfoTypeForString("UNIT_RATHUS"), gc.getInfoTypeForString("UNIT_ALAZKAN")], ["ANY"], "ANY", "ALL"],
[gc.getInfoTypeForString("PROMOTION_MANA_FIELD"), [gc.getInfoTypeForString("UNIT_ARCHMAGE"), gc.getInfoTypeForString("UNIT_ADEPT"), gc.getInfoTypeForString("UNIT_MAGE")], [gc.getInfoTypeForString("IMPROVEMENT_MANA_AIR"), gc.getInfoTypeForString("IMPROVEMENT_MANA_BODY"), gc.getInfoTypeForString("IMPROVEMENT_MANA_CHAOS"), gc.getInfoTypeForString("IMPROVEMENT_MANA_DEATH"), gc.getInfoTypeForString("IMPROVEMENT_MANA_DIMENSIONAL"), gc.getInfoTypeForString("IMPROVEMENT_MANA_EARTH"), gc.getInfoTypeForString("IMPROVEMENT_MANA_ENCHANTMENT"), gc.getInfoTypeForString("IMPROVEMENT_MANA_ENTROPY"), gc.getInfoTypeForString("IMPROVEMENT_MANA_FIRE"), gc.getInfoTypeForString("IMPROVEMENT_MANA_LAW"), gc.getInfoTypeForString("IMPROVEMENT_MANA_LIFE"), gc.getInfoTypeForString("IMPROVEMENT_MANA_MIND"), gc.getInfoTypeForString("IMPROVEMENT_MANA_NATURE"), gc.getInfoTypeForString("IMPROVEMENT_MANA_SHADOW"), gc.getInfoTypeForString("IMPROVEMENT_MANA_SPIRIT"), gc.getInfoTypeForString("IMPROVEMENT_MANA_SUN"), gc.getInfoTypeForString("IMPROVEMENT_MANA_WATER")], "IMPROVEMENT", "SELF"],
[gc.getInfoTypeForString("PROMOTION_TAMED"), [gc.getInfoTypeForString("UNIT_BEASTMASTER")], ["ANY"], "ANY", gc.getInfoTypeForString("UNITCOMBAT_ANIMAL")],
[gc.getInfoTypeForString("PROMOTION_BEAR_FRIEND"), [gc.getInfoTypeForString("UNIT_BEAR")], [gc.getInfoTypeForString("IMPROVEMENT_NONE")], "IMPROVEMENT", gc.getInfoTypeForString("UNITCOMBAT_RECON")],
[gc.getInfoTypeForString("PROMOTION_TIGER_FRIEND"), [gc.getInfoTypeForString("UNIT_TIGER")], [gc.getInfoTypeForString("IMPROVEMENT_NONE")], "IMPROVEMENT", gc.getInfoTypeForString("UNITCOMBAT_RECON")],
[gc.getInfoTypeForString("PROMOTION_GORILLA_FRIEND"), [gc.getInfoTypeForString("UNIT_GORILLA")], [gc.getInfoTypeForString("IMPROVEMENT_NONE")], "IMPROVEMENT", gc.getInfoTypeForString("UNITCOMBAT_RECON")],
[gc.getInfoTypeForString("PROMOTION_NIGHTMARES"), [gc.getInfoTypeForString("UNIT_HEMAH")], ["ANY"], "ANY", "ALL"]]

As you can see quite a beefy variable. After I made that one change in the code, all of a sudden the endgame on a large map was much faster than the endgame on a small map.
 
Patch "e" source is linked in the first post.

@mtagge- I dont know if that would offer increase performance or not. I don't loop on getInfo requests so anytime I run through a loop that uses them I define it outside the loop. As such I think it would be hard to find a place where a global declaration would offer a noticeable improvement.

But thats just my guess, if you can show a change that has any noticable speed improvement I would love to check it out.
 
Patch "e" source is linked in the first post.

@mtagge- I dont know if that would offer increase performance or not. I don't loop on getInfo requests so anytime I run through a loop that uses them I define it outside the loop. As such I think it would be hard to find a place where a global declaration would offer a noticeable improvement.

But thats just my guess, if you can show a change that has any noticable speed improvement I would love to check it out.
Maybe if I get some down time this weekend I will try starting up a new game and getting to the endgame point then timing a few of the turns. Then I'll try pulling out some of the getInfo request out and declaring a few globals then retiming it. If you don't loop it shouldn't be too bad to change a few with the replace command and some mad Ctrl+X, Ctrl+C, Ctrl+V commands. If I get around to it I'll post the results.
 
Maybe if I get some down time this weekend I will try starting up a new game and getting to the endgame point then timing a few of the turns. Then I'll try pulling out some of the getInfo request out and declaring a few globals then retiming it. If you don't loop it shouldn't be too bad to change a few with the replace command and some mad Ctrl+X, Ctrl+C, Ctrl+V commands. If I get around to it I'll post the results.

That would be much appreciated. I can pass you some massive lategame saves if that would make it easier for you?
 
That would be much appreciated. I can pass you some massive lategame saves if that would make it easier for you?
Actually I am looking forward to a OCC Huge Marathon game for a change of pace. See if I can eek out a altar victory while I am at it. (Besides right now I can't download the same games through my company's firewall).

It actually wasn't that bad to change all the globals, the downside is that I am not up to date with the release version, but the results should be the same regardless of the version. I'll post my results here on Monday.

PS Now that I have spent oodles of time looking through the python code, you don't put actual loops in, you have a tendency to write all the code out longhand. A good example is when you define each hero for each civ, you just list each of them on a seperate set of lines.
 
I've tried to found where the scrub were added , but I've found nothing . I've made a search in all python files , SDK and XML with 'FEATURE_SCRUB' , nothing . Since iAppearance = 0 , the feature generator should not add some . So how and when the scrub have been added please ?

Tcho !
 
I've tried to found where the scrub were added , but I've found nothing . I've made a search in all python files , SDK and XML with 'FEATURE_SCRUB' , nothing . Since iAppearance = 0 , the feature generator should not add some . So how and when the scrub have been added please ?

Tcho !

iAppearance is the chance that feature will spread (as forests do). The game places any features on terrain as long as the terrain is valid. So int he scrubs place because we set desert as an acceptable terrain the map generator will put them there. If we take that terrain out it wont autoamtically place them and then could place them via our own script or whatever.
 
iAppearance is the chance that feature will spread (as forests do). The game places any features on terrain as long as the terrain is valid. So int he scrubs place because we set desert as an acceptable terrain the map generator will put them there. If we take that terrain out it wont autoamtically place them and then could place them via our own script or whatever.

I'm sorry but i still do not understand why there is some scrub . iAppearance is the probability (/10000) that the feature generator place some feature on a plot . In fact , if the default SDK function is launched there should not be any forest forest ,jungle or ice . The generic function to place feature is addFeatures in CvMapGeneratorUtil.py :

Spoiler :
Code:
	def addFeaturesAtPlot(self, iX, iY):
		"adds any appropriate features at the plot (iX, iY) where (0,0) is in the SW"
		lat = self.getLatitudeAtPlot(iX, iY)
		pPlot = self.map.sPlot(iX, iY)

		for iI in range(self.gc.getNumFeatureInfos()):
			if pPlot.canHaveFeature(iI):
				if self.mapRand.get(10000, "Add Feature PYTHON") < self.gc.getFeatureInfo(iI).getAppearanceProbability():
					pPlot.setFeatureType(iI, -1)

		if (pPlot.getFeatureType() == FeatureTypes.NO_FEATURE):
			self.addIceAtPlot(pPlot, iX, iY, lat)
			
		if (pPlot.getFeatureType() == FeatureTypes.NO_FEATURE):
			self.addJunglesAtPlot(pPlot, iX, iY, lat)
			
		if (pPlot.getFeatureType() == FeatureTypes.NO_FEATURE):
			self.addForestsAtPlot(pPlot, iX, iY, lat)

As you can see , if you don't tell the process to place a feature , it will not be placed . The chance that a feature spread is based with <iGrowth> like for forest or jungle (in doFeature) . The features like flood plains (with iappearance at 10000 will always be place , oasis with 500 will be placed with a chance of 500/10000) then if there is still no feature , it try to put a forest, jungle or ice .

15 min later ... :)

I've understood now where the scrub are placed ... i've generated a huge map with only 2 players and lots of deserts . The only scrub were near starting locations . This should be normalizeAddExtra that add them thinking this is a good add , but in fact replace some flood plains . This should be great to put <bNoRiver>1</bNoRiver> with scrubs . The simple way to place some would be to put iAppearance to 300-500 like oasis perhaps .

Some other things i've noticed :

_ Sometimes a barbarian city spawn on an unique feature :i've fixed that with CvGamesUtils.cannotFoundCity:

Code:
		iImprovement = pPlot.getImprovementType()
		if iImprovement != -1 :
                        if gc.getImprovementInfo(iImprovement).isUnique() :
                                return True

_ with normalization , a bonus can be added to an unique feature (those that don't spread a bonus) , that would be great to check if the plot don't have an unique improvement in CvPlot::canHaveBonus . This will prevent the game to add some bonus into an unique improvement plot on normalize starting plot functions. But also when you add some bonus during the game like with rite of omega (... not sure of the name) . I've still not wrote the code ,tell me if want me to do it .

Tcho !
 
Ahh, you are absolutly right. I was confusing iApperance and iGrowth. I'll block them from founding by rivers and the block for unique improvements and barb cities as you suggested.
 
Here are the results from my testing over the weekend:

All actual tests using lategame save data did not produce reliable data. It seemed that the code was "remembering" bits of data from the code that was used when the new game started (i.e. errors put in to trigger refered to places and lines that did not exist any longer). Also on my computer I was getting 17 seconds maximum between turns playing marathon, huge, 3 extra civs, living world, no AI building requirements on turns when all civs were at war with at least one other civ. On the upside the tests with the changed FFH code did allow me to find out that the game creates the initial units (and onUnitCreation()) before it runs the onGameStart() code so I got errors for the checks to see if the initial units were elementals or undead. It wasn't a problem onGameLoad()

So, what I did was go a more scientific route and added the following code to the original game:

Spoiler :
def onGameStart(self, argslist):
global inttest
inttest = gc.getInfoTypeForString('PROMOTION_COMBAT1')​

def onBeginGameTurn(self, argslist):
for i in range(0, 9999999):
tempint = gc.getInfoTypeForString('PROMOTION_COMBAT1')
tempint = 1​
When I turn cycled I took lag time readings (spinning globe time) and got a range of 15.10 seconds to 15.56 seconds (although I am by no means a great stopwatch user)

Then I changed the code to this:
Spoiler :
def onGameStart(self, argslist):
global inttest
inttest = gc.getInfoTypeForString('PROMOTION_COMBAT1')​

def onBeginGameTurn(self, argslist):
for i in range(0, 9999999):
tempint = inttest
tempint = 1​
This time I took readings and got a range between 1.35 seconds and 1.9 seconds (again my reflexes are far from perfect, which is why I play CIV rather than any FPS)

From these results it is hard to determine how much overhead is caused by gc calls in the code. Although 10000000 is a large number of times to cycle through the small block of code my laptop doesn't seem to have much of a problem running through all the FFH code on a huge/marathon game running Vista and streaming media to a 360 at the same time. For most machines changing to global variables could have significant gains (or for all I know it could actually slow down the game by having to store too many variables in memory) but it will be hard to get definitive numbers. If someone wants to test the code with a slightly older comp I would be interested in the numbers. Also for some of the most frequently used code (onUnitMove() onUnitKilled() code as well as many of the every turn plot functions maybe although the changelog shows that you moved some of that to the SDK) I don't think it would hurt to make some global variables.
 
The Worker Promotions Thread has a great idea which I want to implement. So any advice on how to add Workrate into the PromotionInfos XML? I know I'll have to change the Schema, and I am confortable with that, but where else will I have to make adjustments?

PromotionInfos (in CvInfos.cpp) will need a new variable to store the tag's value and you'll need to have it read/write it in all the relevant places (easiest way is to find another int value to copy - the screenshot shows where those are for iFirstStrikesChange - you'd just have to add iWorkRateChange in exactly the same places - CodeBlocks doesn't allow you to Copy/Paste the search results - hence the clumsy screenshot).

Then you need to build that into this function in CvUnit.

Code:
int CvUnit::workRate(bool bMax) const
{
	int iRate;

	if (!bMax)
	{
		if (!canMove())
		{
			return 0;
		}
	}

	iRate = m_pUnitInfo->getWorkRate();

	iRate *= std::max(0, (GET_PLAYER(getOwnerINLINE()).getWorkerSpeedModifier() + 100));
	iRate /= 100;

	if (!isHuman() && !isBarbarian())
	{
		iRate *= std::max(0, (GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIWorkRateModifier() + 100));
		iRate /= 100;
	}

	return iRate;
}

You can either check all promotions and work out the work-rate bonus here, or add a variable to CvUnit to store the workrate bonus which is updated when the promotion is added.
 

Attachments

  • IntLocations.png
    IntLocations.png
    7.5 KB · Views: 107
Thanks much for the help Vehem. I'm making my first attempt at it now, hopefully it all goes well.


Another question I had was about the Schema Files: Why aren't all the values just set to MinOccurs = 0? Then the individual XML files could be considerably smaller, and much easier to browse through and change.

EDIT: Having one final problem with my formula. Is this the correct form?
iRate *= (pUnit->getWorkRateChange() + 100);

Using
iRate *= (m_pUnitInfo->getWorkRateChange() + 100);

Gave me an error because getWorkRateChange isn't declared as a part of CvUnitInfo.

EDIT 2: I think I got it now, I changed the initial Definition of the iRate to:
iRate = std::max (0, m_pUnitInfo->getWorkRate() + getWorkRateChange());


It is compiling now at least, so we'll see what other errors I have in there, and if none then attempt to run the dang thing :)

EDIT 3: All compiled now. But is this warning normal? Sure isn't related to what I changed, but might indicate I set things up wrong.

Linking dynamic library: Final Release\CvGameCoreDLL.dll
Creating library Final Release\CvGameCoreDLL.lib and object Final Release\CvGameCoreDLL.exp
LINK : warning LNK4089: all references to 'KERNEL32.dll' discarded by /OPT:REF
Process terminated with status 0 (19 minutes, 11 seconds)
0 errors, 1 warnings

EDIT 4: Whatever the warning was it didn't matter :) Mod works, posting it now.
 
Another question I had was about the Schema Files: Why aren't all the values just set to MinOccurs = 0? Then the individual XML files could be considerably smaller, and much easier to browse through and change.

I've wondered that myself - though a lot of them couldn't be set to that because they need to have some sort of value. Of course - a lot don't...

xienwolf said:
EDIT 3: All compiled now. But is this warning normal? Sure isn't related to what I changed, but might indicate I set things up wrong.

Linking dynamic library: Final Release\CvGameCoreDLL.dll
Creating library Final Release\CvGameCoreDLL.lib and object Final Release\CvGameCoreDLL.exp
LINK : warning LNK4089: all references to 'KERNEL32.dll' discarded by /OPT:REF
Process terminated with status 0 (19 minutes, 11 seconds)
0 errors, 1 warnings

That one is normal - there's no need for Kernel32 to have an entrypoint into CvGameCore as only the Civ4/BtS exe's ever need to use it (Kernel32 is kinda core to Windows and can be used to run code from inside DLLs). I did at one point have it compiling without that warning (in Visual Studio) but the only result was that the DLL was significantly larger.
 
Where is the function that controls the reversion of mana nodes to raw mana when crossing cultures? And how difficult would it be to make that function also remove the improvement on the node that's being reverted?

I poked around (quickly) through the python, but didn't see it anywhere... so I'm guessing it's in the dll?
 
Where is the function that controls the reversion of mana nodes to raw mana when crossing cultures? And how difficult would it be to make that function also remove the improvement on the node that's being reverted?

I poked around (quickly) through the python, but didn't see it anywhere... so I'm guessing it's in the dll?


CvPlot.cpp, in setOwner

Code:
//FfH: Added by Kael 09/01/2007
        if (getBonusType(NO_TEAM) != NO_BONUS)
        {
            if (GC.getBonusInfo((BonusTypes)getBonusType((TeamTypes)NO_TEAM)).getBonusClassType() == GC.getDefineINT("BONUSCLASS_MANA"))
            {
                if (getImprovementType() == NO_IMPROVEMENT || GC.getImprovementInfo((ImprovementTypes)getImprovementType()).isUnique() == false)
                {
                    setBonusType((BonusTypes)GC.getDefineINT("BONUS_MANA"));
                }
            }
        }
//FfH: End Add

Short version - if there is (a) no improvment or (b) a non-unique improvement on a tile with a Bonus of BONUSCLASS_MANA (any mana-type has this class), reset the tile to have the Bonus described as "BONUS_MANA" in the global-defines.

You'd want a setImprovementType here as well, to remove the improvement (possibly checking that the improvment is a mana-related one first)
 
Back
Top Bottom