I found the cause and a fix for the Mekara infinite sluga issue. The following contains a lot of code and discussion. If you just want the fix, simply skip to the end of the post for relevant information.
The Issue:
The infinite war sluga bug is caused by a circular reference to initUnit() caused by the onPromotion event.
The sluga spell is defined 9456:CvSpellInterface.pv
Code:
def spellSlugaCreation(caster, slugaType):
pPlayer = gc.getPlayer(caster.getOwner())
pPlot = caster.plot()
if slugaType == 0:
iUnit = getInfoType("UNIT_SLUGA")
if slugaType == 1:
iUnit = getInfoType("UNIT_BATTLE_SLUGA")
if slugaType == 2:
iUnit = getInfoType("UNIT_SLAVE")
newUnit = pPlayer.initUnit(iUnit, pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
caster.kill(True,0)
This is called with 1 as intended for creating a battle sluga. The issue comes in the creation of the unit in pPlayer.initUnit(
). This is defined in 2628:CvPlayer.cpp which calls CvUnit::init(
) to actually create the unit.
Code:
CvUnit* CvPlayer::initUnit(UnitTypes eUnit, int iX, int iY, UnitAITypes eUnitAI, DirectionTypes eFacingDirection)
{
PROFILE_FUNC();
FAssertMsg(eUnit != NO_UNIT, "Unit is not assigned a valid value");
CvUnit* pUnit = addUnit();
FAssertMsg(pUnit != NULL, "Unit is not assigned a valid value");
if (NULL != pUnit)
{
pUnit->init(pUnit->getID(), eUnit, ((eUnitAI == NO_UNITAI) ? ((UnitAITypes)(GC.getUnitInfo(eUnit).getDefaultUnitAIType())) : eUnitAI), getID(), iX, iY, eFacingDirection);
}
return pUnit;
}
I wont include the full source for init(), but the relevant section is about line 490, a block added by Xienwolf on 07/16/08 which Automatically applies a Promotion if Unit meets conditions at creation. This calls CvUnit:
romote(
), which is defined on line 11080. This seems innocuous until we get to the last line of the function, 11185.
CvEventReporter::getInstance().unitPromoted(this, ePromotion);
This triggers the event handling which ultimately resolves into the python code. (273:CvEventReporter.cpp [m_kPythonEventMgr.reportUnitPromoted(pUnit, ePromotion);])
The relevant python class is CvEventManager.py and the method is on line 3073 (def onUnitPromoted(self, argsList)
. The problem comes about 3109.
Code:
# mekara start - Handles wipes of XP from units converted to sluga
pPlayer = gc.getPlayer( pUnit.getOwner())
if pPlayer.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_MEKARA'):
if pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_SLUGA') or pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_BATTLE_SLUGA'):
newUnit = pPlayer.initUnit(pUnit.getUnitType(), pUnit.getX(), pUnit.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
pUnit.kill(True, 0)
Here, the sluga is deleted and remade to wipe XP on upgrade. The problem is that for the battle_sluga, it can automatically gain a promotion: weapon upgrades (copper, iron at least). This means that the sluga you just created has now created a new sluga! The new sluga gets the promotion, which creates another sluga, which creates another
This is further complicated by the fact that the python eventing does not appear to actually be asynchronous (though I may be wrong). Relevant transition call goes through the core in 24:CvDllPythonEvents.cpp, [bool bOK = gDLL->getPythonIFace()->callFunction(PYEventModule, "onEvent", eventData.makeFunctionArgs(), &lResult);]. This means that CvEventManager.py never reaches line 2914 (pUnit.kill(True, 0)) thereby creating an infinite loop that endlessly creates but never destroys sluga.
This is not an issue for other sluga since the only referenced in the event handling are UNIT_SLUGA, which gets no promotion, and UNIT_BATTLE_SLUGA- the relevant unit of issue.
The simplest fix would be to comment (or remove) the block in CvEventManager.py, though that may reintroduce unwanted behavior. I have tested this change and it appears to work without issue.
The Fix:
If you want to continue playing as the Mekara but dont want to wait for the next patch, open
\Sid Meier's Civilization IV Beyond the Sword\Beyond the Sword\Mods\Ashes of Erebus\Assets\pythonCvEventManager.py with a text editor (notepad++ recommended) and search for # mekara start - Handles wipes or move to line 3109 if your editor allows. Comment out the five lines below that line by placing a # in front of any existing text. The lines to comment are shown in the last code section above. Save the changed file and the bug should be fixed.