• Our friends from AlphaCentauri2.info are in need of technical assistance. If you have experience with the LAMP stack and some hours to spare, please help them out and post here.

How to make a Python mod

Learning to read the API - and to fully understand it - is critical for any kind of effective Python modding.
100%
(I've actually contemplated writing a API tutorial.)
methinks, what's needed most, would be descriptions in telegram style (in the existing API) ... but what was his name ... sysiphos?

:eek::lol::eek::lol::eek:

Now my project has come to its end: the last extensions (now including "random" unittypes, comparison of culture levels in the cities & ownership of surrounding plots) to the Rebel tutorial are completely tested & ready to play (all necessary included in the package below).

It may also be used as a quarry of helpful statements (in rebellion context) or sandbox for experiments in Python programming - as my first steps were also just learning about the making of and modifications to the great original Rebels.py! (My first nomads.py):
Spoiler :
Code:
from CvPythonExtensions import *
from PyHelpers import *
from Popup import PyPopup

gc = CyGlobalContext()
cyGame = CyGame()
cyMap = CyMap()
pyGame = PyGame()

pyBarbarian = PyPlayer(gc.getBARBARIAN_PLAYER())


def showPopup():
   modPopup = PyPopup()
   modPopup.setHeaderString("Tutorial")
   modPopup.setBodyString("This is a Python tutorial.\n\nby Baldyr")
   modPopup.launch()

def checkTurn():
   for pyPlayer in pyGame.getCivPlayerList():
      for pyCity in pyPlayer.getCityList():
         cyCity = pyCity.GetCy()

         if cyCity.isDisorder() and cyCity.getCulturePercentAnger() and not cyCity.isNeverLost(): 
            if cyGame.getSorenRandNum(100, "rebels") < 5:
               lPlots=[]
               iCityX, iCityY = cyCity.getX(), cyCity.getY()
               for iX in range(iCityX - 1, iCityX + 2):
                  for iY in range(iCityY - 1, iCityY + 2):
                     cyPlot = cyMap.plot(iX, iY)
                     if cyPlot.isWater() or cyPlot.isPeak() or cyPlot.isCity(): continue
                     lPlots.append(cyPlot)
               iNumPlots = len(lPlots)

               if iNumPlots:
                  iNumRebels = max(1, cyCity.getMilitaryHappinessUnits() / 4)
                  eUnitType = cyCity.getConscriptUnit()
                  while iNumRebels:
                     cyPlot = lPlots[cyGame.getSorenRandNum(iNumPlots, "spawn")]
                     pyBarbarian.initUnit(eUnitType, cyPlot.getX(), cyPlot.getY())
                     iNumRebels -= 1

Btw, concerning the MinorRevolt() class I want to add some thoughts:
Code:
self.iNumUnits = max(1, min(iUnhappyLevel - iAngryPopulation, iPopulation))
is probably
Code:
self.iNumUnits = max(1, min(iHappyLevel, iPopulation))
I'am uncertain, but there seem to be always (4?) people telling "We are just enjoying our life", so the HappyLevel is greater then zero (as is iPopulation) ... would result in:
Code:
self.iNumUnits = min(iHappyLevel, iPopulation)
Also I think, the iUnhappyLevel seem to be at least iPopulation, as ALL people tell always(?) "It's too overcrowded here" ...
 

Attachments

civjo: Nice! :goodjob:

j_mie6: You're taking notes of what the other guy said, right? :p
 
sort of... of course it makes sense to use happy level as he said! :crazyeye: so I guess he is completly right!

anything else I was meant to be taking notes on?
 
sort of... of course it makes sense to use happy level as he said! :crazyeye: so I guess he is completly right!
I'm not even sure what's what anymore, but since you're doing the design on your own mod you can basically chose which calculation we should use. Which one is it, then?
 
:lol: dont you see? As far as I'm concerned the 2 calculations are EXACTLY the same just his is worded more simply... Am I correct? You can use which ever one you wish to use...
 
Just to point out, that (in question of being a fool) I'm not the guy who keeps the silence and may count as wise ... I speak out and remove any doubt!
of course it makes sense to use happy level as he said!
I did NOT say, that using happy level makes sense - in fact, from my point of view it makes NO sense.
What I wanted to express was that the implementation of this "fact":

iAngryPopulation = iUnhappyLevel - iHappyLevel

would make the given code easier to understand ... (which is for me a principal goal in coding) ...

[[[OFFTOPIC of course this is also a question of personal style!
Eg. those who looked at it have noticed, that I usually define functions, if they really avoid repetition of statements or the calling function is already big enough - more than 2 pages on the screen :D
I feel having not only to remember the variable names, but also _ a lot of _ function names is a burden (for the reader, not the writer) and the hopping around in order to know what they do in detail is a lot like the (for good reasons) abolished GOTO statements ... in fact the call & the return are a goto, but without being named so.
BUT: again: of course this is highly a question of personal style!]]]

As far as I'm concerned the 2 calculations are EXACTLY the same
yes that is my statement
just his is worded more simply...
it is not _mine_ as I would never use iHappyLevel in that calculation.
If you care, you may look into my nomads.py in order to learn, what I think is appropriate in this case.

Ok girls, I hoped to exchange infos & ideas about game variables & their application and want not interfere your design process of your scenario. Good luck!:goodjob:
 
thanks! I have set up my own module to correspond with my other python modules so that I don't have to define my functions everytime I need them!
 
Yes, implicit function definitions are top cool! :goodjob:
Keep the good work! Merry Xmas, btw ...

PS. a single line of information followed by 6 lines of signature makes not only the weak ones :cry:
 
merry Xmas to you to!

(hey I love my signature!:p)
 
The latest 'nomads and rebels' version (download below) adapts to the game speed (GAMESPEED_QUICK, _NORMAL, _EPIC, _MARATHON),
and provides a partly compensation for the technological lag caused by the nomadic phase.
Also new are minor revolts triggered by onCityGrowth & onCultureExpansion.

---

During testing I found a minor problem caused by the game itself:
Characters beyond ASCII ... yes, unbelievable indeed, but until today some european countries use some 'really strange' characters ... :D ... (of course a company like Mastercard can easily ignore this and write my family name wrong even on the card, because I pay with their 'good' name ...)

I'm not sure about trouble in CIV4 with the scandinavian or german special characters, I just stumbled over this:
One of the first Cities of Portugal: Guimar(a~)es
[a~ means the ~ is above the a, just one letter (ie. ã)]

results in:
[[[
ERR: Python function onEvent failed, module CvEventInterface
Traceback (most recent call last):
File "CvEventInterface", line 23, in onEvent
File "CvEventManager", line 192, in handleEvent
File "CvEventManager", line 849, in onCityBuilt ############ also onCityGrowth, onCultureExpansion
File "CvUtil", line 122, in pyPrint
File "<string>", line 13, in write
UnicodeEncodeError
:
'ascii' codec can't encode character u'\xe3' in position 27: ordinal not in range(128)
ERR: Python function onEvent failed, module CvEventInterface
]]]

What can I do? It is an AI player, who wants to build a city with this name
and it is a standard log print instance which wants to write a line like this:

PY:City Built Event: York

but obviously can't with this special character in the name (PY:City Built Event: Guimar^ == character u'\xe3' in position 27).

It is no big deal, but while looking for errors made myself it's annoying to see over and over again the errors made by AI :lol:

---

Btw, Magellan wrote his name this way: Fernão de Magalhães
 

Attachments

This encoding business is a science onto itself, but I know that Rhye uses some field codes all these special characters in the RFC mod. So the Á character would be expressed as &# 193 ; (without the blank spaces around the decimal index number). You can find the decimal numbers of special characters here.
 
Thanks for your immediate reply. The offending character is ö, not á (mastercardwise) ... ;)

They tried to give more flair to the game by using the "original" names like Guimarães, but this is a very(!) long way to go ... what is with Cologne alias Köln?
or Moscow alias &#1052;&#1086;&#1089;&#1082;&#1074;&#1072;?
let alone Beijing alias B&#283;ij&#299;ng (latin letters with correct tonemarks) alias &#21271;&#20140;. Good luck!
Ok, ok, but then the tools are limited to 128 characters ... maybe alright in AD1980. :D

I try to understand what you wrote ... The method of Rhye is the way how to include those 'evil' characters into text shown in the game, right?
In case of 'Guimarães' this would mean 'Guimar&# 227;es'
because "atilde" is hex E3 (as the error message rightfully reports) and dec 227 ... ok

But ... the city name is correct in the game, no problem - besides I am indifferent towards the names anyway. My point is that in the log files lines are missing (PythonDbg) or errors reported (PythonErr) only because of an inability lying in the game itself ... I don't introduce this problem, it is an AI player, who wants to build a city with this name and it is a standard log print instance which wants to print what it cannot.

It just irritates me to have those (unnecessary) error popups during testing and the messages in PythonErr - so it probably boils down to the question, what other developers have done ... learn to successfully ignore it, edit (if possible) a "city name" file for testing purposes only containing clean ascii (where is the download? :goodjob:), or to find out which civs/languages are without problems (lets see: Great Britain, United States, 'Native Americans' ... any more?)
 
I don't think you should ever have any error messages or exceptions. And it doesn't matter if a city is being founded by a AI or a human player. Because propose that you wanna fire some code at the cityBuilt event and this exception would interrupt it.

I never experienced these issues myself, but if I did I would try get it sorted out.
 
I don't think you should ever have any error messages or exceptions.
that was my opinion until last week too
And it doesn't matter if a city is being founded by a AI or a human player.
of course, I just mentioned it, because I could avoid the problem by not using special characters in city names, the AI doesn't avoid ... I tried even to rename the city ... DO YOU know how to switch the civilization during testing? This would solve the problem.
Because propose that you wanna fire some code at the cityBuilt event and this exception would interrupt it.
No, the oncityBuilt event is untouched. 100%
I have never edited this spot in the eventmanager file.
I never experienced these issues myself, but if I did I would try get it sorted out.
Good News! If only 1 city provokes this, it is easy to avoid (don't test with Portugal)

From my point of view, all it needs to receive this exception, is to enable the highest warning level:
HidePythonExceptions = 0
ShowPythonDebugMsgs = 1
LoggingEnabled = 1
SynchLog = 1
OverwriteLogs = 1
RandLog = 1
MessageLog = 1
and play without any mod (or anyone if you like) until Portugal founds this city (it's probably the 2., at the very MOST the 4. city - this test is normal playing, Guimarães was founded around the 35. turn from AI, prince level Human)
 
I still think you should solve the issue rather than try to figure out what player to test with.

The AI isn't making up names, so these are clearly read from somewhere. It could either be the XML civilization infos or in the WBS. Just take the offending character out or change it to a valid field code.
 
The AI isn't making up names, so these are clearly read from somewhere.
yes, this is what I meant with #"city name" file#, but realize now, that were the 'good old' days of civ & civ2 ... I have NO knowledge about XML civilization infos or WBS, and don't intent to get any (Python does all I want) ... so your advise
I still think you should solve the issue
is good and true, but unfortunately not for me (and I suppose for you neither, for the same reason).

I searched the fora, but found nothing, so there probably was no big discussion about that issue.

As you didn't meet this exception, please tell me: Do you use the
ShowPythonDebugMsgs = 1
statement
(default is 0 or statement missing, so it has to be put in actively), and if not, do you see messages like "PY:City Built Event: York" in the log file?

rather than try to figure out what player to test with.
Usually (always) I take the default random settings for all the civs, they are ok ...
(maybe except they choose P. :lol:)

Just take the offending character out or change it to a valid field code.
6 years ago ok, but if 'til today nobody found that necessary and reported, probably there is a better solution or it is just me :crazyeye: Eg. In the beginning I read somewhere the advise to put "ShowPythonDebugMsgs = 1" in ... still I don't know why, I never asked ... btw, maybe there is a reason THEY took it out, why was it removed? The messages are nice, so why?
So maybe THEIR answer was: do without the nice messages (or live with the casual exceptions or edit whatever is necessary, if you can or ...)
 
I don't even seem to have ShowPythonDebugMsgs in my CivilizationIV.ini - what version of BTS are you running? Because you should be using v3.19.
 
I'm using v3.19. (and yes I'm editing the INI which is used by the game) ;)

Sorry for not being clear enough:
In last Oct I read in one of the (other) tutorials the advice to insert "ShowPythonDebugMsgs = 1" in the ini file. (Cannot remember where).
This statement is missing in the vanilla INI file, so it has to be put in actively! FROM SCRATCH. Not only turn 0 to 1.

And please tell me: Do you see messages like "PY:City Built Event: York" in your DBGlog file?
I suspect this is the positive effect if this statement, without it you shouldn't see above messages (in bold), please confirm whether you see those.

I suspect the negative effect if this statement is the exception I experienced (and I speculated Firaxis may have removed it because of that).
 
Aha, now I see. I haven't enabled that particular type of logging then. You really do learn something every day! :king:
 
(on my knees) please tell me whether you receive messages like "PY:City Built Event: York" in your DBGlog file WITHOUT THIS SWITCH ENABLED

(as stated already my gaming & internet PC are km's apart)
 
Back
Top Bottom