Homeland promotion help

Cap'nCanuck

Chieftain
Joined
Aug 25, 2010
Messages
5
Location
Vancouver, B.C.
Hey all, if anyone can give me a quick bit of help on my coding of FfH2's Homeland promotion it'd be greatly appreciated. I know I've done something wrong, or perhaps I even misunderstand what the code does, but I just can't think what.

The promotion is supposed to increase the combat attack value within a player's cultural borders if they have the Protective trait (in FfH it was Defender). I've set it up with FfH's code, but it doesn't want to work in game. The promotion shows up fine, but it applies the 20% both in and outside my city's cultural borders, so obviously I've messed up somehow.

Code:
        <PromotionInfo>
            <Type>PROMOTION_HOMELAND</Type>
            <Description>TXT_KEY_PROMOTION_HOMELAND</Description>
            <Civilopedia>TXT_KEY_PROMOTION_HOMELAND_PEDIA</Civilopedia>
            <Sound>AS2D_IF_LEVELUP</Sound>
            <PromotionPrereqOr1>NONE</PromotionPrereqOr1>
            <PromotionPrereqOr2>NONE</PromotionPrereqOr2>
            <PromotionPrereqOr3>NONE</PromotionPrereqOr3>
            <PromotionPrereqOr4>NONE</PromotionPrereqOr4>
            <PromotionPrereqAnd1>NONE</PromotionPrereqAnd1>
            <PromotionPrereqAnd2>NONE</PromotionPrereqAnd2>
            <PromotionNextLevel>NONE</PromotionNextLevel>
            <TechPrereq>NONE</TechPrereq>
            <BonusPrereq>NONE</BonusPrereq>
            <bBlitz>0</bBlitz>
            <bAmphib>0</bAmphib>
            <bRiver>0</bRiver>
            <bEnemyRoute>0</bEnemyRoute>
            <bAlwaysHeal>0</bAlwaysHeal>
            <bHillsDoubleMove>0</bHillsDoubleMove>
            <bImmuneToFirstStrikes>0</bImmuneToFirstStrikes>
            <bInvisible>0</bInvisible>
            <bHiddenNationality>0</bHiddenNationality>
            <iVisibilityChange>0</iVisibilityChange>
            <iMovesChange>0</iMovesChange>
            <iMoveDiscountChange>0</iMoveDiscountChange>
            <iWithdrawalChange>15</iWithdrawalChange>
            <iCollateralDamageChange>0</iCollateralDamageChange>
            <iBombardRateChange>0</iBombardRateChange>
            <iFirstStrikesChange>0</iFirstStrikesChange>
            <iChanceFirstStrikesChange>0</iChanceFirstStrikesChange>
            <iEnemyHealChange>0</iEnemyHealChange>
            <iNeutralHealChange>0</iNeutralHealChange>
            <iFriendlyHealChange>0</iFriendlyHealChange>
            <iSameTileHealChange>0</iSameTileHealChange>
            <iAdjacentTileHealChange>0</iAdjacentTileHealChange>
            <iCombatPercent>15</iCombatPercent>
            <iCombatPercentDefense>15</iCombatPercentDefense>
            <iExtraCombatStr>0</iExtraCombatStr>
            <iCityAttack>0</iCityAttack>
            <iCityDefense>0</iCityDefense>
            <iHillsDefense>0</iHillsDefense>
            <iCargo>0</iCargo>
            <iAIWeight>0</iAIWeight>
            <iCombatCold>0</iCombatCold>
            <iCombatDeath>0</iCombatDeath>
            <iCombatFire>0</iCombatFire>
            <iCombatHoly>0</iCombatHoly>
            <iCombatLightning>0</iCombatLightning>
            <iCombatPoison>0</iCombatPoison>
            <iCombatUnholy>0</iCombatUnholy>
            <iResistCold>0</iResistCold>
            <iResistDeath>0</iResistDeath>
            <iResistFire>0</iResistFire>
            <iResistHoly>0</iResistHoly>
            <iResistLightning>0</iResistLightning>
            <iResistPoison>0</iResistPoison>
            <iResistUnholy>0</iResistUnholy>
            <TerrainDefenses>
            </TerrainDefenses>
            <FeatureDefenses>
            </FeatureDefenses>
            <SpellTypeFlatMods>
            </SpellTypeFlatMods>
            <SpellTypePercentMods>
            </SpellTypePercentMods>
            <UnitCombatMods>
            </UnitCombatMods>
            <PromotionCombatType>NONE</PromotionCombatType>
            <iPromotionCombatMod>0</iPromotionCombatMod>
            <DomainMods>
            </DomainMods>
            <TerrainDoubleMoves>
            </TerrainDoubleMoves>
            <FeatureDoubleMoves>
            </FeatureDoubleMoves>
            <UnitCombats>
            </UnitCombats>
            <HotKey></HotKey>
            <bAltDown>0</bAltDown>
            <bShiftDown>0</bShiftDown>
            <bCtrlDown>0</bCtrlDown>
            <iHotKeyPriority>0</iHotKeyPriority>
            <Button>Art/Interface/Buttons/Promotions/Homeland.dds</Button>
        </PromotionInfo>

Code:
    def onUnitMove(self, argsList):
        'unit move'
        pPlot,pUnit,pOldPlot = argsList
        player = PyPlayer(pUnit.getOwner())
        unitInfo = PyInfo.UnitInfo(pUnit.getUnitType())
        if (not self.__LOG_MOVEMENT):
            return
        if player and unitInfo:
            CvUtil.pyPrint('Player %d Civilization %s unit %s is moving to %d, %d' 
                %(player.getID(), player.getCivilizationName(), unitInfo.getDescription(), 
                pUnit.getX(), pUnit.getY()))
    
        pUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), False)
        if pPlot.isOwned():
            if (pPlayer.hasTrait(gc.getInfoTypeForString('TRAIT_PROTECTIVE')) and pPlot.getOwner() == pUnit.getOwner()):
                if (pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MELEE') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_RECON') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ARCHER') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MOUNTED') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_DISCIPLE')):
                    pUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), True)

Code:
        pUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), False)
        if pPlot.isOwned():
            if (pPlayer.hasTrait(gc.getInfoTypeForString('TRAIT_DEFENDER')) and pPlot.getOwner() == pUnit.getOwner()):
                if (pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MELEE') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_RECON') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ARCHER') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MOUNTED') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_DISCIPLE')):
                    pUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), True)

I included my Homeland promotion at the top, the code I put in the OnUnit in Python (top bit is superfluous but maybe I missed a space) and FfH's version in the third. Any help is much appreciated. These are the only steps I did and I totally don't know what I'm doing with Python, I just kind of hoped a copy-and-paste would suffice: so if I need to do something else well I guess point me in the right direction. This is the only Python change I'm making in a brief alternate traits mod I want to play around with.
 
Have you enabled Python exceptions in the CivilizationIV.ini file? Because one single typo or anything else causing a syntax error (like messed up indentation) will make all Python code cease to work. This can cause all sorts of unexpected results in-game...

Other than that, try to add the code related to your promotion before the other code (printing out debug data). Because there is a conditional statement that will exit the onUnitMove() method under certain circumstances - and this line is located before your code. So it could potentially cause your code not to be fired at all.
Code:
def onUnitMove(self, argsList):
        'unit move'
        pPlot,pUnit,pOldPlot = argsList

        pUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), False)
        if pPlot.isOwned():
            if (pPlayer.hasTrait(gc.getInfoTypeForString('TRAIT_PROTECTIVE')) and pPlot.getOwner() == pUnit.getOwner()):
                if (pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MELEE') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_RECON') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ARCHER') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MOUNTED') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_DISCIPLE')):
                    pUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), True)

        player = PyPlayer(pUnit.getOwner())
        unitInfo = PyInfo.UnitInfo(pUnit.getUnitType())
[B]        if (not self.__LOG_MOVEMENT):
            return[/B]
        if player and unitInfo:
            CvUtil.pyPrint('Player %d Civilization %s unit %s is moving to %d, %d' 
                %(player.getID(), player.getCivilizationName(), unitInfo.getDescription(), 
                pUnit.getX(), pUnit.getY()))
Spoiler :
Also, the ridiculously long if statement could either be expressed on multiple lines:
Code:
                if (pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MELEE') \
                    or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_RECON') \
                    or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ARCHER') \
                    or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MOUNTED') \
                    or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_DISCIPLE')):
Or it could be shorted down:
Code:
                if pUnit.getUnitCombatType() in [gc.getInfoTypeForString('UNITCOMBAT_MELEE'), gc.getInfoTypeForString('UNITCOMBAT_RECON'), gc.getInfoTypeForString('UNITCOMBAT_ARCHER'), gc.getInfoTypeForString('UNITCOMBAT_MOUNTED'), gc.getInfoTypeForString('UNITCOMBAT_DISCIPLE')]:
And this would also be valid:
Code:
                if pUnit.getUnitCombatType() in [UnitCombatTypes.UNITCOMBAT_MELEE,
                                                 UnitCombatTypes.UNITCOMBAT_RECON,
                                                 UnitCombatTypes.UNITCOMBAT_ARCHER,
                                                 UnitCombatTypes.UNITCOMBAT_MOUNTED,
                                                 UnitCombatTypes.UNITCOMBAT_DISCIPLE]:
But the advanced option would probably be:
Code:
tHomelandCombatTypes = ("Melee", "Recon", "Archer", "Mounted", "Disciple")
lHomelandCombatTypes = list(gc.getInfoTypeForString("UNITCOMBAT_" + string.upper()) for string in tHomelandCombatTypes)
...
                if pUnit.getUnitCombatType() in lHomelandCombatTypes:
Yeah, now I'm just showing off. :p (And anytime soon some real programmer type will arrive to correct all my mistakes. :lol:)
 
Besides what Baldyr mentioned:
PHP:
pPlayer.hasTrait [etc]

pPlayer is not defined, as far as i can see.
A simple pPlayer = gc.getPlayer(pUnit.getOwner()) in the line before should fix it.


Oh, and you're talking about 20%, but the XML says 15%.
 
pPlayer is not defined, as far as i can see.
A simple pPlayer = gc.getPlayer(pUnit.getOwner()) in the line before should fix it.
Well spotted! This is where enabling Python exceptions comes handy.
 
Based on what's been said, this should be it:

Code:
    def onUnitMove(self, argsList):
        'unit move'
        pPlot,pUnit,pOldPlot = argsList
        pPlayer = PyPlayer(pUnit.getOwner())
        unitInfo = PyInfo.UnitInfo(pUnit.getUnitType())
    
        pUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), False)
        if pPlot.isOwned():
            if (pPlayer.hasTrait(gc.getInfoTypeForString('TRAIT_PROTECTIVE')) and pPlot.getOwner() == pUnit.getOwner()):
                if (pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MELEE') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_RECON') or pUnit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ARCHER'):
                    pUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), True)
 
I think similar code should be attached to onUnitCreated and onUnitBuilt to give the promotion to newly created cq built units. Something like this seems to work properly:
Code:
	def onUnitCreated(self, argsList):
		'Unit Completed'
		unit = argsList[0]
		player = PyPlayer(unit.getOwner())
## HOMELAND PROMOTION START ##
		pPlayer = gc.getPlayer(unit.getOwner())
		unitInfo = PyInfo.UnitInfo(unit.getUnitType())

		unit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), False)
		if pPlayer.hasTrait(gc.getInfoTypeForString('TRAIT_PROTECTIVE')):
				if (unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MELEE') \
					or unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_RECON') \
					or unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ARCHER') \
					or unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MOUNTED')):
						unit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), True)
## HOMELAND PROMOTION END ##

		if (not self.__LOG_UNITBUILD):
			return

	def onUnitBuilt(self, argsList):
		'Unit Completed'
		city = argsList[0]
		unit = argsList[1]
		player = PyPlayer(city.getOwner())
## HOMELAND PROMOTION START ##
		pPlayer = gc.getPlayer(unit.getOwner())
		unitInfo = PyInfo.UnitInfo(unit.getUnitType())

		CvAdvisorUtils.unitBuiltFeats(city, unit)

		unit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), False)
		if pPlayer.hasTrait(gc.getInfoTypeForString('TRAIT_PROTECTIVE')):
			if (unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MELEE') \
				or unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_RECON') \
				or unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ARCHER') \
				or unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MOUNTED')):
					unit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HOMELAND'), True)
## HOMELAND PROMOTION END ##
		
		if (not self.__LOG_UNITBUILD):
			return
		CvUtil.pyPrint('%s was finished by Player %d Civilization %s' 
			%(PyInfo.UnitInfo(unit.getUnitType()).getDescription(), player.getID(), player.getCivilizationName()))
 
Back
Top Bottom