Python Help Please!

moopoo

King
Joined
Jan 5, 2008
Messages
729
Location
Adelaide, Australia
Ok. As an attempt to learn Python, I want to code a little piece of code that says once you have the tech astronomy, when you found a city it comes with a granary, aquaduct and forge, and to give them a pop of 3

In psuedo-code, this is how I envisage it will turn out. Note that the pop thing I've taken from Tsentom1's Ag trait:

Spoiler :

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

## Agr Trait Start ## I don't know why iTrait is doing that in here

		player = PyPlayer(city.getOwner())
		pPlayer = gc.getPlayer(city.getOwner())
                iTrait = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_AGRICULTURAL')

		if (pPlayer.hasTrait(iTrait)):
			city.changePopulation(2) # Tsentom originally had a 1 here

## Agr Trait End ##

#My kinda-code start#
               itech = <Insert code that finds and identifies Astronomy>

               if (pPlayer.isHasTech(itech)
                        <something to put aquaduct, granary, forge>
#My kinda-code end#

#Back to Original Code
		if (city.getOwner() == gc.getGame().getActivePlayer()):
			self.__eventEditCityNameBegin(city, False)	
		CvUtil.pyPrint('City Built Event: %s' %(city.getName()))


As you can see, i don't have much there.

Is what I have there structured right, and all that? Any suggestions about how the code identifying Astronomy should look? Any suggestions about what to do about getting buildings in there? Please help, I'm trying really hard to get this :p
 
One problem right off the bat is that you've made the standard Python rookie mistake of mixing tabs and spaces.

This line:
Code:
		pPlayer = gc.getPlayer(city.getOwner())
starts with two tabs, but the line after it:
Code:
                iTrait = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_AGRICULTURAL')
starts with a bunch of spaces. Python uses indentation the same way other languages use braces ({}) to determine where logical code blocks start and end. Mixing tabs and spaces is a sure way to confuse the parser. Since the rest of the file uses tabs, you'll want to change that line to start the same way.

To find whether you have Astronomy, you first need to determine which tech is Astronomy:
Code:
		iTech = gc.getInfoTypeForString("TECH_ASTRONOMY")

And to find out if the player has the tech, you need to do a little extra work and turn the player into a team because techs are team-based.
Code:
		iTeam = pPlayer.getTeam()
		pTeam = gc.getTeam(iTeam)
		if (pTeam.isHasTech(iTech)):
			#adding stuff goes here

As for the buildings themselves, you need to get the building IDs similar to how we got the tech ID and then use CyCity.setNumRealBuilding() to add them:
Code:
			iGranary = gc.getInfoTypeForString("BUILDING_GRANARY")
			city.setNumRealBuilding(iGranary, 1)
You can either do that for each building individually or you could put the buildings into a list and do a little loop which means a little less code and makes it easier to put in extra buildings or take some away later.

BTW, Are you actually using tsentom's Agricultural trait in your mod? And, if so, do you only want the pop increase to happen for civs with that trait? If no for either, then you'd remove the iTrait assignment and the subsequent if check and move the population change under the Astronomy check.

The above should be enough info for you to code it. However, if you want to see how I'd do it, there's a full working example in the spoiler.
Spoiler :
Code:
	def onCityBuilt(self, argsList):
		'City Built'
		city = argsList[0]

		#Astronomy Bonus Start
		iPlayer = city.getOwner()
		pPlayer = gc.getPlayer(iPlayer)
		iTeam = pPlayer.getTeam()
		pTeam = gc.getTeam(iTeam)

		iTech = gc.getInfoTypeForString("TECH_ASTRONOMY")
		if (pTeam.isHasTech(iTech)):
			city.changePopulation(2)
			szAddBuildingsList = ["BUILDING_GRANARY", "BUILDING_AQUEDUCT", "BUILDING_FORGE"]
			for szBuilding in szAddBuildingsList:
				iBuilding = gc.getInfoTypeForString(szBuilding)
				city.setNumRealBuilding(iBuilding, 1)
		#Astronomy Bonus End

		if (city.getOwner() == gc.getGame().getActivePlayer()):
			self.__eventEditCityNameBegin(city, False)	
		CvUtil.pyPrint('City Built Event: %s' %(city.getName()))
 
*Dances* Thankyou thankyou thankyou! You've just helped a guy on his first step in modding =)

I knew the thing abou spaces and tabs (I've read many a tute on python), but that'll be handy to keep in mind.

And thankyou for the reminder regarding Tsentom's Trait.

EDIT: What does the sz on "szBuilding" mean? or is that just a prefix you've used for a new variable?
 
I follow the (usual) Firaxis convention of prefixing variable names with a type indicator. The most common: iFoo is an integer, pFoo is a pointer (generally some game object), and szFoo is a string. I actually don't know why it's "sz" instead of "s", (although I'd guess it means zero-terminated) but I'm used to it. :p

EDIT: It looks like I was right about the "z". This kind of naming is known as Hungarian Notation and it's especially useful for dynamically-typed languages like Python.
 
In your little loop there dresden, how does it know what "szbuilding" is? The first time it appears in the code is at "for szbuilding in szbuildinglist" - does it figure out for itself that "blah" is a single item in "blahlist"?
 
Exactly. for Item in List loops through List one element at a time, assigning the current element to Item.

BTW,iIf you have other programming experience but are new to Python, the online book Dive Into Python is a quick and helpful introduction.
 
Top Bottom