Plots...

Flintlock1415

Emperor
Joined
Feb 24, 2008
Messages
1,057
Location
MN
I don't get them. I'm trying to make it so that if a unit pillages a certain plot with a predefined coordinate that the unit will get a free promotion. I've tried defining the plot as a pointer and I've tried to define each the X and Y coordinates individually as integers, but I don't know how. I'd be actually more interested in the X and Y way, since I understand integers much better than pointers and I can't think of a way to define a plot as an integer.

I could post my code here but I don't think it is needed, unless I have other things wrong.

Thanks!
 
Are you doing this in Python or C++ (the SDK)?

Python's CvEventManager has an event for when a unit pillages an improvement/route. You get the CyUnit object, improvement or route type, and owner (of the plot I assume).

Code:
	def onUnitPillage(self, argsList):
		'Unit pillages a plot'
		pUnit, iImprovement, iRoute, iOwner = argsList
		iPlotX = pUnit.getX()
		iPlotY = pUnit.getY()
		pPlot = CyMap().plot(iPlotX, iPlotY)

Here you can see the standard function is getting the X and Y from the CyUnit. You can use these to test against your desired plot location(s).
 
Yea, its Python, and I'm using that function, but I want it so that the unit only gets the Promotion if he pillages a certain plot.

The thing I don't get is how to check the unit's coordinates against the coordinates I've picked out. Here is my code:

Code:
## William avenges his men at Romney
	def onUnitPillage(self, argsList):
		'Unit pillages a plot'
		pUnit, iImprovement, iRoute, iOwner = argsList
		iPlotX = pUnit.getX()
		iPlotY = pUnit.getY()
		pPlot = CyMap().plot(iPlotX, iPlotY)
		
		CyInterface().addImmediateMessage("X = %d, Y = %d" % (iPlotX, iPlotY), "")
		
		iWilliam = gc.getInfoTypeForString("LEADER_WILLIAM")
		[B]iRomneyX = CyPlot().getX(63)
		iRomneyY = CyPlot().getY(15)[/B]
		
		CyInterface().addImmediateMessage("Romney = %d, %d" % (iRomneyX, iRomneyY), "")
		
		## Makes sure a Norman unit is pillaging Romney
		if iPlotX == iRomneyX and iPlotY == iRomneyY and iOwner == iWilliam:
			CyInterface().addImmediateMessage("Your unit recieves Morale for avenging your men", "")
			pUnit.setHasPromotion(gc.getInfoTypeForString("PROMOTION_MORALE"), 1)
I don't get how to set iRomneyX to 63 and iRomneyY to 15. iPlotX and iPlotY print out correctly, but I get an error for iRomneyX and Y saying that it doesn't match the C++ signature. Here is the error in my log:
Code:
Traceback (most recent call last):

  File "CvEventInterface", line 22, in onEvent

  File "CvEventManager", line 172, in handleEvent

  File "CvCustomEventManager", line 23, in onUnitPillage

ArgumentError: Python argument types in
    CyPlot.getX(CyPlot, int)
did not match C++ signature:
    getX(CyPlot {lvalue})
ERR: Python function onEvent failed, module CvEventInterface

Thanks!
 
There are multiple problems in this code. Instead of "iRomneyX = CyPlot().getX(63)" just write "iRomneyX = 63". Also, iOwner is a player ID, not a leader ID, so comparing against iWilliam will provide unexpected results. You need to get the player ID of the civilization, for which William is the leader. If you already know the civilization name, you can get the civilization ID from the iPlayer you are passed, and check if it is matching. If William could be leading any civ, it is more complicated.
 
Hmm, I tried setting it directly to an integer before, but I never would have thought that iOwner is a player ID.

Thanks again guys!

Here is the code:
Code:
## William avenges his men at Romney
	def onUnitPillage(self, argsList):
		'Unit pillages a plot'
		pUnit, iImprovement, iRoute, iOwner = argsList
		iPlotX = pUnit.getX()
		iPlotY = pUnit.getY()
		pPlot = CyMap().plot(iPlotX, iPlotY)
		
		iWilliam = gc.getInfoTypeForString("LEADER_WILLIAM")
		iRomneyX = 63
		iRomneyY = 15
		
		pPlayer = gc.getPlayer(iOwner)
		
		## Makes sure a Norman unit is pillaging Romney
		if iPlotX == iRomneyX and iPlotY == iRomneyY and pPlayer.getLeaderType() == iWilliam:
			CyInterface().addImmediateMessage("Your unit recieves Morale for avenging your men", "")
			pUnit.setHasPromotion(gc.getInfoTypeForString("PROMOTION_MORALE"), 1)
 
Okay, one more thing I forgot to ask about, how would you guys go about making it so that this event can only occur once? I tried using a while loop, but I must have done it wrong because the game just ignored it.

Here is what I tried:

Code:
def onUnitPillage(self, argsList):
		'Unit pillages a plot'
		pUnit, iImprovement, iRoute, iOwner = argsList
		iPlotX = pUnit.getX()
		iPlotY = pUnit.getY()
		pPlot = CyMap().plot(iPlotX, iPlotY)
		
		iWilliam = gc.getInfoTypeForString("LEADER_WILLIAM")
		iRomneyX = 63
		iRomneyY = 15
		
		pPlayer = gc.getPlayer(iOwner)
		
		## Makes sure a Norman unit is pillaging Romney
		if iPlotX == iRomneyX and iPlotY == iRomneyY and pPlayer.getLeaderType() == iWilliam:
			[B]z = 0
			while z < 1:
				z = z + 1[/B]
				CyInterface().addImmediateMessage("Your unit recieves Morale for avenging your men", "")
				pUnit.setHasPromotion(gc.getInfoTypeForString("PROMOTION_MORALE"), 1)

any thoughts?
 
Well, I'd define a variable as "iEventPillaged", set it to 0 at the top of the python file (Event Manager I'm assuming) and then in your code, after you complete the event, set it to 1. Then you add in a check before you trigger the event.

You'd do it like this (assuming this is Warlords Event Manager), new code is red:

Code:
class CvEventManager:
	def __init__(self):
		#################### ON EVENT MAP ######################
		#print "EVENTMANAGER INIT"
		
		self.bCtrl = False
		self.bShift = False
		self.bAlt = False
		self.bAllowCheats = False
		
		# OnEvent Enums
		self.EventLButtonDown=1
		self.EventLcButtonDblClick=2
		self.EventRButtonDown=3
		self.EventBack=4
		self.EventForward=5
		self.EventKeyDown=6
		self.EventKeyUp=7
	
		self.__LOG_MOVEMENT = 0
		self.__LOG_BUILDING = 0
		self.__LOG_COMBAT = 0
		self.__LOG_CONTACT = 0
		self.__LOG_IMPROVEMENT =0
		self.__LOG_CITYLOST = 0
		self.__LOG_CITYBUILDING = 0
		self.__LOG_TECH = 0
		self.__LOG_UNITBUILD = 0
		self.__LOG_UNITKILLED = 0
		self.__LOG_UNITLOST = 0
		self.__LOG_UNITPROMOTED = 0
		self.__LOG_UNITSELECTED = 0
		self.__LOG_UNITPILLAGE = 0
		self.__LOG_GOODYRECEIVED = 0
		self.__LOG_GREATPERSON = 0
		self.__LOG_RELIGION = 0
		self.__LOG_RELIGIONSPREAD = 0
		self.__LOG_GOLDENAGE = 0
		self.__LOG_ENDGOLDENAGE = 0
		self.__LOG_WARPEACE = 0
		self.__LOG_PUSH_MISSION = 0
		
[COLOR="Red"]		self.iEventPillaged = 0[/COLOR]

And then:

Code:
## William avenges his men at Romney
	def onUnitPillage(self, argsList):
		'Unit pillages a plot'
		pUnit, iImprovement, iRoute, iOwner = argsList
		iPlotX = pUnit.getX()
		iPlotY = pUnit.getY()
		pPlot = CyMap().plot(iPlotX, iPlotY)
		
		iWilliam = gc.getInfoTypeForString("LEADER_WILLIAM")
		iRomneyX = 63
		iRomneyY = 15
		
		pPlayer = gc.getPlayer(iOwner)
		
		## Makes sure a Norman unit is pillaging Romney
		[COLOR="red"]if self.iEventPillaged == 0:[/COLOR]
			if iPlotX == iRomneyX and iPlotY == iRomneyY and pPlayer.getLeaderType() == iWilliam:
				CyInterface().addImmediateMessage("Your unit recieves Morale for avenging your men", "")
				pUnit.setHasPromotion(gc.getInfoTypeForString("PROMOTION_MORALE"), 1)
				[COLOR="red"]self.iEventPillaged = 1[/COLOR]

I think this would work...
 
This does not work when the game is saved and loaded again. Variables in your class are not saved. You can get this effect using pPlot.setScriptData(). This associates any arbitrary string with the plot, and it is saved and loaded for you. So in your onGameStart, do something like:

CyMap().getPlot(63,15).setScriptData("no")

Then in your pillaging code, add something like:
Code:
if CyMap().getPlot(63,15).getScriptData() == "no": 
   CyMap().getPlot(63,15).setScriptData("yes")
   [... continue your pillaging code ...]
 
Ah, right. I remember this problem. Hence why in my mod I purposely used script data to prevent such an occurance....
 
Top Bottom