Tsentom1 Python Wonders

Hi tsentom1,

I am having trouble getting the King Richard's Crusade wonder to work. I have added the Crusade Unit and the Python code to CvEventManager.py. However, the event just never seems to fire. I don't see anything in the logs and the Crusader unit never gets created. Any hints on how I might be mucking this up?

Cheers,
ripple01

Hmm, well the python is less complicated than some of my other wonders as it really only has two sections (technically it only needs 1, but the two function sort of differently)

The first one is on def onBeginPlayerTurn(self, argsList):

Spoiler :
Code:
	def onBeginPlayerTurn(self, argsList):
		'Called at the beginning of a players turn'
		iGameTurn, iPlayer = argsList

## Crusade Start ##

		pPlayer = gc.getPlayer(iPlayer)
		b_Crusade = gc.getInfoTypeForString("BUILDING_CRUSADE")
		obsoleteTech = gc.getBuildingInfo(b_Crusade).getObsoleteTech()

		if ( gc.getTeam(pPlayer.getTeam()).isHasTech(obsoleteTech) == false or obsoleteTech == -1 ):
			for iCity in range(pPlayer.getNumCities()):
				ppCity = pPlayer.getCity(iCity)
				if ppCity.getNumActiveBuilding(b_Crusade) == true:

					iX = ppCity.getX()
					iY = ppCity.getY()
					u_crusader = gc.getInfoTypeForString( 'UNIT_CRUSADER' )

					estiEnd = CyGame().getEstimateEndTurn()
					if ( estiEnd >= 1000 ):
						if ( iGameTurn % 12 ) == 0:
							for i in range(1):
								pNewUnit = pPlayer.initUnit( u_crusader, iX, iY, UnitAITypes.UNITAI_ATTACK_CITY, DirectionTypes.NO_DIRECTION )
					elif ( estiEnd >= 700 ):
						if ( iGameTurn % 8 ) == 0:
							for i in range(1):
								pNewUnit = pPlayer.initUnit( u_crusader, iX, iY, UnitAITypes.UNITAI_ATTACK_CITY, DirectionTypes.NO_DIRECTION )
					elif ( estiEnd >= 500 ):
						if ( iGameTurn % 6 ) == 0:
							for i in range(1):
								pNewUnit = pPlayer.initUnit( u_crusader, iX, iY, UnitAITypes.UNITAI_ATTACK_CITY, DirectionTypes.NO_DIRECTION )

					elif ( estiEnd >= 300 ):
						if ( iGameTurn % 4 ) == 0:
							for i in range(1):
								pNewUnit = pPlayer.initUnit( u_crusader, iX, iY, UnitAITypes.UNITAI_ATTACK_CITY, DirectionTypes.NO_DIRECTION )
					else:
						if ( iGameTurn % 4 ) == 0:
							for i in range(1):
								pNewUnit = pPlayer.initUnit( u_crusader, iX, iY, UnitAITypes.UNITAI_ATTACK_CITY, DirectionTypes.NO_DIRECTION )

					basechance = 12
					estiEnd = CyGame().getEstimateEndTurn()
					if ( estiEnd >= 1000 ):
						basechance = basechance
					elif ( estiEnd >= 700 ):
						basechance = 6
					elif ( estiEnd >= 500 ):
						basechance = 4
					elif ( estiEnd >= 300 ):
						basechance = 2
					else:
						basechance = 1

					chance = CyGame().getSorenRandNum(basechance, "free state religion spread chance")
					if ( chance == 0 ):
						lppCityUber5 = []
						for iiCity in range(pPlayer.getNumCities()):
							ppCity = pPlayer.getCity(iiCity)
							if ( not ppCity.isHasReligion(pPlayer.getStateReligion()) ):
								lppCityUber5.append(ppCity)
						if ( len(lppCityUber5) != 0 ):
							chance = CyGame().getSorenRandNum(len(lppCityUber5), "which city")
							ppCity = lppCityUber5[chance]
							ppCity.setHasReligion(pPlayer.getStateReligion(), true, true, true)

## Crusade End ##

This once controls the unit spawn every X amount of turns depending on game speed (and also the extra state religion spread chance to your cities).

The other one is on def onBuildingBuilt(self, argsList):

Spoiler :
Code:
	def onBuildingBuilt(self, argsList):
		'Building Completed'
		pCity, iBuildingType = argsList
		game = gc.getGame()

### Crusade Start ###

		if ( iBuildingType == gc.getInfoTypeForString("BUILDING_CRUSADE") ):

			pPlayer = gc.getPlayer(pCity.plot().getOwner())
			iPID = pPlayer.getID()
			iTID = pPlayer.getTeam()
			iX = pCity.getX()
			iY = pCity.getY()
			u_crusader = gc.getInfoTypeForString( 'UNIT_CRUSADER' )

			for i in range(1):
				pNewUnit = pPlayer.initUnit( u_crusader, iX, iY, UnitAITypes.UNITAI_ATTACK_CITY, DirectionTypes.NO_DIRECTION )

### Crusade End ###

		if ((not gc.getGame().isNetworkMultiPlayer()) and (pCity.getOwner() == gc.getGame().getActivePlayer()) and isWorldWonderClass(gc.getBuildingInfo(iBuildingType).getBuildingClassType())):
			# If this is a wonder...
			popupInfo = CyPopupInfo()
			popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
			popupInfo.setData1(iBuildingType)
			popupInfo.setData2(pCity.getID())
			popupInfo.setData3(0)
			popupInfo.setText(u"showWonderMovie")
			popupInfo.addPopup(pCity.getOwner())

		CvAdvisorUtils.buildingBuiltFeats(pCity, iBuildingType)

		if (not self.__LOG_BUILDING):
			return
		CvUtil.pyPrint('%s was finished by Player %d Civilization %s' 
			%(PyInfo.BuildingInfo(iBuildingType).getDescription(), pCity.getOwner(), gc.getPlayer(pCity.getOwner()).getCivilizationDescription(0)))
Which basically serves to give you a free crusader unit on the turn the building is built.

So first make sure you have both of those sections.

Now as for the XML. Assuming you've added the unit and building correctly in the unitinfos and unitclass and artdefines, etc. The python calls:

BUILDING_CRUSADE

UNIT_CRUSADER

As the names of the units, so make sure you have both labeled as such in the XML or the python won't find it.

The game won't actually create a log entry in the event logs tab, since then I'd have to connect the python to SDK which makes the mod-comp overly complicated. Instead the unit should just appear on the turns in the city that has the wonder.

If you still can't get it working, you can post your XML and python here and I can take a look at it to see if I can find the problem.

Also, you can try enabling python exceptions and see if an error message comes up on the turns that are supposed to spawn a crusader, which might help us get to the bottom of it.
 
I downloaded the:
-Sphinx
-GGB
-SOH
-HSC
-Colosseum

It recommends me open up with Firefox, but when I do, it just pops up again and leaving a blank tab. What should I do and once I do download it, where do I extract it to?
 
I downloaded the:
-Sphinx
-GGB
-SOH
-HSC
-Colosseum

It recommends me open up with Firefox, but when I do, it just pops up again and leaving a blank tab. What should I do and once I do download it, where do I extract it to?

You should save the downloads on to your computer instead of opening them directly from the download.

The files are compressed with 7zip, however the newest versions of winrar and winzip can extract them as well.

Once download and extracted you could theoretically play them as mods (they are in the format of a mod) but the only difference would be that one wonder is now in the game. Since they all use python they can't be done solely modular, so if you want to play with multiple wonders in your game you need to combine the xml and python files. The downloads are in the form of a mod to show you exactly which files and where the files are that need to be combined. All the python is labeled (usually the download page has the word to search - often just the wonders name - to find the changes), and the xml changes I tried, when possible, to keep at the bottom of the file.
 
You should save the downloads on to your computer instead of opening them directly from the download.

How exactly do I do that?:confused:
 
Sounds easy. I think I got it from here. Thanks for all your help.
 
Hi tsentom1,

I am having trouble getting the King Richard's Crusade wonder to work. I have added the Crusade Unit and the Python code to CvEventManager.py. However, the event just never seems to fire. I don't see anything in the logs and the Crusader unit never gets created. Any hints on how I might be mucking this up?

Cheers,
ripple01

Hi Ripple01

Just thought I's let you know that I've successfully merged King Richards Crusade into my own version of Hisytory in the making and it works like a charm so it must be something you're either doing wrong or some kind of conflict.

\Skodkim
 
I'll have you know, tsentom1, that the rush for the School of Confucius in my game has become a tactic on the level of the Liberalism race, Oracle, the Great Library, and the Pyramids.

And it's not because I think it is a broken wonder. Without a double production resource, you have to invest a significant amount of time to build it. It's just such a cool effect, and it comes at a reasonable tradeoff, like the Pyramids.

So, I'm posting another thanks for the wonder. You have an eye for filling in the gaps and adding content without making it overbearing.
 
I'll have you know, tsentom1, that the rush for the School of Confucius in my game has become a tactic on the level of the Liberalism race, Oracle, the Great Library, and the Pyramids.

And it's not because I think it is a broken wonder. Without a double production resource, you have to invest a significant amount of time to build it. It's just such a cool effect, and it comes at a reasonable tradeoff, like the Pyramids.

So, I'm posting another thanks for the wonder. You have an eye for filling in the gaps and adding content without making it overbearing.

Thanks, I'm glad to hear it. The School of Confucius, being the first wonder I released here, in particular has gone through quite a few balance edits so I'm glad it's reached a point where it nicely fits into your game.
 
I updated Trafalgar Square

I added additional code that now displays a message informing you of how much gold you've plundered and if you've captured an enemy ship.
 
Tom, as always great work.

I tried out the code for the trafalger square (I was looking to incorproate the Comendeer code for one of the "Heros"). Anyway, the message that tells you, you captured a ship fires whether you capture one or not.

Ah thanks, I probably left a typo in when I was testing to see if the message worked at all (so I set it to always fire). I'll fix it in a bit. Sorry about that.
 
Tom, as always great work.

I tried out the code for the trafalger square (I was looking to incorproate the Comendeer code for one of the "Heros"). Anyway, the message that tells you, you captured a ship fires whether you capture one or not.

Yeah I see what I did, I was testing if the message worked itself so it currently is:

Code:
						self.iNewPrivateerNumber = self.getRandomNumber( 4 )

						if self.iNewPrivateerNumber == 0:

							iPrivateer = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_PRIVATEER')
							pClearPlot = self.findClearPlot(pLoser)

							if (pLoser.plot().getNumUnits() == 1 and pClearPlot != -1):
								pPlot = pLoser.plot()
								pLoser.setXY(pClearPlot.getX(), pClearPlot.getY(), false, true, true)
							else:
								pPlot = pWinner.plot()

							newUnit = pPlayer.initUnit(iPrivateer, pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
							pLoser.setDamage(75, False)
							newUnit.convert(pLoser)
							pLoser.setDamage(100, False)
							newUnit.finishMoves()

						iXa = pLoser.getX()
						iYa = pLoser.getY()

						CyInterface().addMessage(pPID,false,15,CyTranslator().getText("TXT_KEY_TRAFALGAR_CAPTURE_SUCCESS",()),'',0,',Art/Interface/Buttons/Units/ICBM.dds,Art/Interface/Buttons/Beyond_the_Sword_Atlas.dds,8,11',ColorTypes(44), iXa, iYa, True,True)

Where it should be:

Code:
						if self.iNewPrivateerNumber == 0:

							iPrivateer = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_PRIVATEER')
							pClearPlot = self.findClearPlot(pLoser)

							if (pLoser.plot().getNumUnits() == 1 and pClearPlot != -1):
								pPlot = pLoser.plot()
								pLoser.setXY(pClearPlot.getX(), pClearPlot.getY(), false, true, true)
							else:
								pPlot = pWinner.plot()

							newUnit = pPlayer.initUnit(iPrivateer, pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
							pLoser.setDamage(75, False)
							newUnit.convert(pLoser)
							pLoser.setDamage(100, False)
							newUnit.finishMoves()
[B]
							iXa = pLoser.getX()
							iYa = pLoser.getY()

							CyInterface().addMessage(pPID,false,15,CyTranslator().getText("TXT_KEY_TRAFALGAR_CAPTURE_SUCCESS",()),'',0,',Art/Interface/Buttons/Units/ICBM.dds,Art/Interface/Buttons/Beyond_the_Sword_Atlas.dds,8,11',ColorTypes(44), iXa, iYa, True,True)[/B]

The last three lines just need to be indented (TAB) onced each. Anyway, I updated the download.
 
Tom, as always great work.

I tried out the code for the trafalger square (I was looking to incorproate the Comendeer code for one of the "Heros"). Anyway, the message that tells you, you captured a ship fires whether you capture one or not.

Currently it's set to give you a privateer when you capture a ship. It's a simple change of one line if you want the captured ship to be the same unit class instead of always a privateer.

Code:
				iPrivateer = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_PRIVATEER')
				pClearPlot = self.findClearPlot(pLoser)

Is what's currently there (after the get random number stuff which determines the chance). Just change it to:

Code:
				iPrivateer = pLoser.getUnitType()
				pClearPlot = self.findClearPlot(pLoser)

In case you were looking for this as the ability instead of always the privateer.
 
Thanks for the heads up. I have been expirimenting with Python since I came back from my Civ Sabatical.

My biggest issure right now is removing the building requirement. Ideally I would like: If Owner has Unit A, you get Unit B 20% chance.

Basically the same thing as the wonder only its unit specific instead of building specific.
 
Thanks for the heads up. I have been expirimenting with Python since I came back from my Civ Sabatical.

My biggest issure right now is removing the building requirement. Ideally I would like: If Owner has Unit A, you get Unit B 20% chance.

Basically the same thing as the wonder only its unit specific instead of building specific.

Oh that's easy, I actually originally wrote the code for JustATourist who wanted it to always fire for Privateers. I only adapted it in wonder form after to release here.

Anyway:

This is the edit to the onCombatResult Section (the bold I explain at the end):
Spoiler :

Code:
	def onCombatResult(self, argsList):
		'Combat Result'
		pWinner,pLoser = argsList
		playerX = PyPlayer(pWinner.getOwner())
		unitX = PyInfo.UnitInfo(pWinner.getUnitType())
		playerY = PyPlayer(pLoser.getOwner())
		unitY = PyInfo.UnitInfo(pLoser.getUnitType())


## Privateer Edit Start ##

		if pWinner.getUnitClassType() == gc.getInfoTypeForString('UNITCLASS_PRIVATEER'):

			pPlayer = gc.getPlayer(pWinner.getOwner())

			[B]iGold = playerY.getGold( )
			iGoldStolen = ( iGold//50 )
			message = 0

			if playerY.getGold( ) >= 2500:
				playerY.changeGold( -50 )
			elif playerY.getGold( ) >= 100:
				playerY.changeGold( -iGoldStolen )
			elif (playerY.getGold( ) >= 2) and (playerY.getGold( ) < 100):
				playerY.changeGold( -2 )

			iGold2 = playerX.getGold( )
			if playerY.getGold( ) >= 2500:
				playerX.changeGold( +50 )
				message = 1
			elif playerY.getGold( ) >= 100:
				playerX.changeGold( +iGoldStolen )
				message = 2
			else:
				playerX.changeGold( +2 )
				message = 3
[/B]


			pPID = pPlayer.getID()
[B]			iX = pWinner.getX()
			iY = pWinner.getY()
			szName = pPlayer.getName()[/B]

[B]			## This only controls the text, all actual gold amounts are done above:
			iGoldStolenMax = ( 2500//50 )
			iGoldStolenMin = ( 100//50 )

			if ( message == 1 ):
				CyInterface().addMessage(pPID,false,15,CyTranslator().getText("TXT_KEY_TRAFALGAR_GOLD1",(szName,iGoldStolenMax)),'',0,',Art/Interface/Buttons/TechTree/Banking.dds,Art/Interface/Buttons/TechTree_Atlas.dds,8,1',ColorTypes(44), iX, iY, True,True)
				### message: %s1 has plundered %d2 [ICON_GOLD]!###
			if ( message == 2 ):
				CyInterface().addMessage(pPID,false,15,CyTranslator().getText("TXT_KEY_TRAFALGAR_GOLD2",(szName,iGoldStolen)),'',0,',Art/Interface/Buttons/TechTree/Banking.dds,Art/Interface/Buttons/TechTree_Atlas.dds,8,1',ColorTypes(44), iX, iY, True,True)
				### message: %s1 has plundered %d2 [ICON_GOLD]!###
			if ( message == 3 ):
				CyInterface().addMessage(pPID,false,15,CyTranslator().getText("TXT_KEY_TRAFALGAR_GOLD3",(szName,iGoldStolenMin)),'',0,',Art/Interface/Buttons/TechTree/Banking.dds,Art/Interface/Buttons/TechTree_Atlas.dds,8,1',ColorTypes(44), iX, iY, True,True)
				### message: %s1 has plundered %d2 [ICON_GOLD]!###[/B]



			self.iNewPrivateerNumber = self.getRandomNumber( 9 )

			if self.iNewPrivateerNumber == 0:

				iPrivateer = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_PRIVATEER')
				pClearPlot = self.findClearPlot(pLoser)

				if (pLoser.plot().getNumUnits() == 1 and pClearPlot != -1):
					pPlot = pLoser.plot()
					pLoser.setXY(pClearPlot.getX(), pClearPlot.getY(), false, true, true)
				else:
					pPlot = pWinner.plot()

				newUnit = pPlayer.initUnit(iPrivateer, pPlot.getX(), pPlot.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_NORTH)
				pLoser.setDamage(75, False)
				newUnit.convert(pLoser)
				pLoser.setDamage(100, False)
				newUnit.finishMoves()

				iXa = pLoser.getX()
				iYa = pLoser.getY()

				CyInterface().addMessage(pPID,false,15,CyTranslator().getText("TXT_KEY_TRAFALGAR_CAPTURE_SUCCESS",()),'',0,',Art/Interface/Buttons/Units/ICBM.dds,Art/Interface/Buttons/Beyond_the_Sword_Atlas.dds,8,11',ColorTypes(44), iXa, iYa, True,True)

## Privateer Edit End ##

		if (not self.__LOG_COMBAT):
			return
		if playerX and playerX and unitX and playerY:
			CvUtil.pyPrint('Player %d Civilization %s Unit %s has defeated Player %d Civilization %s Unit %s' 
				%(playerX.getID(), playerX.getCivilizationName(), unitX.getDescription(), 
				playerY.getID(), playerY.getCivilizationName(), unitY.getDescription()))

This just goes at the very end of the EventManager:

Spoiler :
Code:
## Privateer Edit Start ##

    def findClearPlot(self, pUnit):
        BestPlot = -1
        iBestPlot = 0
        pOldPlot = pUnit.plot()
        iX = pOldPlot.getX()
        iY = pOldPlot.getY()
        for iiX in range(iX-1, iX+2, 1):
            for iiY in range(iY-1, iY+2, 1):
                iCurrentPlot = 0
                pPlot = CyMap().plot(iiX,iiY)
                if pPlot.getNumUnits() == 0:
                    iCurrentPlot = iCurrentPlot + 5
                if iCurrentPlot >= 1:
                    iCurrentPlot = iCurrentPlot + CyGame().getSorenRandNum(5, "findClearPlot")
                    if iCurrentPlot >= iBestPlot:
                        BestPlot = pPlot
                        iBestPlot = iCurrentPlot
        return BestPlot

    def getRandomNumber(self, int):
        return CyGame().getSorenRandNum(int, "Gods")

## Privateer Edit End ##

And these are the text files it calls in the python (the capture gold and ship messages):

Spoiler :
Code:
	<TEXT>
		<Tag>TXT_KEY_TRAFALGAR_GOLD1</Tag>
		<English>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</English>
		<French>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</French>
		<German>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</German>
		<Italian>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</Italian>
		<Spanish>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</Spanish>
	</TEXT>
	<TEXT>
		<Tag>TXT_KEY_TRAFALGAR_GOLD2</Tag>
		<English>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</English>
		<French>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</French>
		<German>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</German>
		<Italian>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</Italian>
		<Spanish>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</Spanish>
	</TEXT>
	<TEXT>
		<Tag>TXT_KEY_TRAFALGAR_GOLD3</Tag>
		<English>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</English>
		<French>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</French>
		<German>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</German>
		<Italian>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</Italian>
		<Spanish>[COLOR_SELECTED_TEXT]%s1 has plundered %d2 [ICON_GOLD]![COLOR_REVERT]</Spanish>
	</TEXT>
	<TEXT>
		<Tag>TXT_KEY_TRAFALGAR_CAPTURE_SUCCESS</Tag>
		<English>[COLOR_SELECTED_TEXT]You have captured an enemy vessel![COLOR_REVERT]</English>
		<French>[COLOR_SELECTED_TEXT]You have captured an enemy vessel![COLOR_REVERT]</French>
		<German>[COLOR_SELECTED_TEXT]You have captured an enemy vessel![COLOR_REVERT]</German>
		<Italian>[COLOR_SELECTED_TEXT]You have captured an enemy vessel![COLOR_REVERT]</Italian>
		<Spanish>[COLOR_SELECTED_TEXT]You have captured an enemy vessel![COLOR_REVERT]</Spanish>
	</TEXT>

Just replace that first edited line:

Code:
if pWinner.getUnitClassType() == gc.getInfoTypeForString('UNITCLASS_PRIVATEER'):

To the unit you are using and it will fire for that unit. Removing the bolded text will remove the capture gold function (which is basically the whole top except the two lines where I define PID and pPlayer--which of course if you remove you don't need the three Gold XML files, though still the last one).
 

The Lubyanka (KGB):




A rather simple wonder (code wise), still I thought it was a cool effect.

The Lubyanka, a.k.a. the headquarters of the KGB, it basically functions as an 'evil' Taj Mahal where, once built, it will place all rival civs into anarchy. The length of anarchy is equal to half a golden age (so it scales with game speed). Spiritual leaders are immune to the effect (as are team mates / vassals). It also increases espionage throughout your empire by 20%.

XML, python, wonder movie: me (tsentom1)
Building: asioasioasio
 
Yay, another new wonder :).

I love the idea... A wonder that has a direct (negative) effect on your opponents... which results in making you come out stronger. There should be more of those!
 
Top Bottom