Not sure what Afforess changed in the codes, but I can tell you even in BTS, this code will fail.
Under normal circumstances, this code is fine. But when a middle city is captured, the ID is screwed up.
For instance, Cities A to E, where A will be ID 0, while E will be ID 4. When City C is captured, number of cities will fall to 4, but City D and E will remain as ID 3 and 4 respectively. Hence, you loop through a range of 4, City ID 2 which used to be City C will be null, while City E is missed.
When a new City F is built, it will take up the missing slot though, so usually nobody will notice.
The solution is to use a while loop, or the inefficient pyhelper method, which uses the while loop and a for loop.
lCities = PyHelpers.PyPlayer(iActivePlayer).getCityList()
for iCity in range( len( lCities ) ):
objCity = gc.getPlayer(iActivePlayer).getCity( lCities[ iCity ].getID( ) )
for iCityID in range(gc.getPlayer(iActivePlayer).getNumCities()):
objCity = gc.getPlayer(iActivePlayer).getCity(iCityID)
Just DLed, will try tomorrow. 1.02 doesn't work for me. Just to let ya know i've tried everything.Hi ! Your discussion was omitted, sorry.
Try to use the latest installer which also allows easy updating instead.
Just install, wait for download to complete and play![]()
A critical bug was fixed since, avoiding some systems to update / download the mod.1.02 doesn't work for me.
45°38'N-13°47'E;13635607 said:Code:lCities = PyHelpers.PyPlayer(iActivePlayer).getCityList() for iCity in range( len( lCities ) ): objCity = gc.getPlayer(iActivePlayer).getCity( lCities[ iCity ].getID( ) )
for objCity in lCities:
pPlayer = gc.getPlayer(iActivePlayer)
(loopCity, iter) = pPlayer.firstCity(False)
while(loopCity):
............
(loopCity, iter) = pPlayer.nextCity(iter, False)
If you are using PyHelpers, the for loop can be simplified to :
Code:for objCity in lCities:
PyHelpers is an inefficient way of coding, but many coders are used to it, because previous coders code using them, so they just C&P without understanding how it works.
Most of the time, I use a while loop directly to get the same task done.
Code:pPlayer = gc.getPlayer(iActivePlayer) (loopCity, iter) = pPlayer.firstCity(False) while(loopCity): ............ (loopCity, iter) = pPlayer.nextCity(iter, False)
What actually happens in PyHelpers is that they use this while loop to loop through all cities and store them in a list.
After which, you use a for loop to loop through this saved list to do what you want.
Then you realise you could have done what you need via the while loop directly, why is there a need for a double loop...
Need more info on what is not working, such as python exceptions.
def drawOutgoingWarheadsContent(self, screen):
self.H_MAP = (self.W_MAP * CyMap().getGridHeight()) / CyMap().getGridWidth()
if (self.H_MAP > self.H_MAP_MAX):
self.W_MAP = (self.H_MAP_MAX * CyMap().getGridWidth()) / CyMap().getGridHeight()
self.H_MAP = self.H_MAP_MAX
screen.addPanel(OUTGOING_WARHEADS_PANEL, u"", "", False, False, 24, 60, 350, 708-60, PanelStyles.PANEL_STYLE_MAIN)
screen.addPanel(OUTGOING_WARHEADS_INNER_PANEL, u"", "", True, True, 34, 60+10+40, 330, 708-(70+15+35), PanelStyles.PANEL_STYLE_IN)
screen.addPanel(OUTGOING_LABEL_PANEL, u"", "", False, False, 29, 60+10, 340, 35, PanelStyles.PANEL_STYLE_MAIN)
screen.setText(self.OUTGOING_LABEL_ID, "Background", self.OUTGOING_LABEL_TEXT, CvUtil.FONT_CENTER_JUSTIFY, 24+(350/2), 60+10+7, self.Z_CONTROLS, FontTypes.TITLE_FONT, WidgetTypes.WIDGET_GENERAL, -1, -1 )
screen.setHitTest(self.OUTGOING_LABEL_ID,HitTestTypes.HITTEST_NOHIT)
screen.addPanel(OUTGOING_SUMMARY_PANEL, u"", "", False, False, 420, self.Y_MAP+self.H_MAP+5, 580, self.H_SCREEN-(self.Y_MAP+self.H_MAP+5)-60, PanelStyles.PANEL_STYLE_MAIN)
screen.addPanel(OUTGOING_SUMMARY_INNER_PANEL, u"", "", True, False, 425+5, self.Y_MAP+self.H_MAP+15+40, 580-20, self.H_SCREEN-(self.Y_MAP+self.H_MAP+5)-(70+35+15), PanelStyles.PANEL_STYLE_IN)
screen.addPanel(OUTGOING_SUMMARY_LABEL_PANEL, u"", "", False, False, 425, self.Y_MAP+self.H_MAP+15, 570, 35, PanelStyles.PANEL_STYLE_MAIN)
screen.setText(self.OUTGOING_SUMMARY_LABEL_ID, "Background", self.OUTGOING_SUMMARY_LABEL_TEXT, CvUtil.FONT_CENTER_JUSTIFY, 425+(570/2), self.Y_MAP+self.H_MAP+15+7, self.Z_CONTROLS, FontTypes.TITLE_FONT, WidgetTypes.WIDGET_GENERAL, -1, -1 )
screen.setHitTest(self.OUTGOING_SUMMARY_LABEL_ID,HitTestTypes.HITTEST_NOHIT)
iCounter = 0
iTotalNukeCount = 0
pPlayer = gc.getPlayer(iActivePlayer)
(objUnit, iter) = pPlayer.firstUnit(False)
while(objUnit):
objUnit = gc.getPlayer(gc.getGame().getActivePlayer()).getUnit(iUnitID)
self.selectedUnitHash[iUnitID] = False;
if(objUnit.getUnitAIType() != UnitAITypes.UNITAI_ICBM):
continue
iTotalNukeCount += 1
if(objUnit.getMADTargetPlot() == None):
continue
if(objUnit.getMADTargetPlot().isNone()):
continue
[COLOR="Red"]screen.attachPanel(OUTGOING_WARHEADS_INNER_PANEL, "UnitPanel%s" %(iUnitID), "", "", True, False, PanelStyles.PANEL_STYLE_OUT)[/COLOR]
screen.attachPanel("UnitPanel%s" %(iUnitID), "UnitInnerPanel%s" %(iUnitID), "", "", True, False, PanelStyles.PANEL_STYLE_EMPTY)
screen.attachLabel( "UnitInnerPanel%s" %(iUnitID), "UnitInnerPanel%sfill1" %(iUnitID), " Located At: %s" %(objUnit.plot().getPlotCity().getName()))
screen.attachLabel( "UnitInnerPanel%s" %(iUnitID), "UnitInnerPanel%sfill2" %(iUnitID), " Targetting: %s" %(objUnit.getMADTargetPlot().getPlotCity().getName()))
screen.attachLabel( "UnitInnerPanel%s" %(iUnitID), "UnitInnerPanel%sfill3" %(iUnitID), " City Owned By: %s" %(gc.getPlayer(objUnit.getMADTargetPlot().getPlotCity().getOwner()).getName()))
# screen.attachLabel( "UnitPanel%s" %(iUnitID), "UnitPanel%sfill1" %(iUnitID), " " )
screen.addCheckBoxGFCAt( "UnitPanel%s" %(iUnitID), "UnitCheckbox%s" %(iUnitID)
, gc.getUnitInfo(objUnit.getUnitType()).getButton()
, ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath()
, 1, 2, 46, 46, WidgetTypes.WIDGET_GENERAL, iUnitID, iUnitID, ButtonStyles.BUTTON_STYLE_LABEL, False)
iCounter +=1
(objUnit, iter) = pPlayer.nextUnit(iter, False)
if(iCounter <= 10):
iTempCounter = 10 - iCounter
for iDummy in range(iTempCounter):
screen.attachPanel(OUTGOING_WARHEADS_INNER_PANEL, "DummyPanel%s" %(iDummy), "", "", True, False, PanelStyles.PANEL_STYLE_EMPTY)
screen.attachLabel( "DummyPanel%s" %(iDummy), "UnitPanel%sfill1" %(iDummy), " " )
screen.attachLabel( "DummyPanel%s" %(iDummy), "UnitPanel%sfill2" %(iDummy), " " )
screen.attachLabel( "DummyPanel%s" %(iDummy), "UnitPanel%sfill3" %(iDummy), " " )
screen.attachLabel( OUTGOING_SUMMARY_INNER_PANEL, "TotalNukes", u"%c<FONT=3b>%s Total Nuclear Warheads</FONT>" %(CyGame().getSymbolID(FontSymbols.BULLET_CHAR), iTotalNukeCount) )
screen.attachLabel( OUTGOING_SUMMARY_INNER_PANEL, "TotalOutgoingNukes", u"%c<FONT=3b>%s Outgoing Nuclear Warheads</FONT>" %(CyGame().getSymbolID(FontSymbols.BULLET_CHAR), iCounter) )
screen.attachLabel( OUTGOING_SUMMARY_INNER_PANEL, "TotalNukesAvailable", u"%c<FONT=3b>%s Available Nuclear Warheads</FONT>" %(CyGame().getSymbolID(FontSymbols.BULLET_CHAR), iTotalNukeCount-iCounter) )
(objUnit, iter) = pPlayer.firstUnit(False)
while(objUnit):
pPlayer = gc.getPlayer(iActivePlayer)
iStateReligion = pPlayer.getStateReligion()
(loopCity, iter) = pPlayer.firstCity(False)
while(loopCity):
if loopCity.isHasReligion(iStateReligion):
loopCity.changePopulation(1)
(loopCity, iter) = pPlayer.nextCity(iter, False)
lCities = PyHelpers.PyPlayer(iActivePlayer).getCityList()
iStateReligion = gc.getPlayer(iActivePlayer).getStateReligion()
for loopCity in lCities:
if loopCity.isHasReligion(iStateReligion):
loopCity.changePopulation(1)
Thanks to your help, i've managed to correctly use the python API. This is not really what i call a good documentation, but yet, it is usable.If you want to change the header, you look for the header section, which I believe BTS pedia use getDescription, while I use short desc instead. The adjective is just to illustrate.
In fact, there are some parts of the documentation for which the underline represents the output type of the function and some parts where that means the input type. Of course, it's mentionned nowhere; that's why i was a bit lostgetCivilizationType will return an int. In this case, it is used as a civilization type. But it is simply just an int which can be used for other purposes. For instance, pPlayer.changeGold(pPlayer.getCivilizationType())
Will work perfectly, resulting in the player gold increased by his civ ID.
I will be surprised to see no errors.
Where is iUnitID defined?
Thanks to your help, i've managed to correctly use the python API. This is not really what i call a good documentation, but yet, it is usable.
In fact, there are some parts of the documentation for which the underline represents the output type of the function and some parts where that means the input type. Of course, it's mentionned nowhere; that's why i was a bit lost![]()
I will be surprised to see no errors.
Where is iUnitID defined?
When you use the while loop method...
Code:(objUnit, iter) = pPlayer.firstUnit(False) while(objUnit):
objUnit is already the CyUnit object which you need where you can do commands like change level, add experience, kill etc.
[CUT]
Anyway, if the for loop method shows 0 for both values, the while loop method will still show 0 when working correctly, because the for loop is just an inefficient version of the while loop method. One drawback with the while loop however is you cannot use continue statements. If you try to continue on the last iteration, it will crash.
iActivePlayer = gc.getGame().getActivePlayer()
pPlayer = gc.getPlayer(iActivePlayer)
# iUnitID = pPlayer.getUnit(iUnitID)
(iUnitID, iter) = pPlayer.firstUnit(False)
while(iUnitID):
# objUnit = gc.getPlayer(gc.getGame().getActivePlayer()).getUnit(iUnitID)
self.selectedUnitHash[iUnitID] = False;
if(iUnitID.getUnitAIType() == UnitAITypes.UNITAI_ICBM):
pass
iTotalNukeCount += 1
if(iUnitID.getMADTargetPlot() != None) and not (iUnitID.getMADTargetPlot().isNone()):
pass
# if(objUnit.getMADTargetPlot().isNone()):
# continue
screen.attachPanel(OUTGOING_WARHEADS_INNER_PANEL, "UnitPanel%s" %(iUnitID), "", "", True, False, PanelStyles.PANEL_STYLE_OUT)
screen.attachPanel("UnitPanel%s" %(iUnitID), "UnitInnerPanel%s" %(iUnitID), "", "", True, False, PanelStyles.PANEL_STYLE_EMPTY)
screen.attachLabel( "UnitInnerPanel%s" %(iUnitID), "UnitInnerPanel%sfill1" %(iUnitID), " Located At: %s" %(iUnitID.plot().getPlotCity().getName()))
screen.attachLabel( "UnitInnerPanel%s" %(iUnitID), "UnitInnerPanel%sfill2" %(iUnitID), " Targetting: %s" %(iUnitID.getMADTargetPlot().getPlotCity().getName()))
screen.attachLabel( "UnitInnerPanel%s" %(iUnitID), "UnitInnerPanel%sfill3" %(iUnitID), " City Owned By: %s" %(gc.getPlayer(iUnitID.getMADTargetPlot().getPlotCity().getOwner()).getName()))
# screen.attachLabel( "UnitPanel%s" %(iUnitID), "UnitPanel%sfill1" %(iUnitID), " " )
screen.addCheckBoxGFCAt( "UnitPanel%s" %(iUnitID), "UnitCheckbox%s" %(iUnitID)
[COLOR="Red"], gc.getUnitInfo(objUnit.getUnitType()).getButton()[/COLOR]
, ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath()
, 1, 2, 46, 46, WidgetTypes.WIDGET_GENERAL, iUnitID, iUnitID, ButtonStyles.BUTTON_STYLE_LABEL, False)
iCounter +=1
(iUnitID, iter) = pPlayer.nextUnit(iter, False)
screen.addCheckBoxGFCAt( "UnitPanel%s" %(iUnitID), "UnitCheckbox%s" %(iUnitID)
[COLOR="Red"], gc.getUnitInfo(objUnit.getUnitType()).getButton()[/COLOR]
, ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath()
, 1, 2, 46, 46, WidgetTypes.WIDGET_GENERAL, iUnitID, iUnitID, ButtonStyles.BUTTON_STYLE_LABEL, False)
screen.addCheckBoxGFCAt( "UnitPanel%s" %(iUnitID), "UnitCheckbox%s" %(iUnitID)
, gc.getUnitInfo(objUnit).getButton()
, ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath()
, 1, 2, 46, 46, WidgetTypes.WIDGET_GENERAL, objUnit, objUnit, ButtonStyles.BUTTON_STYLE_LABEL, False)
iActivePlayer = CyGame().getActivePlayer()
pPlayer = gc.getPlayer(iActivePlayer)
sBorder = ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath()
(pUnit, iter) = pPlayer.firstUnit(False)
while(pUnit):
iUnitID = [COLOR="red"]pUnit.getID()[/COLOR]
self.selectedUnitHash[iUnitID] = False
if pUnit.getUnitAIType() == UnitAITypes.UNITAI_ICBM:
iTotalNukeCount += 1
pPlot = pUnit.plot()
pTargetPlot = pUnit.getMADTargetPlot()
if pTargetPlot and pTargetPlot.isCity() and pPlot.isCity():
pTargetCity = [COLOR="Red"]pTargetPlot.getPlotCity()[/COLOR]
sMainPanel = "UnitPanel%s" %(iUnitID)
sInnerPanel = "UnitInnerPanel%s" %(iUnitID)
screen.attachPanel(OUTGOING_WARHEADS_INNER_PANEL, sMainPanel, "", "", True, False, PanelStyles.PANEL_STYLE_OUT)
screen.attachPanel(sMainPanel, sInnerPanel, "", "", True, False, PanelStyles.PANEL_STYLE_EMPTY)
sLocate = CyTranslator().getText("TXT_KEY_MAD_LOCATE", (pPlot.getPlotCity().getName(),))
sTarget = CyTranslator().getText("TXT_KEY_MAD_TARGET", (pTargetCity.getName(),))
sOwner = CyTranslator().getText("TXT_KEY_MAD_CITY_OWNER", (gc.getPlayer(pTargetCity.getOwner()).getName(),))
screen.attachLabel(sInnerPanel, sInnerPanel + "fill1", sLocate)
screen.attachLabel(sInnerPanel, sInnerPanel + "fill2", sTarget)
screen.attachLabel(sInnerPanel, sInnerPanel + "fill3", sOwner)
screen.addCheckBoxGFCAt(sMainPanel, "UnitCheckbox%s" %(iUnitID), pUnit.getButton(), sBorder
, 1, 2, 46, 46, WidgetTypes.WIDGET_GENERAL, -1, -1, ButtonStyles.BUTTON_STYLE_LABEL, False)
iCounter +=1
(pUnit, iter) = pPlayer.nextUnit(iter, False)
Code:iActivePlayer = CyGame().getActivePlayer() pPlayer = gc.getPlayer(iActivePlayer) sBorder = ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath() (pUnit, iter) = pPlayer.firstUnit(False) while(pUnit): iUnitID = pUnit.getUnitID() self.selectedUnitHash[iUnitID] = False if pUnit.getUnitAIType() == UnitAITypes.UNITAI_ICBM: iTotalNukeCount += 1 pPlot = pUnit.plot() pTargetPlot = pUnit.getMADTargetPlot() if pTargetPlot and pTargetPlot.isCity() and pPlot.isCity(): pTargetCity = pTargetPlot.getCity() sMainPanel = "UnitPanel%s" %(iUnitID) sInnerPanel = "UnitInnerPanel%s" %(iUnitID) screen.attachPanel(OUTGOING_WARHEADS_INNER_PANEL, sMainPanel, "", "", True, False, PanelStyles.PANEL_STYLE_OUT) screen.attachPanel(sMainPanel, sInnerPanel, "", "", True, False, PanelStyles.PANEL_STYLE_EMPTY) sLocate = CyTranslator().getText("TXT_KEY_MAD_LOCATE", (pPlot.getPlotCity().getName(),)) sTarget = CyTranslator().getText("TXT_KEY_MAD_TARGET", (pTargetCity.getName(),)) sOwner = CyTranslator().getText("TXT_KEY_MAD_CITY_OWNER", (gc.getPlayer(pTargetCity.getOwner()).getName(),)) screen.attachLabel(sInnerPanel, sInnerPanel + "fill1", sLocate) screen.attachLabel(sInnerPanel, sInnerPanel + "fill2", sTarget) screen.attachLabel(sInnerPanel, sInnerPanel + "fill3", sOwner) screen.addCheckBoxGFCAt(sMainPanel, "UnitCheckbox%s" %(iUnitID), pUnit.getButton(), sBorder , 1, 2, 46, 46, WidgetTypes.WIDGET_GENERAL, -1, -1, ButtonStyles.BUTTON_STYLE_LABEL, False) iCounter +=1 (pUnit, iter) = pPlayer.nextUnit(iter, False)
1) iUnitID in the original code stands for int Unit ID. Using it as the name of a CyUnit object will be misleading.
2) self.selectedUnitHash[iUnitID] is supposed to take in the Unit ID, but you pass in a CyUnit object.
3) "pass" keyword has no meaning in python. It is merely as a placeholder for future codes.
Whatever codes below will still be activated.
4) It is a pretty bad habit to hard code text which are to be displayed, such as " Located At: %s". When you code like this, there is no way to translate "Located At" to other languages. Use CyTranslater and type the corresponding text in Text XML files.
5) The texts are trying to display names for both the city the nuke is in, as well as the city the nuke is targeting. But there is no check for whether both cities exist in the first place. Tactical Nukes for instance, can be loaded in subs in BTS, though not sure if still do in AND. Hence, checks are added, but this will ignore nukes which are either not in cities, or not tageting cities.
Code:iActivePlayer = CyGame().getActivePlayer() pPlayer = gc.getPlayer(iActivePlayer) sBorder = ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath() (pUnit, iter) = pPlayer.firstUnit(False) while(pUnit): iUnitID = pUnit.getUnitID() self.selectedUnitHash[iUnitID] = False if pUnit.getUnitAIType() == UnitAITypes.UNITAI_ICBM: iTotalNukeCount += 1 pPlot = pUnit.plot() pTargetPlot = pUnit.getMADTargetPlot() if pTargetPlot and pTargetPlot.isCity() and pPlot.isCity(): pTargetCity = pTargetPlot.getCity() sMainPanel = "UnitPanel%s" %(iUnitID) sInnerPanel = "UnitInnerPanel%s" %(iUnitID) screen.attachPanel(OUTGOING_WARHEADS_INNER_PANEL, sMainPanel, "", "", True, False, PanelStyles.PANEL_STYLE_OUT) screen.attachPanel(sMainPanel, sInnerPanel, "", "", True, False, PanelStyles.PANEL_STYLE_EMPTY) sLocate = CyTranslator().getText("TXT_KEY_MAD_LOCATE", (pPlot.getPlotCity().getName(),)) sTarget = CyTranslator().getText("TXT_KEY_MAD_TARGET", (pTargetCity.getName(),)) sOwner = CyTranslator().getText("TXT_KEY_MAD_CITY_OWNER", (gc.getPlayer(pTargetCity.getOwner()).getName(),)) screen.attachLabel(sInnerPanel, sInnerPanel + "fill1", sLocate) screen.attachLabel(sInnerPanel, sInnerPanel + "fill2", sTarget) screen.attachLabel(sInnerPanel, sInnerPanel + "fill3", sOwner) screen.addCheckBoxGFCAt(sMainPanel, "UnitCheckbox%s" %(iUnitID), pUnit.getButton(), sBorder , 1, 2, 46, 46, WidgetTypes.WIDGET_GENERAL, -1, -1, ButtonStyles.BUTTON_STYLE_LABEL, False) iCounter +=1 (pUnit, iter) = pPlayer.nextUnit(iter, False)
1) iUnitID in the original code stands for int Unit ID. Using it as the name of a CyUnit object will be misleading.
2) self.selectedUnitHash[iUnitID] is supposed to take in the Unit ID, but you pass in a CyUnit object.
3) "pass" keyword has no meaning in python. It is merely as a placeholder for future codes.
Whatever codes below will still be activated.
4) It is a pretty bad habit to hard code text which are to be displayed, such as " Located At: %s". When you code like this, there is no way to translate "Located At" to other languages. Use CyTranslater and type the corresponding text in Text XML files.
5) The texts are trying to display names for both the city the nuke is in, as well as the city the nuke is targeting. But there is no check for whether both cities exist in the first place. Tactical Nukes for instance, can be loaded in subs in BTS, though not sure if still do in AND. Hence, checks are added, but this will ignore nukes which are either not in cities, or not tageting cities.
Was coding from memory and cannot test, edited the above codes.