Arian
No more ghostbusting!!
Is there a way to for a city into the "We love the King"-state?
iRequiredRebellionCitySize = 3
iRebelReinforcementPercentage = 45
iMaxRebelReinforcementTurns = 5
iNumRebelReinforcements = 1
iCulturalRebellionPercentage = 75
iResistancePercentage = 60
iResistanceDomesticPercentage = 10
iResistanceDomesticTurns = 5
iDomesticRebellionPercentage = 55
iCivilizedPercentageSubtract = 5
iCapitalHappinessPenalty = 2
iMinorRevoltPercentage = 8
iCivilWarPercentage = 20
iCivilWarUnhappyCitiesPercentage = 30
iRequiredNumCivilWarCities = 6
iRequiredNumCivilWarUnhappiness = 2
iCivilWarRebelArmySize = 6
iSlaveRevoltDenominator = 30
iNumSlaveUnitsPerCitizen = 3
tByzantion = (46, 27)
byzansCapital = "Constantinople"
iByzansRebelArmySize = iCivilWarRebelArmySize
eDefaultUnit = eWarrior
tRebelUnits = (
(eBronzeWorking, eAxeman),
(eIronWorking, eSwordsman),
(eAdvancedBronzeWorking, eAdvancedSpearman),
(eAdvanceIronWorking, eAdvancedSwordsman)
)
tCivilized = ( "Carthage", "Greece", "Rome", "Egypt" )
defaultRebellionMessage = "TXT_KEY_REBELLION_REBELLION"
occupationalRebellionMessage = "TXT_KEY_REBELLION_OCCUPATIONAL_REBELLION"
domesticRebellionMessage = "TXT_KEY_REBELLION_DOMESTIC_REBELLION"
mdomesticRebellionMessage = "TXT_KEY_REBELLION_MINOR_DOMESTIC_REBELLION"
culturalRebellionMessage = "TXT_KEY_REBELLION_CULTURAL_REBELLION"
defaultTerminationMessage = "TXT_KEY_REBELLION_TERMINATION"
defaultUnitSpawnMessage = "TXT_KEY_REBELLION_UNITSPAWN"
civilWarMessage = "TXT_KEY_REBELLION_CIVILWAR"
civilWarTerminationMessage = "TXT_KEY_REBELLION_CIVILWAR_TERMINATION"
civilWarUnitSpawnMessage = "TXT_KEY_REBELLION_CIVILWAR_UNITSPAWN"
slaveRevoltMessage = "TXT_KEY_REBELLION_SLAVEREVOLT"
slaveRevoltTerminationMessage = "TXT_KEY_REBELLION_SLAVEREVOLT_TERMINATION"
byzantiumMessage = "TXT_KEY_REBELLION_ERE"
iRandomSeed = getRandNum(iNumMajorPlayers, "seed")
tRebellionClasses = (
"CulturalInfiltration",
"Resistance",
"DomesticRebellion",
"MinorRevolt",
)
# main functions
def process(iGameTurn):
for pCurrentRebellion in getRebellions():
if pCurrentRebellion.checkTermination(iGameTurn):
removeRebellion(pCurrentRebellion)
pCurrentRebellion.setDeactivate()
pCurrentRebellion.addTerminationMessage()
else:
pCurrentRebellion.process(iGameTurn)
checkRebellion(iGameTurn)
# debug:
if bDebug and getRebellions():
lDebugMessages = [("Active on Game Turn %d:" % (iGameTurn,), False )]
for pCurrentRebellion in getRebellions():
message = "%s (city: %s, starting turn: %d)" % (str(pCurrentRebellion), str(pCurrentRebellion.getCyCity().getName()), pCurrentRebellion.getRebellionTurn())
lDebugMessages.append((message, False))
debug("Rebellion", lDebugMessages)
def checkRebellion(iGameTurn):
pCivPlayer = instance((iGameTurn + iRandomSeed) % iNumMajorPlayers)
if not pCivPlayer.isAlive(): return
lCities = pCivPlayer.get(PyPlayer).getCityList()
lCities.reverse()
lDefectingCities = list()
iNumCities = len(lCities)
bCivilWarValid = iNumCities >= iRequiredNumCivilWarCities #isCivilWarValid(iNumCities)
for pCity in (city.GetCy() for city in lCities):
if not isRebellionValid(pCity): continue
if checkClasses(pCity, pCivPlayer): return
if ( bCivilWarValid
and not CivilWar.isQuota(len(lDefectingCities), iNumCities)
and CivilWar.checkUnhappiness(pCity) ):
lDefectingCities.append(pCity)
if ( bCivilWarValid
and CivilWar.checkConditions(len(lDefectingCities), iNumCities) ):
CivilWar.initCivilWar(pCivPlayer, lDefectingCities)
def checkClasses(pCity, pCivPlayer):
for rebellionClass in tRebellionClasses:
if eval(rebellionClass + ".checkConditions(pCivPlayer, pCity)"):
appendRebellion(eval(rebellionClass + "(pCivPlayer, pCity)"))
return True
def debug(moduleName, lDebugMessages):
debugString = "\n *** " + moduleName + " Debug ***\n"
for (string, bBroadcast) in lDebugMessages:
debugString += (string + "\n")
if bBroadcast:
Interface.addImmediateMessage("Rebellion " + string, "")
print debugString + " ***\n"
# 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 definitions
class Rebellion:
@classmethod
def checkConditions(cls, pCivPlayer, pCity):
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()
self.debug(pCity)
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(3, min(iNatives - 1, iPopulation -2))
def setRebelUnitSettings(self, pCity):
self.iUnitAI = int(eAttackCity)
self.ePromotion = -1
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 + 2
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 != -1
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)
and iGameTurn < self.getRebellionTurn() + iMaxRebelReinforcementTurns ):
self.spawnRebelUnits(iNumRebelReinforcements)
def checkTermination(self, iGameTurn):
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, sound = ""):
if not message: return
if cityKnownByHuman(self.getCyCity()):
addMessage(message, (self.getCityName(),), getColor(*tColor), (-1, -1), sound)
def addTerminationMessage(self, bRed=False, bWhite=True):
bGreen = self.getCityOwner() == pHumanCiv
self.addMessage(self.terminationMessage, (bGreen, bRed, bWhite), "AS2D_REVOLTEND")
createReplayMessage(self.terminationMessage, (self.getCityName(),), self.eCityOwner, self.getCyCity(), eMajorEvent, ePurple)
def addRebellionMessage(self, bGreen=False, bWhite=True):
bRed = self.getCityOwner() == pHumanCiv
self.addMessage(self.rebellionMessage, (bGreen, bRed, bWhite), "AS2D_REVOLTSTART")
createReplayMessage(self.rebellionMessage, (self.getCityName(),), self.eCityOwner, self.getCyCity(), eMajorEvent, ePurple)
def addUnitSpawnMessage(self, bGreen=False):
if self.isRebellionTurn(): return
bRed = self.getCityOwner() == pHumanCiv
self.addMessage(self.unitSpawnMessage, (bGreen, bRed))
def spawnRebelUnits(self, iNumUnits=0):
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)
pUnit = self.getRebelCiv().get(CyPlayer).initUnit(eUnitType, iX, iY, UnitAITypes.UNITAI_ATTACK_CITY, DirectionTypes.NO_DIRECTION)
self.setPromotion(pUnit)
self.setUnitFlag(pUnit)
iNumUnits -= 1
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)
def debug(self, pCity):
if not bDebug: return
lDebugMessages = [
( "Rebellion initialized: " + str(self), False ),
( "Date/Turn: %d/%d" % (Game.getGameTurnYear(), Game.getGameTurn()), False ),
( "City: %s (%s)" % (str(pCity.getName()), str(self.getCityOwner().getName(False))), True ),
( "Units:\nType\tNum\tAI\tProm\tFlag\n%d\t%d\t%d\t%d\t%s"
% (self.eUnitType, self.iNumUnits, self.iUnitAI, self.ePromotion, self.unitFlag), False )
]
debug("Rebellion", lDebugMessages)
class CivilWar(Rebellion):
@classmethod
def checkUnhappiness(cls, pCity):
iAngryCitizens = pCity.angryPopulation(0)
iWarWeariness = pCity.getWarWearinessPercentAnger() / 100
return iAngryCitizens - iWarWeariness >= iRequiredNumCivilWarUnhappiness
@classmethod
def isQuota(cls, iNumRebelCities, iNumTotalCities):
return iNumRebelCities > iNumTotalCities * iCivilWarUnhappyCitiesPercentage / 100
@classmethod
def checkConditions(cls, iNumDefectingCities, iNumTotalCities):
return ( iNumDefectingCities >= iNumTotalCities * iCivilWarUnhappyCitiesPercentage / 100.0
and isChance(iCivilWarPercentage) )
@classmethod
def initCivilWar(cls, pCivPlayer, lDefectingCities):
pRebelHQ = cls.initRebellions(pCivPlayer, lDefectingCities)
if pRebelHQ:
pRebelHQ.setRebelHQ()
@classmethod
def initRebellions(cls, pCivPlayer, lDefectingCities):
tLargestCity = 0, None
for pCity in lDefectingCities:
pCivilWar = CivilWar(pCivPlayer, pCity)
appendRebellion(pCivilWar)
pCivilWar.setActivate()
iPopulation = pCity.getPopulation()
if iPopulation > tLargestCity[0]:
tLargestCity = iPopulation, pCivilWar
return tLargestCity[1]
def setRebelHQ(self):
setCapital(self.getCyCity())
self.spawnRebelUnits()
self.terminationMessage = civilWarTerminationMessage
self.addRebellionMessage()
def __init__(self, pCivPlayer, pCity):
Rebellion.__init__(self, pCivPlayer, pCity)
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, sound = ""):
addMessage(message, (self.getCityOwner().getName(),), getColor(*tColor), (-1, -1), sound)
def addTerminationMessage(self):
bGreen = self.getCityOwner() == pHumanCiv
self.addMessage(self.terminationMessage, (bGreen, False, True))
createReplayMessage(self.terminationMessage, (self.getCityOwner().getName(),), self.eCityOwner, self.getCyCity(), eMajorEvent, ePurple) #CHECK WORKS
def addRebellionMessage(self):
bRed = self.getCityOwner() == pHumanCiv
self.addMessage(self.rebellionMessage, (False, bRed, True), "AS2D_REVOLTSTART")
createReplayMessage(self.rebellionMessage, (self.getCityOwner().getName(),), self.eCityOwner, self.getCyCity(), eMajorEvent, ePurple) #CHECK WORKS
def addUnitSpawnMessage(self):
bRed = self.getCityOwner() == pHumanCiv
Rebellion.addMessage(self, self.unitSpawnMessage, (False, bRed))
def flipCity(self):
pCity = self.getCyCity()
iX, iY = self.getPlotCoords()
pRebelCiv = self.getRebelCiv()
lCityUnits = getCityUnits(pCity)
pRebelCiv.get(CyPlayer).acquireCity(pCity, False, 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 self.getRebelCiv().get(CyPlayer).getNumCities() == 0:
self.getRebelCiv().get(CyPlayer).killUnits()
return True
def process(self, iGameTurn):
pass
class EastRomanEmpire(CivilWar):
@classmethod
def initRebellions(cls, pCivPlayer, lDefectingCities):
tLargestCity = 0, None
for pCity in lDefectingCities:
pERE = EastRomanEmpire(pCivPlayer, pCity)
appendRebellion(pERE)
pERE.setActivate()
iPopulation = pCity.getPopulation()
if getCoords(pCity) == tByzantion:
iPopulation = 99
if iPopulation > tLargestCity[0]:
tLargestCity = iPopulation, pERE
return tLargestCity[1]
def setRebelHQ(self):
setCapital(self.getCyCity())
self.terminationMessage = civilWarTerminationMessage
self.addRebellionMessage()
self.getCyCity().setName(byzansCapital, True)
self.spawnRebelUnits()
def setRebelPlayer(self, pCity):
self.eRebelPlayer = pointer("Byzantium", playerID)
self.updateRebelTechs()
def setNumUnits(self, pCity):
self.iNumUnits = iByzansRebelArmySize
def setMessages(self, pCity):
self.rebellionMessage = byzantiumMessage
self.terminationMessage = ""
self.unitSpawnMessage = civilWarUnitSpawnMessage
def addRebellionMessage(self):
addMessage(self.rebellionMessage, (self.getCyCity().getName(), byzansCapital), getColor(False, True))
createReplayMessage(self.rebellionMessage, (self.getCyCity().getName(), byzansCapital), self.eCityOwner, self.getCyCity(), eMajorEvent, ePurple) #CHECK WORKS
# helper functions
def getPlotID(pPlot):
return Map.plotNum(pPlot.getX(), pPlot.getY())
def getCyPlot(iPlot):
return Map.plotByIndex(iPlot)
def getTechUnitType(pTeam):
for i in xrange(len(tRebelUnits) - 1, -1, -1):
eTechType = tRebelUnits[i][0]
if pTeam.isHasTech(eTechType):
return tRebelUnits[i][1]
return eDefaultUnit
def isRebellionValid(pCity):
return ( not pCity.getScriptData()
and pCity.getPopulation() >= iRequiredRebellionCitySize )
def isCivilized(pCivPlayer):
return pCivPlayer.getName(False) in tCivilized
I don't think it is that much of an exaggeration, I find it nice when I am viewing my own code in debug and watching it perform all it's operations. I think well written code (like Baldyr's) is definately a form of art that only we programmers can truely appriciate![]()
Nice work on the event! Finally i can have revolutions in my mod without having to merge so many things
Is it triggered everytime a city is unhappy? If so ill probably just put a 1 in 1500 chance or something like that on it.
Can we expect more events in the future? No one really does events and we can definatly used some released, I got plenty of ideas![]()
You could then put a simple restriction, capping it off at half of your cities, or saying it needs to be a certain number of unhappinessShould be doable, but that could be balancing-wise be quite problematic (just imagine, defying some UN resolutions puts you over the limit, and nearly all your cities go away...awful!).
Nahh me too, dont like giant codes, they are pretty intimidatingI find the complexity rather scaring, but that's maybe only me.
If you ever do update it, i would put a random restriction on it, since that way people who just want to play it as a solo mod can do so if they do not have modding capabilitiesYes, currently it will happen to every city which is unhappy (until all civ slots are full).
That's why I say in the description that you should change some things in the eventTriggerInfos.xml to better match your mod.
I got plenty, and knowing somewhat how python runs, i won't make any crazy requestsDepends on how complicated your ideas are ^^.
You could then put a simple restriction, capping it off at half of your cities, or saying it needs to be a certain number of unhappiness
[...]
I would like to see it expanded a bit, since doing a simple check of other cities to see if they are unhappy, if yes give to other civ. If that city has more cities then original, stop. Should be a pretty short code plus it shouldnt take a toll on gameplay since your only checking it when theres already a revolution (then again i could be wrong, dont know python)![]()
If you ever do update it, i would put a random restriction on it, since that way people who just want to play it as a solo mod can do so if they do not have modding capabilities
I got plenty, and knowing somewhat how python runs, i won't make any crazy requests
You should release more as the only events are mods, and you can't merge those with mods about specific eras (not that i have a biased opinion there)
hmm just 3..really restricting me hereThen give me 3 ideas, and I'll see.
theres not a lot of indivisual mod comps for events, where it just adds one event. Events usually just come in mods, so it is hard to extract just that event, expecially when its with python.Not sure if I get you here...
hmm just 3..really restricting me here
1)Anti-war riots sweep nation, cities become angry while still during war
2)Currupt Mayor in a city, two options
*Cover it up. 50% chance it is leaked and all cities +1 mad for x turns
*Arrest him. +1 Happiness in all cities for x turns, -Y% culture in that city for x turns
3)Politican assasignated by other civ's extremist(ex. German extremist). 2 options
*Go to war, negative relationship bonus, maybe happiness or culture bonus?
*Keep peace, + mad for x turns, bigger negative relationship bonus
got plenty but those are just off the top of my head
theres not a lot of indivisual mod comps for events, where it just adds one event. Events usually just come in mods, so it is hard to extract just that event, expecially when its with python.
No one really does events and we can definatly used some released, I got plenty of ideas![]()