Mod crashes

Here's the OIM module:
 

Attachments

Looking at the code, the only thing I can fathom is that something is awry with the XML. What the getReligionInquisitor() method does, is it returns the unit description name. It does this through an elaborate process involving iterating through all unit classes. The actual UnitType is determined by looking up the corresponding unit for the player's Civilization.

This suggests to me that some unit - it doesn't have to be a Inquisitor unit - has conflicting settings in the Civilization XML infos. So I'd suggest going through the entries for that Civilization.

The exception itself can be prevented from happening - by adding a check for invalid UnitTypes - but I'd suggest this is a chance to actually clear a potential bug in the XML. In order to debug this, you can add these lines:
Code:
def getReligionInquisitor(iPlayer, iReligion):
	# Limited Religions
	# Returns the Inquisitor Name for the specified Religion
	pPlayer = gc.getPlayer(iPlayer)
	pCivilization = gc.getCivilizationInfo(pPlayer.getCivilizationType())
	PrereqBuildingName = getReligionHolyOffice(iPlayer, iReligion)
[B][COLOR="Red"]	print "Checking getReligionInquisitor() method for player " + str(iPlayer)[/COLOR][/B]
	for iUnitClass in range(gc.getNumUnitClassInfos()):
		if gc.getUnitClassInfo(iUnitClass).getMaxPlayerInstances() > 0:
			iUnit = pCivilization.getCivilizationUnits(iUnitClass)
[B][COLOR="Red"]			print "UnitClass: " + str(iUnitClass) + ", UnitType: " + str(iUnit)[/COLOR][/B]
			if gc.getUnitInfo(iUnit).getPrereqReligion() != -1:
				inqPrereqRel = gc.getUnitInfo(iUnit).getPrereqReligion()			
						
				if inqPrereqRel == iReligion:
					# Look for state Religion Holy Office
					if gc.getUnitInfo(iUnit).getPrereqBuilding() != -1:					
						iPrereqBld = gc.getUnitInfo(iUnit).getPrereqBuilding()
										
						if iPrereqBld == gc.getInfoTypeForString(PrereqBuildingName):
							MyInquisitorName = gc.getUnitInfo(iUnit).getType()
							#CyInterface().addImmediateMessage(str(MyInquisitorName), "")
							return MyInquisitorName
							break
Now, enable logging in the main INI file and try to recreate the exception. Once you manage to get the error message, post your PythonDbg.log file here. Because then we can pinpoint what unit class is invalid for what player.
 
I agree that this is almost certainly caused by the civilization XML, but you should put a check for it in the Python since the setup in the XML that causes this is valid. Most likely, some civ has the unit type set to NONE for some unit class (any unit class since it loops over them all)) to prevent it from building a unit of that class. If this is ever called for the barbarians, then it could be them.

You must check the value of iUnit that is returned by pCivilization.getCivilizationUnits(iUnitClass) to make sure that it is not -1, which is what you get for NONE. If it is -1, then gc.getUnitInfo(iUnit) will not return a valid unit info, instead it will return a "none type object", which not being a valid unit info will not have the getPrereqReligion() method (as per the error message) and therefore it will fail at that point.
 
I agree that this is almost certainly caused by the civilization XML, but you should put a check for it in the Python since the setup in the XML that causes this is valid. Most likely, some civ has the unit type set to NONE for some unit class (any unit class since it loops over them all)) to prevent it from building a unit of that class. If this is ever called for the barbarians, then it could be them.
My initial thought was that the unit causing the exception belonged to the Barbarians or some other minor player, and was created via World Builder. Is this the case?

You must check the value of iUnit that is returned by pCivilization.getCivilizationUnits(iUnitClass) to make sure that it is not -1, which is what you get for NONE. If it is -1, then gc.getUnitInfo(iUnit) will not return a valid unit info, instead it will return a "none type object", which not being a valid unit info will not have the getPrereqReligion() method (as per the error message) and therefore it will fail at that point.
Yeah, this is exactly what we're gonna do, and this is why Farsight needs to run my debug code and post the Python Debug Log.
 
My initial thought was that the unit causing the exception belonged to the Barbarians or some other minor player, and was created via World Builder. Is this the case?
There is not necessarily an actual unit of the class in existence. It isn't checking for an actual unit anywhere, just what kind of unit can be built by the civ for which this is being run.

The "gc.getUnitClassInfo(iUnitClass).getMaxPlayerInstances() > 0" check isn't checking to see if there are any actual units in existence, it's checking for unit classes that have a maximum that can exist for a player at any time. In regular BtS this is all missionaries and corporation executives. Evidently the inquisitors in this mod also have this property, and there may be more.

Since UNITCLASS_EXECUTIVE_1 it the first one with such a limit listed in the unit class info file (unless more unit classes with limited numbers were added before them in this mod) that is probably the one that is causing the problem if it is the barbarian civ that is running this code since barbarians have NONE for the unit type for that class. But it could be some other civ in the mod. In regular BtS the barbarians are the only civ that is not allowed to build units of every class.
 
Yeah, as said; The exception can easily be avoided by adding yet another check. And there are already a number of those, just none that deals with UnitTypes vs UnitClassTypes. If the XML indeed is in order (by the mod author's definition), then the Python portion of this needs to be augmented.
 
... and here is the error log:

Code:
  File "CvScreensInterface", line 705, in forceScreenRedraw

  File "CvMainInterface", line 720, in redraw

  File "CvMainInterface", line 1524, in updateSelectionButtons

  File "OIM", line 854, in showInquisitionButton

  File "OIM", line 180, in getReligionInquisitor

AttributeError: 'NoneType' object has no attribute 'getPrereqReligion'
ERR: Python function forceScreenRedraw failed, module CvScreensInterface
 
No, I said Python Debug Log.

\Documents\Games\Beyond the Sword\Logs\PythonDbg.log

Note however that you probably need to enable logging in the main INI file!
 
Sorry, that was solely the result of me misinterpreting what you said. Here's the Python Dbg log:

Code:
Checking getReligionInquisitor() method for player 0

UnitClass: 9, UnitType: 12

UnitClass: 10, UnitType: 13

UnitClass: 11, UnitType: 14

UnitClass: 12, UnitType: 15

UnitClass: 13, UnitType: 16

UnitClass: 14, UnitType: 17

UnitClass: 15, UnitType: 18

UnitClass: 16, UnitType: 19

UnitClass: 17, UnitType: 20

UnitClass: 18, UnitType: 21

UnitClass: 19, UnitType: 22

UnitClass: 20, UnitType: 23

UnitClass: 21, UnitType: 24

UnitClass: 22, UnitType: 25

UnitClass: 23, UnitType: 27

UnitClass: 24, UnitType: 26

UnitClass: 25, UnitType: 28

UnitClass: 116, UnitType: 125

UnitClass: 118, UnitType: 126

UnitClass: 137, UnitType: -1

PY:OnUnInit
UnInit Python
 
How do I determine that?

On a related note, I have a feeling that I'm actually getting this error because I placed it down in the WorldBuilder. Maybe if I just build it regularly in the game, I won't get the error.
 
What the debug information tells us, is that player 0 (zero) has no UnitType for UnitClassType 137. This is causing the Inquisitor code to throw up an exception, because it was never intended to handle such an event.

In order to fix this, you either change the XML accordingly, or we change the Python script to handle the current XML settings of your mod. But before deciding, make sure that the XML indeed is in order. (Check out what UnitClassType the issue concerns and what the correct XML settings are for the first CivilizationType of the first player in your test.)
 
The unit classes (like just about everything) are numbered in the order they are found in the file where they are defined, with the first one being unit class 0.
 
Yeah, they're enumerated. The default BtS types are these and these.

If you wanna make my debug messages make more sense you could try changing the second print statement to this:
Code:
			print "UnitClass: " + gc.getUnitClassInfo(iUnitClass).getDescription() + ", UnitType: " + str(iUnit)
 
Here's the new Debug log:

Code:
SCREEN OFF

PY:Cuzco has grown
Checking getReligionInquisitor() method for player 2

UnitClass: Wonka Executive, UnitType: 12

UnitClass: CHANGED_TXT_KEY_UNIT_EXECUTIVE_2, UnitType: 13

UnitClass: Dinoco Executive, UnitType: 14

UnitClass: A.C.M.E. Executive, UnitType: 15

UnitClass: Cyberdyne Executive, UnitType: 16

UnitClass: Black Mesa Executive, UnitType: 17

UnitClass: Mooby Executive, UnitType: 18

UnitClass: Jewish Missionary, UnitType: 19

UnitClass: Christian Missionary, UnitType: 20

UnitClass: Islamic Missionary, UnitType: 21

UnitClass: Hindu Missionary, UnitType: 22

UnitClass: Buddhist Missionary, UnitType: 23

UnitClass: Confucian Missionary, UnitType: 24

UnitClass: Taoist Missionary, UnitType: 25

UnitClass: Martian Missionary, UnitType: 27

UnitClass: Yuggoth Missionary, UnitType: 26

UnitClass: Wizarding Missionary, UnitType: 28

UnitClass: Dreadnought, UnitType: 125

UnitClass: Assault Mech, UnitType: 126

UnitClass: TXT_KEY_SPECIALIST_SUPERHERO, UnitType: -1

Checking getReligionInquisitor() method for player 2

UnitClass: Wonka Executive, UnitType: 12

UnitClass: CHANGED_TXT_KEY_UNIT_EXECUTIVE_2, UnitType: 13

UnitClass: Dinoco Executive, UnitType: 14

UnitClass: A.C.M.E. Executive, UnitType: 15

UnitClass: Cyberdyne Executive, UnitType: 16

UnitClass: Black Mesa Executive, UnitType: 17

UnitClass: Mooby Executive, UnitType: 18

UnitClass: Jewish Missionary, UnitType: 19

UnitClass: Christian Missionary, UnitType: 20

UnitClass: Islamic Missionary, UnitType: 21

UnitClass: Hindu Missionary, UnitType: 22

UnitClass: Buddhist Missionary, UnitType: 23

UnitClass: Confucian Missionary, UnitType: 24

UnitClass: Taoist Missionary, UnitType: 25

UnitClass: Martian Missionary, UnitType: 27

UnitClass: Yuggoth Missionary, UnitType: 26

UnitClass: Wizarding Missionary, UnitType: 28

UnitClass: Dreadnought, UnitType: 125

UnitClass: Assault Mech, UnitType: 126

UnitClass: TXT_KEY_SPECIALIST_SUPERHERO, UnitType: -1

Checking getReligionInquisitor() method for player 3

UnitClass: Wonka Executive, UnitType: 12

UnitClass: CHANGED_TXT_KEY_UNIT_EXECUTIVE_2, UnitType: 13

UnitClass: Dinoco Executive, UnitType: 14

UnitClass: A.C.M.E. Executive, UnitType: 15

UnitClass: Cyberdyne Executive, UnitType: 16

UnitClass: Black Mesa Executive, UnitType: 17

UnitClass: Mooby Executive, UnitType: 18

UnitClass: Jewish Missionary, UnitType: 19

UnitClass: Christian Missionary, UnitType: 20

UnitClass: Islamic Missionary, UnitType: 21

UnitClass: Hindu Missionary, UnitType: 22

UnitClass: Buddhist Missionary, UnitType: 23

UnitClass: Confucian Missionary, UnitType: 24

UnitClass: Taoist Missionary, UnitType: 25

UnitClass: Martian Missionary, UnitType: 27

UnitClass: Yuggoth Missionary, UnitType: 26

UnitClass: Wizarding Missionary, UnitType: 28

UnitClass: Dreadnought, UnitType: 125

UnitClass: Assault Mech, UnitType: 126

UnitClass: TXT_KEY_SPECIALIST_SUPERHERO, UnitType: -1

Checking getReligionInquisitor() method for player 3

UnitClass: Wonka Executive, UnitType: 12

UnitClass: CHANGED_TXT_KEY_UNIT_EXECUTIVE_2, UnitType: 13

UnitClass: Dinoco Executive, UnitType: 14

UnitClass: A.C.M.E. Executive, UnitType: 15

UnitClass: Cyberdyne Executive, UnitType: 16

UnitClass: Black Mesa Executive, UnitType: 17

UnitClass: Mooby Executive, UnitType: 18

UnitClass: Jewish Missionary, UnitType: 19

UnitClass: Christian Missionary, UnitType: 20

UnitClass: Islamic Missionary, UnitType: 21

UnitClass: Hindu Missionary, UnitType: 22

UnitClass: Buddhist Missionary, UnitType: 23

UnitClass: Confucian Missionary, UnitType: 24

UnitClass: Taoist Missionary, UnitType: 25

UnitClass: Martian Missionary, UnitType: 27

UnitClass: Yuggoth Missionary, UnitType: 26

UnitClass: Wizarding Missionary, UnitType: 28

UnitClass: Dreadnought, UnitType: 125

UnitClass: Assault Mech, UnitType: 126

UnitClass: TXT_KEY_SPECIALIST_SUPERHERO, UnitType: -1

PY:OnPreSave
 
The point of the debug lines is, of course, the last entry, because after that the code is executed by the exception:
UnitClass: TXT_KEY_SPECIALIST_SUPERHERO, UnitType: -1
So you have a custom unit class without even a proper description. And I'm guessing that no player is able to build any unit belonging to this class, hence the -1 (None) UnitType value.

Do you wanna/need to keep the unit class as-is or should we enhance the Python script in order to tolerate such a thing? Make a decision.
 
I've removed the Superhero class, and here's what the log looks like now:

Code:
UnitClass: TXT_KEY_SPECIALIST_GOLEM, UnitType: 167

UnitClass: TXT_KEY_SPECIALIST_KNIGHT_TEMPLAR, UnitType: 168

UnitClass: TXT_KEY_SPECIALIST_DJINN, UnitType: 169

UnitClass: TXT_KEY_SPECIALIST_VIMANA, UnitType: 170

UnitClass: TXT_KEY_SPECIALIST_SHAOLIN_MONK, UnitType: -1

Since special religion-specific units are a key part of Fictionalization IV, I would like a way to have the Python code try and work with these new units.
 
Sure thing, try this (add one single line, marked with red):
Code:
def getReligionInquisitor(iPlayer, iReligion):
	# Limited Religions
	# Returns the Inquisitor Name for the specified Religion
	pPlayer = gc.getPlayer(iPlayer)
	pCivilization = gc.getCivilizationInfo(pPlayer.getCivilizationType())
	PrereqBuildingName = getReligionHolyOffice(iPlayer, iReligion)
	for iUnitClass in range(gc.getNumUnitClassInfos()):
		if gc.getUnitClassInfo(iUnitClass).getMaxPlayerInstances() > 0:
			iUnit = pCivilization.getCivilizationUnits(iUnitClass)
[COLOR="Red"]			if iUnit == -1: continue[/COLOR]
			if gc.getUnitInfo(iUnit).getPrereqReligion() != -1:
				inqPrereqRel = gc.getUnitInfo(iUnit).getPrereqReligion()			
						
				if inqPrereqRel == iReligion:
					# Look for state Religion Holy Office
					if gc.getUnitInfo(iUnit).getPrereqBuilding() != -1:					
						iPrereqBld = gc.getUnitInfo(iUnit).getPrereqBuilding()
										
						if iPrereqBld == gc.getInfoTypeForString(PrereqBuildingName):
							MyInquisitorName = gc.getUnitInfo(iUnit).getType()
							#CyInterface().addImmediateMessage(str(MyInquisitorName), "")
							return MyInquisitorName
							break
Note that you should take out the print statements posted earlier, they're not doing you any more favors.
 
Okay, the mod works now. Thank you for all the help.
 
Nice! :goodjob:
 
Back
Top Bottom