Python please :)

This is the version (albeit crude) I am using at the moment
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)

				if CyGame().getSorenRandNum(100, "Bob") <= 100: # 10% global chance for diseased units undergoing change
					
					if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_DISEASED')) and not pUnit2.isHasPromotion(gc.getInfoTypeForString('PROMOTION_DISEASED')):
						pUnit2.setHasPromotion((gc.getInfoTypeForString('PROMOTION_DISEASED')), True)
						CyInterface().addMessage(pUnit2.getOwner(),True,25,'A unit has become diseased!','AS2D_DISEASED',1,'Art/Interface/Buttons/Promotions/Diseased.dds',ColorTypes(7),pUnit2.getX(),pUnit2.getY(),True,True)
						return

					if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_IMMUNE')) and not pUnit2.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ACQUIREDIMMUNITY')):
						pUnit2.setHasPromotion((gc.getInfoTypeForString('PROMOTION_ACQUIREDIMMUNITY')), True)
						CyInterface().addMessage(pUnit2.getOwner(),True,25,'A unit has become immune!','AS2D_DISEASED',1,'Art/Interface/Buttons/Promotions/Curedisease.dds',ColorTypes(8),pUnit2.getX(),pUnit2.getY(),True,True)
						return

					if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_IMMUNE')) and pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ACQUIREDIMMUNITY')):
						pUnit.setHasPromotion((gc.getInfoTypeForString('PROMOTION_ACQUIREDIMMUNITY')), False) # so no unit can have both immune and acquired promotions
						return

					if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_DISEASED')) and pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ACQUIREDIMMUNITY')):
						if CyGame().getSorenRandNum(100, "Bob") <= 50: # 5% global chance for diseased units becoming cured

							pUnit.setHasPromotion((gc.getInfoTypeForString('PROMOTION_DISEASED')), False) # cure unit (kinda senseless)
						else:
							pUnit.setHasPromotion((gc.getInfoTypeForString('PROMOTION_ACQUIREDIMMUNITY')), False) # so no unit can have both diseased and acquired promotions (kinda senseless)

					if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_DISEASED')) and pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ACQUIREDIMMUNITY')):
						if CyGame().getSorenRandNum(100, "Bob") <= 50: # 5% global chance for diseased units becoming cured

							pUnit.setHasPromotion((gc.getInfoTypeForString('PROMOTION_DISEASED')), False) # cure unit (kinda senseless)
						else:
							pUnit.setHasPromotion((gc.getInfoTypeForString('PROMOTION_ACQUIREDIMMUNITY')), False) # so no unit can have both diseased and acquired promotions (kinda senseless)

					if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_IMMUNE')) and pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_DISEASED')):
						if CyGame().getSorenRandNum(100, "Bob") <= 50: # 5% global chance for diseased units becoming cured

							pUnit.setHasPromotion((gc.getInfoTypeForString('PROMOTION_DISEASED')), False) # cure unit (kinda senseless)
						else:
							pUnit.setHasPromotion((gc.getInfoTypeForString('PROMOTION_IMMUNE')), False) # so no unit can have both diseased and immune promotions (kinda senseless)

					if CyGame().getSorenRandNum(100, "Bob") <= 5: # 5% global chance for diseased units becoming cured

						if pUnit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_DISEASED')):
							pUnit.kill(True,0)
							CyInterface().addMessage(pUnit.getOwner(),True,25,'The diseased unit has died!','AS2D_DISEASED',1,'Art/Interface/Buttons/Promotions/Diseased.dds',ColorTypes(7),pUnit.getX(),pUnit.getY(),True,True)

Yes, I know, it is slow and messy, but it works for now
 
I cannot see any reason why that code should only pick the last unit at the moment... unless there's something weird going on with the pPlot.getUnit(i) function where there are blanks in the list.

This code will run only once if either of the first three conditions are met. The return statement will end the function there and then. I'm not sure if this is intended or not.

I wonder when I'll stop seing "Bob" in code to do with random numbers. He just keeps coming back ;)
 
The Great Apple said:
I cannot see any reason why that code should only pick the last unit at the moment... unless there's something weird going on with the pPlot.getUnit(i) function where there are blanks in the list.

That is no longer a problem which is why I eddited my post a few minutes after writing it. Upon restarting civ iv, the problem was gone. Maybe it was the 452 Mb python error log file :lol:

The Great Apple said:
This code will run only once if either of the first three conditions are met. The return statement will end the function there and then. I'm not sure if this is intended or not.

That is why I called this a messy p-o-s. Need to clean it up and improve functionality before I can call it not-a-p-o-s

The Great Apple said:
I wonder when I'll stop seing "Bob" in code to do with random numbers. He just keeps coming back ;)

WHAT! You have a problem with BOB? BLASPHEMY! :mischief:
 
Oh right, didn't see that you'd actually fixed it. Goodo. :thumbsup:

ocedius said:
WHAT! You have a problem with BOB? BLASPHEMY! :mischief:
I'll have you know I was the first person to use Bob on this forum, so if anybody can have a problem with him it should be me! (Although I think Kael was the cause of his thusfar long and healthy life...)

Incedently, that string is the string that shows up in the the log when the random number is generated. It helps to track down what is doing what.
 
The Great Apple said:
Oh right, didn't see that you'd actually fixed it. Goodo. :thumbsup:


I'll have you know I was the first person to use Bob on this forum, so if anybody can have a problem with him it should be me! (Although I think Kael was the cause of his thusfar long and healthy life...)

Incedently, that string is the string that shows up in the the log when the random number is generated. It helps to track down what is doing what.

Many appologies creator of Bob. I beg thee forgiveness :lol:
 
Incidently, would anyone care to help a noobie out with a little problem. I have a funny issue with a compiled mod. The terraform fuunctions are taken from blacksun's terraform mod (English translation courtesy of swan).

The worker's can and do terraform the city with a forest build, so on occasion I end up trying to take over a city with a wall & forest bonus, ontop of the standard pikeman/musketman fortify :mad:

I need a way to go through the city list, and render all city.plot (0,0) as unimproveable. Suggestions?
 
ocedius said:
Incidently, would anyone care to help a noobie out with a little problem. I have a funny issue with a compiled mod. The terraform fuunctions are taken from blacksun's terraform mod (English translation courtesy of swan).

The worker's can and do terraform the city with a forest build, so on occasion I end up trying to take over a city with a wall & forest bonus, ontop of the standard pikeman/musketman fortify :mad:

I need a way to go through the city list, and render all city.plot (0,0) as unimproveable. Suggestions?

I'm not sure how that mod works, but if it works by making the "Terraform" or "Plant forest" a build (you can check by seeing if the terraform build is located in the Civ4BuildInfos.xml file) then you could probably add a line inside CvUnit::canBuild in the SDK. Something simple like:

Code:
if (eBuild == TERRAFORM_TYPE && pPlot->isCity())
{
	return false;
}

Otherwise, you could find out exactly how they make that action available, and do the same. So, if they programmed it as a Mission, make sure to make such a change in CvUnit::canStartMission. If it's a command, in CvUnit::canDoCommand.


Edit: P.S., using Bob is fun, but as TGA said you might want to make sure that each call to those random functions has a name that can easily pinpoint where it is. It can prove extremely helpful if you ever run into OOS problems with a Multiplayer mod.
 
Firstly, many thanks to those who helped me out earlier in my quest to slay the might python. And it worked brilliantly for the most part. Got a lot done in a lot of ways, except now I have another problem and my limited skills seem to be back to bite my in the arse.

I have used the add/remove trait SDK mod and it does that quite nicely. It is passing it the if-then-else thats causing me a lot of hairpulling which wouldn't be all that bad if it worked.

Code:
	def onBeginPlayerTurn(self, argsList):
		'Called at the beginning of a players turn'
		iGameTurn, iPlayer = argsList
		py = PyPlayer(iPlayer)
		pPlayer = gc.getPlayer(iPlayer)
		iTeam = gc.getTeam(pPlayer.getTeam())
		bPlayer = gc.getPlayer(gc.getBARBARIAN_PLAYER())

		if iTeam.isHasTech(gc.getInfoTypeForString('TECH_LIBERALISM')):
			if pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_RAGNAR') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_BRENNUS') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_GENGHIS_KHAN'):
				pPlayer.removeTrait(gc.getInfoTypeForString('TRAIT_BARBARIAN'))
		elif not iTeam.isHasTech(gc.getInfoTypeForString('TECH_LIBERALISM')):
			if pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_RAGNAR') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_BRENNUS') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_GENGHIS_KHAN'):
				pPlayer.addTrait(gc.getInfoTypeForString('TRAIT_BARBARIAN'))

		listTeams = []
		if not bPlayer:
			for iPlayer2 in range(gc.getMAX_PLAYERS()):
				pPlayer2 = gc.getPlayer(iPlayer2)
				if (pPlayer2.isAlive() and iPlayer2 != iPlayer):
					iRivalTeam = pPlayer2.getTeam()
					listTeams.append(gc.getTeam(iRivalTeam))

					if pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_RAGNAR') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_BRENNUS') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_GENGHIS_KHAN'):
						if iTeam.isAtWar(iRivalTeam):
							pPlayer.addTrait(gc.getInfoTypeForString('TRAIT_SCORCHED_EARTH'))
							pPlayer.removeTrait(gc.getInfoTypeForString('TRAIT_BARBARIAN'))
						elif iTeam.makePeace(iRivalTeam):
							pPlayer.removeTrait(gc.getInfoTypeForString('TRAIT_SCORCHED_EARTH'))
							pPlayer.addTrait(gc.getInfoTypeForString('TRAIT_BARBARIAN'))
						if not iTeam.isAtWar(iRivalTeam):
							pPlayer.removeTrait(gc.getInfoTypeForString('TRAIT_SCORCHED_EARTH'))

simply put, this is called at the beginplayer turn and doesn't work as it is supposed to. I wanted a code which would remove the Barbarian trait is the player had researched liberalism. It does that fine with the:
Code:
if iTeam.isHasTech(gc.getInfoTypeForString('TECH_LIBERALISM')):
	if pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_RAGNAR') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_BRENNUS') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_GENGHIS_KHAN'):
		pPlayer.removeTrait(gc.getInfoTypeForString('TRAIT_BARBARIAN'))

Beyond this things go screwy. I also want the civs with these leaders to switch traits if they are at war, so civs addtrait.scorchedearth and removetrait.barbarian if at war. It doesn't happen. This particular varient has me stuck in constant scorchedearth mode even without war, and liberalism causes a loss of the barbarian trait (which is ok I guess) which is what is supposed to happen.

What I am trying to say is could someone point out what I am doing wrong? I though Kael's Ffh would've had something more complex tht this with the add/remove SDK, but turns out its rather simple and really on adds traits and removes them in one case.

Edit: Btw this is supposed to go into the PbP mod. Which reminds me (and I hate recruitment threads so bear with me will ya), would some python expert be interested in joining the PbP team? :)
 
ocedius said:
Code:
	def onBeginPlayerTurn(self, argsList):
		'Called at the beginning of a players turn'
		iGameTurn, iPlayer = argsList
		py = PyPlayer(iPlayer)
		pPlayer = gc.getPlayer(iPlayer)
		iTeam = gc.getTeam(pPlayer.getTeam())
		bPlayer = gc.getPlayer(gc.getBARBARIAN_PLAYER())

		if iTeam.isHasTech(gc.getInfoTypeForString('TECH_LIBERALISM')):
			if pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_RAGNAR') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_BRENNUS') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_GENGHIS_KHAN'):
				pPlayer.removeTrait(gc.getInfoTypeForString('TRAIT_BARBARIAN'))
		elif not iTeam.isHasTech(gc.getInfoTypeForString('TECH_LIBERALISM')):
			if pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_RAGNAR') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_BRENNUS') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_GENGHIS_KHAN'):
				pPlayer.addTrait(gc.getInfoTypeForString('TRAIT_BARBARIAN'))

		listTeams = []
		if not bPlayer:
			for iPlayer2 in range(gc.getMAX_PLAYERS()):
				pPlayer2 = gc.getPlayer(iPlayer2)
				if (pPlayer2.isAlive() and iPlayer2 != iPlayer):
					iRivalTeam = pPlayer2.getTeam()
					listTeams.append(gc.getTeam(iRivalTeam))

					if pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_RAGNAR') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_BRENNUS') or pPlayer.getLeaderType() == gc.getInfoTypeForString('LEADER_GENGHIS_KHAN'):
						if iTeam.isAtWar(iRivalTeam):
							pPlayer.addTrait(gc.getInfoTypeForString('TRAIT_SCORCHED_EARTH'))
							pPlayer.removeTrait(gc.getInfoTypeForString('TRAIT_BARBARIAN'))
						elif iTeam.makePeace(iRivalTeam):
							pPlayer.removeTrait(gc.getInfoTypeForString('TRAIT_SCORCHED_EARTH'))
							pPlayer.addTrait(gc.getInfoTypeForString('TRAIT_BARBARIAN'))
						if not iTeam.isAtWar(iRivalTeam):
							pPlayer.removeTrait(gc.getInfoTypeForString('TRAIT_SCORCHED_EARTH'))

I also want the civs with these leaders to switch traits if they are at war, so civs addtrait.scorchedearth and removetrait.barbarian if at war. It doesn't happen. This particular varient has me stuck in constant scorchedearth mode even without war, and liberalism causes a loss of the barbarian trait (which is ok I guess) which is what is supposed to happen.

I may have read the code wrong, and I'm not too familiar with the trait scripting mod, but it seems to me that you will constantly be considered at war or not at war depending on the last civ you check. Even if you're not at war with the first 18 civs, when you check the last civ (barbarians) you will run the script and set your traits depending on your status against then, removing all the previous changes. It could be you're always in your war-time traits because you're always at war with the barbarians.
 
oh sorry, should have included this earlier:

Code:
	def onGameStart(self, argsList):
		'Called at the start of the game'
		if (gc.getGame().getStartEra() == gc.getDefineINT("STANDARD_ERA")):
			for iPlayer in range(gc.getMAX_PLAYERS()):
				pPlayer = gc.getPlayer(iPlayer)
				if pPlayer.isAlive():
					if pPlayer.hasTrait(gc.getInfoTypeForString('TRAIT_BARBARIAN')):
						iTeam = gc.getTeam(player.getTeam())
						bTeam = gc.getPlayer(gc.getBARBARIAN_PLAYER()).getTeam()
						bTeam.makePeace(iTeam)

So you see, I am at peace with the Barbs but not at the same team. Still this version end up with 4 traits. I am completely stumped.

Also, in the earlier code, should't the "if not bPlayer:" remove the barbarian civ from the array of civs to check as teams at war?
 
Also, another real funny thing with this is the war period is ammusingly short. If any civ with the _barbarian trait declares war at another with the same trait, both civs remain at war for exactly one turn before automatically declaring peace. So you can declare war at the viking or vice versa, but not do anything with it. :lol:
 
Yes, I am back with yet another question. Here is build city code:

Code:
	def onCityBuilt(self, argsList):
		'City Built'
		city = argsList[0]
		if (city.getOwner() == CyGame().getActivePlayer()):
			self.__eventEditCityNameBegin(city, False)	
		CvUtil.pyPrint('City Built Event: %s' %(city.getName()))

ANd here is the onunitlost one from the settler.py:
Code:
		if (unit.getUnitType() != gc.getInfoTypeForString("UNIT_SETTLER")):
			return
		if (self.city):
			iReligion = gc.getInfoTypeForString(unit.getScriptData())
			if (iReligion > -1):
				self.city.setHasReligion(iReligion, true, true, true)
			self.city = None

What I am trying to do is if unithaspromotion.blah, on cityoncitybuilt give it blah religion. Any ideas.

It keeps telling me that:

AttributeError: CvEventManager instance has no attribute 'city'
ERR: Python function onEvent failed, module CvEventInterface
Traceback (most recent call last):

File "CvEventInterface", line 23, in onEvent

File "CvEventManager", line 173, in handleEvent

File "CvEventManager", line 960, in onUnitLost

I understand that I am not using a script for this, but how else can you pass information between two events?

The settler and all units for that matter have a religion promotion, if is set, it is randomly created from a list of religions the originating city has and units die normally also, but apart from that, I don't know how to link the two events from within cvEventManager without using an additional .py file.
 
You haven't defined self.city. In onCityBuilt you have defined city, but that is local to that method, while self.city would be local to the class.

To get this to work properly you must inialize self.city to None in the __init__ method of the class, and then on the city built event you need to set self.city equal to city.

Be careful though - onCityBuilt triggers for all players... I don't know exactly what you want to do with this, but you may need an array storing it for all players. You'll lose it over save/reload, so I suggest you just strap it in the global scriptdata using the SD-Toolkit.
 
So if I read you correctly, I need to go to the top of cveventmanager, copy:
Code:
	def __init__(self, pEventManager):
		self.city = None
		self.iSettlerID = gc.getInfoTypeForString("UNIT_SETTLER")
                pEventManager.addEventHandler("unitBuilt", self.onUnitBuilt)
                pEventManager.addEventHandler("unitLost", self.onUnitLost)
                pEventManager.addEventHandler("cityBuilt", self.onCityBuilt)

And then edit the already present methods to:
Code:
	def onUnitLost(self, argsList):
		unit = argsList[0]
		if (unit.getUnitType() != gc.getInfoTypeForString("UNIT_SETTLER")):
			return
		if (self.city):
			iReligion = gc.getInfoTypeForString(unit.getScriptData())
			if (iReligion > -1):
				self.city.setHasReligion(iReligion, true, true, true)
			self.city = None

	def onCityBuilt(self, argsList):
		city = argsList[0]
		self.city = city

Is that correct? Or do I need to drink more coffee?
 
TGA,

Thanks for all the work you've shared here. I hope you can help me as well.

I need code to visit each of the human players units and set them to fortify. I know that version 1.61 has this functionality built in, but I am trying to modify Paasky's WW2Europe mod which already has a lot of modified python, and so far my attempts to adapt it have only made a mess. In other words, the "sleep" command you can give each unit in the WBS file does not work, so I want to have them all be fortified when the scenario starts so I don't have to visit each unit and give it that order one-at-a-time. It would save a tremendous amount of time troubleshooting play as I try to add other mods.

Thanks.
 
Hmm. May or may not work. Not tested. I'm pretty sure it won't give you the 25% fortify bonus, and I can't see a way of doing that easily.
Code:
	def	onBeginGameTurn(self, argsList):
		iGameTurn = argsList[0]
		if iGameTurn == 0:
			PlayerList = PyGame().getCivPlayerList()
			for player in PlayerList:	
				pPlayer = player.CyGet()
				unitList = player.getUnitList()
				for pUnit in unitList:
					pGroup = pUnit.getGroup()
					if pGroup.getActivityType() != ActivityTypes.ACTIVITY_SLEEP:
						pGroup.setActivityType(ActivityTypes.ACTIVITY_SLEEP)
 
Wow, that was fast. Thanks. I will test it and report back.

... I do appreciate the help.
 
Back
Top Bottom