Quick Modding Questions Thread

[...] Thanks for checking it out. Hm, but is Relation Caching about relations or do you mean some caching from it is used for the yields tag?
It's a bunch of lists of CvInfo instances that have some relationship with each other. E.g. the list of improvements related to a given building contains those improvements whose yield gets boosted by the building either locally or globally or which generate a free specialist (Forest Preserve with National Park). Here's the CvGameCoreUtils function that establishes these relationships:
Spoiler :
C++:
bool isImprovementRelatedToBuilding(ImprovementTypes eImprovement, BuildingTypes eBuilding)
{
	const CvBuildingInfo& kBuilding = GC.getBuildingInfo(eBuilding);
	
	if (kBuilding.getImprovementFreeSpecialist(eImprovement) != 0)
	{
		return true;
	}

	// MOD - START - Advanced Yield and Commerce Effects
	for (int iMem = 0; iMem < kBuilding.getNumImprovementYieldChanges(); iMem++)
	{
		if ((ImprovementTypes)kBuilding.getImprovementYieldChangeImprovement(iMem) == eImprovement)
		{
			return true;
		}
	}

	for (int iMem = 0; iMem < kBuilding.getNumGlobalImprovementYieldChanges(); iMem++)
	{
		if ((ImprovementTypes)kBuilding.getGlobalImprovementYieldChangeImprovement(iMem) == eImprovement)
		{
			return true;
		}
	}
	// MOD - END - Advanced Yield and Commerce Effects

	return false;
}
I wouldn't adopt this caching mechanism just for the sake of the building improvement yield tags. The loops through the cached lists can be replaced with nested loops over all building-improvement pairs instead.

Some other quick pointers: A pair of helper function templates SetEconomicEffectEnumeration in CvXMLLoadUtility.h (declared and defined in the header) is used for loading the building improvement yield tags from XML. The yield effects get stored by CvCity:: processBuilding (renamed to "processBuildingActivation" in RI) and CvPlayer:: processBuilding for the local and global effect respectively. Everything related to initializing, accessing, serializing, deallocating that CvCity/ CvPlayer data will need to be adopted. CvCity also uses a helper struct ImprovementYieldChange defined in CvStructs. In CvPlot, the BBAI function calculateImprovementYieldChange will be important, specifically the pWorkingCity parameter added for the local (per-city) yield effect. The call locations of the function will require attention too because that's where this new parameter gets passed along. For the help text, there's setBuildingHelpActual and setImprovementHelp in CvGameTextMgr and also stuff in CvDLLWidgetData:: parseActionHelp. And AI support in CvCityAI, CvPlayerAI.

What I would need to change here to make the deal breaker suffer the attitude penalty instead of the other side/both?
I don't think the CvDeal class can tell which side broke a deal. You may have to add a parameter ("eCancelPlayer" or so) and make sure that the info gets passed along. That's what I've done in AdvCiv. (CvDeal handling AI memory at all is questionable software design, but that's probably difficult to refactor.)

I have modded the map sizes, to larger than unmodded, global highlands map script (and only this script) isn't working as it should, its producing no oceans as it should. Does the global highlands script have any size limits?
The script does refer to the original WorldSizeTypes in two places. So, if you've added a new world size, it should probably also be added in those two places. If you've only increased the dimensions of the existing world sizes, then it looks like the getGridSize function of Global_Highlands will ignore such changes. Either way, I don't really see why there would be no Ocean.

It seems using modules only works when adding additional code to the xmls. I cannot replace existing details. For the example I am using a Nuclear Plant module and trying to change the GameText strategy text. [...] The attached example file is a module intended for AdvCiv mod.
Odd. Maybe a known issue with modular loading. Here's one thread I was able to find. In the (BtS) code, it looks like a bug:
Spoiler :
C++:
bool CvXMLLoadUtility::LoadGlobalText()
{
	// ...
	{
	// ...
		gDLL->enumerateFiles(aszFiles, "xml\\text\\*.xml");

		if (gDLL->isModularXMLLoading())
		{
			gDLL->enumerateFiles(aszModfiles, "modules\\*_CIV4GameText.xml");
			aszFiles.insert(aszFiles.end(), aszModfiles.begin(), aszModfiles.end());
		}

		for(std::vector<CvString>::iterator it = aszFiles.begin(); it != aszFiles.end(); ++it)
		{
			bLoaded = LoadCivXml(m_pFXml, *it); // Load the XML
			if (!bLoaded)
			{
				// (error handling)
			}
			if (bLoaded)
			{
				// if the xml is successfully validated
				SetGameText("Civ4GameText", "Civ4GameText/TEXT");
			}
		}
	// ...
	}
	// ...
}
The debugger shows that the enumerateFiles call for "Text" folders first adds the mod's game text files to the aszFiles list and then the original game's files. Which strongly suggests that the first <TEXT> with a given tag string that gets loaded is the one that prevails. This ultimately seems to get handled outside of our view by this addText call in CvXMLLoadUtility::SetGameText:
gDLL->addText(textInfo.getType() /*id*/, textInfo.getText(), textInfo.getGender(), textInfo.getPlural());
Presumably, if the "id" (tag string) of the new textInfo already exists, addText discards it. If that's true, then the game text in modules needs to be put at the beginning of aszFiles, so it should be aszFiles.insert(aszFiles.begin(),... after the second enumerateFiles call. If I change it that way, your module seems to work as intended. So I guess I'll make this change in AdvCiv.
 
Some other quick pointers
I could guess most of those, but thanks for the extra explanation.
I don't think the CvDeal class can tell which side broke a deal. You may have to add a parameter ("eCancelPlayer" or so) and make sure that the info gets passed along. That's what I've done in AdvCiv.
Oh, ok. Not surprising it was such a mess. I'll check out. Just assumed cancellation also had a direction and that's why From and To were around.
 
Is there a way to implement mutually exclusive buildings using only XML? For example having three different buildings A, B, C you can choose to build but once you build A then B and C are no longer available. It's fine if that restriction is player wide and not just city wide. Just want to check before I am building a solution myself.
 
I don't think this can be done using XML only per city. When I did a similar thing for RI, I added a tag to SpecialBuildingInfo that disallowed more than one instance of a given SpecialBuildingInfo member per city.
 
AND2 has some code for just that: NotBuildingRequired (or something similar) that that does exactly what you described on a city level.
And C2C has added code (also backported to AND2) that allows much more complex logical relation for building construction and unit training, like IF, AND, OR, NOT relations to almost anything (civics, leader, trait, route, etc).
 
I don't think this can be done using XML only per city. When I did a similar thing for RI, I added a tag to SpecialBuildingInfo that disallowed more than one instance of a given SpecialBuildingInfo member per city.
AND2 has some code for just that: NotBuildingRequired (or something similar) that that does exactly what you described on a city level.
And C2C has added code (also backported to AND2) that allows much more complex logical relation for building construction and unit training, like IF, AND, OR, NOT relations to almost anything (civics, leader, trait, route, etc).
Yeah, adding this to SpecialBuildingInfo also was my alternative solution if there wasn't a creative XML way to achieve this. Thanks!
 
The script does refer to the original WorldSizeTypes in two places. So, if you've added a new world size, it should probably also be added in those two places. If you've only increased the dimensions of the existing world sizes, then it looks like the getGridSize function of Global_Highlands will ignore such changes. Either way, I don't really see why there would be no Ocean.
Oh boy this is a little beyond my skills it is easy to change? any hints where to start?
 
I ran into a bug the other day and I realized it can affect BTS mods too. In CvDLLWidgetData the exe calls multiple functions with CvWidgetDataStruct reference arguments. Since they aren't const, it is actually possible to alter the data. Some modder did that at some point, altering iData1 and iData2 thinking it was a local variable (presumably). However it actually changed the widget itself so those two ints were changed the next time the data was provided by the exe, which meant the first mouse over text worked, but the second was broken. I have added wrapper functions to ensure that the code only has const access to CvWidgetDataStruct references. That way the compiler won't accept a similar bug in the future.

Apparently it's actually possible to change WidgetTypes and similar of already created widgets this way. It's just too bad that all use cases I can think of for this would be bugs. I can't think of any case where this would be a useful feature.
 
@kristopherb: Let's see, one use of WorldSizeTypes is this:
Spoiler :
Python:
def getGridSize(argsList):
	"Enlarge the grids! Need extra land to cover that 'wasted' by all the peaks!"
	grid_sizes = {
		WorldSizeTypes.WORLDSIZE_DUEL:		(13,8),
		WorldSizeTypes.WORLDSIZE_TINY:		(16,10),
		WorldSizeTypes.WORLDSIZE_SMALL:		(21,13),
		WorldSizeTypes.WORLDSIZE_STANDARD:	(26,16),
		WorldSizeTypes.WORLDSIZE_LARGE:		(32,20),
		WorldSizeTypes.WORLDSIZE_HUGE:		(38,24)
	}
Assuming that your extra large size was simply added in Civ4WorldSizeInfo.xml (maybe by copying all the XML for Huge as a starting point), the new size won't have an associated constant like WorldSizeTypes.WORLDSIZE_HUGE. But I think you can just use WorldSizeTypes.WORLDSIZE_HUGE+1 to refer to your new size. As for the dimensions, I notice that the script's author (Sirian) simply uses the dimensions from the next higher size, i.e. a Large Global Highlands map will have Huge dimensions. So I guess you'd want to imagine how large a size one greater than yours would be. Or maybe just go with 20-25% more than (38,24), e.g.:
Spoiler :
Python:
	grid_sizes = {
		WorldSizeTypes.WORLDSIZE_DUEL:		(13,8),
		WorldSizeTypes.WORLDSIZE_TINY:		(16,10),
		WorldSizeTypes.WORLDSIZE_SMALL:		(21,13),
		WorldSizeTypes.WORLDSIZE_STANDARD:	(26,16),
		WorldSizeTypes.WORLDSIZE_LARGE:		(32,20),
		WorldSizeTypes.WORLDSIZE_HUGE:		(38,24),
		WorldSizeTypes.WORLDSIZE_HUGE + 1:	(46,29)
	}
The other spot (already with my suggested addition):
Spoiler :
Python:
	# Varying grains for hills/peaks per map size and Mountain Ranges setting.
	# [clustered_grain, ridgelines_grain, scattered_grain]
	worldsizes = {
		WorldSizeTypes.WORLDSIZE_DUEL:      [3,4,5],
		WorldSizeTypes.WORLDSIZE_TINY:      [3,4,5],
		WorldSizeTypes.WORLDSIZE_SMALL:     [4,5,6],
		WorldSizeTypes.WORLDSIZE_STANDARD:  [4,5,6],
		WorldSizeTypes.WORLDSIZE_LARGE:     [4,5,6],
		WorldSizeTypes.WORLDSIZE_HUGE:      [4,5,6],
		WorldSizeTypes.WORLDSIZE_HUGE + 1:  [4,5,6]
		}
Perhaps this new size should use even coarser grain values (5,6,7?); maybe some tests would show what difference it makes. Probably not so important. It is important that the new world size is addressed somehow in those two places. When I just tried it with an extra size in XML and no change to the map script, I got a Python crash (PythonErr.log with LoggingEnabled=1 in My Games\Beyond the Sword\CivilizationIV.ini) during map generation, which indeed resulted in a map without water. I suppose it was just the usual all-Grassland map that often is the result of a Python crash during map generation, – but, in this case, I suppose it didn't look entirely broken because the map has a lot going on other than terrain, namely peaks, hills, rivers. (Well, what Civ 4 calls "terrain", e.g. Grassland – I'd say that's a biome. In the normal sense of the word, hills are of course very much a kind of terrain. In Civ 4, that's a "plot type".)
 
I am merging platyping's Natural Wonders with CoM and trying to figure out how to put them on a different tab on the pedia.
The problem is that platy has provided his own version of the pedia with the archive but CoM has Sevopedia.
I was tryin to look into other mods and files to understand things but no success on that :(
I haven't found any other mod that uses both Sevopedia and Natural Wonders.
 
Last edited:
Hello all,
.
I received a crash to desktop today which is very rare seeing as that I've played many numerous games and hours without any issues. I have attached a screenshot of the python exception I'm getting that leads to the crash. Any ideas what is occurring / what I can do to fix?
 

Attachments

  • Crash1.jpg
    Crash1.jpg
    343.3 KB · Views: 27
I received a crash to desktop today which is very rare seeing as that I've played many numerous games and hours without any issues. I have attached a screenshot of the python exception I'm getting that leads to the crash. Any ideas what is occurring / what I can do to fix?
The error message says it's a problem with CvMainInterface.py line 3329. On top of that it tells that it's a C++ exception, so odds are that this line calls the exe or dll with invalid arguments. Without knowing your CvMainInterface.py or mod you are using, it can be tricky to try to guess. It does say the function is updateTimeText, so that's a clue to what the game is trying to do, but not so much why it doesn't work.
 
I ran into a bug the other day and I realized it can affect BTS mods too. In CvDLLWidgetData the exe calls multiple functions with CvWidgetDataStruct reference arguments. [...]
Apparently it's actually possible to change WidgetTypes and similar of already created widgets this way. It's just too bad that all use cases I can think of for this would be bugs. I can't think of any case where this would be a useful feature.
Thanks for the warning. It seems that changing a widget type in one of the handlers would only serve as some kind of message to those handlers themselves. Could probably accomplish that in a cleaner way. Anyway, also not seeing the potential, not even for the diplo screen.

The two open recent questions seem to be resolving themselves elsewhere btw: Fractional year increments causing crashes in updateTimeText; new Sevopedia sections.
 
I have three issues. If someone can help me understan their nature I will be thankful.

First of all, I haven't tinkered with anything else than XML. I am currently probing XML only. I haven't jumped into python scripting or SDK yet. I will do it eventually once I get to know the XML files better. So, if these questions have very obvious answers once you know those other systems, then is ok if you just tell me "you'll find out once you get to python/c++". But right now, at least I need to know if this is an XML matter or not, so I don't lose time searching for an answer that I won't find with my current level of knowledge.

1.- I have seen that forested tiles remove trees to open space for improvements. I made a new improvement, but whenever a place it on a forest, the trees don't disappear to open up space. As a result, it is difficult to spot the improvement. Why is this happening and where should I look to correct this?

2.- I created two new specialists. However, in the city screen, the first two specialists at the top of the lists can't be hovered over. First I thought there was something wrong with my specialists (they were the ones at the top), but then I changed their places and realized that it is always the ones at the top, above the 7th specialist from bottom to top. I can't hover on them. Why is this happening and where should I look to correct this?

I believe this is an UI matter (python?), maybe the upper panel (resources) is getting above the 7th+ specialists and prevents the hovering? Can someone confirm me this is tha case?

3.- I have noticed that some improvements add/change features of the land: like farms adding a farmed land sprite, or quarries modifying the shape of the stone. How can I replicate this? Where should I look?
 
Last edited:
Back
Top Bottom