Begin the Caffeine induced rambling
[tab]Boom shaka laka, shaka laka, shaka laka Boom!
[tab]If you a child of the 80's as I am you are probably wondering how you can combine your love for electronic wargaming and a certain MTV hit from way back, (when MTV actually played videos, yes I know kiddies, it sounds weird, but its true) Pop Up Video.
[tab]The premise of the show was simple. That America's attention span had become so short, and we were so full of sugar, caffeine and less legal substances that we were unable to maintain the focus required to watch a whole 60 second rock video. Despite the fact that each scene flared with explosions, half naked women, loud music and enormous hair. We would find ourselves drifting off 15 seconds in and forgetting who the characters were and what was going on (hence the constant rock'n'roll chorus's to remind us).
[tab]But MTV was wise, they invented popup videos to help. Now as we watched these videos we could learn interesting facts that occasionally had something to do with the video. Did you know that Jon "Cougar" Melancamp got his fancy middle name from the family gerbil? That Madonna used to not have a British accent? That Boy George sometime goes by the alias "Woodelf" when he is online? We learned all of these things from Pop Up Video.
Now on to something coherent
[tab]By now you are probably wondering how to bring this magic to your mod. Popups are surprisingly easy once they are understood. The type we are going to cover here allows us to present the player with a popup box with as many buttons as we want, and depending on the button they press a different python event kicks off:
[tab]Okay, lets walk through the above function. Lines 1-8 are the standard onGameStart function. Basically, isolating this to an event that occurs when the game begins and only for human players. You will want to make sure not to push popup's to AI players. If you want the AI to react to the same sorts of events you will need to follow your functions with an 'else:' on the 'isHuman()' or an 'if isHuman() == False:' and then call the python routines directly based on whatever logic you want the AI to use.
[tab]Line 9: popupInfo = CyPopupInfo() declares the popupInfo object we are going to create and use. Its not much different than saying newUnit = pPlayer.initUnit(..), its just a definition of a new object. But by itself it doesn't do much, we need to define its characteristics.
[tab]Line 10: popupInfo.setButtonPopupType() I honestly don't know how many ButtonPopupTypes there are, or what the differences between them are. BUTTONPOPUP_PYTHON is the one I always use and it works well.
[tab]Line 11: popupInfo.setText() This is the body text for the popup window. In the example I'm running it through the translator so it can be localized in different languages but you could simply have: popupInfo.setText('Select your bonus Trait')
[tab]Line 12: popupInfo.setData1() This is for any int data you want to pass to the python functions. You can have up to 4 data elements (setData1(), setData2(), setData3(), setData4()) defined in the popup and I will show you how we use them when we get to the events on the button presses.
[tab]Line 13: popupInfo.setOnClickedPythonCallback() This is the python routine that is called when any button is pressed. Notice that the same python routine is called regardless of which button is pressed. I will show you when we declare the python event how to tell which button it was. The most important thing to remember with this is that the python routine must exist in the CvScreensInterface.py file.
[tab]Line 14-21: popupInfo.addPythonButton() This is easy, it just adds a button for each line like this we have. The text that is included as the argument shows up on the button. As with the set text command above you could simply have: popupInfo.addPythonButton('Aggresive')
[tab]Line 22: popupInfo.addPopup() The command that launches the popup. The argument here is the int value of the player that is supposed to receive it.
[tab]Now let's look at the actual python event that it calls. Remember the following goes in the CvScreensInterface.py file:
[tab]Notice all of the arguments that are passed to the function by the popup. You can see where we breakout our Data1 – 4 elements and we could even pass a text string over and 2 boolens.
[tab]The magic of figuring out what button the user pushed is that the first argument the popup passes to the python function is the number of the button. These are counted ordinally (starting with 0) so if you have 8 buttons you will have 0 – 7. With an if statements for each of the possible values of iButtonId we can run whatever python routines we want, or even send them off into other functions or other popups (oh, popups of popups, wouldn't MTV be proud).
[tab]That’s it, nothing too complicated with the process. But I would expect you might have a few questions I'll try to answer here:
1. pPlayer.addTrait(), whats that?
[tab]Very observant of you, man who types exactly like me. That cool little function is from TheLopez's Scriptable Leader Traits modpack. It is very cool, check it out if you have a chance.
2. Besides adding traits to players with TheLopez's mudpack what can we do with this?
[tab]Anything you can do with python. Want to give the player an option when he captures a city or defeats a special unit, this is how you do it. Want to give them a list of options to deal with revolting peasants or the ability to share the secrets of the alternative fuel source or keep it (and their oil monopoly) to themselves? The sky is the limit.
3. This is all well and good, but shouldn't your function check for <insert thing I forgot to do>?
[tab]Probably. And I did really simplify my code to make it easy for beginning programmers (ie: me) to understand. There are quite a few checks but they aren't nessesary to understand popups and I thought they would just confuse the guide. If you really want to see what the real code looks like it is below:
[tab]Boom shaka laka, shaka laka, shaka laka Boom!
[tab]If you a child of the 80's as I am you are probably wondering how you can combine your love for electronic wargaming and a certain MTV hit from way back, (when MTV actually played videos, yes I know kiddies, it sounds weird, but its true) Pop Up Video.
[tab]The premise of the show was simple. That America's attention span had become so short, and we were so full of sugar, caffeine and less legal substances that we were unable to maintain the focus required to watch a whole 60 second rock video. Despite the fact that each scene flared with explosions, half naked women, loud music and enormous hair. We would find ourselves drifting off 15 seconds in and forgetting who the characters were and what was going on (hence the constant rock'n'roll chorus's to remind us).
[tab]But MTV was wise, they invented popup videos to help. Now as we watched these videos we could learn interesting facts that occasionally had something to do with the video. Did you know that Jon "Cougar" Melancamp got his fancy middle name from the family gerbil? That Madonna used to not have a British accent? That Boy George sometime goes by the alias "Woodelf" when he is online? We learned all of these things from Pop Up Video.
Now on to something coherent
[tab]By now you are probably wondering how to bring this magic to your mod. Popups are surprisingly easy once they are understood. The type we are going to cover here allows us to present the player with a popup box with as many buttons as we want, and depending on the button they press a different python event kicks off:
Code:
1: def onGameStart(self, argsList):
2: 'Called at the start of the game'
3: iPlayerNum = 0
4: for iPlayer in range(gc.getMAX_PLAYERS()):
5: player = gc.getPlayer(iPlayer)
6: if player.isAlive():
7: iPlayerNum = iPlayerNum + 1
8: if player.isHuman():
9: popupInfo = CyPopupInfo()
10: popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON)
11: popupInfo.setText(CyTranslator().getText("TXT_KEY_POPUP_SELECT_TRAIT",()))
12: popupInfo.setData1(iPlayer)
13: popupInfo.setOnClickedPythonCallback("selectTrait")
14: popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_TRAIT_AGGRESSIVE", ()), "")
15: popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_TRAIT_CREATIVE", ()), "")
16: popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_TRAIT_EXPANSIVE", ()), "")
17: popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_TRAIT_FINANCIAL", ()), "")
18: popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_TRAIT_INDUSTRIOUS", ()), "")
19: popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_TRAIT_ORGANIZED", ()), "")
20: popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_TRAIT_PHILOSOPHICAL", ()), "")
21: popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_TRAIT_SPIRITUAL", ()), "")
22: popupInfo.addPopup(iPlayer)
[tab]Okay, lets walk through the above function. Lines 1-8 are the standard onGameStart function. Basically, isolating this to an event that occurs when the game begins and only for human players. You will want to make sure not to push popup's to AI players. If you want the AI to react to the same sorts of events you will need to follow your functions with an 'else:' on the 'isHuman()' or an 'if isHuman() == False:' and then call the python routines directly based on whatever logic you want the AI to use.
[tab]Line 9: popupInfo = CyPopupInfo() declares the popupInfo object we are going to create and use. Its not much different than saying newUnit = pPlayer.initUnit(..), its just a definition of a new object. But by itself it doesn't do much, we need to define its characteristics.
[tab]Line 10: popupInfo.setButtonPopupType() I honestly don't know how many ButtonPopupTypes there are, or what the differences between them are. BUTTONPOPUP_PYTHON is the one I always use and it works well.
[tab]Line 11: popupInfo.setText() This is the body text for the popup window. In the example I'm running it through the translator so it can be localized in different languages but you could simply have: popupInfo.setText('Select your bonus Trait')
[tab]Line 12: popupInfo.setData1() This is for any int data you want to pass to the python functions. You can have up to 4 data elements (setData1(), setData2(), setData3(), setData4()) defined in the popup and I will show you how we use them when we get to the events on the button presses.
[tab]Line 13: popupInfo.setOnClickedPythonCallback() This is the python routine that is called when any button is pressed. Notice that the same python routine is called regardless of which button is pressed. I will show you when we declare the python event how to tell which button it was. The most important thing to remember with this is that the python routine must exist in the CvScreensInterface.py file.
[tab]Line 14-21: popupInfo.addPythonButton() This is easy, it just adds a button for each line like this we have. The text that is included as the argument shows up on the button. As with the set text command above you could simply have: popupInfo.addPythonButton('Aggresive')
[tab]Line 22: popupInfo.addPopup() The command that launches the popup. The argument here is the int value of the player that is supposed to receive it.
[tab]Now let's look at the actual python event that it calls. Remember the following goes in the CvScreensInterface.py file:
Code:
def selectTrait(argsList):
iButtonId = argsList[0]
iData1 = argsList[1]
iData2 = argsList[2]
iData3 = argsList[3]
iData4 = argsList[4]
szText = argsList[5]
bOption1 = argsList[6]
bOption2 = argsList[7]
pPlayer = gc.getPlayer(iData)
iTrait = -1
if iButtonId == 0:
iTrait = gc.getInfoTypeForString('TRAIT_AGGRESSIVE')
if iButtonId == 1:
iTrait = gc.getInfoTypeForString('TRAIT_CREATIVE')
if iButtonId == 2:
iTrait = gc.getInfoTypeForString('TRAIT_EXPANSIVE')
if iButtonId == 3:
iTrait = gc.getInfoTypeForString('TRAIT_FINANCIAL')
if iButtonId == 4:
iTrait = gc.getInfoTypeForString('TRAIT_INDUSTRIOUS')
if iButtonId == 5:
iTrait = gc.getInfoTypeForString('TRAIT_ORGANIZED')
if iButtonId == 6:
iTrait = gc.getInfoTypeForString('TRAIT_PHILOSOPHICAL')
if iButtonId == 7:
iTrait = gc.getInfoTypeForString('TRAIT_SPIRITUAL')
if iTrait != -1:
pPlayer.addTrait(iTrait)
[tab]Notice all of the arguments that are passed to the function by the popup. You can see where we breakout our Data1 – 4 elements and we could even pass a text string over and 2 boolens.
[tab]The magic of figuring out what button the user pushed is that the first argument the popup passes to the python function is the number of the button. These are counted ordinally (starting with 0) so if you have 8 buttons you will have 0 – 7. With an if statements for each of the possible values of iButtonId we can run whatever python routines we want, or even send them off into other functions or other popups (oh, popups of popups, wouldn't MTV be proud).
[tab]That’s it, nothing too complicated with the process. But I would expect you might have a few questions I'll try to answer here:
1. pPlayer.addTrait(), whats that?
[tab]Very observant of you, man who types exactly like me. That cool little function is from TheLopez's Scriptable Leader Traits modpack. It is very cool, check it out if you have a chance.
2. Besides adding traits to players with TheLopez's mudpack what can we do with this?
[tab]Anything you can do with python. Want to give the player an option when he captures a city or defeats a special unit, this is how you do it. Want to give them a list of options to deal with revolting peasants or the ability to share the secrets of the alternative fuel source or keep it (and their oil monopoly) to themselves? The sky is the limit.
3. This is all well and good, but shouldn't your function check for <insert thing I forgot to do>?
[tab]Probably. And I did really simplify my code to make it easy for beginning programmers (ie: me) to understand. There are quite a few checks but they aren't nessesary to understand popups and I thought they would just confuse the guide. If you really want to see what the real code looks like it is below:
Spoiler :
Code:
def onGameStart(self, argsList):
'Called at the start of the game'
iPlayerNum = 0
for iPlayer in range(gc.getMAX_PLAYERS()):
player = gc.getPlayer(iPlayer)
if player.isAlive():
iPlayerNum = iPlayerNum + 1
if player.hasTrait(gc.getInfoTypeForString('TRAIT_ADAPTIVE')):
if player.isHuman():
popupInfo = CyPopupInfo()
popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON)
popupInfo.setText(CyTranslator().getText("TXT_KEY_POPUP_SELECT_TRAIT",()))
popupInfo.setData1(iPlayer)
popupInfo.setOnClickedPythonCallback("selectTrait")
szText = CyTranslator().getText("TXT_KEY_TRAIT_AGGRESSIVE", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_AGGRESSIVE')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_ARCANE", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_ARCANE')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_CREATIVE", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_CREATIVE')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_DEFENDER", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_DEFENDER')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_EXPANSIVE", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_EXPANSIVE')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_FINANCIAL", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_FINANCIAL')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_INDUSTRIOUS", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_INDUSTRIOUS')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_ORGANIZED", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_ORGANIZED')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_MAGIC_RESISTANT", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_MAGIC_RESISTANT')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_PHILOSOPHICAL", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_PHILOSOPHICAL')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_RAIDERS", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_RAIDERS')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
szText = CyTranslator().getText("TXT_KEY_TRAIT_SPIRITUAL", ())
if player.hasTrait(gc.getInfoTypeForString('TRAIT_SPIRITUAL')):
szText = szText + CyTranslator().getText("TXT_KEY_TRAIT_ALREADY_KNOWN", ())
popupInfo.addPythonButton(szText, "")
popupInfo.addPopup(iPlayer)
else:
if player.getLeaderType() == gc.getInfoTypeForString('LEADER_VARN'):
player.addTrait(gc.getInfoTypeForString('TRAIT_FINANCIAL'))
if player.getLeaderType() == gc.getInfoTypeForString('LEADER_CARDITH'):
player.addTrait(gc.getInfoTypeForString('TRAIT_PHILOSOPHICAL'))
if player.getLeaderType() == gc.getInfoTypeForString('LEADER_CASSIEL'):
player.addTrait(gc.getInfoTypeForString('TRAIT_INDUSTRIOUS'))
if player.getLeaderType() == gc.getInfoTypeForString('LEADER_SHEELBA'):
player.addTrait(gc.getInfoTypeForString('TRAIT_MAGIC_RESISTANT'))
if player.getLeaderType() == gc.getInfoTypeForString('LEADER_JONUS'):
player.addTrait(gc.getInfoTypeForString('TRAIT_EXPANSIVE'))