Quick Modding Questions Thread

My best bet is a problem with tabs vs. spaces at that line or the one just before or after. The "for" being indented farther than the preceding comment and closing brace is unusual, but, to my knowledge, not incorrect. The use of items also seems to be correct.
 
I'm 99% sure that the problem is somewhere else, because it doesn't work for me in platy's original modcomp either:

Could anyone download it and confirm whether Natural Wonders movies work for them or not?
I have set up and attached a save game for testing.
So... No one answered this but I'm suspecting that the problem is not not in the code but somewhere in my "machine".
Is it possible that Python misbehaves because of some local settings or something? (I have Win10)
 
It is much more likely that the cause is your specific combination of mods you are running, rather than a system issue.
 
It is much more likely that the cause is your specific combination of mods you are running, rather than a system issue.
Okay, but I instal platyping's mod ALONE it still doesn't work. That's why I asked if someone could double check if the very same mod I downloaded and installed is working or not? If his mod in a vanilla state works for others than there IS something wrong with my system. And if his code doesn't work for others either... 🙂
 
So... No one answered this but I'm suspecting that the problem is not not in the code but somewhere in my "machine".
Oh, I had meant to give it a try - if no one else would. :mischief:
So, if I load your savegame and found a bunch of cities next to natural wonders, then no movies play. The wonders are not announced to me in any way. The wonder buildings do get placed. But onBuildingBuilt in Python is not getting called. That's where wonder movies normally get launched. Looking at the DLL, the BuildingBuilt event is tied to a construction order getting completed. If they don't sweat for it, they get no movie. Ah, but the wonder buildings aren't technically wonders anyway (no instance limits). Instead, the movies are supposed to play when revealing a natural wonder (checkReveal in NaturalWonders.py). If I Alt-Z to Shaka in your savegame and move a Scout southeast, I do get the movie. One could probably move Platy's movie code to whichever setNumRealBuilding call(s) in his code is/are relevant in order to get the movie upon claiming the wonder instead.

On a side note, I see that Ctrl+F shows plot indicators for all revealed natural wonders for a few seconds. That's a cool idea for a low-key, low-effort info layer.
 
Oh, I had meant to give it a try - if no one else would. :mischief:
I knew I could count on you :bowdown:
the movies are supposed to play when revealing a natural wonder (checkReveal in NaturalWonders.py). If I Alt-Z to Shaka in your savegame and move a Scout southeast, I do get the movie.
Oh, wow! 😍
In the past I was told that it was impossible to display a movie in any other way than building a wonder. This great news. Double great news 🤩


Looking at the DLL, the BuildingBuilt event is tied to a construction order getting completed. If they don't sweat for it, they get no movie. Ah, but the wonder buildings aren't technically wonders anyway (no instance limits)
So if a building had no cost AND building limit, it can't have a movie, right? So I need to change either the dll or the python code or do some workaround, right?
Great thanks!
 
Well, I hope that it really does work for you as well (when revealing tiles at least).

It seems that this fragment of Platy's is doing the job:
Spoiler :
Python:
if pPlayerX.isHuman() and not CyGame().GetWorldBuilderMode():
	popupInfo = CyPopupInfo()
	popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
	popupInfo.setData1(iFeature)
	popupInfo.setData3(3)
	popupInfo.setText(u"showWonderMovie")
	popupInfo.addPopup(iPlayerX)
I assume that he used the BtS code in obBuildingBuilt as his starting point. This should result in a call to
Python:
wonderMovie = CvWonderMovieScreen.CvWonderMovieScreen()
def showWonderMovie(argsList):
	wonderMovie.interfaceScreen(argsList[0], argsList[1], argsList[2])
in CvScreensInterface.py, and CvWonderMovieScreen also is available to us – and has been modified by Platy to accommodate his tag type naming convention for his natural wonder movies. Which is to say: Modders should have a lot of control over wonder movies.
So if a building had no cost AND building limit, it can't have a movie, right? So I need to change either the dll or the python code or do some workaround, right?
The wonder status is, I think, just something that onBuildingBuilt checks before showing a movie. But it's just Python code, an exception could be added e.g. for specific building types. And having a cost won't help because onBuildingBuilt only gets called when a city finishes constructing a building. I don't think setNumRealBuilding triggers this event – even if the building has a cost. However, if you can determine where NaturalWonders.py adds the city buildings, you could just move the wonder screen launch code to that place. I wouldn't even consider that a workaround. And I don't think the building needs to have any particular properties for this to work. placeWonderBuilding sounded like the place where the buildings get added, but when I tried it this afternoon, a print statement I put there did not seem to get reached. Maybe I just didn't test it carefully enough.
 
Well, I hope that it really does work for you as well (when revealing tiles at least).

It seems that this fragment of Platy's is doing the job:
Spoiler :
Python:
if pPlayerX.isHuman() and not CyGame().GetWorldBuilderMode():
    popupInfo = CyPopupInfo()
    popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
    popupInfo.setData1(iFeature)
    popupInfo.setData3(3)
    popupInfo.setText(u"showWonderMovie")
    popupInfo.addPopup(iPlayerX)
I assume that he used the BtS code in obBuildingBuilt as his starting point. This should result in a call to
Python:
wonderMovie = CvWonderMovieScreen.CvWonderMovieScreen()
def showWonderMovie(argsList):
    wonderMovie.interfaceScreen(argsList[0], argsList[1], argsList[2])
in CvScreensInterface.py, and CvWonderMovieScreen also is available to us – and has been modified by Platy to accommodate his tag type naming convention for his natural wonder movies. Which is to say: Modders should have a lot of control over wonder movies.
The wonder status is, I think, just something that onBuildingBuilt checks before showing a movie. But it's just Python code, an exception could be added e.g. for specific building types. And having a cost won't help because onBuildingBuilt only gets called when a city finishes constructing a building. I don't think setNumRealBuilding triggers this event – even if the building has a cost. However, if you can determine where NaturalWonders.py adds the city buildings, you could just move the wonder screen launch code to that place. I wouldn't even consider that a workaround. And I don't think the building needs to have any particular properties for this to work. placeWonderBuilding sounded like the place where the buildings get added, but when I tried it this afternoon, a print statement I put there did not seem to get reached. Maybe I just didn't test it carefully enough.
Okay, I'll try to work long these lines once I got over my nightshifts :sleep:
I'll be back with more questions for sure :)
Thanks again :goodjob:
 
Hello, I've added 11 new religions on top of the existing religions (total 18) and I can't find where I would edit the religious advisor screen so that I could view/select most of the new religions (they're off screen and there's no scrollbar). Where would I go to either add a scrollbar or wrap the icons on screen?
 
The load order is BtS before Warlords before the base game (edit: ugh, that's an ambiguous way to put it; I mean the pre-BtS files get loaded unless BtS - or the mod - has a copy). Seems that CvReligionScreen.py gets loaded from the base game (Python\Screens). So that's the file to copy and modify.
On a quick glance, wrap-around might be a matter of changing the x and y coordinates in this call:
Python:
screen.addCheckBoxGFC(szButtonName, gc.getReligionInfo(i).getButton(), ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath(), self.X_RELIGION_AREA + xLoop - self.BUTTON_SIZE/2, self.Y_RELIGION_AREA + self.Y_RELIGION - self.BUTTON_SIZE/2, self.BUTTON_SIZE, self.BUTTON_SIZE, WidgetTypes.WIDGET_GENERAL, -1, -1, ButtonStyles.BUTTON_STYLE_LABEL)
The comment "Put everything on a scrollable area" a few lines above perhaps means that the screen already is scrollable in one direction. In that case, it probably can't have another scrollbar.
 
Last edited:
As I recall, you have Visual Studio installed and working. If so, you could try to reproduce the crash with the debugger attached. Even if the resulting information – hopefully a line of code in your DLL source code and the call stack – don't make sense to you, you could still post them here as screenshots. To launch BtS with your mod and the VS debugger attached, select the "Debug" configuration in VS and, under "Configuration Properties" - "Debugging", enter Civ4BeyondSword.exe with its full path into the "Command" field and mod=\Gorm Revolution (or whichever command works for loading your mod) into "Command Arguments". VS will store this in the .vcxproj.user file, so this only needs to be configured once. You can then compile the DLL and "Start Debugging" via the "Debug" menu. I would recommend disabling fullscreen mode beforehand. When the crash occurs, VS should inform you that a breakpoint has been encountered, and after clicking "Break" (I think that's what the button says), the location and context of the crash should get shown. As the Debug DLL also has runtime assertions enabled, you might run into failed assertions prior to the crash that may or may not be related to the crash. Actually, you could also try just compiling a Debug or Assert build to see if there are useful assertion failures - before configuring and using the debugger.

If I were to download/install the mod and savegame, unless the timing of the crash is somehow very telling, all I could do would be to set up the development environment myself and perform the steps above.
 
The load order is BtS before Warlords before the base game (edit: ugh, that's an ambiguous way to put it; I mean the pre-BtS files get loaded unless BtS - or the mod - has a copy). Seems that CvReligionScreen.py gets loaded from the base game (Python\Screens). So that's the file to copy and modify.
On a quick glance, wrap-around might be a matter of changing the x and y coordinates in this call:
Python:
screen.addCheckBoxGFC(szButtonName, gc.getReligionInfo(i).getButton(), ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath(), self.X_RELIGION_AREA + xLoop - self.BUTTON_SIZE/2, self.Y_RELIGION_AREA + self.Y_RELIGION - self.BUTTON_SIZE/2, self.BUTTON_SIZE, self.BUTTON_SIZE, WidgetTypes.WIDGET_GENERAL, -1, -1, ButtonStyles.BUTTON_STYLE_LABEL)
The comment "Put everything on a scrollable area" a few lines above perhaps means that the screen already is scrollable in one direction. In that case, it probably can't have another scrollbar.
Yes looking at it I don't think I can make it scroll. What should I change the X and Y values to (default -1?) to make them wrap? Also, would changing the button size from 2 to 1 condense the list or just the icons?
 
As I recall, you have Visual Studio installed and working. If so, you could try to reproduce the crash with the debugger attached. Even if the resulting information – hopefully a line of code in your DLL source code and the call stack – don't make sense to you, you could still post them here as screenshots. To launch BtS with your mod and the VS debugger attached, select the "Debug" configuration in VS and, under "Configuration Properties" - "Debugging", enter Civ4BeyondSword.exe with its full path into the "Command" field and mod=\Gorm Revolution (or whichever command works for loading your mod) into "Command Arguments". VS will store this in the .vcxproj.user file, so this only needs to be configured once. You can then compile the DLL and "Start Debugging" via the "Debug" menu. I would recommend disabling fullscreen mode beforehand. When the crash occurs, VS should inform you that a breakpoint has been encountered, and after clicking "Break" (I think that's what the button says), the location and context of the crash should get shown. As the Debug DLL also has runtime assertions enabled, you might run into failed assertions prior to the crash that may or may not be related to the crash. Actually, you could also try just compiling a Debug or Assert build to see if there are useful assertion failures - before configuring and using the debugger.

If I were to download/install the mod and savegame, unless the timing of the crash is somehow very telling, all I could do would be to set up the development environment myself and perform the steps above.
thank you, I noticed that the crash happens sometimes, I don't know why but sometimes the game advances to the next round and sometimes it crashes CTD.
EDIT: in console i find this: warn: !applyTransform flags: 0 projidx: 4
 
Last edited:
@Sturmgewher88mm: The parameter names are (acording to the Python API):
C++:
VOID addCheckBoxGFC (
	STRING szName, STRING szTexture, STRING szHiliteTexture,
	INT iX, INT iY, INT iWidth, INT iHeight,
	WidgetType eWidgetType, INT iData1, INT iData2,
	ButtonStyle eStyle)
So we've got
Python:
iX = self.X_RELIGION_AREA + xLoop - self.BUTTON_SIZE/2,
iY = self.Y_RELIGION_AREA + self.Y_RELIGION - self.BUTTON_SIZE/2,
iWidth = iHeight = self.BUTTON_SIZE
And xLoop gets updated as xLoop += self.DX_RELIGION. The constants in question:
Python:
self.DX_RELIGION = 98
self.BUTTON_SIZE = 48
So changing the BUTTON_SIZE constant (near the top of the file) will not affect xLoop, i.e. the dynamic element of the positioning. But also decreasing DX_RELIGION should do the job. Since your mod is apparently not based on the BUG mod (that would bring its own religion screen), you can experiment with Python changes at runtime; the game detects when a file is changed on disk and then automatically reloads the Python module. (BUG breaks that feature.) Maybe best to close the religion screen in between code changes.

For wrapping around, iY (not just iX) would need to depend on the number of loop iterations. Currently, it's only based on constants. Maybe a job for AI. Perplexity.ai gives me this:
Spoiler AI convo :
Could you make these button icons wrap around?
Python:
		# Religion buttons at the top
		xLoop = self.X_RELIGION_START
		for i in range(gc.getNumReligionInfos()):
			szButtonName = self.getReligionButtonName(i)
			if gc.getGame().getReligionGameTurnFounded(i) >= 0:
				screen.addCheckBoxGFC(szButtonName, gc.getReligionInfo(i).getButton(), ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath(), self.X_RELIGION_AREA + xLoop - self.BUTTON_SIZE/2, self.Y_RELIGION_AREA + self.Y_RELIGION - self.BUTTON_SIZE/2, self.BUTTON_SIZE, self.BUTTON_SIZE, WidgetTypes.WIDGET_GENERAL, -1, -1, ButtonStyles.BUTTON_STYLE_LABEL)
			xLoop += self.DX_RELIGION
It should be a matter of choosing
iX = self.X_RELIGION_AREA + xLoop - self.BUTTON_SIZE/2
and
iY = self.Y_RELIGION_AREA + self.Y_RELIGION - self.BUTTON_SIZE/2
differently – increasing iY to second (or third etc.) row when iX would exceed some vertical right edge boundary.

AI answer said:
To make the button icons wrap around to the next row when they reach a certain boundary, you can adjust the iX and iY coordinates based on the current position and the boundary. Here's how you can modify your code to achieve this:
Python:
# Religion buttons at the top
xLoop = self.X_RELIGION_START
yRow = 0  # Initialize row counter
maxX = self.X_RELIGION_AREA + self.MAX_WIDTH  # Define the right boundary

for i in range(gc.getNumReligionInfos()):
	szButtonName = self.getReligionButtonName(i)
	if gc.getGame().getReligionGameTurnFounded(i) >= 0:
		# Calculate x and y positions
		iX = self.X_RELIGION_AREA + xLoop - self.BUTTON_SIZE/2
		iY = self.Y_RELIGION_AREA + self.Y_RELIGION + (yRow * self.BUTTON_SIZE) - self.BUTTON_SIZE/2

		# Check if the next button would exceed the boundary
		if iX + self.BUTTON_SIZE > maxX:
			# Move to the next row
			xLoop = self.X_RELIGION_START
			yRow += 1
			# Recalculate iX and iY for the new row
			iX = self.X_RELIGION_AREA + xLoop - self.BUTTON_SIZE/2
			iY = self.Y_RELIGION_AREA + self.Y_RELIGION + (yRow * self.BUTTON_SIZE) - self.BUTTON_SIZE/2

		# Add the button
		screen.addCheckBoxGFC(szButtonName, gc.getReligionInfo(i).getButton(), ArtFileMgr.getInterfaceArtInfo("BUTTON_HILITE_SQUARE").getPath(), iX, iY, self.BUTTON_SIZE, self.BUTTON_SIZE, WidgetTypes.WIDGET_GENERAL, -1, -1, ButtonStyles.BUTTON_STYLE_LABEL)

		# Increment xLoop for the next button
		xLoop += self.DX_RELIGION
In this code:
maxX defines the right boundary beyond which buttons should wrap to the next row.
yRow keeps track of the current row number.
• When a button would exceed maxX, it resets xLoop to start a new row and increments yRow. The iX and iY coordinates are recalculated for the new row before adding the button.

Make sure to define self.MAX_WIDTH as the maximum width available for the buttons before they should wrap. This value should be adjusted based on your specific layout and design requirements.
This looks legit to me, but I haven't tested it, and I'd try to use it as a guide rather than copy-paste it. Calculating iY twice is clearly unnecessary. Hm, searching for all uses of DX_RELIGION, I see that there are several other loops that place labels, which probably need to be aligned with the one I gave to the chat bot. And the iX, iY formulas are repeated in an "else" branch that places nonselectable images for religions not yet founded. So getting wrap-around to work will probably require changes in a number of places (or a good amount of code restructuring). Whereas changes to DX_RELIGION and other constants should only need to be changed in a single place (toward the top, where they're defined).
 
@Darkator: Then it could easily be an out-of-bounds memory access. Though it could also easily be something else. Anyway, still impossible for me to guess what kind of XML change causes it (or Python change; but XML-only modders run into these problems too). Then just enabling assertions ("Assert" configuration) seems worth a try. Assertions like
FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
clutter the DLL codebase just to make issues with array bounds easier to resolve. If your problem happens to be covered by such an assertion, the assertion should fail predictably, i.e. even when there is no crash.
EDIT: in console i find this: warn: !applyTransform flags: 0 projidx: 4
What console? Or is it a logfile? applyTransform and projidx don't mean anything to me.
 
Oh, so this is on Wine. Then I don't know if debugging with Visual Studio would be as easy as I described it. The Assert build should work just as well on Wine though. In this post, you were trying to compile your own DLL, but perhaps this didn't actually pan out, and, if you can't recompile the DLL, the advice with the Assert build also isn't useful.
 
I managed to compile Cvgamecoredll myself, only sometimes I don't know what but at the same time both on Windows and Linux, an error (CTD) in the mod occurs during the game, I don't know what causes it. That's why I updated the mod on github and went to the save where the error occurs, (it randomly occurs after a few turns)
 
Back
Top Bottom