Technical documentation

I'm asking this question here even though it pertains to my mod because I'm using the specific SoI respawn code. I'm trying to make a civ collapse and then respawn as a different civ, like Armenia>Cilicia or Ghorids>Delhi in SoI. I have been changing values (tRespawn, tResurrectionPossibility), and the putting my civs in place of the Armenians and Ghorids in RiseAndFall historical resurrections, and the collapse is working, but a different civ is respawning, even though their tRespawn is 0. I also set iMinNumTurns in def resurrection to equal 1 in the case of the civ I want to respawn. there is at least a 10 turn gap between the collapse and tRespawn.

I added print statements and it is correctly picking the civ on the right turn in the historical resurrection part and passing the values I want into def resurrection. I don't understand the next part of the code however. I'm confused about iForcedCiv and iDeadCiv. I thought iForcedCiv, the value passed from historical resurrections, was the civ that was respawning, so what is iDeadCiv?
 
Rhye's resurrection code loops through all civs, starting with a random one, and tries to resurrect one if viable and a random roll succeeds, then it stops. iDeadCiv is simply the current's civ in the loop.

My iForcedCiv variable simply makes sure that the above loop starts from this particular civ and its resurrection chance is 100%. If the next civ is resurrected instead, this simply means that the conditions for respawning your iForcedCiv failed, and the next civ in loop was resurrected instead.

So, check your respawn conditions. The reasons could be:
- less than 50 turns have passed since civ birth
- less than 20 (or iMinTurns) turns have passed since last resurrection
- it's past this civ's "fall" date (tFallRespawned)
- there's not enough viable cities for this civ (less than iMinNumCities), notice there complex conditions for the city to rebel... the owner must not be too stable, the city can't be in his core, it needs to have some kind of unhappiness or unhealthiness or be far away etc.
 
thanks its working now. the relevant respawn region (there was only 1) had only 2 cities in it.

took me a while to see that
Code:
for j in range(iRndnum, iRndnum + iNumPlayers):
			iDeadCiv = j % iNumPlayers
is just a loop-through starting part way through. cool.
 
well the respawn is working but the renaming only partly. here is my code with a print statement letting me know it is being called:

Spoiler :
Code:
	def onCivRespawn(self, iPlayer):
		sd.setCivStatus(iPlayer, 1)
		
		if iPlayer in self.respawnedNames:
			pPlayer = gc.getPlayer(iPlayer)
			if iPlayer == con.iMauryans:
				print "re-naming Mauryans"
				self.setCivDesc(iPlayer, self.respawnedNames[iPlayer], "TXT_KEY_CIV_SUNGA_SHORT_DESC", "TXT_KEY_CIV_SUNGA_ADJECTIVE")
				pPlayer.setName(localText.getText("TXT_KEY_LEADER_PUSYAMITRA_SUNGA", ()))
				pPlayer.setCivilizationType(con.iSungas)

the leader name changes correctly but when they respawn the text message says "Mauryan cities have declared independence from foreign domination" and then "you have made peace with Sunga Empire"
 

Attachments

  • Civ4ScreenShot0088.JPG
    Civ4ScreenShot0088.JPG
    157.6 KB · Views: 306
Incidentally, I haven't been able to change civ short description or adjective using the CvPlayer::setCivName() method either, so I'm interested in that as well. The only thing that worked was changing the civilization type before the civ becomes active, so that they are using the short description and adjective of the new civ. Should be possible in your situation, too.

Unfortunately I want to make the change while the civ is already alive ...
 
I tried placing the name change, using code from RisaAndFall.py in DoC with print statements to confirm it was being called, just ahead of the resurrection call in my RiseAndFall.py but the results are the same as before.

totally unrelated to the above, using "if (not gc.getGame().isReligionFounded(con.iChristianity)):" returns that Christianity is founded when it isn't. is there something in SoI that makes it always say that all religions are founded?
 
Where exactly did you copy from in DoC?
 
Ah, okay. Maybe you did't do it early enough? If the civ is already alive at that point the change likely won't have an effect.
 
I noticed something when looking at the cvdlltranslator.cpp
Why are none of the new icons of rfc (from the gamefont files) defined there?

EDIT:
I found that those icons are referenced this way in the cvmaininterface.py: getSymbolID(FontSymbols.POWER_CHAR) + c
Where c is a const, so they are simply based on a BtS defined character
But is this sufficient everywhere?
If I want to use those characters, I can simply do it this way everywhere in the game, without any actual dll definition for them?
 
I noticed something when looking at the cvdlltranslator.cpp
Why are none of the new icons of rfc (from the gamefont files) defined there?

Because Rhye didn't add them (it wasn't really needed, see below).

I found that those icons are referenced this way in the cvmaininterface.py: getSymbolID(FontSymbols.POWER_CHAR) + c
Where c is a const, so they are simply based on a BtS defined character
But is this sufficient everywhere?
If I want to use those characters, I can simply do it this way everywhere in the game, without any actual dll definition for them?

A symbol defined in CvDLLTranslator works in both Python and XML, while %c & getSymbolID(...) works in Python only. That's why I also use POWER_CHAR+index for my new interface icons, but I defined religion and corporation icons in the DLL so that I can use them in Civlopedia and Help Popups, which are in the XML. If you never use your new letters in the XML I guess you could stick to Python, though with high frequency of use shorthands would be more convenient.
 
Oh, and I forgot to mention that the documentation has been updated to reflect 0.5.0 changes. I need to update the spreadsheet to I guess, although it's a minor thing (all C++ braces have to be changed to plain parentheses since maps are now in Python).
 
Your 0.5 update is pretty awesome. I will have to redo everything I guess but at least I'll be able to fire up the map and check stuff without having to do everything! Much appreciated.
 
2. As I said, SoI / RFCM handles StoredData differently. It has all the scriptData functions moved to StoredData module which is imported by other modules, while RFC/E has them scattered over several files. So instead of copying these functions to StoredData, copy them to RFCUtils.py, remove the self. prefix from their code, and then change all parts of my code that refer to these functions to refer to the proper module (utils.* instead of sd.*)

Do you think it's worth it to move the scriptdata functions into storeddata.py in RFCE too?
What's the actual benefits of that?
 
Do you think it's worth it to move the scriptdata functions into storeddata.py in RFCE too?
What's the actual benefits of that?

No benefit in itself, it's part of a larger fix. One thing implemented very badly in RFC is the handling of scriptData, notably the fact that serializing and deserializing is done every time scriptData is accessed or set. The process of de/serializing (pickling) is relatively CPU-intensive and in RFC it's done tens of times per turn, while it's only really needed to be done when the game is loaded and saved... So mine & Baldyr's changes fix that - scriptData is kept in memory as a single instance of StoredData class imported by every module, and it's only pickled on load/save. It translates to a few percents decrease in turn times, which isn't small as it adds up with other optimizations. Switching over to this method needs a lot of work on the code, though.

If you do it, note that you can either move everything to StoredData and make all the code use it, or you can modify the existing scriptData functions in every module to point to StoredData instance (it's done this way in one module of SoI - RFCUtils, since a lot of modules use these functions). All that matters is to get rid of pickle from anywhere but the start/load/save methods of StoredData.py.
 
1. In CvDLLTranslator you used consts like JUDAISM and PROTESTANTISM - make sure they are actually defined as numbers corresponding to XML indexes in CvRhyes.h

I'm not entirely sure how to do this in RFCE
Your rhyes.h would handle it somehiw this AFAIK:

enum MyReligions
{
PROTESTANTISM,
ISLAM,
CATHOLICISM,
ORTHODOXY,
JUDAISM,
NUM_RELIGIONS
};

But in RFCE wasn't all thewe things moved to python?
Do I still define them somehow in the CvRhyes.h?


EDIT: probably not the most elegant solution, but I simply added them manually:
#define PROTESTANTISM (1)
#define ISLAM (2)
#define CATHOLICISM (3)
#define ORTHODOXY (4)
#define JUDAISM (5)

Seems to be working fine
I couldn't figure out, how you used to handle this when you still had cvrhyes.h and cvrhyes.cpp
 
No benefit in itself, it's part of a larger fix. One thing implemented very badly in RFC is the handling of scriptData, notably the fact that serializing and deserializing is done every time scriptData is accessed or set. The process of de/serializing (pickling) is relatively CPU-intensive and in RFC it's done tens of times per turn, while it's only really needed to be done when the game is loaded and saved... So mine & Baldyr's changes fix that - scriptData is kept in memory as a single instance of StoredData class imported by every module, and it's only pickled on load/save. It translates to a few percents decrease in turn times, which isn't small as it adds up with other optimizations. Switching over to this method needs a lot of work on the code, though.

If you do it, note that you can either move everything to StoredData and make all the code use it, or you can modify the existing scriptData functions in every module to point to StoredData instance (it's done this way in one module of SoI - RFCUtils, since a lot of modules use these functions). All that matters is to get rid of pickle from anywhere but the start/load/save methods of StoredData.py.

Yeah, I noticed I had to add an extra pickle to each of your functions in the storeddata.py when I converted them to be in the rfcutils.py

I'm not sure when I will be able to convert to your method, but it's definitely something to consider

EDIT:
or you can modify the existing scriptData functions in every module to point to StoredData instance (it's done this way in one module of SoI - RFCUtils, since a lot of modules use these functions).

Actually this doesn't sound that hard or that much extra work
If I only do that part of your optimization, would it already make any difference for the mod?
 
Actually this doesn't sound that hard or that much extra work
If I only do that part of your optimization, would it already make any difference for the mod?

No, you still have to do the StoredData part. This method just saves you changing all the self.setSomething or utils.getSomething to sd.* equivalents in all Python files. It actually doubles the amount of functions but keeps the code backward compatible.
 
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
 
Back
Top Bottom