Python Question

thecowwarrior

Warlord
Joined
May 28, 2010
Messages
204
Location
USA
Hello all! I am pretty new to the modding scene - especially Python. In the current build I am testing for the next release of my Mod, I have noticed a strange error. I have added King Richard's Crusade (http://forums.civfanatics.com/downloads.php?do=file&id=11387) as a wonder, and I've played many games where I receive my free Crusaders exactly as I should - but there has now been two times I've built the wonder and I got the initial free Crusader the turn it was completed, but none afterward. My state religion was present in the city. I've played games where the computer builds the wonder, gets free Crusaders, eventually I capture the city and I then got free Crusaders as well. I am not sure why it randomly doesn't work. I'm positive I added the XML correctly. As I'm not great with Python, I'm hoping it is a simple mistake in the way I merged the code - there are other wonders that added code near the Crusade code, but all except the Crusade seem to be working correctly. If someone here could take a quick look at my CvEventManager.py file (search for CRUSADE) and tell me if I screwed something up that would be great! :) Thanks in advance!
 

Attachments

After a bit more fooling around in WB, I have discovered the root of my problem - starting at line 386 where Topkapi Palace (http://forums.civfanatics.com/downloads.php?do=file&id=11315) and King Richard's Crusade meet. If the same empire builds both of these wonders, neither works properly. However, if only one is built, it will work perfectly. I'm going to take a closer look at the code tomorrow, but if someone else comes up with a fix before then I wouldn't complain!
 
Can't see the problem in the code :dunno:.
Is it only the turnwise bonus which isn't working, or do you also not get the UU replacements after building the topkapi?

If I build both wonders I no longer receive crusaders or the uu replacements. If I only have one of the two wonders, it will work fine.
 
If you could post the section of code that isn't working right, it would be easier for folks to try and help you.

This is the section in question.
Edit: see code posted below
 
hhmm...:dunno:
Are python exceptions enabled?

I'm sorry to sound ignorant, but as I said this is all new to me.. I don't actually know Python, I just used WinMerge and common sense to merge the code together. So I don't really know what you mean. :(
 
Firstly, enable Python exceptions, logging and in-game pop-ups in the CivilizationIV.ini file. Do it now. Right now.

Secondly, post the code in question with the appropriate
Code:
 tags, not as a mere spoiler or qoute. Otherwise the indentation of the code isn't showing, and that is what defines the flow of the code in Python. Without the flow there basically is no logic, and without logic a program cannot function. No one will be able to evaluate your code if it doesn't make any sense.

Thirdly, you might consider learning programming before attempting it. Its not hard, nor does it take long to learn. In any case, copy-pasting someone else's code is hardly programming, and you won't get anywhere without at least some minumum of base knowledge. Try again.
 
I'm sorry to sound ignorant, but as I said this is all new to me.. I don't actually know Python, I just used WinMerge and common sense to merge the code together. So I don't really know what you mean. :(

In My Documents\My Games\BtS open the civilization4.ini and change

PHP:
; Set to 1 for no python exception popups
HidePythonExceptions = 1

to 0.
Then try again building both, you should hopefully then get an error message, which will help us to find the problem.

Thirdly, you might consider learning programming before attempting it. Its not hard, nor does it take long to learn. In any case, copy-pasting someone else's code is hardly programming, and you won't get anywhere without at least some minumum of base knowledge. Try again.

Totally not necessary here. The code is coded in a way which is suitable for merging without changing anything, the problem is elsewhere.
 
Firstly, enable Python exceptions, logging and in-game pop-ups in the CivilizationIV.ini file. Do it now. Right now.

Thanks for telling me to do something but not how.

Secondly, post the code in question with the appropriate
Code:
 tags, not as a mere spoiler or qoute. Otherwise the indentation of the code isn't showing, and that is what defines the flow of the code in Python. Without the flow there basically is no logic, and without logic a program cannot function. No one will be able to evaluate your code if it doesn't make any sense.[/QUOTE]

Fair enough, my mistake there.  Will repost.

[quote="Baldyr, post: 10469379"]Thirdly, you might consider learning programming before attempting it. Its not hard, nor does it take long to learn. In any case, copy-pasting someone else's code is hardly programming, and you won't get anywhere without at least some minumum of base knowledge. Try again.[/QUOTE]

I never claimed I'm a programmer.  I'm not trying to create anything original here, just do a simple merge.  I took a few programming classes back in my college days so I do have some "base knowledge," thank you.  I must have done a decent enough job, seeing as how The_J said it looks fine.  I'm not going to learn an entire programming language just to do one simple little thing.  I don't mean to climb on a soapbox here, but why is it that anytime, on any forum, that someone asks for help (in a forum that is DESIGNED for that exact purpose) someone feels the need to come in and berate the person for not already being an expert?  Say something constructive or nothing at all.

The_J, thank you for all your help, I really appreciate it.  I will continue to post whatever I can to help you help me figure out the problem here.  :)
 
In My Documents\My Games\BtS open the civilization4.ini and change

PHP:
; Set to 1 for no python exception popups
HidePythonExceptions = 1

to 0.
Then try again building both, you should hopefully then get an error message, which will help us to find the problem.

Okay, did that, no error messages popped up. :confused:


Repost of code:

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

## Topkapi Palace Start ##

		pPlayer = gc.getPlayer(iPlayer)
		iTeam = pPlayer.getTeam()
		pTeam = gc.getTeam(iTeam)

		b_Topkapi = gc.getInfoTypeForString("BUILDING_TOPKAPI_PALACE")
		obsoleteTech = gc.getBuildingInfo(b_Topkapi).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_Topkapi) == true:

					for iPlayer in range(gc.getMAX_PLAYERS()):
						ppPlayer = gc.getPlayer(iPlayer)
						if ( (ppPlayer.isAlive()==true) and (ppPlayer.isBarbarian()==false) ):
							if ( gc.getTeam(ppPlayer.getTeam()).isVassal(iTeam) == true ):

								iGold = ppPlayer.getGold( )
								if ppPlayer.getGold( ) >= 5000:
									ppPlayer.changeGold( 50 )
								if ppPlayer.getGold( ) < 5000:
									if ppPlayer.getGold( ) >= 100:
										ppPlayer.changeGold( iGold//50 )
									else:
										ppPlayer.changeGold( 2 )

								ppPlayer.changeCombatExperience( +1 )
	
## Topkapi Palace End ## 

## 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 ##

## e-Bank Start ##

		pPlayer = gc.getPlayer(iPlayer)
		b_eBank = gc.getInfoTypeForString("BUILDING_E_BANK")
		obsoleteTech = gc.getBuildingInfo(b_eBank).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_eBank) == true:
					pPID = pPlayer.getID()
					iGold = pPlayer.getGold( )
					pPlayer.changeGold( iGold//50 )
					
## e-Bank End ##

	def onEndPlayerTurn(self, argsList):
		'Called at the end of a players turn'
		iGameTurn, iPlayer = argsList
 
One thing that stood out for me was the fact that you're resetting pPlayer in each section.

Code:
pPlayer = gc.getPlayer(iPlayer)

Not a big deal normally (though it is unnecessary), but in the Topkapi code, iPlayer is being used as a variable to loop through all the players.

Code:
for iPlayer in range(gc.getMAX_PLAYERS()):

So when you get to your new code, iPlayer is no longer pointing at the correct player. Try simply removing the pPlayer = gc.getPlayer(iPlayer) line of code from your Crusade section and see what happens.
 
The code is coded in a way which is suitable for merging without changing anything, the problem is elsewhere.
Obviously it wasn't that straight forward. :p

"Merging" code is a stupid enterprise, because the people who write the code don't use the same naming conventions for variables and such. So you still need to understand what is going on, in order to get the script working. And if you can read the code alright, you might as well write your own. In my humble experience its faster and requires less debugging. This is what I meant by my comment.

If I get the time I will revisit this thread and get this particular issue sorted out. Right now I sadly don't have that time, but it shouldn't be hard at all. Since I do know a little programming, after all.

And for the record, I do apologize to thecowwarrior. I'm sorry for the attitude, man. I'll try to be more helpful in my next post.
 
Hey, you realize that both modcomps are from the same person, so it should follow the same conventions and should work together quite nice, right ;)?

One thing that stood out for me was the fact that you're resetting pPlayer in each section.

Code:
pPlayer = gc.getPlayer(iPlayer)

That's because they are independent mod components, and both include all the necessary code to make them completly work.

Not a big deal normally (though it is unnecessary), but in the Topkapi code, iPlayer is being used as a variable to loop through all the players.

Code:
for iPlayer in range(gc.getMAX_PLAYERS()):

So when you get to your new code, iPlayer is no longer pointing at the correct player. Try simply removing the pPlayer = gc.getPlayer(iPlayer) line of code from your Crusade section and see what happens.

:wallbash: oh god, right. :wallbash:
 
Yeah, merging will cause things like this. Because those scripts are NOT prepared to be used together by copy-paste.

Also, I noticed that the Topcapi script has a bug that will cause the effect of the wonder fail, from time to time. This because city IDs aren't always a straight array from zero and up. The proper way to iterate CyCity objects is through CyCity.firstCity() and CyCity.nextCity() but this is somewhat hairy. Thankfully there is the PyPlayer.getCityList() method in the PyHelpers module for this.

edit: Oh, yeah. I was supposed to be more helpful this time around. Replace this:
Code:
			for iCity in range(pPlayer.getNumCities()):
				ppCity = pPlayer.getCity(iCity)
...with this:
Code:
			for city in PyPlayer(iPlayer).getCityList():
				ppCity = city.GetCy()
 
Thanks a ton for all the responses! I'm on holiday for the next few days, will try these suggestions out when I get a chance and let you guys know how it goes.

Thanks again!
 
Back from my vacation. I made the suggested changes and my tests in WB so far have worked beautifully. Will play a real game or two when I get a chance to make sure everything is working properly.

My sincerest thanks to The_J, Baldyr, and Tholal for taking the time to help! My Mod is nearly complete now and I hope that you all will try it out and enjoy it once I release it. Thanks again! :)
 
After several playtests, this is what I have seen happen:

King Richard's Crusade works perfectly, every time.

Topkapi Palace works, sometimes. Haven't been able to figure out any reason why it doesn't work - it isn't something simple such as having Wonder "x" also and then Topkapi fails.

I've uploaded the newest build of my mod to Atomic Gamer. It's a pretty hefty download due to all the leader heads and units I have added, ~375MB. I haven't used PakBuild on the art folder yet because I'm not quite finished yet, so it will take a minute to open. I will post a save game of the latest playtest I've done, in this particular game the Topkapi Palace DID work. However if you start a new game, go into world builder, give yourself a vassal and the Topkapi Palace, it will work about 50% of the time. If anyone is generous enough to take a look at this, that would be a great help to me, :goodjob:

Link to mod: http://atomicgamer.com/file.php?id=92017
 

Attachments

Back
Top Bottom