# Final Frontier
# Civilization 4 (c) 2007 Firaxis Games
# Designed & Programmed by: Jon 'Trip' Shafer
from CvPythonExtensions import *
import CvUtil
import CvEventInterface
import PyHelpers
from CvSolarSystem import printd
import CvSolarSystem
import CvAI
# globals
gc = CyGlobalContext()
localText = CyTranslator()
class FFGameUtils:
"Miscellaneous game functions"
def __init__(self):
self.dBuildingBonuses = { gc.getInfoTypeForString("BUILDING_FARM") : gc.getInfoTypeForString("BONUS_WHEAT"),
gc.getInfoTypeForString("BUILDING_RANCH") : gc.getInfoTypeForString("BONUS_COW"),
gc.getInfoTypeForString("BUILDING_HARBOR") : gc.getInfoTypeForString("BONUS_FISH"),
gc.getInfoTypeForString("BUILDING_PLANTATION") : gc.getInfoTypeForString("BONUS_SPICES"),
gc.getInfoTypeForString("BUILDING_WINERY") : gc.getInfoTypeForString("BONUS_WINE"),
gc.getInfoTypeForString("BUILDING_COTTONMILL") : gc.getInfoTypeForString("BONUS_COTTON")}
def isVictoryTest(self):
return True #Don't check for starting settlers- there aren't any!
def isVictory(self, argsList):
eVictory = argsList[0]
return True
def isPlayerResearch(self, argsList):
ePlayer = argsList[0]
return True
def getExtraCost(self, argsList):
ePlayer = argsList[0]
return 0
def createBarbarianCities(self):
return False
def createBarbarianUnits(self):
return False
def skipResearchPopup(self,argsList):
ePlayer = argsList[0]
return False
def showTechChooserButton(self,argsList):
ePlayer = argsList[0]
return True
def getFirstRecommendedTech(self,argsList):
ePlayer = argsList[0]
return TechTypes.NO_TECH
def getSecondRecommendedTech(self,argsList):
ePlayer = argsList[0]
eFirstTech = argsList[1]
return TechTypes.NO_TECH
def canRazeCity(self,argsList):
iRazingPlayer, pCity = argsList
return True
def canDeclareWar(self,argsList):
iAttackingTeam, iDefendingTeam = argsList
return True
def skipProductionPopup(self,argsList):
pCity = argsList[0]
return False
def showExamineCityButton(self,argsList):
pCity = argsList[0]
return True
def getRecommendedUnit(self,argsList):
pCity = argsList[0]
return UnitTypes.NO_UNIT
def getRecommendedBuilding(self,argsList):
pCity = argsList[0]
return BuildingTypes.NO_BUILDING
def updateColoredPlots(self):
return False
def isActionRecommended(self,argsList):
pUnit = argsList[0]
iAction = argsList[1]
return False
def unitCannotMoveInto(self,argsList):
ePlayer = argsList[0]
iUnitId = argsList[1]
iPlotX = argsList[2]
iPlotY = argsList[3]
return False
def cannotHandleAction(self,argsList):
pPlot = argsList[0]
iAction = argsList[1]
bTestVisible = argsList[2]
return False
def canBuild(self,argsList):
iX, iY, iBuild, iPlayer = argsList
return -1 # Returning -1 means ignore; 0 means Build cannot be performed; 1 or greater means it can
def cannotFoundCity(self,argsList):
iPlayer, iPlotX, iPlotY = argsList
return False
def cannotSelectionListMove(self,argsList):
pPlot = argsList[0]
bAlt = argsList[1]
bShift = argsList[2]
bCtrl = argsList[3]
return False
def cannotSelectionListGameNetMessage(self,argsList):
eMessage = argsList[0]
iData2 = argsList[1]
iData3 = argsList[2]
iData4 = argsList[3]
iFlags = argsList[4]
bAlt = argsList[5]
bShift = argsList[6]
return False
def cannotDoControl(self,argsList):
eControl = argsList[0]
return False
def canResearch(self,argsList):
ePlayer = argsList[0]
eTech = argsList[1]
bTrade = argsList[2]
return False
def cannotResearch(self,argsList):
ePlayer = argsList[0]
eTech = argsList[1]
bTrade = argsList[2]
return False
def canDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
return False
def cannotDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
return False
def canTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
def canConstruct(self,argsList):
pCity = argsList[0]
eBuilding = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
return False
def cannotConstruct(self,argsList):
pCity = argsList[0]
eBuilding = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
# CP - validate eBuilding (I don't know why this is needed - if it is calling this with an
# invalid building code then something in the caller is broken)
if (eBuilding < 0):
CvSolarSystem.printd("CvGameUtils.cannotConstruct, passed eBuilding < 0 (%d)" % (eBuilding) )
return True
#FinalFrontier = CvEventInterface.getEventManager().FinalFrontier #FFPBUG
pSystem = CvSolarSystem.getSystemAt(pCity.getX(), pCity.getY()) #FFPBUG
pPlanet = pSystem.getPlanet(pSystem.getBuildingPlanetRing())
pCivilization = gc.getCivilizationInfo( gc.getPlayer(pCity.getOwner()).getCivilizationType())
bNotHere = False
pBuildingInfo = gc.getBuildingInfo(eBuilding)
# Cannot build a building if it already exists on the currently "Building" Planet
if (pPlanet):
if (pPlanet.isHasBuilding(eBuilding)):
bNotHere = True
else:
return True # this should never happen
#Moon and Rings restrictors moved to XML tags: TC01
if (pBuildingInfo.isMoon()) and (not pPlanet.isMoon()):
bNotHere = true
if (pBuildingInfo.isRings()) and (not pPlanet.isRings()):
bNotHere = true
if (eBuilding in self.dBuildingBonuses):
if not pPlanet.isBonus():
bNotHere = True
elif (pPlanet.getBonusType() != self.dBuildingBonuses[eBuilding]):
# the planet has a bonus, but it is the wrong one - since there can be only one bonus in a system
# and we know it has the wrong one, theis building can not be built anywhere in this system
return True
# On a disabled planet we can only build nuke immune buildings
if (not pBuildingInfo.isNukeImmune()) and pPlanet.isDisabled():
bNotHere = True
# Prereqs are required for the Planet
for iNeededBuildingClassLoop in range(gc.getNumBuildingClassInfos()):
if (pBuildingInfo.isBuildingClassNeededOnPlanet(iNeededBuildingClassLoop)):
iNeededBuildingLoop = pCivilization.getCivilizationBuildings(iNeededBuildingClassLoop )
if (not pPlanet.isHasBuilding(iNeededBuildingLoop)):
bNotHere = True
break
# CP - now for the "if we can't build it here, try it on some other planet in the system" upgrade.
# This is the core functionality of the improvement, and is all new.
# Skip if this if this is for a player, not an AI.
#
# Note: I'm not positive that this is working properly. If the AI ever calls this function when
# the build queue is not empty, then it can change the current build planet out from under whatever
# is currently being built, possibly continuing to build the thing currently in the queue on an
# invalid planet (such as one that already has the building, or that does not have a prereq building
# on it). So far I have not seen any mysterious bad behavior, but I can't be certain.
if bNotHere and (not gc.getPlayer(pCity.getOwner()).isHuman()):
for iPlanetLoop in range(pSystem.getNumPlanets()):
pLoopPlanet = pSystem.getPlanetByIndex(iPlanetLoop)
if (pLoopPlanet != pPlanet) and (pLoopPlanet.isPlanetWithinCulturalRange()) :
# skip the planet we are already using and planets not in the cultural range
if (pBuildingInfo.isMoon()) and (not pLoopPlanet.isMoon()):
continue
if (pBuildingInfo.isRings()) and (not pLoopPlanet.isRings()):
continue
if (pLoopPlanet.isHasBuilding(eBuilding)):
continue # already has one here, skip rest of loop
if (eBuilding in self.dBuildingBonuses):
if not pPlanet.isBonus():
# planet does not have bonus but one is required by this building
continue
elif (pPlanet.getBonusType() != self.dBuildingBonuses[eBuilding]):
# the planet has a bonus, but it is the wrong one - since there can be only one bonus in a system
# and we know it has the wrong one, this building can not be built anywhere in this system
return True
if (not pBuildingInfo.isNukeImmune()) and pLoopPlanet.isDisabled():
continue
hasPrereq = True
for iNeededBuildingClassLoop in range(gc.getNumBuildingClassInfos()):
if (pBuildingInfo.isBuildingClassNeededInCity(iNeededBuildingClassLoop)):
iNeededBuildingLoop = pCivilization.getCivilizationBuildings(iNeededBuildingClassLoop ) # get this civilization's building for this buildingclass
if (not pLoopPlanet.isHasBuilding(iNeededBuildingLoop)):
hasPrereq = False
break # one missing prereq is all that has to happen so skip checking for more
# If we get here with hasPrereq == True then we are at a planet that is
# not the one we started with, is within the cultural/influence range,
# does not already have a building of this type, and does have all prereq buildings.
# At this point we may, in the furture, want to add some additional checks, in particular
# we may want to check if the planet has any population assigned to it and skip if if
# it doesn't but the building type is one of the ones that modifies the planet's yield
# (which gains you nothing if the planet has no people on it). At the moment I'm not doing
# this because it may work fine without it - when the system's population assignments are
# recalculated it may shift people to the planet after the improvement is done.
# Also, we may want to add the planet to a list and then do some sort of selection
# process to determine which of the possible planets to use - for now, this is just
# using the first planet that it finds.
if (hasPrereq == True) :
bNotHere = False # don't block the build
if (not bTestVisible) : # only actually change the ring if not just testing "visibility"
pSystem.setBuildingPlanetRing(pLoopPlanet.getOrbitRing()) # switch to this new planet
CvSolarSystem.printd("CvGameUtils.cannotConstruct, %s active planet ring set to %d (turn = %d, owner = %s, building = %s, bContinue = %d, bTestVisible = %d)" % (pCity.getName(), pLoopPlanet.getOrbitRing(), CyGame().getElapsedGameTurns(), gc.getPlayer(pCity.getOwner()).getName(), pBuildingInfo.getType(), bContinue, bTestVisible) )
else:
CvSolarSystem.printd("CvGameUtils.cannotConstruct, %s active planet ring not set, bTestVisible = true (turn = %d, owner = %s, building = %s, bContinue = %d, bTestVisible = %d)" % (pCity.getName(), CyGame().getElapsedGameTurns(), gc.getPlayer(pCity.getOwner()).getName(), pBuildingInfo.getType(), bContinue, bTestVisible) )
break # we have done what we needed to do, bail out of the loop entirely
return bNotHere
def canCreate(self,argsList):
pCity = argsList[0]
eProject = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
def cannotCreate(self,argsList):
pCity = argsList[0]
eProject = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
def canMaintain(self,argsList):
pCity = argsList[0]
eProcess = argsList[1]
bContinue = argsList[2]
return False
def cannotMaintain(self,argsList):
pCity = argsList[0]
eProcess = argsList[1]
bContinue = argsList[2]
return False
def AI_chooseTech(self,argsList):
ePlayer = argsList[0]
bFree = argsList[1]
return TechTypes.NO_TECH
def AI_chooseProduction(self,argsList):
pCity = argsList[0]
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
bOverride = FinalFrontier.getAI().doCityAIProduction(pCity)
return bOverride
def AI_unitUpdate(self,argsList):
pUnit = argsList[0]
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
bOverride = false
# Only do it for actual AI units, not automated human ones
pPlayer = gc.getPlayer(pUnit.getOwner())
if (not pPlayer.isHuman()) and (not pPlayer.isBarbarian()) and pPlayer.isAlive() and (not pUnit.isNone()) and (not pUnit.isDead()):
iConstructShip = gc.getInfoTypeForString(gc.getDefineSTRING("CONSTRUCT_SHIP"))
if (pUnit.getUnitClassType() == iConstructShip):
bOverride = FinalFrontier.getAI().doConstructionShipAI(pUnit)
return bOverride
def AI_doWar(self,argsList):
eTeam = argsList[0]
return False
def AI_doDiplo(self,argsList):
ePlayer = argsList[0]
return False
def calculateScore(self,argsList):
ePlayer = argsList[0]
bFinal = argsList[1]
bVictory = argsList[2]
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
iMaxPopulation = FinalFrontier.iMaxPopulation
iPopulationScore = CvUtil.getScoreComponent(gc.getPlayer(ePlayer).getPopScore(), gc.getGame().getInitPopulation(), iMaxPopulation, gc.getDefineINT("SCORE_POPULATION_FACTOR"), True, bFinal, bVictory)
printd("Pop Score Stuff")
printd(gc.getPlayer(ePlayer).getPopScore())
printd(gc.getGame().getInitPopulation())
printd(iMaxPopulation)
printd(iPopulationScore)
iPlayerLandScore = gc.getPlayer(ePlayer).getTotalLand()
iLandScore = CvUtil.getScoreComponent(iPlayerLandScore , gc.getGame().getInitLand(), gc.getGame().getMaxLand(), gc.getDefineINT("SCORE_LAND_FACTOR"), True, bFinal, bVictory)
printd("Land Score Stuff")
printd(iPlayerLandScore)
printd(gc.getGame().getInitLand())
printd(gc.getGame().getMaxLand())
printd(iLandScore)
iTechScore = CvUtil.getScoreComponent(gc.getPlayer(ePlayer).getTechScore(), gc.getGame().getInitTech(), gc.getGame().getMaxTech(), gc.getDefineINT("SCORE_TECH_FACTOR"), True, bFinal, bVictory)
iWondersScore = CvUtil.getScoreComponent(gc.getPlayer(ePlayer).getWondersScore(), gc.getGame().getInitWonders(), gc.getGame().getMaxWonders(), gc.getDefineINT("SCORE_WONDER_FACTOR"), False, bFinal, bVictory)
iTotalScore = int(iLandScore + iWondersScore + iTechScore + iPopulationScore)
printd("Player %d Score: %d Pop: %d Land: %d Tech: %d Wonders: %d" %(ePlayer, iTotalScore, iPopulationScore, iLandScore, iTechScore, iWondersScore))
return iTotalScore
def doHolyCity(self):
return False
def doHolyCityTech(self,argsList):
eTeam = argsList[0]
ePlayer = argsList[1]
eTech = argsList[2]
bFirst = argsList[3]
return False
def doGold(self,argsList):
ePlayer = argsList[0]
return False
def doResearch(self,argsList):
ePlayer = argsList[0]
return False
def doGoody(self,argsList):
ePlayer = argsList[0]
pPlot = argsList[1]
pUnit = argsList[2]
return False
def doGrowth(self,argsList):
pCity = argsList[0]
return False
def doProduction(self,argsList):
pCity = argsList[0]
return False
def doCulture(self,argsList):
pCity = argsList[0]
return False
def doPlotCulture(self,argsList):
pCity = argsList[0]
bUpdate = argsList[1]
return False
def doReligion(self,argsList):
pCity = argsList[0]
return False
def cannotSpreadReligion(self,argsList):
iOwner, iUnitID, iReligion, iX, iY = argsList[0]
return False
def doGreatPeople(self,argsList):
pCity = argsList[0]
return False
def doMeltdown(self,argsList):
pCity = argsList[0]
pSystem = CvSolarSystem.getSystemAt(pCity.getX(), pCity.getY())
iMeltPlanet = -1
# check to see if there is a meltdown
for iBuilding in range(gc.getNumBuildingInfos()):
if pCity.getNumBuilding(iBuilding) > 0 :
iBuildingNukeExRand = gc.getBuildingInfo(iBuilding).getNukeExplosionRand()
if iBuildingNukeExRand != 0 :
if CyGame().getSorenRandNum(iBuildingNukeExRand, "FFP: meltdown check in doMeltdown callback") == 0 :
# a building has had a meltdown, check planets for buildings of this type and pick one
lPlanets = []
for iPlanet in range(pSystem.getNumPlanets()):
pPlanet = pSystem.getPlanetByIndex(iPlanet)
if pPlanet.isHasBuilding(iBuilding) :
lPlanets.append(pPlanet)
iMeltPlanet = CyGame().getSorenRandNum(len(lPlanets), "FPP: meltdown planet")
pMeltPlanet = lPlanets[iMeltPlanet]
# for the sake of simplicity, have it so that no star system will get more than one meltdown in a turn
break # break out of building loop
if iMeltPlanet == -1 :
# no meltdown so exit now (always return True to avoid DLL's meltdown processing)
return True
pPlayer = gc.getPlayer(pCity.getOwner()) # defined now since we don't need it above
pCityPlot = pCity.plot()
# Meltdown effects (same as nuke effects, but applied to meltdown planet instead of best planet)
# 1) set the planet to be disabled
# 2) remove all buildings from the now dead planet, dealing with capitol if on this planet
# 3) if thre was a bonus on the planet, remove it from planet and plot
# 4) chance of specified feature being distributed around system
# 5) unit damage (possibly killed)
# 6) population reduction
# 1) disable
pMeltPlanet.setDisabled(true)
pMeltPlanet.setPopulation(0)
# 2) remove buildings
for iBuilding in range(gc.getNumBuildingInfos()):
if pMeltPlanet.isHasBuilding(iBuilding) and not gc.getBuildingInfo(iBuilding).isNukeImmune():
bRemove = True
if (gc.getBuildingInfo(iBuilding).isCapital()):
if (pPlayer.getNumCities () > 1):
# The following call moves the capitol building, removing it from this city's data
# in the DLL (which is why there is no manual setNumRealBuilding in here)
# and adding it to the new capital city's data in the DLL plus adding it to that system's
# current build planet to get it into the Python planet data.
printd("Meltdown: finding new capial system")
pPlayer.findNewCapital()
else:
# This is this civ's only system so we can't move the capitol building to a different one.
# Try to move it to a different planet instead.
printd("Meltdown: moving capitol to different planet in same system")
# Select the planet that is the largest population limit planet
# (using production as tie breaker) that is not the planet being wiped out
bRemove = False
aiPlanetList = pSystem.getSizeYieldPlanetIndexList(1) # 1 is production, arbitrarily selected
for iLoopPlanet in range( len(aiPlanetList)):
pLoopPlanet = pSystem.getPlanetByIndex(aiPlanetList[iLoopPlanet][2])
if (pLoopPlanet.getOrbitRing() != pMeltPlanet.getOrbitRing()):
pLoopPlanet.setHasBuilding(iBuilding, true)
printd("Meltdown: moved Capitol to planet at ring %d" % pLoopPlanet.getOrbitRing())
bRemove = True
break
else:
pCity.setNumRealBuilding(iBuilding, pCity.getNumRealBuilding(iBuilding)-1)
if bRemove :
# The only time this is not the case is when it is the capitol and there is no other
# planet it can be moved to. You always need a Capitol, so it stays on the dead planet
pMeltPlanet.setHasBuilding(iBuilding, false)
# 2.5) unlisted above, but here anyway
if (pSystem.getBuildingPlanetRing() == pMeltPlanet.getOrbitRing()):
# This system's current build planet is the planet being wiped out,
# change it to some other planet, like the new "best" planet.
# There is an issue if every planet in the current infuence range is dead -
# in such a case there is no planet that should be having things built on it.
# With any luck, this will never come up.
pSystem.setBuildingPlanetRing(pSystem.getPlanetByIndex(CvSolarSystem.getBestPlanetInSystem(pSystem)).getOrbitRing())
# 3) remove bonus
if (pMeltPlanet.isBonus()): # planet being melted has a bonus, remove it from the planet and the plot
pMeltPlanet.setBonusType(-1)
pCityPlot.setBonusType(-1)
# 4) feature spread
for iDX in range(-1, 2) :
for iDY in range (-1, 2) :
if (iDX != 0) and (iDY != 0) :
pPlot = plotXY( pCity.getX(), pCity.getY(), iDX, iDY)
if pPlot and not pPlot.isNone():
if not pPlot.isImpassable() and (FeatureTypes.NO_FEATURE == pPlot.getFeatureType()) :
if (CyGame().getSorenRandNum(100, "Meltdown Fallout") < gc.getDefineINT("NUKE_FALLOUT_PROB")) :
pPlot.setImprovementType(ImprovementTypes.NO_IMPROVEMENT)
pPlot.setFeatureType(gc.getDefineINT("NUKE_FEATURE"), 0)
# 5) unit damage - only check units on this plot!
lUnit = []
for i in range(pCityPlot.getNumUnits()):
pLoopUnit = pCityPlot.getUnit(i)
if ( not pLoopUnit.isDead()): #is the unit alive?
lUnit.append(pLoopUnit) #add unit instance to list
for pUnit in lUnit :
if not pUnit.isDead() and not pUnit.isNukeImmune() :
iNukeDamage = gc.getDefineINT("NUKE_UNIT_DAMAGE_BASE") + CyGame().getSorenRandNum(gc.getDefineINT("NUKE_UNIT_DAMAGE_RAND_1"), "Nuke Damage 1") + CyGame().getSorenRandNum(gc.getDefineINT("NUKE_UNIT_DAMAGE_RAND_2"), "Nuke Damage 2")
iNukeDamage *= max(0, (pCity.getNukeModifier() + 100))
iNukeDamage /= 100
if pUnit.canFight() or (pUnit.airBaseCombatStr() > 0) :
printd("Meltdown: unit %s damaged for %d" % (pUnit.getName().encode('unicode_escape'), iNukeDamage))
pUnit.changeDamage(iNukeDamage, PlayerTypes.NO_PLAYER)
elif iNukeDamage >= gc.getDefineINT("NUKE_NON_COMBAT_DEATH_THRESHOLD") :
printd("Meltdown: non-combat unit %s killed from damage over threshold" % (pUnit.getName().encode('unicode_escape'),))
pUnit.kill(false, PlayerTypes.NO_PLAYER)
# 6) population reduction
iNukedPopulation = (pCity.getPopulation() * (gc.getDefineINT("NUKE_POPULATION_DEATH_BASE") + CyGame().getSorenRandNum(gc.getDefineINT("NUKE_POPULATION_DEATH_RAND_1"), "Population Nuked 1") + CyGame().getSorenRandNum(gc.getDefineINT("NUKE_POPULATION_DEATH_RAND_2"), "Population Nuked 2"))) / 100
iNukedPopulation *= max(0, (pCity.getNukeModifier() + 100))
iNukedPopulation /= 100
pCity.changePopulation(-(min((pCity.getPopulation() - 1), iNukedPopulation)))
# Now update the city and display
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
FinalFrontier.getAI().doCityAIUpdate(pCity)
pSystem.updateDisplay()
# give message that this has happened
szBuffer = localText.getText("TXT_KEY_MISC_MELTDOWN_CITY", (pCity.getName(),))
CyInterface().addMessage( pCity.getOwner(), False, gc.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer,
"AS2D_MELTDOWN", InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
CyArtFileMgr().getInterfaceArtInfo("INTERFACE_UNHEALTHY_PERSON").getPath(), gc.getInfoTypeForString("COLOR_RED"),
pCity.getX(), pCity.getY(), True, True)
return True
def doReviveActivePlayer(self,argsList):
"allows you to perform an action after an AIAutoPlay"
iPlayer = argsList[0]
return False
def doPillageGold(self, argsList):
"controls the gold result of pillaging"
pPlot = argsList[0]
pUnit = argsList[1]
iPillageGold = 0
iPillageGold = CyGame().getSorenRandNum(gc.getImprovementInfo(pPlot.getImprovementType()).getPillageGold(), "Pillage Gold 1")
iPillageGold += CyGame().getSorenRandNum(gc.getImprovementInfo(pPlot.getImprovementType()).getPillageGold(), "Pillage Gold 2")
iPillageGold += (pUnit.getPillageChange() * iPillageGold) / 100
return iPillageGold
def doCityCaptureGold(self, argsList):
"controls the gold result of capturing a city"
pOldCity = argsList[0]
iCaptureGold = 0
iCaptureGold += gc.getDefineINT("BASE_CAPTURE_GOLD")
iCaptureGold += (pOldCity.getPopulation() * gc.getDefineINT("CAPTURE_GOLD_PER_POPULATION"))
iCaptureGold += CyGame().getSorenRandNum(gc.getDefineINT("CAPTURE_GOLD_RAND1"), "Capture Gold 1")
iCaptureGold += CyGame().getSorenRandNum(gc.getDefineINT("CAPTURE_GOLD_RAND2"), "Capture Gold 2")
if (gc.getDefineINT("CAPTURE_GOLD_MAX_TURNS") > 0):
iCaptureGold *= cyIntRange((CyGame().getGameTurn() - pOldCity.getGameTurnAcquired()), 0, gc.getDefineINT("CAPTURE_GOLD_MAX_TURNS"))
iCaptureGold /= gc.getDefineINT("CAPTURE_GOLD_MAX_TURNS")
return iCaptureGold
def citiesDestroyFeatures(self,argsList):
iX, iY= argsList
return False
def canFoundCitiesOnWater(self,argsList):
iX, iY= argsList
return True
def doCombat(self,argsList):
pSelectionGroup, pDestPlot = argsList
return False
def getConscriptUnitType(self, argsList):
iPlayer = argsList[0]
iConscriptUnitType = -1 #return this with the value of the UNIT TYPE you want to be conscripted
return iConscriptUnitType
def getCityFoundValue(self, argsList):
iPlayer, iPlotX, iPlotY = argsList
iFoundValue = -1 # Any value besides -1 will be used
pPlot = CyMap().plot(iPlotX, iPlotY)
iFeatureIDSolarSystem = gc.getInfoTypeForString('FEATURE_SOLAR_SYSTEM')
if (pPlot.getFeatureType() == iFeatureIDSolarSystem and not pPlot.isCity()):
printd("Determing Found Value for Plot at %d, %d" %(iPlotX, iPlotY))
# CP - Adjust base value based on path distance from capital (not straight line distance)
pCapCity = gc.getPlayer(iPlayer).getCapitalCity()
if pCapCity and not pCapCity.isNone() :
iDistance = CyMap().calculatePathDistance(pCapCity.plot(), pPlot)
if iDistance == -1 : # can't get there from here
return 0
else : # no capital city, - would normally mean first city not founded yet, I suppose.
iDistance = 1
iFoundValue = 10000 / (iDistance + 1) # CP - this provides only a small distance penalty
# Determine System value by planetary composition
if (CyGame().getElapsedGameTurns() > 0):
#iFoundValue = 0
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
pSystem = CvSolarSystem.getSystemAt(iPlotX, iPlotY) #FFPBUG
for iPlanetLoop in range(pSystem.getNumPlanets()):
pPlanet = pSystem.getPlanetByIndex(iPlanetLoop)
iPlanetValue = 0
# Green Planet
if (pPlanet.getPlanetType() == CvSolarSystem.iPlanetTypeGreen):
iPlanetValue = 400
# Not Green Planet
else:
iPlanetValue = 200
# CP - Give some value to planetary resources (God-Emperor, for version 1.6)
if (pPlanet.isBonus()):
iPlanetValue += 100 # This may need adjusting
# Two Civ-specific increase to this.
# The Forge gets -1 food in each system, so extra food is good for them meaning +50 for the resources that give extra food
# Trade routes are very good for the Red Syndicate, so +50 for each trade route
iTraitForge = gc.getInfoTypeForString('TRAIT_THE_FORGE')
iTraitSyndicate = gc.getInfoTypeForString('TRAIT_SYNDICATE')
pPlayer = gc.getPlayer(iPlayer)
pBonus = gc.getBonusInfo(pPlanet.getBonusType())
if (pPlayer.hasTrait(iTraitForge) and pBonus.getHealth() > 0): # all heath providing bonuses increase the planet's food
iPlanetValue += 50
elif (pPlayer.hasTrait(iTraitSyndicate) and pBonus.getHappiness() > 0): # all happy providing bonuses' related buildings give at least 1 extra trade route
pBonusBuilding = gc.getBuildingInfo(FinalFrontier.dBonusBuildings[pPlanet.getBonusType()])
iPlanetValue += 50 * pBonusBuilding.getTradeRoutes()
# Planet Size
iPlanetValue *= (pPlanet.getPlanetSize() + 1) + 2 # The +2 is to simply weight things a bit so that large planets aren't THAT much more valuable than small ones
# Can it be used right away?
if (pPlanet.getOrbitRing() < CvSolarSystem.g_iPlanetRange3):
iPlanetValue *= 2
printd("Orbit Ring %d iPlanetValue: %d" %(pPlanet.getOrbitRing(), iPlanetValue))
iFoundValue += iPlanetValue
else:
iFoundValue = 0
return iFoundValue
def canPickPlot(self, argsList):
pPlot = argsList[0]
return true
def getUnitCostMod(self, argsList):
iPlayer, iUnit = argsList
iCostMod = -1 # Any value > 0 will be used
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
iCostMod = FinalFrontier.getUnitCostMod(iPlayer, iUnit)
return iCostMod
def getBuildingCostMod(self, argsList):
iPlayer, iCityID, iBuilding = argsList
iCostMod = -1 # Any value > 0 will be used
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
iCostMod = FinalFrontier.getBuildingCostMod(iPlayer, iCityID, iBuilding)
return iCostMod
def canUpgradeAnywhere(self, argsList):
iOwner, iUnitID = argsList
pUnit = gc.getPlayer(iOwner).getUnit(iUnitID)
return False
def getWidgetHelp(self, argsList):
eWidgetType, iData1, iData2, bOption = argsList
printd("eWidgetType %d, iData1 %d, iData2 %d, bOption %d" % (eWidgetType, iData1, iData2, bOption))
szHelpText = u""
# All the FF specific widget help is for widgets with a type of WidgetTypes.WIDGET_GENERAL (FFP post 1.81, for B5, by G-E)
if (eWidgetType == WidgetTypes.WIDGET_GENERAL):
# Only show tool tip help when players have the tutorial on
if (not CyUserProfile().getPlayerOption(PlayerOptionTypes.PLAYEROPTION_MODDER_1)):
# Selected Planet
if (iData1 == 666):
szHelpText = localText.getText("TXT_KEY_FF_INTERFACE_SELECTED_PLANET_HELP", ())
# Planet Population
elif (iData1 == 667):
szHelpText = localText.getText("TXT_KEY_FF_INTERFACE_PLANET_POPULATION_HELP", ())
# Planet Yield
elif (iData1 == 668):
szHelpText = localText.getText("TXT_KEY_FF_INTERFACE_PRODUCES_HELP", ())
# Planet Assign Building
elif (iData1 == 669):
szHelpText = localText.getText("TXT_KEY_FF_INTERFACE_PLANET_BUILDINGS_HELP", ())
# Planet Widgets in Lower-Right
if (iData1 >= 671 and iData1 <= 678):
pHeadSelectedCity = CyInterface().getHeadSelectedCity()
pSystem = CvSolarSystem.getSystemAt(pHeadSelectedCity.getX(), pHeadSelectedCity.getY()) #FFPBUG
iPlanetRing = iData1 - 670
pPlanet = pSystem.getPlanet(iPlanetRing)
iFood = pPlanet.getTotalYield(pHeadSelectedCity.getOwner(), 0)
iProduction = pPlanet.getTotalYield(pHeadSelectedCity.getOwner(), 1)
iCommerce = pPlanet.getTotalYield(pHeadSelectedCity.getOwner(), 2)
iCultureLevel = pPlanet.getPlanetCulturalRange()
if pPlanet.isBonus():
szHelpText = pPlanet.getName() + "\n" + localText.getText("TXT_KEY_FF_INTERFACE_PLANET_SELECTION_HELP_0", (iFood, iProduction, iCommerce)) + "\n" + localText.getText("TXT_KEY_FFPLUS_PLANET_SELECTION_HELP", (iCultureLevel,)) + "\n" + u"%c " % gc.getBonusInfo(pPlanet.getBonusType()).getChar() + localText.getText("TXT_KEY_FFPLUS_PLANET_SELECTION_BONUS", (gc.getBonusInfo(pPlanet.getBonusType()).getDescription(),)) # Planetary Resource Indicator
else:
szHelpText = pPlanet.getName() + "\n" + localText.getText("TXT_KEY_FF_INTERFACE_PLANET_SELECTION_HELP_0", (iFood, iProduction, iCommerce)) + "\n" + localText.getText("TXT_KEY_FFPLUS_PLANET_SELECTION_HELP", (iCultureLevel,))
if (not CyUserProfile().getPlayerOption(PlayerOptionTypes.PLAYEROPTION_MODDER_1)):
szHelpText += "\n" + localText.getText("TXT_KEY_FF_INTERFACE_PLANET_SELECTION_HELP", ())
return szHelpText
def getUpgradePriceOverride(self, argsList):
iPlayer, iUnitID, iUnitTypeUpgrade = argsList
pPlayer = gc.getPlayer(iPlayer)
pUnit = pPlayer.getUnit(iUnitID)
return -1
def getExperienceNeeded(self, argsList):
# use this function to set how much experience a unit needs
iLevel, iOwner = argsList
iExperienceNeeded = 0
# regular epic game experience
iExperienceNeeded = iLevel * iLevel + 1
iModifier = gc.getPlayer(iOwner).getLevelExperienceModifier()
if (0 != iModifier):
iExperienceNeeded += (iExperienceNeeded * iModifier + 99) / 100
return iExperienceNeeded