General
This will just be the start, much more is to follow, but a combination of having to get the scenarios done in time and RL issues made me fall behind schedule a bit.
There are basically 4 ways to use Python:
1) Map generation - there won't be additional documentation for this in the short run, but the existing scripts are well documented so you can learn a lot by studying those. Creating completely new map scripts is not for the faint-of-heart though, some grasp of OO programming and the mathemetical concepts underlying the scripts is required. You can find the mapscripts in the PublicMaps folder
2) UI modding - documentation here isn't really needed, the code is more or less self-explanatory. You can find the UI files in the Assets/Python/Screens folder
3) Events - the most common way in which you will use Python, there are many different applications, not just for your standard scenario events. A list of available events is below. The core event manager is Assets/Python/CvEventManager.py
4) Overrides - some game functions can be overwritten, for example what can be built in what cities, what civics/techs/religions/etc are available to who (all dynamically, so on a case-by-case and turn-by-turn basis, much more powerful than the static XML files), some AI behaviour, Barbarian spawning, victory conditions, etc. These overrides are in Assets/Python/CvGameUtils.py
There are some other very specific Python applications, but those you'll normally not need. In the short run at least, there will be no documentation for them (just give me and the community time though )
A note of caution: please do NOT, I repeat, do NOT mess with the Python files in the default Assets folder, this will cause all kinds of problems with future patching, MP play, tournaments, etc. Please use the mod setup that's also used for the in-game scenarios, see the Mods folder. Here you only need to keep the things you add/change, files that remain unchanged you can leave out, the game will just take the version from the default Assets folder for any file it's missing (similar to CtP modding, for those familiar with it -- only this time it actually works). More detailed info will follow but I think most people will be able to figure this out soon enough, it's pretty simple.
API
As any programmer knows, to help you write Python code that actually interacts with the Civ4 engine, rather than just being a stand-alone application, you will need to use a so-called API (Application Programming Interface) -- basically a list of functions you can use to access routines in the game engine. I made a script to extract this info in HTML form from the SDK, but of course you guys don't have the SDK yet, so I'll just have to publish the HTML files. A few isues to keep in mind:
1) My script can only get info from the SDK, while some of the API calls are not in the SDK (game-engine related stuff). I had to add those functions manually and left them mostly undocumented (for now). Classes that have a lot of bright green ??? in them are basically the ones that are not from the SDK.
2) Documentation on what these functions do is pretty poor, I'm working on more complete info. Most of the time the name of the function pretty much tells you what it does though, so this shouldn't keep anyone from using them (it certainly hasn't kept me).
3) This is for a not-quite-final version of the game, there might be some minor changes in the release version but it should be only really minor stuff, if anything changed at all. For an even-closer-but-still-not-quite-final build my script is FUBARed, I'll have to check what goes wrong there, and then ask Soren or Trip to run my script on the release version of the SDK (which I don't have myself either) to get this fully up-to-date (there are no changes to the API itself between these two builds though). For now this version will work absolutely fine though, at least 99.99% of this should still be accurate.
4) Hmm, there was another issue but I forgot. Oh well, I'll update this post when I remember it.
You can browse the API reference here: http://civilization4.net/files/modding/PythonAPI/
A zip version that you can extract and browse on your own PC is here: http://civilization4.net/files/modding/PythonAPI.zip
Events
As promised, the list of events that's available to you in the game (sorry for the poor formatting, I don't have terribly much time today). This was also generated based on source files (with a few notes from myself) for a not-quite-final build, more detailed and final info will follow:
onKbdEvent
'keypress handler - return 1 if the event was consumed'
arguments: eventType,key,mx,my,px,py
onInit
'Called when Civ starts up'
arguments: -
onUpdate
'Called every frame'
arguments: fDeltaTime
onWindowActivation
'Called when the game window activates or deactivates'
arguements: bActive
onUnInit
'Called when Civ shuts down'
arguments: -
onPreSave
"called before a game is actually saved"
arguments: -
onSaveGame
"return the string to be saved - Must be a string"
arguments: -
onLoadGame
-
arguments: -
onGameStart
'Called at the start of the game'
arguments: -
onGameEnd
'Called at the End of the game'
arguments: -
onBeginGameTurn
'Called at the beginning of the end of each turn'
arguments: iGameTurn
onEndGameTurn
'Called at the end of the end of each turn'
arguments: iGameTurn
onBeginPlayerTurn
'Called at the beginning of a players turn'
arguments: iGameTurn, iPlayer
onEndPlayerTurn
'Called at the end of a players turn'
arguments: iGameTurn, iPlayer
onEndTurnReady
-
arguments: iGameTurn
onFirstContact
'Contact'
arguments: iTeamX,iHasMetTeamY
onCombatResult
'Combat Result'
arguments: pWinner,pLoser
onCombatCalc
'Combat Result'
arguments: cdAttacker, cdDefender, iDefenderOdds
onCombatHit
'Combat Message'
cdAttacker, cdDefender, iIsAttacker, iDamage
onImprovementBuilt
'Improvement Built'
arguments: iImprovement, iX, iY
onRouteBuilt
'Route Built' (note: routes = road or railroad)
arguments: iRoute, iX, iY
onPlotRevealed
'Plot Revealed'
arguments: pPlot, iTeam
onBuildingBuilt
'Building Completed' (note: building = improvement or wonder)
arguments: pCity, iBuildingType
onProjectBuilt
'Project Completed' (note: project = space ship part, Appollo Program, 1 or 2 other modern wonders)
arguments: pCity, iProjectType
onUnitMove
'unit move'
arguments: pPlot,pUnit
onUnitSetXY
'units xy coords set manually' (note: i.e. teleport)
arguments: pPlot,pUnit
onUnitCreated
'Unit Completed'
arguments: unit
onUnitBuilt
'Unit Completed'
arguments: city, unit
onUnitKilled
'Unit Killed'
arguments: unit, iAttacker
onUnitLost
'Unit Lost'
arguments: unit
onUnitPromoted
'Unit Promoted'
arguments: pUnit, iPromotion
onUnitSelected
'Unit Selected'
arguments: unit
onUnitRename
'Unit is renamed'
arguments: pUnit
onGoodyReceived
'Goody received'
arguments: iPlayer, pPlot, pUnit, iGoodyType
onGreatPersonBorn
'Unit Promoted' (note: obviously not, should be 'Great Peson Born')
arguments: pUnit, iPlayer, pCity
onTechAcquired
'Tech Acquired'
arguments: iTechType, iTeam, iPlayer, bAnnounce
onTechSelected
'Tech Selected'
arguments: iTechType, iPlayer
onReligionFounded
'Religion Founded'
arguments: iReligion, iFounder
onReligionSpread
'Religion Has Spread to a City'
arguments: iReligion, iOwner, pSpreadCity
onGoldenAge
'Golden Age'
arguments: iPlayer
onEndGoldenAge
'End Golden Age'
arguments: iPlayer
onChangeWar
'War Status Changes'
arguments: bIsWar, iPlayer, iRivalTeam
onChat
'Chat Message Event'
arguments: chatMessage
onSetPlayerAlive
'Set Player Alive Event' (note: either when a player dies or is revived (only in scenarios))
arguments: iPlayerID, bNewValue
onCityBuilt
'City Built'
arguments: city
onCityRazed
'City Razed'
arguments: city, iPlayer
onCityAcquired
'City Acquired'
arguments: owner,playerType,city,bConquest,bTrade
onCityLost
'City Lost'
arguments: city
onCultureExpansion
'City Culture Expansion'
arguments: pCity, iPlayer
onCityGrowth
'City Population Growth'
arguments: pCity, iPlayer
onCityDoTurn
'City Production'
arguments: pCity, iPlayer
onCityBuildingUnit
'City begins building a unit'
arguments: pCity, iUnitType
onCityBuildingBuilding
'City begins building a Building'
arguments: pCity, iBuildingType
onCityRename
'City is renamed'
arguments: pCity
onVictory
'Victory'
arguments: iTeam, iVictory
onGameUpdate
'sample generic event, called on each game turn slice' (note: at least in theory about 4 times per second (didn't test it))
arguments: turnSlice
onMouseEvent
'mouse handler - returns 1 if the event was consumed'
arguments: eventType,mx,my,px,py,interfaceConsumed,screens
Example
Finally, I'll give one simple example of how to use all this code in practice. For more examples, see the Python code in the Mods folder, the various scenarios come with a lot of interesting code.
Note that this example overwrites the existing event code, normally you will want to either append to it, or subclass it (more info on that will follow), for simplicity's sake I didn't do that here.
If anyone has any Python-related questions, I'll try to answer them as best as I can.
This will just be the start, much more is to follow, but a combination of having to get the scenarios done in time and RL issues made me fall behind schedule a bit.
There are basically 4 ways to use Python:
1) Map generation - there won't be additional documentation for this in the short run, but the existing scripts are well documented so you can learn a lot by studying those. Creating completely new map scripts is not for the faint-of-heart though, some grasp of OO programming and the mathemetical concepts underlying the scripts is required. You can find the mapscripts in the PublicMaps folder
2) UI modding - documentation here isn't really needed, the code is more or less self-explanatory. You can find the UI files in the Assets/Python/Screens folder
3) Events - the most common way in which you will use Python, there are many different applications, not just for your standard scenario events. A list of available events is below. The core event manager is Assets/Python/CvEventManager.py
4) Overrides - some game functions can be overwritten, for example what can be built in what cities, what civics/techs/religions/etc are available to who (all dynamically, so on a case-by-case and turn-by-turn basis, much more powerful than the static XML files), some AI behaviour, Barbarian spawning, victory conditions, etc. These overrides are in Assets/Python/CvGameUtils.py
There are some other very specific Python applications, but those you'll normally not need. In the short run at least, there will be no documentation for them (just give me and the community time though )
A note of caution: please do NOT, I repeat, do NOT mess with the Python files in the default Assets folder, this will cause all kinds of problems with future patching, MP play, tournaments, etc. Please use the mod setup that's also used for the in-game scenarios, see the Mods folder. Here you only need to keep the things you add/change, files that remain unchanged you can leave out, the game will just take the version from the default Assets folder for any file it's missing (similar to CtP modding, for those familiar with it -- only this time it actually works). More detailed info will follow but I think most people will be able to figure this out soon enough, it's pretty simple.
API
As any programmer knows, to help you write Python code that actually interacts with the Civ4 engine, rather than just being a stand-alone application, you will need to use a so-called API (Application Programming Interface) -- basically a list of functions you can use to access routines in the game engine. I made a script to extract this info in HTML form from the SDK, but of course you guys don't have the SDK yet, so I'll just have to publish the HTML files. A few isues to keep in mind:
1) My script can only get info from the SDK, while some of the API calls are not in the SDK (game-engine related stuff). I had to add those functions manually and left them mostly undocumented (for now). Classes that have a lot of bright green ??? in them are basically the ones that are not from the SDK.
2) Documentation on what these functions do is pretty poor, I'm working on more complete info. Most of the time the name of the function pretty much tells you what it does though, so this shouldn't keep anyone from using them (it certainly hasn't kept me).
3) This is for a not-quite-final version of the game, there might be some minor changes in the release version but it should be only really minor stuff, if anything changed at all. For an even-closer-but-still-not-quite-final build my script is FUBARed, I'll have to check what goes wrong there, and then ask Soren or Trip to run my script on the release version of the SDK (which I don't have myself either) to get this fully up-to-date (there are no changes to the API itself between these two builds though). For now this version will work absolutely fine though, at least 99.99% of this should still be accurate.
4) Hmm, there was another issue but I forgot. Oh well, I'll update this post when I remember it.
You can browse the API reference here: http://civilization4.net/files/modding/PythonAPI/
A zip version that you can extract and browse on your own PC is here: http://civilization4.net/files/modding/PythonAPI.zip
Events
As promised, the list of events that's available to you in the game (sorry for the poor formatting, I don't have terribly much time today). This was also generated based on source files (with a few notes from myself) for a not-quite-final build, more detailed and final info will follow:
onKbdEvent
'keypress handler - return 1 if the event was consumed'
arguments: eventType,key,mx,my,px,py
onInit
'Called when Civ starts up'
arguments: -
onUpdate
'Called every frame'
arguments: fDeltaTime
onWindowActivation
'Called when the game window activates or deactivates'
arguements: bActive
onUnInit
'Called when Civ shuts down'
arguments: -
onPreSave
"called before a game is actually saved"
arguments: -
onSaveGame
"return the string to be saved - Must be a string"
arguments: -
onLoadGame
-
arguments: -
onGameStart
'Called at the start of the game'
arguments: -
onGameEnd
'Called at the End of the game'
arguments: -
onBeginGameTurn
'Called at the beginning of the end of each turn'
arguments: iGameTurn
onEndGameTurn
'Called at the end of the end of each turn'
arguments: iGameTurn
onBeginPlayerTurn
'Called at the beginning of a players turn'
arguments: iGameTurn, iPlayer
onEndPlayerTurn
'Called at the end of a players turn'
arguments: iGameTurn, iPlayer
onEndTurnReady
-
arguments: iGameTurn
onFirstContact
'Contact'
arguments: iTeamX,iHasMetTeamY
onCombatResult
'Combat Result'
arguments: pWinner,pLoser
onCombatCalc
'Combat Result'
arguments: cdAttacker, cdDefender, iDefenderOdds
onCombatHit
'Combat Message'
cdAttacker, cdDefender, iIsAttacker, iDamage
onImprovementBuilt
'Improvement Built'
arguments: iImprovement, iX, iY
onRouteBuilt
'Route Built' (note: routes = road or railroad)
arguments: iRoute, iX, iY
onPlotRevealed
'Plot Revealed'
arguments: pPlot, iTeam
onBuildingBuilt
'Building Completed' (note: building = improvement or wonder)
arguments: pCity, iBuildingType
onProjectBuilt
'Project Completed' (note: project = space ship part, Appollo Program, 1 or 2 other modern wonders)
arguments: pCity, iProjectType
onUnitMove
'unit move'
arguments: pPlot,pUnit
onUnitSetXY
'units xy coords set manually' (note: i.e. teleport)
arguments: pPlot,pUnit
onUnitCreated
'Unit Completed'
arguments: unit
onUnitBuilt
'Unit Completed'
arguments: city, unit
onUnitKilled
'Unit Killed'
arguments: unit, iAttacker
onUnitLost
'Unit Lost'
arguments: unit
onUnitPromoted
'Unit Promoted'
arguments: pUnit, iPromotion
onUnitSelected
'Unit Selected'
arguments: unit
onUnitRename
'Unit is renamed'
arguments: pUnit
onGoodyReceived
'Goody received'
arguments: iPlayer, pPlot, pUnit, iGoodyType
onGreatPersonBorn
'Unit Promoted' (note: obviously not, should be 'Great Peson Born')
arguments: pUnit, iPlayer, pCity
onTechAcquired
'Tech Acquired'
arguments: iTechType, iTeam, iPlayer, bAnnounce
onTechSelected
'Tech Selected'
arguments: iTechType, iPlayer
onReligionFounded
'Religion Founded'
arguments: iReligion, iFounder
onReligionSpread
'Religion Has Spread to a City'
arguments: iReligion, iOwner, pSpreadCity
onGoldenAge
'Golden Age'
arguments: iPlayer
onEndGoldenAge
'End Golden Age'
arguments: iPlayer
onChangeWar
'War Status Changes'
arguments: bIsWar, iPlayer, iRivalTeam
onChat
'Chat Message Event'
arguments: chatMessage
onSetPlayerAlive
'Set Player Alive Event' (note: either when a player dies or is revived (only in scenarios))
arguments: iPlayerID, bNewValue
onCityBuilt
'City Built'
arguments: city
onCityRazed
'City Razed'
arguments: city, iPlayer
onCityAcquired
'City Acquired'
arguments: owner,playerType,city,bConquest,bTrade
onCityLost
'City Lost'
arguments: city
onCultureExpansion
'City Culture Expansion'
arguments: pCity, iPlayer
onCityGrowth
'City Population Growth'
arguments: pCity, iPlayer
onCityDoTurn
'City Production'
arguments: pCity, iPlayer
onCityBuildingUnit
'City begins building a unit'
arguments: pCity, iUnitType
onCityBuildingBuilding
'City begins building a Building'
arguments: pCity, iBuildingType
onCityRename
'City is renamed'
arguments: pCity
onVictory
'Victory'
arguments: iTeam, iVictory
onGameUpdate
'sample generic event, called on each game turn slice' (note: at least in theory about 4 times per second (didn't test it))
arguments: turnSlice
onMouseEvent
'mouse handler - returns 1 if the event was consumed'
arguments: eventType,mx,my,px,py,interfaceConsumed,screens
Example
Finally, I'll give one simple example of how to use all this code in practice. For more examples, see the Python code in the Mods folder, the various scenarios come with a lot of interesting code.
Code:
def onGameStart(self, argsList): 'Create a popup message at the start of the game' popup = PyPopup.PyPopup() popup.setBodyString( 'Hello World' ) popup.launch() def onCityBuilt(self, argsList): 'For player 1, create a Warrior (index 17) in every city that is built' city = argsList[0] if city.getOwner() == 1: city.getOwner().initUnit(17, city.getX(), city.getY(), UnitAITypes.NO_UNITAI)
If anyone has any Python-related questions, I'll try to answer them as best as I can.
Comment