Simple Python Things

Ah...so it was BUG...

I'll try it myself, but if it doesn't work, I'll settle on waiting for your merge. That tutorial is a lot to read :eek:
 
Sure ;).

Change:
PHP:
###believer trait start part 1
		pPlayer = gc.getPlayer(city.getOwner())
		if pPlayer.hasTrait(gc.getInfoTypeForString("TRAIT_BELIEVER")):
                        iReligion = pPlayer.getStateReligion()
                        if  iReligion>-1:
                                city.setHasReligion(iReligion,True,True,True)
                                NumBuildings = gc.getNumBuildingInfos ()
                                for i in xrange(NumBuildings):
                                        MyBuilding = gc.getBuildingInfo(i)
                                        if MyBuilding.getPrereqReligion ()==iReligion:
                                                if MyBuilding.getSpecialBuildingType ()==gc.getInfoTypeForString("SPECIALBUILDING_TEMPLE"):
                                                        city.setNumRealBuilding(i,1)
                                                        break
                                        
###believer trait end part 1

to:
PHP:
###believer trait start part 1
		pPlayer = gc.getPlayer(city.getOwner())
		if pPlayer.hasTrait(gc.getInfoTypeForString("TRAIT_BELIEVER")):
                        iReligion = pPlayer.getStateReligion()
                        if  iReligion>-1:
                                city.setHasReligion(iReligion,True,True,True)

(just remove the lower part)

and do the same here, change:
PHP:
###believer trait start part 2
		pPlayer = gc.getPlayer(pCity.getOwner())
		if pPlayer.hasTrait(gc.getInfoTypeForString("TRAIT_BELIEVER")):
                        iReligion = pPlayer.getStateReligion()
                        if  iReligion>-1:
                                if not pCity.isHasReligion(iReligion):
                                        pCity.setHasReligion(iReligion,True,True,True)
                                NumBuildings = gc.getNumBuildingInfos ()
                                for i in xrange(NumBuildings):
                                        MyBuilding = gc.getBuildingInfo(i)
                                        if MyBuilding.getPrereqReligion ()==iReligion:
                                                if MyBuilding.getSpecialBuildingType ()==gc.getInfoTypeForString("SPECIALBUILDING_TEMPLE"):
                                                        pCity.setNumRealBuilding(i,1)
                                                        break
                                        
###believer trait end part 2

to:
PHP:
###believer trait start part 2
		pPlayer = gc.getPlayer(pCity.getOwner())
		if pPlayer.hasTrait(gc.getInfoTypeForString("TRAIT_BELIEVER")):
                        iReligion = pPlayer.getStateReligion()
                        if  iReligion>-1:
                                if not pCity.isHasReligion(iReligion):
                                        pCity.setHasReligion(iReligion,True,True,True)

                                        
###believer trait end part 2
 
I got recently 2 requests for stuff about which i was already thinking, so i took a short break from...the modding break :mischief:. I'll probably not code anything else in the next time, because i'm currently playing Risen and i'm still far away from the end.


So, what i've uploaded:
- Kathy requested another religion advisor for more religions. Due to some problems the scrollable one from Johny smith did not work, so i coded one with 2 rows (download). Did this without knowing that we have another fine set of advisor screens here. I do not recommend to anyone to use my screen here, because my changes are really messy :blush:. Might still be useful for some special occassions. E.g. i planned to add 2 different types of religions to my mod, "earth" religions and "mars" religions, and i wanted to have them in different rows, for some graphical separation, that's why i thought about such a thing. If anyone plans something similar...
- Spillsandstains asked what could be done with randomizing stuff. I had long time ago the idea of a wonder, which doesn't really do anything, besides creating another random available wonder. I originally did not code it, because it can be frustrating when you've nearly completed a wonder, and someone rushes the random wonder and gets it instead. This thing here has a negative component for everyone else, so i do not consider it really fun, but due to the request: The alchemy lab.

I hope they are useful for someone :).
 
Ah, should have thought of giving an example :wallbash:.

But that's not really a big thing, needs only a minor change.

Currently the code looks like this:
PHP:
		if (gc.getGame().getGameTurnYear() == gc.getDefineINT("START_YEAR") and not gc.getGame().isOption(GameOptionTypes.GAMEOPTION_ADVANCED_START)):
			for iPlayer in range(gc.getMAX_PLAYERS()):
				player = gc.getPlayer(iPlayer)
				if (player.isAlive() and player.isHuman()):
					popupInfo = CyPopupInfo()
					popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_TEXT)
					szBody = localText.getText("TXT_KEY_MOD_HEADER", ()) + "\n\n" + localText.getText("TXT_KEY_MOD_TEXT", ())
					popupInfo.setText(szBody)
					popupInfo.addPopup(iPlayer)

to change the text depending on map, you can just change it in this way:
PHP:
		if (gc.getGame().getGameTurnYear() == gc.getDefineINT("START_YEAR") and not gc.getGame().isOption(GameOptionTypes.GAMEOPTION_ADVANCED_START)):
			for iPlayer in range(gc.getMAX_PLAYERS()):
				player = gc.getPlayer(iPlayer)
				if (player.isAlive() and player.isHuman()):
					popupInfo = CyPopupInfo()
					popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_TEXT)
					szBody = localText.getText("TXT_KEY_MOD_HEADER", ()) + "\n\n" + localText.getText("TXT_KEY_MOD_TEXT", ())
					if CyMap().getMapScriptName () =="myMap.CivBeyondSwordWBSave":  szBody = localText.getText("TXT_KEY_SOME_OTHER_TEXT_HEADER", ()) + "\n\n" + localText.getText("TXT_KEY_SOME_OTHER_MOD_TEXT", ())
					popupInfo.setText(szBody)
					popupInfo.addPopup(iPlayer)

if you copy the additional line, then make sure, that if you paste it into your python file, that it has exactly the same number of whitespaces in front of the text like the line above. Do not rely on the whitespaces here, copy them in the file, paste them in the file.
And attention, the map names are case sensitive.
 
Ah, should have thought of giving an example :wallbash:.

But that's not really a big thing, needs only a minor change.

Currently the code looks like this:
PHP:
		if (gc.getGame().getGameTurnYear() == gc.getDefineINT("START_YEAR") and not gc.getGame().isOption(GameOptionTypes.GAMEOPTION_ADVANCED_START)):
			for iPlayer in range(gc.getMAX_PLAYERS()):
				player = gc.getPlayer(iPlayer)
				if (player.isAlive() and player.isHuman()):
					popupInfo = CyPopupInfo()
					popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_TEXT)
					szBody = localText.getText("TXT_KEY_MOD_HEADER", ()) + "\n\n" + localText.getText("TXT_KEY_MOD_TEXT", ())
					popupInfo.setText(szBody)
					popupInfo.addPopup(iPlayer)

to change the text depending on map, you can just change it in this way:
PHP:
		if (gc.getGame().getGameTurnYear() == gc.getDefineINT("START_YEAR") and not gc.getGame().isOption(GameOptionTypes.GAMEOPTION_ADVANCED_START)):
			for iPlayer in range(gc.getMAX_PLAYERS()):
				player = gc.getPlayer(iPlayer)
				if (player.isAlive() and player.isHuman()):
					popupInfo = CyPopupInfo()
					popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_TEXT)
					szBody = localText.getText("TXT_KEY_MOD_HEADER", ()) + "\n\n" + localText.getText("TXT_KEY_MOD_TEXT", ())
					if CyMap().getMapScriptName () =="myMap.CivBeyondSwordWBSave":  szBody = localText.getText("TXT_KEY_SOME_OTHER_TEXT_HEADER", ()) + "\n\n" + localText.getText("TXT_KEY_SOME_OTHER_MOD_TEXT", ())
					popupInfo.setText(szBody)
					popupInfo.addPopup(iPlayer)

if you copy the additional line, then make sure, that if you paste it into your python file, that it has exactly the same number of whitespaces in front of the text like the line above. Do not rely on the whitespaces here, copy them in the file, paste them in the file.
And attention, the map names are case sensitive.

Thanks thats exactly what i need! That will definatly work, Thanks:goodjob:
 
I nearly have no experience with the sevopedia, everything graphical is scaring me like hell, and putting the whole tech tree in there is probably another sort of it's own contest, because the drawing probably heavily relies on some functions of the underlying screen type, which will probably not be available in the sevopedia (or in another way) -> sorry :sad:, no, currently i'll not even try to take a look at this.
 
Hey any way you can make a civilopedia page for the tech tree, for latest sevopedia for BTS, im sure this wont be to hard, it can look just like the actuall tree, but also still keep the regular tech page

Ask that question in the General Forum area, you might get a response from good python/SDK person/people, never know.
 
Oh, is this thread the place where people are making Python requests? Because I do love some quick scripting before work, like 6 AM. :D That sort of thing is currently all the modding and programming I have time for, awaiting my life sorting itself out, and junk.

So request away...
 
Alright here ya go.

Here's the code start:

Code:
def reqScorch(caster):
	pPlot = caster.plot()
	pPlayer = gc.getPlayer(caster.getOwner())

	if (pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_PLAINS') or pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_FIELDS_OF_PERDITION')):
		if pPlayer.isHuman() == False:
			if caster.getOwner() == pPlot.getOwner():
				return False
                        [COLOR="Red"]<NEW CODE HERE>[/COLOR]
		return True
	return False

In the noted spot, I wish to add code to find out if the plot owner is another player, and if so, return false unless the caster is at war with the owning player. Seems like it should be simple, but I just can't seem to figure out the right pointers to get this to work.
 
Try this:
Code:
def reqScorch(caster):
	pPlot = caster.plot()
	pPlayer = gc.getPlayer(caster.getOwner())

	if (pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_PLAINS') or pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_FIELDS_OF_PERDITION')):
		if pPlayer.isHuman() == False:
[COLOR="Red"]			ePlotOwner = pPlot.getOwner()
			return caster.getOwner() != ePlotOwner or gc.getTeam(pPlayer.getTeam()).isAtWar(gc.getPlayer(ePlotOwner).getTeam())[/COLOR]
	return False
Note how I didn't use nonsensical parenthesis in the return statement; It works just the same.

The key for this was of course that diplomatic status is a CyTeam feature, not a CyPlayer one. Also, you need to differentiate between the CyTeam instance and the TeamType value.

Most of the time you wanna check players and not teams, so you could add this helper function to your mod:
Code:
def isAtWar(pPlayer1, pPlayer2):
	return gc.getTeam(pPlayer1.getTeam()).isAtWar(pPlayer2.getTeam())
Then you call this helper from the function above:
Code:
			return caster.getOwner() != ePlotOwner or [COLOR="Red"]isAtWar(pPlayer, gc.getPlayer(ePlotOwner))[/COLOR]
edit: It could also be noted that the request was sorta nonsensical, since the function would already return True because of the plot not being owned by the unit's owner. So there really is no need to check whether or not that player is at war with the plot owner. Since this is basically a design issue, I'm not gonna mess with it. Merely pointing it out.
 
Try this:
Code:
[COLOR="Red"]ePlotOwner = pPlot.getOwner()
return caster.getOwner() != ePlotOwner or gc.getTeam(pPlayer.getTeam()).isAtWar(gc.getPlayer(ePlotOwner).getTeam())[/COLOR]

I find this return line confusing. What exactly is it doing?

edit: It could also be noted that the request was sorta nonsensical, since the function would already return True because of the plot not being owned by the unit's owner. So there really is no need to check whether or not that player is at war with the plot owner. Since this is basically a design issue, I'm not gonna mess with it. Merely pointing it out.

I dont understand what you're trying to say here. The function shouldn't be returning True just because the casting owner doesnt equal the plot owner. In fact, most of the time it should return False. I only want it to return true if the two civs are at war. That's the functionality I want to place in the red section. The code isn't complete without that.
 
This is probably what you need:
Code:
def reqScorch(caster):
	pPlot = caster.plot()
	pPlayer = gc.getPlayer(caster.getOwner())

	if (pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_PLAINS') or pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_FIELDS_OF_PERDITION')):
		if pPlayer.isHuman() == False:
			return gc.getTeam(pPlayer.getTeam()).isAtWar(gc.getPlayer(pPlot.getOwner()).getTeam())
	return False
How the return statement works, is it returns some value. Since the CyTeam.isAtWar() statement returns either True or False, this is also what the function returns once the script reaches the line. You would probably express it like this:
Code:
			if gc.getTeam(pPlayer.getTeam()).isAtWar(gc.getPlayer(pPlot.getOwner()).getTeam() == True:
				return True
I find that rather silly, really. It only adds lines and code, but no additional logic. Its like saying: "if True equals True, then its True and thus we return True". Nonsense.
 
First, I think the boolean condition in the return statement should be "and": you want to return True if the plot is not owned by the owner of the casting unit *and* that unit's owner is at war with the plots owner. (To some extent this is redundant: you are never going to be at war with yourself, so the "at war" condition could be sufficient. In practice, having separate "sanity checks" on what is happening is often a good idea so I would be inclined to not eliminate it.)

However, you should note that a lot of plots are not owned by anybody. What happens if ePlotOwner is -1? Python exception when you try to use the getTeam function on the None type object returned by the gc.getPlayer(ePlotOwner). (This is also part of the "sanity check" phase. Plots can be owned by nobody, so what do you do then? You should consider this sort of thing for every piece of data you are getting from someplace outside the current function.)

Perhaps something more like:
Code:
def reqScorch(caster):
	pPlot = caster.plot()
	pPlayer = gc.getPlayer(caster.getOwner())

	if (pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_PLAINS') or pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_FIELDS_OF_PERDITION')):
		if pPlayer.isHuman() == False:
			ePlotOwner = pPlot.getOwner()
			if (ePlotOwner == caster.getOwner()) or (ePlotOwner == -1):
				return False
			return gc.getTeam(pPlayer.getTeam()).isAtWar(gc.getPlayer(ePlotOwner).getTeam())
	return False
This rules out an AI "scorching" its own plots or unowned plots, allowing it only for plots owned by someone the AI's team is at war with.

If you want to allow it on unowned plots too, try changing that "if" code to this:
Code:
			if ePlotOwner == caster.getOwner():
				return False
			elif ePlotOwner == -1:
				return True

It would also be possible to fold the elif condition into the condition on the war check return line with an "or" since Python does "shortcut evaluation" and if one thing in a set of "or" conditions is true the entire condition is true so if the first one is true it never even evaluates the later conditional checks (thus saving you from trying to run functions on a non-exist ant player object for the owner of an unowned plot).
 
Well, God-Emperor has very valid points, as always. I'd definitely go with his script. :king:
 
Back
Top Bottom