Requesting following features

in the slave revolt how can I use slave revolt again event as condition as well?
because it can only happen on the first slave revolt and not if it is ignored and continued (by second event)
 
AFAIK the doSlaveRevolt callup is done with all three slave revolt events in CIV4EventInfos. :confused:
 
there are two triggers, the first and then there is one that only happens are the first trigger was told: I don't care.. then the event Slave_revolt_again can then be called. Check it out in the event infos
 
Use this tag?
Code:
<PythonCallback>doSlaveRevolt</PythonCallback>
This is how the first event is triggering the Python script.
 
mine doesn't do that :p

interesting... I guess I never put in the event infos!

Is this is the trigger infos or event infos?
 
As I said, its CIV4EventInfos. Check the associated tag for all the slave revolt entries.
 
thanks, should I use all the events do you think or just the third kind?? probably all three
 
I really wouldn't know. :p Perhaps only add the Python calls to CIV4EventTriggerInfos and nothing in CIV4EventInfos? (I'm thinking that you really shouldn't double-up on the callbacks.) At least try it.
 
ok I have these exceptions (though I have the feeling the second was caused by the first one interupting it...

Traceback (most recent call last):

File "CvEventInterface", line 23, in onEvent

File "CvEventManager", line 187, in handleEvent

File "CvEventManager", line 382, in onBeginGameTurn

File "CatapultConstruction", line 184, in process

File "CatapultConstruction", line 120, in checkUnits

RuntimeError: unidentifiable C++ exception
ERR: Python function onEvent failed, module CvEventInterface

Traceback (most recent call last):

File "CvEventInterface", line 23, in onEvent

File "CvEventManager", line 187, in handleEvent

File "CvEventManager", line 381, in onBeginGameTurn

File "Rebellion", line 76, in process

File "Rebellion", line 95, in checkRebellion

File "Rebellion", line 107, in checkClasses

File "<string>", line 0, in ?

File "Rebellion", line 378, in __init__

File "Rebellion", line 156, in __init__

File "Rebellion", line 256, in fire

File "Rebellion", line 304, in spawnRebelUnits

RuntimeError: unidentifiable C++ exception
ERR: Python function onEvent failed, module CvEventInterface
 
Line 120 is, still, this one:
Code:
if pPlot.getFeatureType() == eForest:
I, still, have no idea what the problem is. None of the fixes seem to have helped with this issue.

I guess I'll have to start testing this myself, for real. Any autosaves where this happens would be helpful! :p
 
might have one somehwwere... what about the other
 
might have one somehwwere...
I think I already have some of the older saves and will be taking a look at those.

edit: Nope, none of those saves seem to be producing any exceptions, at least not in a couple of turn's time.

But try to always test with autosave enabled, and make a copy of those autosaves once you find a bug.

what about the other
It seems like you're running a different version of Rebellion.py than the one I have, so I really wouldn't know. But you might check line #304 in yours and post the line (or the whole spawnRebelUnits() method - with that line highlighted).
 
I don't seem to be able to replicate this bug... :p At least I don't have the time to play entire games in order to test things for real.

The problem seems to be that the data structure holding all the catapult construction data seems to be reconstructed any time the game is restarted - instead of being saved along with the game session. So any invalid CyUnit instances potentially causing the bug (I'm of course thinking about those negative map coordinates posted earlier) are probably weeded out if I try to recreate the bug with a supplied save game.

I'll have another look at the entire Catapult Construction code in order to spot any obvious mistakes of mine.
 
Ok, here's another hotfix. In CvEventManager, add this line:
Code:
	def onUnitKilled(self, argsList):
		'Unit Killed'
		unit, iAttacker = argsList
		player = PyPlayer(unit.getOwner())
		attacker = PyPlayer(iAttacker)

[B]		CC.index(unit)[/B]

		if (not self.__LOG_UNITKILLED):
			return
		CvUtil.pyPrint('Player %d Civilization %s Unit %s was killed by Player %d' 
			%(player.getID(), player.getCivilizationName(), PyInfo.UnitInfo(unit.getUnitType()).getDescription(), attacker.getID()))
This addition to the code should make sure that no dead units linger in the catapult construction data - at least as long as the Python code isn't interrupted by any exceptions (other than the one we already know about).

Try it in a real game and get back to me if the erroneous unit coordinates are still appearing in the Python Debug Log.
 
heres my version:

Spoiler :

Code:
### Rebellion mod component written for Jamie's Rome Mod, by Baldyr

from Helpers import *
from eNums import *

# constants

bDebug = True

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, 23)
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):
        if not message: return
        if cityKnownByHuman(self.getCyCity()):
            addMessage(message, (self.getCityName(),), getColor(*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):
        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)
            [B]pUnit = self.getRebelCiv().get(CyPlayer).initUnit(eUnitType, iX, iY, UnitAITypes.UNITAI_ATTACK_CITY, DirectionTypes.NO_DIRECTION[/B])
            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 CulturalInfiltration(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())

    def setMessages(self, pCity):
        self.rebellionMessage = culturalRebellionMessage
        self.terminationMessage = defaultTerminationMessage
        self.unitSpawnMessage = defaultUnitSpawnMessage


class Resistance(Rebellion):
#Occupational!#
    @classmethod
    def checkConditions(cls, pCivPlayer, pCity):
        return ( pCity.isDisorder()
                 and pCity.isOccupation()
                 and isChance(iResistancePercentage) )

    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)

    def setMessages(self, pCity):
        self.rebellionMessage = occupationalRebellionMessage
        self.terminationMessage = defaultTerminationMessage
        self.unitSpawnMessage = defaultUnitSpawnMessage


class DomesticRebellion(Rebellion):

    @classmethod
    def checkConditions(cls, pCivPlayer, pCity):
        return ( pCity.isDisorder()
                 and isChance(iDomesticRebellionPercentage - isCivilized(pCivPlayer) * iCivilizedPercentageSubtract) )
    
    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)
        iDistance = getDistanceToCapital(pCity, self.getCityOwner().get(CyPlayer))
        self.iNumUnits = max(3, min(iUnhappyLevel - 2, iDistance - 3))

    def checkTermination(self, iGameTurn):
        if Rebellion.checkTermination(self, iGameTurn):
            self.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)

    def setMessages(self, pCity):
        self.rebellionMessage = domesticRebellionMessage
        self.terminationMessage = defaultTerminationMessage
        self.unitSpawnMessage = defaultUnitSpawnMessage
    

class MinorRevolt(Rebellion):

    @classmethod
    def checkConditions(cls, pCivPlayer, pCity):
        return ( pCity.angryPopulation(0)
                 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(0)
        iPopulation = pCity.getPopulation()
        if iPopulation > 6:
            iPop = iPopulation - 2
        else:
            iPop = iPopulation
        self.iNumUnits = max(1, min(iAngryPopulation + 2, iPop)) #if fails use iPopulation

    def setMessages(self, pCity):
        self.rebellionMessage = mdomesticRebellionMessage
        self.terminationMessage = defaultTerminationMessage
        self.unitSpawnMessage = defaultUnitSpawnMessage
        
class SlaveRevolt(Rebellion):
    
    @classmethod
    def checkConditions(cls, pCity):
        return isChance(pCity.getHurryAngerTimer() * iSlaveRevoltDenominator)

    def __init__(self, ePlayer, pCity):
        Rebellion.__init__(self, instance(ePlayer), pCity)
        appendRebellion(self)
        self.setActivate()

    def fire(self):
        self.spawnRebelUnits()
        self.changeCitySize(-self.getNumSlaveCitizens(self.getNumUnits()))
        self.addRebellionMessage()
        
    def setRebelPlayer(self, pCity):
        self.eRebelPlayer = pointer("Slaves", playerID)
        
    def setNumUnits(self, pCity):
        self.iNumUnits = pCity.getPopulation() - 1

    def setRebelUnitSettings(self, pCity):
        self.iUnitAI = int(eAttackCity)
        self.ePromotion = -1
        self.unitFlag = str(pCity.getName())

    def setMessages(self, pCity):
        self.rebellionMessage = slaveRevoltMessage
        self.terminationMessage = slaveRevoltTerminationMessage
        self.unitSpawnMessage = defaultUnitSpawnMessage

    def addTerminationMessage(self):
        pass

    def addEmancipationMessage(self):
        bGreen = self.getCityOwner() == pHumanCiv
        addMessage(self.terminationMessage, (), getColor(bGreen, False, True))

    def checkTermination(self, iGameTurn):
        if self.getCityOwner().get(CyPlayer).getCivics(eLabor) != eSlavery:
            self.changeCitySize(self.getNumSlaveCitizens(self.countRebelUnits()))
            self.killRebelUnits()
            self.revertSlaveCities()
            self.addEmancipationMessage()
            return True
        return Rebellion.checkTermination(self, iGameTurn)

    def revertSlaveCities(self):
        for pCity in (city.GetCy() for city in self.getRebelCiv().get(PyPlayer).getCityList()):
            if ( pCity.getPreviousOwner() == self.getCityOwner().get(playerID)
                 and pCity.getOwner() == self.getRebelCiv().get(playerID) ):
                self.getCityOwner().get(CyPlayer).acquireCity(pCity, False, False)

    def process(self, iGameTurn):
        pass

    def countRebelUnits(self):
        flag = self.getUnitFlag()
        iNumUnits = 0
        for scriptData in (unit.getScriptData() for unit in self.getRebelCiv().get(PyPlayer).getUnitList()):
            if scriptData == flag:
                iNumUnits += 1
        return iNumUnits

    def getNumSlaveCitizens(self, iNumUnits):
        return iNumUnits / iNumSlaveUnitsPerCitizen

    def changeCitySize(self, iValue):
        self.getCyCity().changePopulation(iValue)


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):
##        removeRebellion(pCivilWar)
##        pCivilWar.setDeactivate()

    @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)
##        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(),), getColor(*tColor))

    def addTerminationMessage(self):
        bGreen = self.getCityOwner() == pHumanCiv
        self.addMessage(self.terminationMessage, (bGreen, False, True))

    def addRebellionMessage(self):
        bRed = self.getCityOwner() == pHumanCiv
        self.addMessage(self.rebellionMessage, (False, bRed, True))

    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.terminateCivilWar()
##            CivilWar.resetCivilWar()
            self.getRebelCiv().get(CyPlayer).killUnits()
            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 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))

# 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

##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 isCivilWarValid(iNumCities):
##    return ( not CivilWar.isCivilWarActive()
##             and iNumCities >= iRequiredNumCivilWarCities )
 
And what line is #304?
 
Code:
pUnit = self.getRebelCiv().get(CyPlayer).initUnit(eUnitType, iX, iY, UnitAITypes.UNITAI_ATTACK_CITY, DirectionTypes.NO_DIRECTION)

I bolded it...
 
Oh, thanks.

I've seen this one before, and then it was a case of supplying a invalid UnitType value to CyPlayer.initUnit(). I need the Python Debug Log to see what rebellion type is acting up...

Otherwise a autosave would still be helpful in this case.

edit: Add this debug message in the method and if you see the error again, look in the logs for the debug entry.
Code:
    def spawnRebelUnits(self, iNumUnits=0):
        if not iNumUnits:
            iNumUnits = self.getNumUnits()
        eUnitType, eUnitAI = self.getUnitType(), self.getUnitAI()
        [B]print str(self) + " .spawnRebelUnits(): " + str(eUnitType)[/B]
        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()
This line can be disabled (commented out/deleted) once the bug has been found and squashed.
 
I lost my autosa ves so I will load the original save to do this :D (log went with it) :rolleyes:
 
I have not had time recently but I will work on it as soon as possible!
 
Top Bottom