Religeous Unity

OrionVeteran

Deity
Joined
Dec 25, 2003
Messages
2,443
Location
Newport News VA
I was looking at the religeous victory in BMarnz' Inquisition Mod and decided I want to add one more requirement to the existing religious influence setting found in the CIV4VictoryInfo.xml file.

The new requirement is Religeous Unity, which requires the following:

1. All of a player's cities must have the official state religion established.
2. All of a player's cities must not have any non-state religions established.

I wrote the following untested code to determine if a player has achieved Religious Unity:

Code:
Def isReligiousUnity(Self):
	# Code to determine if all cities have religious unity
	RUnity = True
	Player = gc.getActivePlayer()
	If pPlayer.getNumCities()>0:
		For iReligionLoop in range(gc.getNumReligionInfos()):
			# Does the city have a religion?
			If pCity.isHasReligion(iReligionLoop):
				# Does the religion match the player’s state religion?
				If pPlayer.getStateReligion() != iReligionLoop:
					RUnity = False
			Else:
				# No religion was found in city
				RUnity = False
		If RUnity = False
			# The player has not achieved religious unity
			Return False
		Else:
			# The player has achieved religious unity
			If getReligionInfluence(pPlayer.getStateReligion()) = 85
				# The religious influence for the player’s state religion is 85%
				Return True

My question is: How can I add this Religious unity requirement to override the existing religious influence setting found in the CIV4VictoryInfo.xml file with this code? :confused:

Also, feel free to make any comments about my proposed religious unity code.

Sincerely,

Orion Veteran :cool:
 
First you need to disable the victory for the religious victory in CvGameUtils (will call "VICTORY_RELIGIOUS" in the code , up to you to find the good type) :

Spoiler :
Code:
	def isVictory(self, argsList):
		eVictory = argsList[0]
		if eVictory == gc.getInfoTypeForString("VICTORY_RELIGIOUS"):
                        return False
		return True

Why disabling the victory ? because if two player met the requirements for the original religious victory and if you put your code here (testing all players). Nothing makes sure the good player will be chosen for the victory.

So you will check if the player achieve the victory at the beginning of each player turn . Note that gc.getActivePlayer() is not MP compatible and doesn't return the current player but the player who have the PC.

Here your code fixed (i Think and not tested) you should in CvEventManager.onBeginPlayerTurn :

Spoiler :
Code:
                # Code to determine if all cities have religious unity
                if (pPlayer.getNumCities() > 0) and (CyGame().getNumCivCities() > 2 * CyGame().countCivPlayersAlive()): # be sure the game is advanced enough to test a religious victory
                        bUnity = True
                        iStateReligion = pPlayer.getStateReligion()

                        if iStateReligion == -1 :
                                bUnity = False

                        if bUnity :
                                if not pPlayer.hasHolyCity(iStateReligion) :
                                        bUnity = False

                        if bUnity :
                                if CyGame().calculateReligionPercent(iStateReligion) < 85 :
                                        bUnity = False

                        if bUnity :
                                for pyCity in PyHelpers.PyPlayer(iPlayer).getCityList() :
                                        if not bUnity :
                                                break

                                        for iReligionLoop in range(gc.getNumReligionInfos()):
                                                if iReligionLoop == iStateReligion :
                                                        if not pyCity.hasReligion(iReligionLoop) :
                                                                bUnity = False
                                                                break
                                                elif pyCity.hasReligion(iReligionLoop) :
                                                        bUnity = False
                                                        break

                        if bUnity :
                                CyGame().setWinner(pPlayer.getTeam(), gc.getInfoTypeForString("VICTORY_RELIGIOUS"))


Don't forget to enable the debugger when you will test the victory. Perhaps onBeginGameTurn is better and loop over all player alive !? Don't forget that AI will probably not be able to achieve such a victory .

Tcho !
 
Here your code fixed (i Think and not tested) you should in CvEventManager.onBeginPlayerTurn :

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

                # Code to determine if all cities have religious unity
                If (pPlayer.getNumCities() > 0) and (CyGame().getNumCivCities() > 2 * CyGame().countCivPlayersAlive()): # be sure the game is advanced enough to test a religious victory
                        bUnity = True
                        iStateReligion = pPlayer.getStateReligion()

                        if iStateReligion == -1 :
                                bUnity = False

                        if bUnity :
                                if not pPlayer.hasHolyCity(iStateReligion) :
                                        bUnity = False

                        if bUnity :
                                if CyGame().calculateReligionPercent(iStateReligion) < 85 :
                                        bUnity = False

                        if bUnity :
                                for pCity in PyHelpers.PyPlayer(iPlayer).getCityList() :
                                        if not bUnity :
                                                break

                                        For iReligionLoop in range(gc.getNumReligionInfos()):
                                                if iReligionLoop == iStateReligion :
                                                        If not pCity.isHasReligion(iReligionLoop) :
                                                                bUnity = False
                                                                break
                                                elif pCity.isHasReligion(iReligionLoop) :
                                                        bUnity = False
                                                        break

                        if bUnity :
                                CyGame().setWinner(pPlayer.getTeam(), gc.getInfoTypeForString("VICTORY_RELIGIOUS"))

After a lot of testing the code dies in at least 3 places. Suffice to say I have fixed all but one area : Looping through all cities to make sure all non-state religions exist and that every city has the official state religion established. Obviously this is the most important part of the code. It is located where you had the following strategy: Starting line reads:

for pCity in PyHelpers.PyPlayer(iPlayer).getCityList() :

Can you provide better alternative coding? The code needs to loop through all of the player's cities. When I did debug this code, only 5 of my 16 cities was selected in the loop. :confused:

Sincerely,

Orion Veteran :cool:
 
After a lot of testing the code dies in at least 3 places. Suffice to say I have fixed all but one area : Looping through all cities to make sure all non-state religions exist and that every city has the official state religion established. Obviously this is the most important part of the code. It is located where you had the following strategy: Starting line reads:

for pCity in PyHelpers.PyPlayer(iPlayer).getCityList() :

Can you provide better alternative coding? The code needs to loop through all of the player's cities. When I did debug this code, only 5 of my 16 cities was selected in the loop. :confused:

Sincerely,

Orion Veteran :cool:

Ok , the code is fixed in the post below and tested . That's works this time

There was 3 typo errors (If instead of if and For instead of for). There was also another error the pCity instance are pHelpers instance (take a look at pyhelpers.py) and isHasreligion is changed with hasReligion. (should have been tired this day)

If you want an alternative to get the city list , just take the pyHelpers one and append pLoopCity instead of pyCity.

This is normal that the loop don't go over every city , as soon as the loop met a city that don't have all requirements -> it stops , no need to check any other city.

Tcho !
 
Ok , the code is fixed in the post below and tested . That's works this time'

First, I'd like to thank you for your invaluable help with this code that checks for religious unity. :goodjob:

Please note:

Code:
for pyCity in PyHelpers.PyPlayer(iPlayer).getCityList():
		if not bUnity:
			break
		for iReligionLoop in range(gc.getNumReligionInfos()):						
			if iReligionLoop == iStateReligion:			                   
				if pyCity.hasReligion(iReligionLoop) == -1:									
					# Message1
					bUnity = False
					break								
		elif pyCity.hasReligion(iReligionLoop) != -1:
			#Message2
			bUnity = False
			break

Ran multiple tests and discovered the following.

1. The code would not run unless I replaced the word "NOT" with:

.....a. == -1: for false
.....b. != -1: for True

2. The result indicated by Message2 came up when I had one remaining city that had a non-state religion. When I used an inquisitor to remove it, I had complete religious unity, but the code still returned Message2 instead of a victory. :(

Any ideas for how we can fix this loop section?

Very Respectfully,

Orion Veteran :cool:
 
First, I'd like to thank you for your invaluable help with this code that checks for religious unity. :goodjob:

Please note:

Code:
for pyCity in PyHelpers.PyPlayer(iPlayer).getCityList():
		if not bUnity:
			break
		for iReligionLoop in range(gc.getNumReligionInfos()):						
			if iReligionLoop == iStateReligion:			                   
				if pyCity.hasReligion(iReligionLoop) == -1:									
					# Message1
					bUnity = False
					break								
		elif pyCity.hasReligion(iReligionLoop) != -1:
			#Message2
			bUnity = False
			break

Ran multiple tests and discovered the following.

1. The code would not run unless I replaced the word "NOT" with:

.....a. == -1: for false
.....b. != -1: for True

2. The result indicated by Message2 came up when I had one remaining city that had a non-state religion. When I used an inquisitor to remove it, I had complete religious unity, but the code still returned Message2 instead of a victory. :(

Any ideas for how we can fix this loop section?

Very Respectfully,

Orion Veteran :cool:

my code :

Code:
                                        for iReligionLoop in range(gc.getNumReligionInfos()):
                                                if iReligionLoop == iStateReligion :
                                                        if not pyCity.hasReligion(iReligionLoop) :
                                                                bUnity = False
                                                                break
                                                elif pyCity.hasReligion(iReligionLoop) :
                                                        bUnity = False
                                                        break

that mean : for each city , for each religion : 1 -> if the religion tested is the state religion and the current city don't have it STOP no unity . 2 -> you check another religion -> if the city have the religion no unity STOP .

Your code : "elif pyCity.hasReligion(iReligionLoop) != -1:" this test return a boolean (in python 0 or None for False and anything else is True) , but a boolean is jsut an integer that have a value 0 or 1 so everytime != -1 so the test is always True . and "if pyCity.hasReligion(iReligionLoop) == -1:" is always false. There is nothing like that in the code i've provided. I think you should post your entire code. Especialy with the structure , the first code you have post in the thread ,even without synthax error don't do what you want and wrote.

Tcho !

Edit : i don't understand why you get some problems with "not" . It's used in the original files and i always use it. Put == False or == True if you want to change that. Note i've tested the victory with the religious victory of FFH and get no problem.
 
Edit : i don't understand why you get some problems with "not" . It's used in the original files and i always use it. Put == False or == True if you want to change that. Note i've tested the victory with the religious victory of FFH and get no problem.

Sorry about being a pain, but I really want to get this right. After defragging my PC and rebooting the "NOT" now seems to work correctly without crashing the code (exception: The .hasHolyCity still requires the change or it returns bUnity = False. :crazyeye:

Message 1 now comes up, when all of my cities have the state religion and no non-state religions exist. There are 3 cities in the game left with other religions, but they all belong to rival civs.

As you requested, here is my test code with messages indicating the results.

Code:
if (pPlayer.getNumCities() > 0) and (CyGame().getNumCivCities() > 2 * CyGame().countCivPlayersAlive()):
	bUnity = True
	iStateReligion = pPlayer.getStateReligion()								
                        		
	if iStateReligion == -1:					
		# No State Religion was Found
		bUnity = False

	if bUnity:					
		if pPlayer.hasHolyCity(iStateReligion) == -1:					
			# No Holy City was Found for the official state religion
			bUnity = False
			CyInterface().addMessage(CyGame().getActivePlayer(),True,25,'No Holy City!','AS2D_DISCOVERBONUS',1,'Art/Interface/Buttons/TerrainFeatures/Forest.dds',ColorTypes(8),iX,iY,False,False)
									
	if bUnity:					
		for pyCity in PyHelpers.PyPlayer(iPlayer).getCityList() :				
			if not bUnity:
				break						
						
			for iReligionLoop in range(gc.getNumReligionInfos()):			                		
				if iReligionLoop == iStateReligion:
					if not pyCity.hasReligion(iReligionLoop) :
						bUnity = False
						CyInterface().addMessage(CyGame().getActivePlayer(),True,25,'Message 1!','AS2D_DISCOVERBONUS',1,'Art/Interface/Buttons/TerrainFeatures/Forest.dds',ColorTypes(8),iX,iY,False,False)									
						break
				elif pyCity.hasReligion(iReligionLoop) :
					bUnity = False
					CyInterface().addMessage(CyGame().getActivePlayer(),True,25,'Message 2!','AS2D_DISCOVERBONUS',1,'Art/Interface/Buttons/TerrainFeatures/Forest.dds',ColorTypes(8),iX,iY,False,False)			
					break
				
	if bUnity :
		if CyGame().calculateReligionPercent(iStateReligion) < 80 :
			# Religeous influence is less than 80%
			bUnity = False

	if bUnity :
		# The player has achieved religious unity
		CyInterface().addMessage(CyGame().getActivePlayer(),True,25,'Victory!','AS2D_DISCOVERBONUS',1,'Art/Interface/Buttons/TerrainFeatures/Forest.dds',ColorTypes(8),iX,iY,False,False)
		#CyGame().setWinner(pPlayer.getTeam(), gc.getInfoTypeForString("VICTORY_RELIGIOUS"))

Why am I still getting Message 1, bUnity = False? :confused:
 
This test is launch for every player at the "beginning" (of the end ) of their turn. So the message can come from the test for another player perhaps . You should enable the log and put some print instead of putting some message ( where iX and iY are not defined , you should get an exception here !? ). Add "print iPlayer" at the beginning , "print pyCity.getName()" after for pyCity in ..., print "no state religion" for message1, print "another religion" for message2 . Then to check what happen , press alt-tab and check the log .

That's better than adding some message without arguments .

Tcho !
 
This test is launch for every player at the "beginning" (of the end ) of their turn. So the message can come from the test for another player perhaps.

You hit the nail right on the head! The code was actually checking the first computer player only. The answer was to loop through all of the players and run our bUnity checks against each player. If was flawless! ;)

Here are my changes:
Code:
#################################################
# Code to determine if all cities have 5 "Religious Unity" Prerequisits by Orion Veteran
# Special thanks to STO for providing the code strategy - Great Job! 
#
# 1. A player must have an official State Religion
# 2. A player must have the Holy City for the official State Religion		
# 3. All of a player's cities must have the official state religion established.
# 4. All of a player's cities must not have any non-state religions established.
# 5. Religious influence must be at least 80%

for iPlayer in range(gc.getMAX_CIV_PLAYERS()):
	if (gc.getPlayer(iPlayer).isAlive()):
		loopPlayer = PyPlayer(gc.getPlayer(iPlayer).getID())
		if (loopPlayer.isNone() or not loopPlayer.isAlive()):
			continue
		else:					
			if (pPlayer.getNumCities() > 0) and (CyGame().getNumCivCities() > 2 * CyGame().countCivPlayersAlive()): # be sure the game is advanced enough to test a religious victory				
				bUnity = True
				iStateReligion = pPlayer.getStateReligion()								
                        		
				if iStateReligion == -1:					
					# No State Religion was Found - Prerequisit 1
                               		bUnity = False

				if bUnity:					
					if pPlayer.hasHolyCity(iStateReligion) == -1:					
						# No Holy City was Found for the official state religion - Prerequisit 2
						bUnity = False
                                      		CyInterface().addMessage(CyGame().getActivePlayer(),True,25,'No Holy City!','AS2D_DISCOVERBONUS',1,'Art/Interface/Buttons/TerrainFeatures/Forest.dds',ColorTypes(8),iX,iY,False,False)
									
				if bUnity:					
					for pyCity in PyHelpers.PyPlayer(iPlayer).getCityList() :				
						if not bUnity:
							break						
						
						for iReligionLoop in range(gc.getNumReligionInfos()):			                		
							if iReligionLoop == iStateReligion:
								if not pyCity.hasReligion(iReligionLoop) :
									# City does not have the official state religion - Prerequisit 3
									bUnity = False																				
			                        	      		break
							elif pyCity.hasReligion(iReligionLoop) :
								# City has a non-State religion - Prerequisit 4
								bUnity = False													
			                        		break
				
				if bUnity :
					if CyGame().calculateReligionPercent(iStateReligion) < 80 :
						# Religeous influence is less than 80% - Prerequisit 5
                                       		bUnity = False

				if bUnity :							
					# If we got a valid winner.							
					if pPlayer.isHuman() != -1 :
						# The player has achieved all 5 religious unity Prerequisits								
						CyGame().setWinner(pPlayer.getTeam(), gc.getInfoTypeForString("VICTORY_RELIGIOUS"))
						break
I'm going to play a couple of more games over the next few days just to be 100% certain. The only other thing I should ask is how can I create a call to the code like:

Def DoReligiousUnityCheck()

Code...

This call might be more effective if there is already existing code in the def onBeginPlayerTurn(self, argsList):

Very respectfully,

Orion Veteran :cool:
 
But , onBeginPlayerTurn is called for every alive player ,each turn. You don't need to loop over each player or put this function in onBeginGameTurn ...
 
onBeginPlayerTurn is called for every alive player ,each turn.

That's exactly the problem, it was calling the first alive player, which happens to be a computer player. The first computer player failed the bUnity checks, as it should. It never called the third player, a human player, even though it was the beginning of the human player's turn. As soon as I looped through all of the players, the bUnity checks failed for the two alive computer palyers, but passed for third player, the human player. Victory was achieved for the right player.

Without the player loop, I have no idea why the code was checking the first computer player and not the actual player, the human player, whose turn was actually beginning. :confused: With the player loop it works. I'm concerned the code, as it is now, may not work correctly for multiplayer. I think I need to focus the loop code to test only the active player.
 
That's exactly the problem, it was calling the first alive player, which happens to be a computer player. The first computer player failed the bUnity checks, as it should. It never called the third player, a human player, even though it was the beginning of the human player's turn. As soon as I looped through all of the players, the bUnity checks failed for the two alive computer palyers, but passed for third player, the human player. Victory was achieved for the right player.

Without the player loop, I have no idea why the code was checking the first computer player and not the actual player, the human player, whose turn was actually beginning. :confused: With the player loop it works. I'm concerned the code, as it is now, may not work correctly for multiplayer. I think I need to focus the loop code to test only the active player.

This is normal since the code is called at the beginning of the end of the player turn . It you keep this loop put the function in onBeginGameTurn and not in onBegninplayerturn. Thisd is important. You should check also if the current game accept the religious victory. You should also check your code ... not safe. I let you think about what you've added .

Tcho !
 
If you keep this loop put the function in onBeginGameTurn and not in onBegninplayerturn. Thisd is important. You should check also if the current game accept the religious victory. You should also check your code ... not safe. I let you think about what you've added .

I moved the code over to onBeginGameTurn, but it just failed to run. :( I moved it back to onBegninplayerturn, and it works and victory is achieved. :crazyeye:

If my loop code is:

Code:
for iPlayer in range(gc.getMAX_CIV_PLAYERS()):
	if pPlayer.isAlive():
		loopPlayer = PyPlayer(pPlayer.getID())
		if (loopPlayer.isNone() or not loopPlayer.isAlive()):
			continue
		else: 
			bUnity checks

Do you have any recommendations to improve it?
 
The second code I've post was working ( The only thing that miss is a test to check if the game is victory religious.) . That's why i don't understand why you want to change change all. For an example, here you should change iPlayer by iLoopPlayer (just to prevent an error if there is another function in onBeginPlayerTurn). There is still some "pyCity.hasReligion(..) != -1" !?.

When you work with python . You should enable the debugger and add some log to check what really happen. You have added some parts of code that have no use I think . I still do not understand why you want to loop over all players . I don't understand why you use PyPlayer to check alive or not just after calling the cyplayer instance to do the same thing.

Tcho !
 
The second code I've post was working ( The only thing that miss is a test to check if the game is victory religious.)

It worked for you. Currently, I have 2 games advanced to the point where I am only one turn each away from religious unity and victory. This makes testing easy. Your second code failed on the line below and would not advance to the next bUnity check or achieve victory.

if not pPlayer.hasHolyCity(iStateReligion) :

Once I changed it to == - 1: Then the code executed properly on test games having the state religion Holy City and one without. Both tests worked after this change; bUnity was true for having the Holy City and false for not having it.

if pPlayer.hasHolyCity(iStateReligion) == -1:

That's why i don't understand why you want to change change all.

I changed this code because without it, the code failed to advance to the next bUnity check and the code crashed. I know this because I could not rename a city. Only one line of bad code anywhere in the function will cause it to crash. So, I am not changing the code just because I feel like it, I changed it because I had to to get the code to run properly.

For an example, here you should change iPlayer by iLoopPlayer (just to prevent an error if there is another function in onBeginPlayerTurn).

OK that makes good sense. I'll make that change and see what it does.

There is still some "pyCity.hasReligion(..) != -1" !?.

I changed it back and it tested good.

if not pyCity.hasReligion(iReligionLoop) :

When you work with python . You should enable the debugger and add some log to check what really happen.

Yes, I think it might help.

You have added some parts of code that have no use I think . I still do not understand why you want to loop over all players.

I had to loop through all players because the code was actually checking the first computer player for victory and never checked the human player at all. That is why the code failed the bUnity checks for the existance of a state religion and the existance of any non-state religions. With the player loop the two computer players failed the test, but victory was achieved for the human player because I had achieved religious unity for all cities. There was no victory without the loop.

I don't understand why you use PyPlayer to check alive or not just after calling the cyplayer instance to do the same thing.

I used an example I found on the internet. Perhaps you can show me a safer and better way to perform the loop.

Very Respectfully,

Orion Veteran :cool:
 
Sto,

I enabled Python debugger and fixed one line error in Smartmap.py. No errors came up, when I ran our function. The log file was empty. This re-enforces my confidence in the code changes I made. I tried to change iPlayer by iLoopPlayer, but the code crashed.

Can you post your recommendations for how the loop code should look like?

V/R,

Orion Veteran :cool:
 
No errors came up, when I ran our function. The log file was empty. This re-enforces my confidence in the code changes I made. I tried to change iPlayer by iLoopPlayer, but the code crashed.

An empty log doesn't mean your code is right but that you get no exception. I hope you edit the files with python or at least notepad ++ (if not this is the first thing to do while reading the python tutorial ... "the code crash" when you change the name of a variable !?). I can't help you more since you seem to have some different results with me and the same code. You should restart from the beginning (with the code i've provided) adding some logs (see post 8) to check what really happen in PythonDbg.log (an interface message is not a good way and you can miss some with the delay and max message). Pass some turns with the log and you will check what happen in the code . For each player, for each city you will be able to check what happen. Then , if you encounter some problems , try to fix them step by step (not by adding a part of code you don't understand ... the player loop) and if you get stuck, post the problem.

That's the better way to learn and advance I think.

Tcho !
 
An empty log doesn't mean your code is right but that you get no exception. I hope you edit the files with python or at least notepad ++ (if not this is the first thing to do while reading the python tutorial ... "the code crash" when you change the name of a variable !?).
I can't help you more since you seem to have some different results with me and the same code. You should restart from the beginning (with the code i've provided) adding some logs (see post 8) to check what really happen in PythonDbg.log (an interface message is not a good way and you can miss some with the delay and max message). Pass some turns with the log and you will check what happen in the code . For each player, for each city you will be able to check what happen. Then , if you encounter some problems , try to fix them step by step (not by adding a part of code you don't understand ... the player loop) and if you get stuck, post the problem.

That's the better way to learn and advance I think.

Tcho !

OK I have to admit, I messed up. You were right and I was very wrong. I was using Notepad and not Notepad++ :hammer2: :wallbash:

By using Notepad++, I found the indentations were incorrect and had to be fixed. What a difference! It changed the results completely. Re-testing "without the loop" produced a successful victory for the onBeginPlayerTurn player. Although I still had to change the bunity check that verifies the existence of the official state religion holy city. The code fails to work unless it reads this way:

if pPlayer.hasHolyCity(iStateReligion) == -1 :

Not bad. I now have a solid bug free function to check for Religious unity. :dance::banana::bounce: This code is going to make a lot of people happy in my next release of the Orion's Challenge Mod. :) You are awesome! :goodjob: :hatsoff:

Thanks for all the help :thanx:

Sincerely,

Orion Veteran :cool:
 
The code fails to work unless it reads this way:

if pPlayer.hasHolyCity(iStateReligion) == -1 :

Since pPlayer.hasHolyCity(iStateReligion) return a Boolean ( an integer that have a value of 0 or 1) this test should never be True !? :crazyeye:

You should also add another check : "if CyGame().isVictoryValid(gc.getInfoTypeForString("VICTORY_RELIGIOUS")) :" , because the player is not forced to play a game with this victory.

Tcho !
 
Since pPlayer.hasHolyCity(iStateReligion) return a Boolean ( an integer that have a value of 0 or 1) this test should never be True !? :crazyeye:

You should also add another check : "if CyGame().isVictoryValid(gc.getInfoTypeForString("VICTORY_RELIGIOUS")) :" , because the player is not forced to play a game with this victory.

Tcho !

1. The Holy City check makes perfect sense to me. If the player does not have the holy city for the official state religion, then bUnity is False (-1).

2. Done. I added this victory check just before the command that declares victory. It tested good and victory was achieved.

:thanx: Sto,

Orion Veteran :cool:
 
Top Bottom