### Rebellion mod component written for Jamie's Rome Mod, by Baldyr
from ModSettings import *
# constants
iNumTechs = len(tRebelUnitTechs)
iRandomSeed = getRandNum(iNumMajorPlayers, "seed")
tRebellionClasses = (
"CulturalRebellion",
"Resistance",
"DomesticRebellion",
"MinorRevolt"
)
# main functions
def process(iGameTurn):
print "process()"
checkRebellion()
for pCurrentRebellion in getRebellions():
print pCurrentRebellion
if pCurrentRebellion.checkTermination(iGameTurn):
removeRebellion(pCurrentRebellion)
pCurrentRebellion.setDeactivate()
pCurrentRebellion.addTerminationMessage()
else:
pCurrentRebellion.process(iGameTurn)
def checkRebellion():
print "checkRebellion()"
#pCivPlayer = instance((iGameTurn + iRandomSeed) % iNumMajorPlayers)
pCivPlayer = Civ("Rome")
if not pCivPlayer.isAlive(): return
lCities = pCivPlayer.get(PyPlayer).getCityList()
lCities.reverse()
lDefectingCities = list()
iNumCities = len(lCities)
bCivilWarValid = not CivilWar.isCivilWarActive() and iNumCities >= iRequiredNumCivilWarCities
for pCity in (city.GetCy() for city in lCities):
print pCity.getName()
if isRebellion(pCity) or pCity.getPopulation() < iRequiredRebellionCitySize: continue
if checkClasses(pCity, pCivPlayer): return
if bCivilWarValid and CivilWar.checkUnhappiness(pCity):
lDefectingCities.append(pCity)
if ( bCivilWarValid
and CivilWar.checkConditions(len(lDefectingCities), iNumCities) ):
CivilWar.initCivilWar(pCivPlayer, lDefectingCities)
def checkClasses(pCity, pCivPlayer):
print "checkClasses()"
for rebellionClass in tRebellionClasses:
print rebellionClass
if eval(rebellionClass + ".checkConditions(pCivPlayer, pCity)"):
appendRebellion(eval(rebellionClass + "(pCivPlayer, pCity)"))
return True
# data storage
def setup():
setGlobalData("lCurrentRebellions", list())
def getRebellions():
return getGlobalData("lCurrentRebellions")
def appendRebellion(pCurrentRebellion):
lCurrentRebellions = getRebellions()
lCurrentRebellions.append(pCurrentRebellion)
setGlobalData("lCurrentRebellions", lCurrentRebellions)
def removeRebellion(pCurrentRebellion):
lCurrentRebellions = getRebellions()
lCurrentRebellions.remove(pCurrentRebellion)
setGlobalData("lCurrentRebellions", lCurrentRebellions)
class Rebellion:
# class methods for external access
@classmethod
def checkConditions(cls, pCivPlayer, pCity):
print "Rebellion.checkConditions()"
return pCity.isDisorder()
# initialization
def __init__(self, pCivPlayer, pCity):
self.iRebellionTurn = Game.getGameTurn()
self.plotID = getPlotID(pCity.plot())
self.eCityOwner = pCivPlayer.get(playerID)
self.setRebelPlayer(pCity)
self.setUnitType(pCity)
self.setNumUnits(pCity)
self.setRebelUnitSettings(pCity)
self.setMessages(pCity)
self.setActivate()
self.fire()
print self
def setRebelPlayer(self, pCity):
self.eRebelPlayer = eBarbarian
def setUnitType(self, pCity):
self.eUnitType = getTechUnitType(self.getCityOwner().get(CyTeam))
def setNumUnits(self, pCity):
iNatives = pCity.getCulturePercentAnger() / 100
iPopulation = pCity.getPopulation()
self.iNumUnits = max(1, min(iNatives, iPopulation))
def setRebelUnitSettings(self, pCity):
self.iUnitAI = int(eAttackCity)
self.ePromotion = None
self.unitFlag = "rebel"
def setMessages(self, pCity):
self.rebellionMessage = defaultRebellionMessage
self.terminationMessage = defaultTerminationMessage
self.unitSpawnMessage = defaultUnitSpawnMessage
# class instance interface
def isRebellionTurn(self):
return Game.getGameTurn() == self.iRebellionTurn
def getRebellionTurn(self):
return self.iRebellionTurn
def getCityOwner(self):
return instance(self.eCityOwner)
def getRebelCiv(self):
if self.eRebelPlayer == eBarbarian:
return pBarbarianCiv
else:
return instance(self.eRebelPlayer)
def getRebelPlayer(self):
return self.eCityOwner + iNumMajorPlayers
def getUnitType(self):
return self.eUnitType
def getPlotID(self):
return self.plotID
def getCyPlot(self):
return Map.plotByIndex(self.getPlotID())
def getPlotCoords(self):
return getCoords(self.getCyPlot())
def getCyCity(self):
return self.getCyPlot().getPlotCity()
def getCityName(self):
return self.getCyCity().getName()
def getNumUnits(self):
return self.iNumUnits
def getUnitAI(self):
return UnitAITypes(self.iUnitAI)
def isPromotion(self):
return self.ePromotion != None
def getPromotion(self):
return self.ePromotion
def isUnitFlag(self):
return self.unitFlag != ""
def getUnitFlag(self):
return self.unitFlag
def setPromotion(self, pUnit):
if self.isPromotion():
pUnit.setHasPromotion(self.getPromotion())
def setUnitFlag(self, pUnit):
if self.isUnitFlag():
pUnit.setScriptData(self.getUnitFlag())
def setActivate(self):
self.getCyCity().setScriptData("rebellion")
def setDeactivate(self):
self.getCyCity().setScriptData("")
def isActive(self):
return self.getCyCity().getScriptData() == "rebellion"
# shared customizable functionality
def fire(self):
self.spawnRebelUnits()
self.addRebellionMessage()
def process(self, iGameTurn):
if isChance(iRebelReinforcementPercentage):
self.spawnRebelUnits(iNumRebelReinforcements)
def checkTermination(self, iGameTurn):
print "Rebellion.checkTermination()"
if self.getCyCity().isDisorder(): return False
unitFlag = self.getUnitFlag()
for pUnit in self.getRebelCiv().get(PyPlayer).getUnitList():
if pUnit.getScriptData() == unitFlag:
return False
return True
def killRebelUnits(self):
flag = self.getUnitFlag()
for pUnit in self.getRebelCiv().get(PyPlayer).getUnitList():
if pUnit.getScriptData() == flag:
pUnit.kill(True, self.getCityOwner().get(playerID))
def addMessage(self, message, tColor):
if not message: return
if cityKnownByHuman(self.getCyCity()):
addMessage(message, (self.getCityName(),), tColor)
def addTerminationMessage(self, bRed=False, bWhite=True):
bGreen = self.getCityOwner() == pHumanCiv
self.addMessage(self.terminationMessage, (bGreen, bRed, bWhite))
def addRebellionMessage(self, bGreen=False, bWhite=True):
bRed = self.getCityOwner() == pHumanCiv
self.addMessage(self.rebellionMessage, (bGreen, bRed, bWhite))
def addUnitSpawnMessage(self, bGreen=False):
bRed = self.getCityOwner() == pHumanCiv
self.addMessage(self.unitSpawnMessage, (bGreen, bRed))
def spawnRebelUnits(self, iNumUnits=0):
print "Rebellion.spawnRebelUnits()"
if not iNumUnits:
iNumUnits = self.getNumUnits()
eUnitType, eUnitAI = self.getUnitType(), self.getUnitAI()
lPlots = self.getPlotList()
if len(lPlots) == 0: return
while iNumUnits:
iX, iY = getRandomCoords(lPlots)
print (iX, iY, eUnitType, eUnitAI)
pUnit = self.getRebelCiv().get(CyPlayer).initUnit(eUnitType, iX, iY, UnitAITypes.UNITAI_ATTACK_CITY, DirectionTypes.NO_DIRECTION)
self.setPromotion(pUnit)
self.setUnitFlag(pUnit)
iNumUnits -= 1
if not self.isRebellionTurn():
self.addUnitSpawnMessage()
def getPlotList(self):
lPlots = list()
iX, iY = self.getPlotCoords()
for eDirection in range(DirectionTypes.NUM_DIRECTION_TYPES):
pPlot = plotDirection(iX, iY, DirectionTypes(eDirection))
if isSpawnValid(pPlot):
lPlots.append(pPlot)
return lPlots
def updateRebelTechs(self):
rebelCiv = self.getRebelCiv().get(PyPlayer)
for eTech in self.getCityOwner().get(PyPlayer).getResearchedTechList():
if rebelCiv.hasResearchedTech(eTech): continue
rebelCiv.setHasTech(eTech)
class CulturalRebellion(Rebellion):
@classmethod
def checkConditions(cls, pCivPlayer, pCity):
return ( pCity.isDisorder()
and not pCity.isOccupation()
and not pCity.isNeverLost()
and isChance(iCulturalRebellionPercentage) )
def __init__(self, pCivPlayer, pCity):
Rebellion.__init__(self, pCivPlayer, pCity)
def fire(self):
self.setAtWar()
self.spawnRebelUnits()
self.addRebellionMessage()
def setRebelPlayer(self, pCity):
self.eRebelPlayer = getHighestCityCulturalRival(pCity)
if self.eRebelPlayer == -1:
self.eRebelPlayer = self.getRebelPlayer()
self.updateRebelTechs()
def setAtWar(self):
setAtWar(self.getRebelCiv(), self.getCityOwner())
class Resistance(Rebellion):
@classmethod
def checkConditions(cls, pCivPlayer, pCity):
return ( pCity.isDisorder()
and pCity.isOccupation()
and isChance(iResistancePercent) )
def __init__(self, pCivPlayer, pCity):
Rebellion.__init__(self, pCivPlayer, pCity)
def setRebelPlayer(self, pCity):
self.eRebelPlayer = pCity.getPreviousOwner()
def setUnitType(self, pCity):
self.eUnitType = getTechUnitType(self.getRebelCiv().get(CyTeam))
def process(self, iGameTurn):
if ( iGameTurn - self.getRebellionTurn() >= iResistanceDomesticTurns
and isChance(iResistanceDomesticPercentage) ):
self.killRebelUnits()
removeRebellion(self)
appendRebellion(DomesticRebellion(self.getCityOwner(), self.getCyCity()))
else:
Rebellion.process(self, iGameTurn)
class DomesticRebellion(Rebellion):
@classmethod
def checkConditions(cls, pCivPlayer, pCity):
return ( pCity.isDisorder()
and isChance(iDomesticRebellionPercentage - isCivilized(pCivPlayer) * 5) )
def __init__(self, pCivPlayer, pCity):
Rebellion.__init__(self, pCivPlayer, pCity)
def fire(self):
self.spawnRebelUnits()
self.addRebellionMessage()
self.setCapital()
self.changeCapitalHappinessPenalty(-iCapitalHappinessPenalty)
def setRebelPlayer(self, pCity):
self.eRebelPlayer = self.getRebelPlayer()
self.updateRebelTechs()
def setNumUnits(self, pCity):
iUnhappyLevel = pCity.unhappyLevel(0)
iPopulation = pCity.getPopulation()
iDistance = getDistanceToCapital(pCity)
self.iNumUnits = iPopulation / 2 * iUnhappyLevel + iDistance
def checkTermination(self, iGameTurn):
if Rebellion.checkTermination(self, iGameTurn):
rebellion.changeCapitalHappinessPenalty(iCapitalHappinessPenalty)
return True
def changeCapitalHappinessPenalty(self, value):
self.getCapital().changeExtraHappiness(value)
def setCapital(self):
self.iCapital = self.getCityOwner().get(CyPlayer).getCapitalCity().getID()
def getCapital(self):
return self.getCityOwner().get(CyPlayer).getCity(self.iCapital)
class MinorRevolt(Rebellion):
@classmethod
def checkConditions(cls, pCivPlayer, pCity):
return ( pCity.angryPopulation()
and isChance(iMinorRevoltPercentage) )
def __init__(self, pCivPlayer, pCity):
Rebellion.__init__(self, pCivPlayer, pCity)
def setRebelPlayer(self, pCity):
self.eRebelPlayer = self.getRebelPlayer()
self.updateRebelTechs()
def setNumUnits(self, pCity):
iUnhappyLevel = pCity.unhappyLevel(0)
iAngryPopulation = pCity.angryPopulation()
iPopulation = pCity.getPopulation()
self.iNumUnits = max(1, min(iUnhappyLevel - iAngryPopulation, iPopulation))
class CivilWar(Rebellion):
lCivilWarCities = list()
@classmethod
def isCivilWarActive(cls):
return len(cls.lCivilWarCities) > 0
@classmethod
def resetCivilWar(cls):
cls.lCivilWarCities = list()
@classmethod
def appendCivilWar(cls, pCivilWar):
cls.lCivilWarCities.append(pCivilWar)
appendRebellion(pCivilWar)
pCivilWar.setActivate()
@classmethod
def removeCivilWar(cls, pCivilWar):
## cls.lCivilWarCities.remove(pCivilWar)
removeRebellion(pCivilWar)
pCivilWar.setDeactivate()
@classmethod
def checkUnhappiness(cls, pCity):
iAngryCitizens = pCity.angryPopulation()
iWarWeariness = pCity.getWarWearinessPercentAnger() / 100
return iAngryCitizens - iWarWeariness >= iRequiredNumCivilWarUnhappiness
@classmethod
def checkConditions(cls, iNumDefectingCities, iNumTotalCities):
return ( iNumDefectingCities >= iNumTotalCities * iCivilWarUnhappyCitiesPercentage / 100.0
and isChance(iCivilWarPercentage) )
@classmethod
def initCivilWar(cls, pCivPlayer, lDefectingCities):
tLargestCity = None, 0, None
for pCity in lDefectingCities:
pCivilWar = CivilWar(pCivPlayer, pCity)
iPopulation = pCity.getPopulation()
if iPopulation > tLargestCity[1]:
tLargestCity = pCity, iPopulation, pCivilWar
pRebelHQ = tLargestCity[2]
setCapital(pRebelHQ.getCyCity())
pRebelHQ.spawnRebelUnits()
pRebelHQ.terminationMessage = civilWarTerminationMessage
pRebelHQ.addRebellionMessage()
def __init__(self, pCivPlayer, pCity):
Rebellion.__init__(self, pCivPlayer, pCity)
CivilWar.appendCivilWar(self)
self.fire()
def fire(self):
self.flipCity()
def setRebelPlayer(self, pCity):
self.eRebelPlayer = self.getRebelPlayer()
self.updateRebelTechs()
def setNumUnits(self, pCity):
self.iNumUnits = iCivilWarRebelArmySize
def setMessages(self, pCity):
self.rebellionMessage = civilWarMessage
self.terminationMessage = ""
self.unitSpawnMessage = civilWarUnitSpawnMessage
def addMessage(self, message, tColor):
addMessage(message, (self.getCityOwner().getName(),), tColor)
def addTerminationMessage(self, bRed=False, bWhite=True):
bGreen = self.getCityOwner() == pHumanCiv
self.addMessage(self.terminationMessage, (bGreen, bRed, bWhite))
def addRebellionMessage(self, bGreen=False, bWhite=True):
bRed = self.getCityOwner() == pHumanCiv
self.addMessage(self.rebellionMessage, (bGreen, bRed, bWhite))
def addUnitSpawnMessage(self, bGreen=False):
bRed = self.getCityOwner() == pHumanCiv
Rebellion.addMessage(self, self.unitSpawnMessage, (bGreen, bRed))
def flipCity(self):
pCity = self.getCyCity()
iX, iY = self.getPlotCoords()
pRebelCiv = self.getRebelCiv()
lCityUnits = getCityUnits(pCity)
pRebelCiv.get(CyPlayer).acquireCity(pCity, True, False)
for pUnit in lCityUnits:
pRebelUnit = pRebelCiv.get(PyPlayer).initUnit(pUnit.getUnitType(), iX, iY)
pRebelUnit.convert(pUnit)
self.setUnitFlag(pRebelUnit)
def checkTermination(self, iGameTurn):
if not self.getRebelCiv().isAlive():
self.terminateCivilWar()
return True
def terminateCivilWar(self):
for pCivilWar in self.lCivilWarCities:
if pCivilWar == self: continue
self.removeCivilWar(pCivilWar)
CivilWar.resetCivilWar()
def process(self, iGameTurn):
pass
class SlaveRevolt(Rebellion):
@classmethod
def checkConditions(cls, pCity):
iSlaveryAnger = pCity.getHurryAngerModifier()
return isChance(iSlaveRevoltDenominator + iSlaveRevoltDenominator * iSlaveryAnger)
def __init__(self, ePlayer, pCity):
Rebellion.__init__(self, instance(ePlayer), pCity)
appendRebellion(self)
def fire(self):
self.spawnRebelUnits()
self.changeCitySize(-getNumSlaveCitizens(self.getNumUnits()))
self.addRebellionMessage()
def setRebelPlayer(self, pCity):
self.eRebelPlayer = eSlaves
def setNumUnits(self, pCity):
self.iNumUnits = pCity.getPopulation()
def setRebelUnitSettings(self, pCity):
self.iUnitAI = int(eAttackCity)
self.ePromotion = None
self.unitFlag = pCity.getCityName()
def setMessages(self, pCity):
self.rebellionMessage = slaveRevoltMessage
self.terminationMessage = slaveRevoltTerminationMessage
self.unitSpawnMessage = defaultUnitSpawnMessage
def addTerminationMessage(self, bRed=False, bWhite=True):
bGreen = self.getCityOwner() == pHumanCiv
addMessage(self.terminationMessage, (), (bGreen, bRed, bWhite))
def checkTermination(self, iGameTurn):
if self.getCityOwner().get(CyPlayer).getCivics(eLabor) != eSlavery:
self.changeCitySize(self.getNumSlaveCitizens(self.countRebelUnits())
self.killRebelUnits()
self.revertSlaveCities()
return True
return Rebellion.checkTermination(self, iGameTurn)
def revertSlaveCities(self):
pPlayer = self.getCityOwner().get(CyPlayer)
for pCity in (city.GetCy() for city in self.getRebelCiv().get(PyPlayer).getCityList()):
pPlayer.acquireCity(pCity, False, False)
def process(self, iGameTurn):
pass
def countRebelUnits(self):
flag = self.getUnitFlag()
iNumUnits = 0
for scriptData in (unit.CyGet().getScriptData() for unit in self.getRebelCiv().get(PyPlayer).getUnitList()):
if scriptData == flag:
iNumUnits += 1
return iNumUnits
def getNumSlaveCitizens(self, iNumUnits):
return self.countRebelUnits() / iNumSlaveUnitsPerCitizen
def changeCitySize(self, value):
self.getCyCity().changePopulation(value)
# helper functions
def getPlotID(pPlot):
return Map.plotNum(pPlot.getX(), pPlot.getY())
def getCyPlot(iPlot):
return Map.plotByIndex(iPlot)
def getPlotUnitStrength(pCity):
pPlot = pCity.plot()
iNumUnits = pPlot.getNumUnits()
iUnit = iStrength = 0
while iUnit < iNumUnits:
pUnit = pPlot.getUnit(iUnit)
iStrength += pUnit.baseCombatStr()
iUnit += 1
return iStrength
def getNumStrenghtUnits(eUnitType, iStrength):
return max(1, iStrength / gc.getUnitInfo(eUnitType).getCombat())
def isSpawnValid(pPlot):
return not ( pPlot.isWater()
or pPlot.isPeak()
or pPlot.isCity() )
def getRandomCoords(lPlots):
iRandNum = Game.getSorenRandNum(len(lPlots), "random plot")
pPlot = lPlots[iRandNum]
return getCoords(pPlot)
def cityKnownByHuman(pCity):
return pCity.isRevealed(pHumanCiv.get(teamID), True) # change to False?
def getTechUnitType(pTeam):
for i in xrange(iNumTechs - 1, -1, -1):
eTechType = tRebelUnitTechs[i]
if pTeam.isHasTech(eTechType):
return tAdvancedRebelUnits[i]
return eDefaultUnit
def getHighestCityCulturalRival(pCity):
eOwner = pCity.getOwner()
eCulturalOwner = pCity.findHighestCulture()
if eCulturalOwner != eOwner:
return eCulturalOwner
else:
tCurrentLeader = -1, 0
for ePlayer in CivPlayer.getPlayers(index=playerID):
if ePlayer == eOwner or ePlayer == eCulturalOwner: continue
iCulture = pCity.getCulture(ePlayer)
if iCulture > tCurrentLeader[1]:
tCurrentLeader = ePlayer, iCulture
return tCurrentLeader[0]
def isRebellion(pCity):
return pCity.getScriptData() == "rebellion"
def isCivilized(pCivPlayer):
return pCivPlayer in lCivilized
def getDistanceToCapital(pCity, pPlayer):
iCityX, iCityY = getCoords(pCity)
iCapitalX, iCapitalY = getCoords(pPlayer.getCapitalCity())
return min(abs(iCityX - iCapitalX), abs(iCityY - iCapitalY))
def getCityUnits(pCity):
eOwner = pCity.getOwner()
lUnits = list()
for pUnit in (pCity.getUnit(iUnit) for iUnit in range(pCity.getNumUnits())):
if pUnit.getOwner() != eOwner: continue
lUnits.append(pUnit)
return lUnits
def setCapital(pCity):
pCity.setNumRealBuilding(ePalace, 1)
def setAtWar(pCivPlayer1, pCivPlayer2):
pTeam1 = pCivPlayer1.get(CyTeam)
team2ID = pCivPlayer2.get(teamID)
if not pTeam1.isAtWar(team2ID):
pTeam1.declareWar(team2ID, True, -1)