Settlers! Mod causes OOS. How to fix the python?

Cuteunit

Danse Macabre
Joined
Sep 5, 2007
Messages
618
Settlers adds a few Settler replacements, the Colonist and the Pioneer, who found cities that come with a few basics like a lighthouse et al, and a higher pop.

But it causes OOS in multiplayer every single time one is used to found a city.

this is the SettlersEventManager.py from the Rise of Mankind mod.

Code:
from CvPythonExtensions import *

gc = CyGlobalContext()

class SettlersEventManager:
	def __init__(self, eventManager):
		eventManager.addEventHandler("cityBuilt", self.onCityBuilt)

	def onCityBuilt(self, argsList):
		'City Built'
		city = argsList[0]

		pUnit = CyInterface().getHeadSelectedUnit()
		if pUnit:
			#if pUnit.getUnitClassType() == gc.getInfoTypeForString("UNITCLASS_SETTLER"):
			#	## Do Nothing
			#	pass

			if pUnit.getUnitClassType() == gc.getInfoTypeForString("UNITCLASS_COLONIST"):
				city.setPopulation(3)
				_addBuilding(city, "BUILDINGCLASS_BARRACKS")
				_addBuilding(city, "BUILDINGCLASS_GRANARY")
				_addBuilding(city, "BUILDINGCLASS_FORGE")
				_addBuilding(city, "BUILDINGCLASS_MARKET")
				if city.plot().isCoastalLand():
					_addBuilding(city, "BUILDINGCLASS_HARBOR")
					_addBuilding(city, "BUILDINGCLASS_LIGHTHOUSE")
					_addBuilding(city, "BUILDINGCLASS_FISHERMAN_HUT")

			elif pUnit.getUnitClassType() == gc.getInfoTypeForString("UNITCLASS_PIONEER"):
				city.setPopulation(4)
				_addBuilding(city, "BUILDINGCLASS_GARRISON")
				_addBuilding(city, "BUILDINGCLASS_GRANARY")
				_addBuilding(city, "BUILDINGCLASS_FORGE")
				_addBuilding(city, "BUILDINGCLASS_COURTHOUSE")
				_addBuilding(city, "BUILDINGCLASS_MARKET")
				_addBuilding(city, "BUILDINGCLASS_STABLE")
				_addBuilding(city, "BUILDINGCLASS_GROCER")
				_addBuilding(city, "BUILDINGCLASS_DOCTOR")
				_addBuilding(city, "BUILDINGCLASS_BANK")
				_addBuilding(city, "BUILDINGCLASS_LIBRARY")
				if city.plot().isCoastalLand():
					_addBuilding(city, "BUILDINGCLASS_PORT")
					_addBuilding(city, "BUILDINGCLASS_LIGHTHOUSE")
					_addBuilding(city, "BUILDINGCLASS_FISHERMAN_HUT")

			#elif pUnit.getUnitClassType() == gc.getInfoTypeForString("UNITCLASS_ARCHITECT"):
			#	_addBuilding(city, "BUILDINGCLASS_BARRACKS")
			#	_addBuilding(city, "BUILDINGCLASS_GRANARY")
			#	_addBuilding(city, "BUILDINGCLASS_COURTHOUSE")
			#	_addBuilding(city, "BUILDINGCLASS_MARKET")
			#	_addBuilding(city, "BUILDINGCLASS_STABLE")
			#	_addBuilding(city, "BUILDINGCLASS_GROCER")
			#	_addBuilding(city, "BUILDINGCLASS_AQUEDUCT")
			#	_addBuilding(city, "BUILDINGCLASS_BANK")
			#	_addBuilding(city, "BUILDINGCLASS_FORGE")
			#	_addBuilding(city, "BUILDINGCLASS_LIBRARY")
			#	_addBuilding(city, "BUILDINGCLASS_JAIL")
			#	_addBuilding(city, "BUILDINGCLASS_OBSERVATORY")
			#	_addBuilding(city, "BUILDINGCLASS_THEATRE")
			#	_addBuilding(city, "BUILDINGCLASS_CUSTOM_HOUSE")
			#	_addBuilding(city, "BUILDINGCLASS_INDUSTRIAL_PARK")
			#	_addBuilding(city, "BUILDINGCLASS_LEVEE")
			#	_addBuilding(city, "BUILDINGCLASS_PUBLIC_TRANSPORTATION")
			#	if city.plot().isCoastalLand():
			#		_addBuilding(city, "BUILDINGCLASS_HARBOR")
			#		_addBuilding(city, "BUILDINGCLASS_LIGHTHOUSE")


def _addBuilding(pCity, szBuilding):
	iBuilding = gc.getInfoTypeForString(szBuilding)
	iUniqueBuilding = gc.getCivilizationInfo(gc.getPlayer(pCity.getOwner()).getCivilizationType()).getCivilizationBuildings(iBuilding)
	if iUniqueBuilding > -1:
		if pCity.canConstruct(iUniqueBuilding, False, True, False):
			pCity.setNumRealBuilding(iUniqueBuilding, pCity.getNumRealBuilding(iUniqueBuilding) + 1)

How can I edit this to allow these units to work as intended in multi? Please advise.
 
The line that cause an OOS is pUnit = CyInterface().getHeadSelectedUnit(). This unit is different with each PC so the result becomes different for each human player and cause the game an OOS. I guess also that if you group the unit that settle with some other unit and click on "found city", the function should not work even in SG game.

I don't think about a good simple solution to prevent that ... except implementing a differrent found city for each unit (should requires some SDK changes).

Tcho !
 
Perhaps use sendModNetMessage. But this feature is for Human player only ?
 
This should work (not tested) :

Spoiler :
Code:
from CvPythonExtensions import *

gc = CyGlobalContext()

class SettlersEventManager:
	def __init__(self, eventManager):
		eventManager.addEventHandler("cityBuilt", self.onCityBuilt)
[COLOR="Red"]		eventManager.addEventHandler("ModNetMessage", self.onModNetMessage)
[/COLOR]
	def onCityBuilt(self, argsList):
		'City Built'
		city = argsList[0]

		if city.getOwner() == gc.getGame().getActivePlayer() :
                        pUnit = CyInterface().getHeadSelectedUnit() # note that if the unit is grouped,headUnit is not forced to be the settler
                        if pUnit:
                                iOwner = city.getOwner()
                                iCityID = city.getID()
                                iUnitClass = pUnit.getUnitClassType()
                                CyMessageControl().sendModNetMessage(167, iOwner, iCityID, iUnitClass, -1) # be sure 167 is not use for another mod net message, the best should be to add an id in CvUtil like for events
                        
	def onModNetMessage(self, argsList):
		'Called whenever CyMessageControl().sendModNetMessage() is called - this is all for you modders!'
		
		iData1, iData2, iData3, iData4, iData5 = argsList
		if iData1 == 167 :
                        addBuildings(iData2, iData3, iData4)

		CvUtil.pyPrint( 'onModNetMessage' )

def addBuildings(iOwner, iCityID, iUnitClass):
        city = gc.getPlayer(iOwner).getCity(iCityID)

        #if iUnitClass == gc.getInfoTypeForString("UNITCLASS_SETTLER"):
        #	## Do Nothing
        #	pass

        if iUnitClass == gc.getInfoTypeForString("UNITCLASS_COLONIST"):
                city.setPopulation(3)
                _addBuilding(city, "BUILDINGCLASS_BARRACKS")
                _addBuilding(city, "BUILDINGCLASS_GRANARY")
                _addBuilding(city, "BUILDINGCLASS_FORGE")
                _addBuilding(city, "BUILDINGCLASS_MARKET")
                if city.plot().isCoastalLand():
                        _addBuilding(city, "BUILDINGCLASS_HARBOR")
                        _addBuilding(city, "BUILDINGCLASS_LIGHTHOUSE")
                        _addBuilding(city, "BUILDINGCLASS_FISHERMAN_HUT")

        elif iUnitClass == gc.getInfoTypeForString("UNITCLASS_PIONEER"):
                city.setPopulation(4)
                _addBuilding(city, "BUILDINGCLASS_GARRISON")
                _addBuilding(city, "BUILDINGCLASS_GRANARY")
                _addBuilding(city, "BUILDINGCLASS_FORGE")
                _addBuilding(city, "BUILDINGCLASS_COURTHOUSE")
                _addBuilding(city, "BUILDINGCLASS_MARKET")
                _addBuilding(city, "BUILDINGCLASS_STABLE")
                _addBuilding(city, "BUILDINGCLASS_GROCER")
                _addBuilding(city, "BUILDINGCLASS_DOCTOR")
                _addBuilding(city, "BUILDINGCLASS_BANK")
                _addBuilding(city, "BUILDINGCLASS_LIBRARY")
                if city.plot().isCoastalLand():
                        _addBuilding(city, "BUILDINGCLASS_PORT")
                        _addBuilding(city, "BUILDINGCLASS_LIGHTHOUSE")
                        _addBuilding(city, "BUILDINGCLASS_FISHERMAN_HUT")

        #elif iUnitClass == gc.getInfoTypeForString("UNITCLASS_ARCHITECT"):
        #	_addBuilding(city, "BUILDINGCLASS_BARRACKS")
        #	_addBuilding(city, "BUILDINGCLASS_GRANARY")
        #	_addBuilding(city, "BUILDINGCLASS_COURTHOUSE")
        #	_addBuilding(city, "BUILDINGCLASS_MARKET")
        #	_addBuilding(city, "BUILDINGCLASS_STABLE")
        #	_addBuilding(city, "BUILDINGCLASS_GROCER")
        #	_addBuilding(city, "BUILDINGCLASS_AQUEDUCT")
        #	_addBuilding(city, "BUILDINGCLASS_BANK")
        #	_addBuilding(city, "BUILDINGCLASS_FORGE")
        #	_addBuilding(city, "BUILDINGCLASS_LIBRARY")
        #	_addBuilding(city, "BUILDINGCLASS_JAIL")
        #	_addBuilding(city, "BUILDINGCLASS_OBSERVATORY")
        #	_addBuilding(city, "BUILDINGCLASS_THEATRE")
        #	_addBuilding(city, "BUILDINGCLASS_CUSTOM_HOUSE")
        #	_addBuilding(city, "BUILDINGCLASS_INDUSTRIAL_PARK")
        #	_addBuilding(city, "BUILDINGCLASS_LEVEE")
        #	_addBuilding(city, "BUILDINGCLASS_PUBLIC_TRANSPORTATION")
        #	if city.plot().isCoastalLand():
        #		_addBuilding(city, "BUILDINGCLASS_HARBOR")
        #		_addBuilding(city, "BUILDINGCLASS_LIGHTHOUSE")

def _addBuilding(pCity, szBuilding):
	iBuilding = gc.getInfoTypeForString(szBuilding)
	iUniqueBuilding = gc.getCivilizationInfo(gc.getPlayer(pCity.getOwner()).getCivilizationType()).getCivilizationBuildings(iBuilding)
	if iUniqueBuilding > -1:
		if pCity.canConstruct(iUniqueBuilding, False, True, False):
			pCity.setNumRealBuilding(iUniqueBuilding, pCity.getNumRealBuilding(iUniqueBuilding) + 1)

Tcho !
 
Sorry i've forgotten a line in __init__ . I've put it in red.
 
Hmm maybe that's it then. It was working in singleplayer but in MP colonists acted just like Settlers.

I'll try it with the added line later on
 
I don't know if it would work, but my first thought would be, when a City is Founded, loop through all the Units on that Plot and check what their current Mission is. If that Mission is "Found a City" then get your data from that Unit.

That way it will work for any Civ, Human or AI, in both SP and MP games.
 
Back
Top Bottom