Python please :)

ocedius

C++ induced baldness
Joined
Jun 27, 2003
Messages
617
Location
TX and proud of it!
Could you Python modders please post a list of all python commands used in civ IV? I mean commands like how to refresh a current screen, or how to dump current selected unit attributes into a log file etc.

Tried searching through the forums and unfortunatley reading through modded python code just isn't as helpful.
 
The list of all the python functions is here in the API. The python tutorial that got me started was The Great Apple's, which is found here. There are others that are very good as well.

It's slow going learning at first, but once you get the hang of it, it's very rewarding. Just remember, you can't do everything in python. Good luck :goodjob:
 
ok. While the python command list is very helpful, I get the ~there is no such command~ blah blah blah error when I try to use the updatevisibility() for forcing a screen rebuild. The first attachment is what my man-made lakes look like with plot = ocean, and terrain = coast, and the second is the same screen after a save game reload.

Could someone tell me where I am going wrong?

Code:
		if(iImprovement==gc.getInfoTypeForString('IMPROVEMENT_NEW_WATER')):
			numberofunits = pPlot.getNumUnits()
			while(numberofunits > 0):
				pPlot.getUnit(0).jumpToNearestValidPlot()
				numberofunits = pPlot.getNumUnits()
			pPlot.setTerrainType(gc.getInfoTypeForString("TERRAIN_COAST"),1,1)
			pPlot.setImprovementType(-1)
			CyInterface().addImmediateMessage("A new area was inundated!", "AS2D_NEW_ERA")

		if(iImprovement==gc.getInfoTypeForString('IMPROVEMENT_NEW_LAND')):
				numberofunits = pPlot.getNumUnits()
				while(numberofunits > 0):
					pPlot.getUnit(0).jumpToNearestValidPlot()
					numberofunits = pPlot.getNumUnits()
				pPlot.setTerrainType(gc.getInfoTypeForString("TERRAIN_PLAINS"),1,1)
				CyInterface().addImmediateMessage("A new land extension has been created!", "AS2D_NEW_ERA")


pPlot.Updatevisibility()
 

Attachments

  • 1.JPG
    1.JPG
    154.3 KB · Views: 117
  • 2.JPG
    2.JPG
    142.1 KB · Views: 110
The function names are all case sensitive. Try updateVisibility instead of Updatevisibility.
 
If the indentation posted is the indentation you're using, then it's wrong. It needs to be at the same indentation as the code you want it to run with.
 
ok here is the full code with which I am working right now:

Code:
class Terraform:
	def onImprovementBuilt(self,argsList):
		iImprovement, iX, iY = argsList
		pPlot = CyMap().plot(iX,iY)

		if(iImprovement==gc.getInfoTypeForString('IMPROVEMENT_NEW_WATER')):
			numberofunits = pPlot.getNumUnits()
			while(numberofunits > 0):
				pPlot.getUnit(0).jumpToNearestValidPlot()
				numberofunits = pPlot.getNumUnits()
			pPlot.setTerrainType(gc.getInfoTypeForString("TERRAIN_COAST"),1,1)
			pPlot.setImprovementType(-1)
			CyInterface().addImmediateMessage("A new area was inundated!", "AS2D_NEW_ERA")
			pPlot.updateVisibility()

		if(iImprovement==gc.getInfoTypeForString('IMPROVEMENT_NEW_LAND')):
				numberofunits = pPlot.getNumUnits()
				while(numberofunits > 0):
					pPlot.getUnit(0).jumpToNearestValidPlot()
					numberofunits = pPlot.getNumUnits()
				pPlot.setTerrainType(gc.getInfoTypeForString("TERRAIN_PLAINS"),1,1)
				CyInterface().addImmediateMessage("A new land extension has been created!", "AS2D_NEW_ERA")

		if(iImprovement==gc.getInfoTypeForString('IMPROVEMENT_NEW_FLATLAND')):
			pPlot.setTerrainType(gc.getInfoTypeForString("TERRAIN_PLAINS"),1,1)
			pPlot.setImprovementType(-1)
			CyInterface().addImmediateMessage("A hill was leveled!", "AS2D_NEW_ERA")

		if(iImprovement==gc.getInfoTypeForString('IMPROVEMENT_NEW_HILL')):
			pPlot.setTerrainType(gc.getInfoTypeForString("TERRAIN_HILL"),1,1)
			pPlot.setImprovementType(-1)
			CyInterface().addImmediateMessage("A hill was formed by pilling up dirt and rubble!", "AS2D_NEW_ERA")

		pPlot.updateVisibility()
 
My bad. I have and onImprovement call for a function 'Terraform' in a modcomponent.py file. The Terraform function contains the what-to-do I have included in the earlier post. The worker has relevent buttons for the actions which call the terraform sequence, allowing for improvments like turn land to coast etc.

The function works, and the events yield the result, except, the terrain changes from land to coast, but the graphics remain at ocean state, so I can bring a work boat onto the tilewhich was formerly land and now appears like an ocewan tile. I am trying to force a refresh event for purly graphical reasons. Right now, if I save and reload the game, the terrain changes to the correct graphics.

Please see the attached .jpgs , they are of the same screen, before and after and save game reload.
 
Aaah - graphical.

Okies. I think you need to use pPlot.setPlotType(...) to change the plot type from Land->Sea. Something like:

Code:
pPlot.setPlotType(gc.getInfoTypeForString("PLOT_OCEAN"),1,1)

If that doesn't work - IIRC the world builder is all handled in python, so I'd check the code out for that.
 
Actually that is how I started working on it, by changing the plot and then the terrain before removing improvments etc.

But I got this error, which is why I skipped the plot change step:

ArgumentError: Python argument types in
CyPlot.setPlotType(CyPlot, int, int, int)
did not match C++ signature:
setPlotType(class CyPlot {lvalue}, enum PlotTypes, bool, bool)
ERR: Python function onEvent failed, module CvEventInterface
Traceback (most recent call last):

Code:
			pPlot.setPlotType(gc.getInfoTypeForString("PLOT_OCEAN"),1,1)

I know, my computer is cursed :)

Just tinkered around some more and reused even older code I got to work originally for turnign land to water. I tried the:
Code:
			pPlot.setPlotType(PlotTypes.PLOT_OCEAN, true, true)

This yields a different error and the screen graphics change to ocean plot: The pythonErr.log file indicates this as the last error: Traceback (most recent call last):
File "CvEventInterface", line 24, in onEvent
File "CvEventManager", line 174, in handleEvent
File "CvEventManager", line 316, in onBeginGameTurn
File "Modcomponents", line 389, in onBeginPlayerTurn
ValueError
:
need more than 1 value to unpack

ERR: Python function onEvent failed, module CvEventInterface

Traceback (most recent call last):
File "CvEventInterface", line 24, in onEvent
File "CvEventManager", line 174, in handleEvent
File "CvEventManager", line 316, in onBeginGameTurn
File "Modcomponents", line 389, in onBeginPlayerTurn
ValueError: need more than 1 value to unpack

.. Did I mention my computer was cursed?
 
ocedius said:
Actually that is how I started working on it, by changing the plot and then the terrain before removing improvments etc.



Just tinkered around some more and reused even older code I got to work originally for turnign land to water. I tried the:
Code:
			pPlot.setPlotType(PlotTypes.PLOT_OCEAN, true, true)

This yields a different error and the screen graphics change to ocean plot: The pythonErr.log file indicates this as the last error: Traceback (most recent call last):
File "CvEventInterface", line 24, in onEvent
File "CvEventManager", line 174, in handleEvent
File "CvEventManager", line 316, in onBeginGameTurn
File "Modcomponents", line 389, in onBeginPlayerTurn
ValueError
:
need more than 1 value to unpack

ERR: Python function onEvent failed, module CvEventInterface

Traceback (most recent call last):
File "CvEventInterface", line 24, in onEvent
File "CvEventManager", line 174, in handleEvent
File "CvEventManager", line 316, in onBeginGameTurn
File "Modcomponents", line 389, in onBeginPlayerTurn
ValueError: need more than 1 value to unpack

.. Did I mention my computer was cursed?

Be careful about your true's. In python, the True and False values should be uppercase.

What is on line 389? Is it one of those:

something = argsList

if so, perhaps you need:

something, somethingElse = argsList

?
 
WTF! You mean you can use something called "while" instead of just "if" and "elif" ? TGA, please explain!
 
nope. true = TRUE = True, same result. The screen doesn't refresh the terrain graphics until after the game save-n-reload. Maybe its related to the whole air-units-won't-play-intercept-animations thingy?

ok, this is the whole line 389 error part of the modcomponents.py file:

Code:
 	def onBeginPlayerTurn(self, argsList):
		iGameTurn, iPlayer = argsList   <<-- THIS IS LINE 389
		pPlayer = gc.getPlayer(iPlayer)
		
		if (pPlayer.getCivics(gc.getInfoTypeForString("CIVICOPTION_LABOR")) == gc.getInfoTypeForString("CIVIC_SLAVERY")):
			return
		else: 
			# Not a slaver--check units to see if there are any slaves about.	
			unitsKilled = 0
			for iUnit in range (0,pPlayer.getNumUnits()+1):
				if (pPlayer.getUnit(iUnit).getNameKey() == 'TXT_KEY_UNIT_SLAVE'):
					pPlayer.getUnit(iUnit).kill(1,0)
					unitsKilled = 1
					
					# Here's the catch: We just killed this unit...thereby reducing the total # of units by 1, 
					# and shifting the entire player unit array.  Thus, we must re-run this index as it now
					# holds a new unit. So:
					iUnit = iUnit - 1
					
			if (unitsKilled == 1):
				CyInterface().addMessage(pPlayer.getID(),True,15,"Your slaves have been freed!",'AS2D_WELOVEKING',1,'Art/Interface/Buttons/units/slave.dds',ColorTypes(8),-1,-1,True,True)
 
ocedius said:
nope. true = TRUE = True, same result.

Really? Is that a Civ4-specific thing? Perhaps they have those values pre-defined somewhere else.

Code:
>>> def foo(b):
	if (b):
		print "This value is True"
	else:
		print "This value is False"

>>> foo(true)

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in -toplevel-
    foo(true)
NameError: name 'true' is not defined
>>> foo(TRUE)

Traceback (most recent call last):
  File "<pyshell#7>", line 1, in -toplevel-
    foo(TRUE)
NameError: name 'TRUE' is not defined
>>> foo(True)
This value is True
>>>

But in any case, I have no idea on the line 389 error, it looks like the argsList tuple is being unpacked correctly. BTW, the difference between these two lines:

Code:
pPlot.setPlotType(gc.getInfoTypeForString("PLOT_OCEAN"),1,1)
pPlot.setPlotType(PlotTypes.PLOT_OCEAN, true, true)

is the the first argument. On the first line, the argument is a simple integer. On the second, it's an enumerated type. That's why the first line doesn't work, because it's asking for "enum PlotTypes".

The second line should work. It appears your error is coming from another function somewhere else. Perhaps there's an indentation problem?
 
Thankyou one and all who answered and helped out. I can safely say my piethong has improved, even if my spelling hasn't :p

Still, now I pray to the gods of scripting to answer another question before my head explodes with debugging.

Code:
	def onBeginPlayerTurn(self, argsList):
		'Called at the beginning of a players turn'
		iGameTurn, iPlayer = argsList
		py = PyPlayer(iPlayer)
		for pUnit in py.getUnitList():
			pPlot = pUnit.plot()
			for i in range(pPlot.getNumUnits()):
				pUnit2 = pPlot.getUnit(i)
		............	while pUnit != pUnit2     ..............

I am running this to get a list of units on a plot, when a diseased-type unit is present there. Supposedly, so I can randomely change unit-health using the diseased promotion to set a healthy unit as diseased, and spread a plague across the lands :devil:

But this always does the same thing. Only the last unit in the list is affected. What am I doing wrong?

oh crap. Found an indentation error. Sorry you'all. Problem fixed.
 
Can you post up the complete code? That while loops concernes me greatly, although I can't see that it would be causing the symtoms you say it is.

As far as I can tell pUnit will never equal pUnit2, as I think pUnit is a PyUnit entity, while pUnit 2 is a CyUnit entity. This should cause an infinite loop, and a crash.... which it isn't doing so I may be mistaken here.
 
Top Bottom