Error here:
http://forums.civfanatics.com/showpost.php?p=4490630&postcount=11
Save can be found here:
http://forums.civfanatics.com/attachment.php?attachmentid=137302&d=1157228078
Problem in this code:
MercenaryUtils.py:
Code:
# Places the mercenary in the city specified by the objCity variable
def place(self, objCity):
# Return immediately if the mercenary is already in the game
if(self.objUnit != None):
return
# get the player instance
player = gc.getPlayer(self.iOwner)
# return nothing if the player is an invalid value
if(player == None):
player = gc.getPlayer(self.iBuilder)
if(player == None):
return
# return nothing if the player is dead
if(player.isAlive() == false):
return
unitType = gc.getInfoTypeForString(self.objUnitInfo.getType())
# Create the unit and place it in the game
[b]self.objUnit = player.initUnit(unitType, objCity.getX(), objCity.getY(), UnitAITypes.NO_UNITAI)[/b]
So far, I've come up with the fact that the function is getting passed a city whose X and Y are -1, -1. Thus, apparently the unit is being init'd at -1, -1. Apparently, the AI bought a unit and something went ka-blammo?
I'm still working on it.
Edit: So far, I think there's a problem in the function used in the merc mod where it gets a random city. It gets a random number between 0 and the number of cities the player owns, and uses that number to get the city object using pPlayer.getCity(i). The problem is that I don't believe that that is how the getCity function works.
Say you create three cities (0, 1, 2). You now have 3 cities. Say city 1 gets knocked off. You're down to two cities, affectionately named 0 and 2. However, 2 doesn't "move over" to fill the gap in the city list, because it's stored in a fixed array. So, you have a city object in index 0 and 2, and a NULL in spot 1. Now, say you go through this bit of code:
Code:
def getMercenaryStartingLocation(self, iPlayer):
' CyCity - the starting city for hired mercenaries'
player = gc.getPlayer(iPlayer)
objCity = None
if(g_strMercenaryStartingLocation == "Capital City"):
objCity = player.getCapitalCity()
elif(g_strMercenaryStartingLocation == "Civilization Edge"):
objCity = self.getCivilizationEdgeCity(iPlayer)
elif(g_strMercenaryStartingLocation == "Random"):
[b]objCity = player.getCity(gc.getGame().getMapRand().get(player.getNumCities(), "Random City"))[/b]
elif(len(g_strMercenaryStartingLocation) > 0):
objCity = self.getRandomCityWithBuildings(iPlayer)
else:
[b]objCity = player.getCity(gc.getGame().getMapRand().get(player.getNumCities(), "Random City"))[/b]
if(objCity == None):
[b]objCity = player.getCity(gc.getGame().getMapRand().get(player.getNumCities(), "Random City"))[/b]
return objCity
In all of those places, you have a chance of getting back a city object that is actually invalid, because with 2 cities, your random number will either be 0 or 1. If it's one, you will call getCity(1), which will get you this code in the SDK:
Code:
CyCity* CyPlayer::getCity(int iID)
{
return m_pPlayer ? new CyCity(m_pPlayer->getCity(iID)) : NULL;
}
Because what is actually returned is a new CyCity object, it won't be returned as None.
I'm gonna' go try to confirm this with TheLopez however.
Edit 2: Posted this
report to TheLopez.