Code:
def importCustomModules():
if CyGame().isFinalInitialized():
global MyModule
import MyModule
Ha! This one is great too!!
If you already know the integer values representing all the stuff in your mod you don't actually need to refer to any XML. Then you can just define any constants as integers.
You know what? I had started 'quick & dirty' making on paper a list of bonustype numbers (hence the prints in the first program version), but halfway through running around with the nomads, seeking new boni, I stopped, because I thought, it is bad style, of course it works, but I don't like do that. In principle it invites heavy compatibility problems - for CIV4 there will be no more patch, so no potential future compatibility problem, just 'in principle'.
The same are the fix unit numbers I used, of course the settler is created first, the anchor of chained objects, so it is unit(0). Followed by unit(1), which can't be assigned until you declare which civilization you wanna play, ie. you choose implicit a warrior or a scout. unit(2) & unit(3) are the 2 workers created in onStartGame(). I don't believe any patch would change _that_ ... still it looks poor.
But as I said - its not always easy to figure these things out ...
... especially if the example uses incorrect values

But knowing the solution, I think, I SHOULD have been able to figure it out by myself
I thought I tested my range() in IDLE (the default Python GUI) but I guess not
Pah, testing is for softies! No cisc, no fun.
Code:
if abs(iX) == 4 == abs(iY):
First I thought: well, if it is syntactical ok (from left to right ... !?), and the boolean (abs(iX) == 4) isn't a type mismatch with the integer (abs(iY)), methinks it is never true - with iX, iY of [-4, -3, -2, 2, 3, 4]
I have to get used to this syntax ... is it valid then to write:
a = 5 = b
or
a, b = 5
4 = x, y
I guess the values 3 and 2 should really be 2 and 1. Or something, logic makes me dizzy.
I figured out 3 and 4, distance seems to be far away!
(I'd like to copy just your cute code, but would have to make long distance calls in case of changing anything, in order to discuss the consequences.)
The i and e variable name prefixes are basically interchangeable.
Yes, of course, in principle names need no prefix at all. Besides that the prefixes shouldn't be interchangeable, they should clearly and correct describe the type of the variable (as the variables ie. return values and arguments of given methods should follow a clear and consistent concept!).
I am used to a language (C) which requires explicit variable declarations, so (just in case the type is easily to look up and) usually no type pre- / postfix is given in the name. In this Python (like in BASIC) variables are implicit declared (and defined), this is convenient, sure! I don't like it. Because if a variable is implicit declared as return value of a method of a class, which you only can guess ... pyXXX, cyXXX ... cyGame, cyPlayer, cyUnit ... you are in for a (long) search ... all this consumes (for the beginner) much more time than is saved for not to have explicit declarations.
Use whatever you like, because most of them are integers anyway.
I have seen awful code, done by generations of programmers; if 'it' grows over a long time this is probably unavoidable ... I am not sure, that this was necessary for the CIV4 python interface ... it shows inferior 'whatever'.
In the case eTeam I expected it to be an enumeration type as in eHuman ... but the calculateNatureYield method told me, what I was supplying (the return value of getTeam) to be an INT despite it is expecting an enumeration type ... so I REFUSE to name the return value of getTeam 'eTeam'

(revenge of the weak and helpless)
Seriously, if it doesn't matter that much, why not ALL int, so you can at least use the running variable of loops as index into arrays without fiddling around with typecasts or even worse functioncalls just to satisfy the typeo-needs...
But its still good to know why you are doing something
absolutely, most of the time!!!
Instead of using pop-ups for your player messages you might consider using in-game text messages.
You mean Interface.addImmediateMessage()??
Just to be sure, in-game text messages are those appearing on top of the map, telling something like "while camping in the highlands your warriors killed a barbarian lamb", and disappearing after a while??
Sounds great, if can I choose anywhere a bigger font and/or a longer display time for them ... usually I miss some of them ...

(this is no joke, my visual performance is not so good)
Code:
if ... iX == 0 == iY: continue
...
or pPlot.isCity()
seems to be redundant
Code:
if ( pPlot.isWater()
or pPlot.isPeak()
I supposed isWater() means Ocean, Coast, Lake (maybe even River).
But my barbarian wolves ignored isWater() and are generated on Ocean & Coast (onshore next turn), the same with peaks, no problems with generation there. In my test I had no event on Lake, so I don't know whether it works there.
Code:
or not pPlot.isOwned() ):
means what? Plot is neutral, not belonging to a civ?
This is by the way what the custom Rebels module looks like:
I think it is good to see the similar rebels code in a slightly different context, so anybody can try to adapt it more easily to his own ideas.
Especially I like the aspect of generating with priority the rebels belonging to the original civ. I thought about that, but hesitated to ask for this.
Code:
def checkCity(pCity, pOriginalOwner, pCurrentOwner, iForeigners):
iForeigners isn't used right now
Code:
max(iForeigners, pCity.unhappyLevel(0) - pCity.getMilitaryHappinessUnits())
pCity.unhappyLevel(0) sounds interesting, what is it? The effective result of happiness calculation (people not working) or the number of red faces before meeting the yellow faces or??