Technical documentation

I couldn't figure out, how you used to handle this when you still had cvrhyes.h and cvrhyes.cpp

Sorry, I missed this post. Nothing changed, this part wasn't in CvRhyes, it was in CvEnums already. The code you posted, both solutions are fine, and this part cannot really be moved to Python.
 
In your inquisition popup code, how do you handle the lPersecutionReligions?
Somehow I cannot get the setPersecutionReligions to work properly
At leats the religionList stays at 0:
the 'for iReligion in religionList' cycle in the showPersecutionPopup don't add any entries on the popup, no matter what I do

From what you write it seems that you're not saving the value in setPersecutionReligions to scriptData properly. Remember to pickle & save and then load & unpickle, if you haven't switched to my less pickly method. Also remember to put lPersecutionData & lPersecutionReligions into the dictionary up top.
 
This is how the functions look like in the RFCUtils.py:
Code:
def getPersecutionData(self):
                scriptDict = pickle.loads( gc.getGame().getScriptData() )
                return scriptDict['lPersecutionData'][0], scriptDict['lPersecutionData'][1], scriptDict['lPersecutionData'][2]

        def setPersecutionData(self, iPlotX, iPlotY, iUnitID):
                scriptDict = pickle.loads( gc.getGame().getScriptData() )
                scriptDict['lPersecutionData'] = [iPlotX, iPlotY, iUnitID]

        def getPersecutionReligions(self):
                scriptDict = pickle.loads( gc.getGame().getScriptData() )
                return scriptDict['lPersecutionReligions']

        def setPersecutionReligions(self, val):
                scriptDict = pickle.loads( gc.getGame().getScriptData() )
                scriptDict['lPersecutionReligions'] = val

I put the lPersecutionData and lPersecutionReligions as last entries into the storeddata.py
I'm not sure what do you mean by moving them up top in the dictionary...

EDIT: Oh I see what I missed from unpickle
gc.getGame().setScriptData( pickle.dumps(scriptDict) )

EDIT2: Thanks, the popup seems to work fine now :)
 
Another question regarding inquisitors:

The popup works perfectly for the human, and I realize that you added a religion 'choice' for the AI based on the con.tPersecutionOrder in the doPersecution function
But how do you actually call the doPersecution for the AI?
I'm afraid I don't understand your code in the CvUnitAI.cpp

In RFCE the actual function to purge is defined in the dll (in the CvCity.cpp: canPurgeReligion and doPurgeReligion), not in the RFCUtils.py
I guess exactly because the call from CvUnitAI.cpp
What's more straightforward to do:
move the function to python, like in SoI?
or update the dll function there, and somehow get the religion choice based on the python popup?
 
The CvUnitAI part only does one thing: it redirects the AI logic for Persecutor unit to AI_unitUpdate method in CvGameUtils.py

In CvGameUtils: AI_unitUpdate calls doInquisitorCore_AI, which moves the Inquisitor to a city to persecute, based on the Leader's tolerance and religion, then if at the city, it calls doPersecution.

My implementation is not straightforward or pretty and 3Miro probably won't like it ;) but it offers more functionality that I wouldn't easily do in C++. With the amount of AI Persecutors in the game, it's not hurting performance at all, it's just not straightforward.
 
Well, if I want to remove only one religion at a time, I have to do something like this anyway
3Miro's dll code currently removes all religion (expect state religion)
If I want to put that in line with the chooseable religion for the human player, I would need at least one python callback anyway
So I guess it's more convenient to use your method... I just feel bad to remove 3Miro's code

Btw, your code for the AI actually building persecutors (CvCityAI.cpp) is totally separated from this, right?
Also, I saw you based that part on 3Miro's, how is it improved?
 
Btw, your code for the AI actually building persecutors (CvCityAI.cpp) is totally separated from this, right?
Also, I saw you based that part on 3Miro's, how is it improved?

Yes, it is separate. IIRC 3Miro's code added a chance for the AI to switch to building of Persecutor whenever it decided to build a Missionary. When I tested it, it didn't work well because the AI builds Missionaries only if it has a holy city, or (very rarely) if it still has cities without religion. With the original code the persecutor was almost never built, so I added the same chance to the Spy.

I also added a check to skip the whole thing if there are no non-state religions in AI's empire (at least I think that part was mine), and the probability is not fixed but based on leader's buildPersecutorProb stat.

Persecutor unit type is also determined by the unit ability in the XML, rather than by constant.
 
Minor questions connected to your dopersecution code:

1;
#determine the target religion, if not supplied by the popup decision
if not iReligion:
for iReligion in con.tPersecutionOrder[iStateReligion]:
here you loop through the religions' order in the consts.py based on the statereligion
but what happens if the AI civ doesn't have a state religion?
or the AI will never persecute without a state religion?

2;
you use the pCity.getReligionCount() function
AFAIK it was exposed to python, and RFCE already uses the function in a couple places (in c++ at least)
why is it needed then to add these lines in cycity.cpp?
// edead: start
int CyCity::getReligionCount()
{
return m_pCity ? m_pCity->getReligionCount() : -1;
}
// edead: end


3;
you added the new AttitudeExtra diplomacy modifier
(IIRC I already asked this earlier, but didn't found your answer)
Is it possible to add memory decays to this attitude too?
Is it possible to lose the attitude modifier when the other civ switches from that state religion?


4;
# chance to work: 50-75 based on piety
iChance = 50 + max(25, pPlayer.getFaith()/2)
I think you made a typo here
Didn't you want to add min(25, pPlayer.getFaith()/2) ?


5;
Another possible mistake here
Your code:
# kill / expel some population
if pCity.getPopulation() > 3:
pCity.changePopulation(-1)
elif pCity.getPopulation() > 9:
pCity.changePopulation(-2)
elif pCity.getPopulation() > 14:
pCity.changePopulation(-3)


Shouldn't it be this?
# kill / expel some population
if city.getPopulation() > 14:
city.changePopulation(-3)
elif city.getPopulation() > 9:
city.changePopulation(-2)
elif city.getPopulation() > 3:
city.changePopulation(-1)

I'm not sure, you may have it intentionally that way
I just wanted to mention, that currently your code always kills only one population (if it's at least 4 of course)
 
1. There would be a Pyton exception, but that can't really happen because you need a state religion to build a Religious Persecutor (also in RFCE, I believe I borrowed that part from you - the state religion requirement that is). Moreover, it's impossible to switch to non-state religion in SoI, but you might want to add some sanity check in RFCE.

2. Err, these lines is what exposes it to Python.

3. I answered that earlier actually: I didn't add the Attitude Extra, it's part of BTS and already has memory decay (EVENT_BAD_TO_US). I only renamed the negative text from "Past events have drawn our people apart" (something like that) to the current persecution text, as it wasn't used by anything.

4-5. Yeah, thanks! (although considering the price of a persecutor, maybe I should update the comment instead...)

P.S. Update your sig ;)
 
Hey edead!
I think there is a small mistake in the CvCity.cpp, when is the city allowed to produce persecutors
Code:
if (!((GET_PLAYER(getOwnerINLINE()).getStateReligion() == NO_RELIGION) || (isHasReligion(GET_PLAYER(getOwnerINLINE()).getStateReligion()))))

You want them to be buildable only if your civ has a state religion, and the state religion is spread to the actual city, right?
Currently your code allows persecutors in cities without the state religion too
(because no religion is always not true if the second part can be true)

This is what I currently use in RFCE:
Code:
if ( !( (GET_PLAYER(getOwnerINLINE()).getStateReligion() != NO_RELIGION) && (isHasReligion( GET_PLAYER(getOwnerINLINE()).getStateReligion())) ) )

EDIT: Tried it out in SoI, works correctly
But then I'm not sure why is the first part of the code needed in your version
I don't see the point in !(GET_PLAYER(getOwnerINLINE()).getStateReligion() == NO_RELIGION)
 
One more thing: I think you forgot to deal with holy cities in the doInquisitorCore_AI function
So if a religion's holy city is the next city when looping through the city list, the AI won't move on
Even if there are many "good" candidates for persecution after this city (in the cities order)


Also, the AI will always choose a city based on tReligiousTolerance, so they will almost never move to the correct cities

For example even if a civ has a hated religion all over it's cities, Persecutors will go to the first city which has Zoroastrianism or Judaism, and will purge there
The purge is based on the tPersecutionOrder though, so it will purge the hated religion first (correctly).
But the problem is that it won't move on to the next city before Zoroastrianism or Judaism is removed from this city, so these religions basically have priority over the hated religions
If a catholic hater civ has 2 jewish and 10 catholic cities, it won't purge at least 8 of those catholic cities before the 2 jewish cities are purged

Probably it would be better if the PersecutionOrder was also used when choosing the target city
 
EDIT: Tried it out in SoI, works correctly
But then I'm not sure why is the first part of the code needed in your version
I don't see the point in !(GET_PLAYER(getOwnerINLINE()).getStateReligion() == NO_RELIGION)

Well, like you said, it works correctly, and that's what counts ;) There are several ways to check for the same thing and it's hard to tell why I did it this way... I probably added the first statement because checking for state religion in a city always returns true if state religion is NO_RELIGION.
 
One more thing: I think you forgot to deal with holy cities in the doInquisitorCore_AI function
So if a religion's holy city is the next city when looping through the city list, the AI won't move on
Even if there are many "good" candidates for persecution after this city (in the cities order)

Yeah, thanks. Fixed.

Also, the AI will always choose a city based on tReligiousTolerance, so they will almost never move to the correct cities

For example even if a civ has a hated religion all over it's cities, Persecutors will go to the first city which has Zoroastrianism or Judaism, and will purge there
The purge is based on the tPersecutionOrder though, so it will purge the hated religion first (correctly).
But the problem is that it won't move on to the next city before Zoroastrianism or Judaism is removed from this city, so these religions basically have priority over the hated religions
If a catholic hater civ has 2 jewish and 10 catholic cities, it won't purge at least 8 of those catholic cities before the 2 jewish cities are purged
Probably it would be better if the PersecutionOrder was also used when choosing the target city

Yeah, just change range(con.iNumReligions) to con.tPersecutionOrder[iOwner]
 
Yeah, thanks. Fixed.

Really? I can't find what did you change regarding this
What was your fix for it?

Yeah, just change range(con.iNumReligions) to con.tPersecutionOrder[iOwner]

Yeah, I had done the same initially (but you meant con.tPersecutionOrder[iStateReligion] I guess)
Btw, I switched the pCity and iReligion loops. So it won't check each city in the specific order and look for target religion(s) in it (until the city only has state religion), but look for the most hated religion, and loop through the cities to check if any of them has it.

A couple thoughts: pCity in apCityList puts your cities in an order based on foundation date? Or based on coordinates on the map?
Anyway, I was thinking of randomizing the city order a little bit.
Maybe somehow base it on religion number as well.

I was also thinking about adding a check, that the AI skips religions in a city not only when it's a holy city of that religion, but also when there is a wonder tied to that religion
I don't see too many cases where the AI should remove a wonder (in RFCE it's good for the player for a couple UHVs, but otherwise wonders worth to keep)
 
Really? I can't find what did you change regarding this
What was your fix for it?

Err, right, I thought I did, but I fixed something else. I did fix it now, though.

Yeah, I had done the same initially (but you meant con.tPersecutionOrder[iStateReligion] I guess)

Oops yeah.

A couple thoughts: pCity in apCityList puts your cities in an order based on foundation date? Or based on coordinates on the map?

Based on C++ array order, which should correspond to foundation dates and/or acquisition dates (i.e. with conquered cities appended at the end, but I'm not 100% sure).

Anyway, I was thinking of randomizing the city order a little bit.
Maybe somehow base it on religion number as well.

The result has to be the same every turn so it can't be random, but if you use modulo religion index, I guess that should work fine.

I was also thinking about adding a check, that the AI skips religions in a city not only when it's a holy city of that religion, but also when there is a wonder tied to that religion
I don't see too many cases where the AI should remove a wonder (in RFCE it's good for the player for a couple UHVs, but otherwise wonders worth to keep)

Well, I don't think wonders should be removed at all - religious "wonders" were at worst converted to the new religion, but still remained, like Hagia Sophia.
 
Btw, I switched the pCity and iReligion loops. So it won't check each city in the specific order and look for target religion(s) in it (until the city only has state religion), but look for the most hated religion, and loop through the cities to check if any of them has it.

Maybe it would be better if you also switched the two loops
Cycling primarly based on the religion hate order makes more sense IMO

The result has to be the same every turn so it can't be random, but if you use modulo religion index, I guess that should work fine.

Yeah, it can't be totally random of course. Will see if I implement something like this in the end. Probably not that important

Well, I don't think wonders should be removed at all - religious "wonders" were at worst converted to the new religion, but still remained, like Hagia Sophia.

It makes sense to enable it for human players in RFCE, for a couple UHVs
I did make a little addition to the persecution function though:
Code:
		# count the number of religious buildings and wonders (for the chance)
		if iReligion > -1:
			lReligionBuilding = []
			lReligionWonder = 0
			for iBuilding in xrange(gc.getNumBuildingInfos()):
				if city.getNumRealBuilding(iBuilding):
					BuildingInfo = gc.getBuildingInfo(iBuilding)
					if BuildingInfo.getPrereqReligion() == iReligion:
						lReligionBuilding.append(iBuilding)
						if isWorldWonderClass(BuildingInfo.getBuildingClassType()) or isNationalWonderClass(BuildingInfo.getBuildingClassType()):
							lReligionWonder += 1
		else:
			return False	# when there is no available religion to purge

		# base chance to work: about 50-90, based on faith:
		## iChance = 60 + max(-10, min(30, pPlayer.getFaith()/3))
		iChance = 55 + pPlayer.getFaith()/3
		# lower chance for purging any religion from Jerusalem:
		if (iPlotX == con.iJerusalem[0] and iPlotY == con.iJerusalem[1]):
			iChance -= 25
		# lower chance if the city has the chosen religion's buildings/wonders:
		iChance -= (len(lReligionBuilding) * 8 + lReligionWonder * 17)		# the wonders have an extra chance reduction (in addition to the first reduction)

		if gc.getGame().getSorenRandNum(100, "purge chance") < iChance:
So religious buildings (and religious wonders to a much bigger amount) decrease the chance of a successful persecution
But as I said, I have to add a check to the AI here (to skip cities with religious wonders) in the doInquisitorCore_AI
Otherwise it won't get to the next city in the loop, only after the persecution finally succeeds and the wonder is removed.
If you want to have it impossible in SoI to remove wonders, then it's unnecessary for you of course
 
I have some assert failures with the mainscreen mercenary manager button
So I tried to add a new controltype for it, like you did in SoI (cvmaininterface.py, line 300)
I added the corresponding lines into cvgameinterface.cpp, cvenums.h and cvenumsinterface.cpp
But I still get a python exception on game start: "AttributeError: 'NoneType' object has no attribute 'getActionInfoIndex'"
Do you have any ideas what did I miss?
 
I'm curious to know how much of K-mod is in this version. everything you thought was worth it?
 
Back
Top Bottom