Is their an easier way to debug civ 4 functions in python

But you need a PyPlayer instance. Would say anything to that, but i even can't find the commad getCityList :confused:.

A PyPlayer is not a CyPlayer...

The class used by the DLL is the CyPlayer class. This is what you get via gc.getPlayer.

PyPlayer is a class that is defined in PyHelpers.py. It actually includes the CyPlayer class for the player (which you can access via either PyPlayer.CyGet or PyPlayer.getPlayer), it defines some of the same methods as the CyPlayer which just saves you some notation (you can do a PyPlayer.getName instead of PyPlayer.getPlayer.getName), and it defines a variety of methods to get lists of things (like a list of all techs the player has researched, all cities done correctly via the iterator, all units done correctly via the iterator, a list of all plots owned by the player, a list of all plots owned by the player which have some specific bonus on them, etc.), and a few other things.
 
Ok, but if you need a pyPlayer instance - it is already specified isn't it (line 7 below). As I said, I tried it with both CityList = pUnitOwnerID.getCityList() and with CityList = pUnitOwner.getCityList(), and neither of the two work.

PHP:
	if (inputClass.getNotifyCode() == 11 and inputClass.getData1() == 301 and inputClass.getData2() == 301):
			self.iPushedButtonUnit = g_pSelectedUnit
			pUnit = g_pSelectedUnit
			iX = self.iPushedButtonUnit.getX()
			iY = self.iPushedButtonUnit.getY()
			pMerchantLocation = CyMap().plot(iX, iY)
			pUnitOwner = gc.getPlayer( pUnit.getOwner( ))
			if pMerchantLocation.isCity():
				TradeCity = pMerchantLocation.getPlotCity ()
				pTradePlayer = gc.getPlayer(TradeCity.getOwner())
				if pTradePlayer.getID() != pUnitOwner.getID() : # This now works 
					pUnitOwner.changeGold( game.getSorenRandNum(60,"Trade Result")) # will make this part of an if... elif once all functions work
					pUnitOwnerID = pUnitOwner.getID()
					gc.getTeam(pUnitOwner.getTeam()).changeResearchProgress (pUnitOwner.getCurrentResearch(),60,pUnitOwnerID) #works now, but seems cumbersome
					CityList = pUnitOwnerID.getCityList()
					iRnd = CyGame().getSorenRandNum(len(CityList), "Pick City")
					for i in range (0, len(CityList)):
						if i == iRnd :
							iTargetCity = CityList [i]
							iTargetCity.changePopulation(1) 
							iTargetCity.changeCulture (pUnitOwnerID, 60, True)
							break
					g_pSelectedUnit.finishMoves() # try this to end
 
A PyPlayer is a different object from a CyPlayer which is different from a player's ID. Yes, there are good reasons for all these objects. No, it's not easy to pick up--especially with the lack of documentation.

A PyPlayer is a purely Python helper class that wraps a CyPlayer object. Wrapping is an object-oriented term for having one object that provides a "nicer" interface to a different object. CyPlayer has two functions that allow you to loop over all of a player's cities: firstCity() and nextCity(). They operate on what's called an iterator which is another object that keeps track of where in the list your loop currently is.

I could explain how that works, but you can already see that it's more complicated than "give me the list of cities." PyPlayer, on the other hand, has that exact function: getCityList() which returns a list of CyCity objects in one call. You can use Python to easily loop over this list.

PyPlayer needs the player's ID which it uses to lookup the CyPlayer. You can pick a random city like this:

Code:
import PyHelpers
...
pyUnitOwner = PyHelpers.PyPlayer(pUnit.getOwner())
cities = pyUnitOwner.getCityList()
if len(cities) > 0:
    iCity = gc.getGame().getSorenRandNum(len(cities), "random city")
    pCity = cities[iCity]
    ... use pCity ...

A note about variable names: the BTS code (and most modders) tend to use a form of naming variables called Hungarian Notation. The "p" prefix is a carry-over from C that means pointer (to an object). Some code then uses "py" to distinguish objects from the PyHelpers module. Python doesn't care how you name your variables, but if you stick with Hungarian you should not put "p" in front of ints like player IDs--use "i" for that. The C++ code and some Python code use "e" for enumeration, e.g. PlayerTypes, UnitTypes, DomainTypes, etc.
 
Ok, but if you need a pyPlayer instance - it is already specified isn't it (line 7 below). As I said, I tried it with both CityList = pUnitOwnerID.getCityList() and with CityList = pUnitOwner.getCityList(), and neither of the two work.

PHP:
	if (inputClass.getNotifyCode() == 11 and inputClass.getData1() == 301 and inputClass.getData2() == 301):
			self.iPushedButtonUnit = g_pSelectedUnit
			pUnit = g_pSelectedUnit
			iX = self.iPushedButtonUnit.getX()
			iY = self.iPushedButtonUnit.getY()
			pMerchantLocation = CyMap().plot(iX, iY)
			pUnitOwner = gc.getPlayer( pUnit.getOwner( ))
			if pMerchantLocation.isCity():
				TradeCity = pMerchantLocation.getPlotCity ()
				pTradePlayer = gc.getPlayer(TradeCity.getOwner())
				if pTradePlayer.getID() != pUnitOwner.getID() : # This now works 
					pUnitOwner.changeGold( game.getSorenRandNum(60,"Trade Result")) # will make this part of an if... elif once all functions work
					pUnitOwnerID = pUnitOwner.getID()
					gc.getTeam(pUnitOwner.getTeam()).changeResearchProgress (pUnitOwner.getCurrentResearch(),60,pUnitOwnerID) #works now, but seems cumbersome
					CityList = pUnitOwnerID.getCityList()
					iRnd = CyGame().getSorenRandNum(len(CityList), "Pick City")
					for i in range (0, len(CityList)):
						if i == iRnd :
							iTargetCity = CityList [i]
							iTargetCity.changePopulation(1) 
							iTargetCity.changeCulture (pUnitOwnerID, 60, True)
							break
					g_pSelectedUnit.finishMoves() # try this to end

You are not using a PyPlayer. One does not appear anywhere in the above code.

Your current code has "CityList = pUnitOwnerID.getCityList()", but pUnitOwnerID was set via "pUnitOwnerID = pUnitOwner.getID()" and is therefore a (poorly named) plain old integer.

The variable pUnitOwner was set via "pUnitOwner = gc.getPlayer( pUnit.getOwner( ))" and is therefore an object of class CyPlayer, not PyPlayer.

The code in EmperorFool's post shows how to get the appropriate PyPlayer class object.
 
Here's what Final Frontier uses to display the production popup on the first turn:
Code:
		# Loop through all of players
		for iPlayer in range(gc.getMAX_PLAYERS()):
			pPlayer = gc.getPlayer(iPlayer)
			
			if (pPlayer.isAlive()):
				pyPlayer = PyPlayer(iPlayer)
				
				# Show production popup for cities which don't have assigned production yet
				
				apCityList = pyPlayer.getCityList()
				for pyCity in apCityList:
					pCity = pyCity.GetCy()
					# Production assigned? If not, bring up the popup
					if (not pCity.isProduction()):
						pCity.chooseProduction(-1,-1,-1, false, false)
 
Top Bottom