Quick Modding Questions Thread

Anyone here familiar with modular loading? Basically I have a situation that is as such:
- Module 1 contains a bunch of effects defined via a combo of .nif and .xml.
- Module 2 contains a bunch of .kf files referencing those effects.

When all effects are in the same module as the .kf files the effects work just fine. But separated into two modules they just don't appear at all. It is as if the kf can't read XML from another module.

Any ideas?
 
Have you tried providing the full path from Assets? I mean module 1 contains the path modules/Module 2/art... instead of just art.

Alternatively ../Module 2/Art might work too.

When a file is loaded, the game will try to load from assets. The fact that kf files are in Art seems to be like that for human benefit, not engine benefit. This means you should be able to place a .kf file in xml if you like, or in this case in modules. I haven't played around much with this as preserving the vanilla layout makes sense, but based on what I have tried, it would likely work if you tell it to look in modules.
 
It's not a case of linking files though. Effects are tracked in the .kf by the name they are given in the XML, not by any path.
 
It's not a case of linking files though. Effects are tracked in the .kf by the name they are given in the XML, not by any path.
If you refer to the Type tag, then try to open the xml file in question and edit the file path in xml to be the full path. Since it works when the files are in the same module, then it's obviously some sort of path issue.

You could also try renaming Module 2 to come last in the alphabet to ensure Module 1 is actually loaded by the time Module 2 tries to use Module 1 data. While the source code isn't completely clear (part of the code is in the exe), it seems modules could very well be loaded alphabetically.
 
I am talking about the actual kf files. When you want to attach an effect to a unit there you create a blank node in the nif and than add Effect:[empty item from nif]:[effect name from XML] in the NiTextKeyExtraData of the KF. File paths play no part there.

Also, the folders are alphabetical. They are called Effects and Navy respectively in my actual code. Thanks for the suggestion though.
 
I am talking about the actual kf files. When you want to attach an effect to a unit there you create a blank node in the nif and than add Effect:[empty item from nif]:[effect name from XML] in the NiTextKeyExtraData of the KF. File paths play no part there.
I'm referring to the [effect name from XML] part. Somewhere you have an xml file where that name is set in Type. My guess would be xml\misc\CIV4EffectInfos.xml. That file happens to have a Path tag. Change it in that file to the full path including the modules prefix.

Example. Say [effect name from XML] is EFFECT_FOOTSTEP_ON. This is the first entry in vanilla and it looks like

PHP:
<EffectInfo>
    <Type>EFFECT_FOOTSTEP_ON</Type>
    <Description>EFFECT_FOOTSTEP_ON</Description>
    <fScale>1.0</fScale>
    <fUpdateRate>1.0</fUpdateRate>
    <Path>Art/Interface/Effects/FootStep_ON.nif</Path>
    <bIsProjectile>0</bIsProjectile>
</EffectInfo>
Adding Modules\Module 1\ to the Path here seems trivial once you have the right entry.

You can copy paste the EffectInfo into Module 2. It will then overwrite whatever has the Type in question already loaded and because Module 2 is loaded last, it will overwrite what it is in Module 1 or non-module. This will allow Module 2 to mod Module 1 without touching the files in Module 1.

If this doesn't work, then I'm out of ideas. It would then be something nif/kf specific and I never really looked into those files. In fact I pretty much looked closely into loading modded files of all other extensions than those two and how the DLL loads the files (particularly xml).
 
I do not think you understand what I am talking about. I do not have problems loading effects in modules. That works just fine. And yes, I use relative paths or else it would not work just fine. My problem is explicitly that if I define an effect in one module it won't cross connect to another module even though it can be used perfectly fine in the module it was designed in.

Module 1 uses effects from module one :)
Module 2 uses effects from module 2 :)
Module 1 uses effects from module 2 :(
Module 2 uses effects from module 1 :(

This happens even if Modules 1 and 2 are exact clones of each other.

TLDR:
I have a big module full of ships and another big module full of ground units. And I want them to share the same effects files. Back when those two big modules were small they were all part of the one monolithic module and everything worked perfectly. My units used the custom effects just fine.

But they grew huge so I broke them up into two for easier management. And since I did not want to have duplicate effect files I created a third module for the effects only. And now they don't cross connect properly for some reason.
 
Last edited:
Not completely sure, but i think there is a load order of modules. Didnt a guy/team once make something called world of civilization where the load order could be set?

BTW, just loaded my old VIP mod on a new computer (win10), and turning python exceptions on gives me a message about latin letters not accepted or something like that. Apparently the cities Guimarães and Évora (Portugal) messes up the game. I also had troubles compiling cvGameTextMgr.cpp also because of latin letters error, so ended commenting out szString.assign(L"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[×]^_`abcdefghijklmnopqrstuvwxyz\n");
Neither of these errors were/are on my old win7 machine.

Is it a win 10 issue?
 
Not completely sure, but i think there is a load order of modules. Didnt a guy/team once make something called world of civilization where the load order could be set?
Never heard of it, but most (all?) of the module loading code is in CvXMLLoadUtilitySet.cpp, meaning it isn't a farfetched idea for a mod to control the loading order.

A link would be nice.

BTW, just loaded my old VIP mod on a new computer (win10), and turning python exceptions on gives me a message about latin letters not accepted or something like that. Apparently the cities Guimarães and Évora (Portugal) messes up the game. I also had troubles compiling cvGameTextMgr.cpp also because of latin letters error, so ended commenting out szString.assign(L"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[×]^_`abcdefghijklmnopqrstuvwxyz\n");
Neither of these errors were/are on my old win7 machine.
Characters with a higher value than 0x7F are known to cause issues unless handled in the same way as vanilla does those (html escapes in xml etc). However I can't see any of those in that string, meaning I can't really tell what the problem would be. Sounds rather odd.

Is it a win 10 issue?
We can blame windows 10 for a lot of issues and we can blame the Steam DRM too. The disc and GOG versions gives more freedom, though Steamless helps with that problem. At least it allows debugging the steam version.

However you can't blame everything on windows. I once had a teacher's assistant in programming, who was asked why some code wouldn't compile. He blamed windows and told the students to use Linux instead because it would solve all problems. The problem was a missing ; and as such not platform specific. The TA quit not long after that, most likely because he was heading towards being fired for incompetence.
 
Thanks :)
A link to the mod. It was pretty big at one time, and RoM used it too iirc https://forums.civfanatics.com/forums/civ4-world-of-civilization.276/

The reason why I wanted to blame win10 is because the errors doesn't show up on win7. Though I have the civ4 complete GOG version on my win10 and the old disc version on win7 (no cd drive on my new laptop).
But that would only explain the python exception as the compiling error appears in visual studio 10.So its 2 separate character issues. Maybe im missing some language addon on my new laptop?

edit: the error in VS10:
CvGameTextMgr.cpp
1>CvGameTextMgr.cpp(2091): error C2002: invalid wide-character constant
 
The compile error fixed itself after I wanted to see which character made the issue. After I took out parts of the string and compiled it worked until the last [x] was the only thing missing, however when I readded it, it strangely worked without issues. Very strange.

The python exception however still exists.

upload_2018-12-21_16-53-46.png


Edit
even in vanilla bts it comes up as an issue with special letters:
upload_2018-12-21_17-8-4.png
 
Last edited:
The civ4 engine use the windows locale to figure out which characterset the game should use. Microsoft have for quite a while recommended using unicode instead and in order to make game/application developers do that, they broke windows locale in windows 10. Good for new releases, bad for running old software. Microsoft provided a program called AppLocale to make an application run using a different locale than the one used by windows. They broke that one too with windows 10.

There are 3rd party attempts at making an AppLocale clone for windows 10:
They seem to be aimed at running Japanese software on English computers, but they should be able to be configured to run English locale on any computer. I haven't actually tried either of those though as I'm not having problems with the locale. I did use AppLocale in the past on Windows 7 to test Russian in Colonization when setting up the game for a Russian translator and it actually worked, replacing the western European characters with Russian characters.
 
I have another bizarre issue. I've been looking at the great prophet highlight effect, in particular changing it's color. But it just won't work. I've even tried repainting all the relevant textures into plain blocks of red and it still just looks like nothing changed. It's as if the effect nif is just refusing to load my custom textures and instead draws on the default ones from the BTS folder. (my work is inside a module)

Does anyone have any ideas?

I am quoting my own question from ages ago because I found a solution. And it's such a bizarre one that I feel it deserves documentation for others, should they be in the same position. As I doubt that they would just bump into it as I did.

So to get to it the fix is simple. Just rename the texture names to something different from the default. In my cases I removed fx_ from the beginning. Apparently when the file names are the same as default the game loads the default textures for whatever reason. But if you just change the name it forces the game to load the new ones.

No idea why this works but it does.
 
Is there a way to cause the game to give a free building to a city as soon as it gets the State Religion (or, if that's not possible, as soon as it gets any religion)?
 
Is there a way to cause the game to give a free building to a city as soon as it gets the State Religion (or, if that's not possible, as soon as it gets any religion)?

You can use the code below. Go to CvEventManager.py, find the onReligionSpread() function and insert the part that starts with iStateReligion. Replace the BUILDING_WALLS with the building you want to be placed when the state religion spreads.

Code:
    def onReligionSpread(self, argsList):
        'Religion Has Spread to a City'
        iReligion, iOwner, pSpreadCity = argsList
        
        iStateReligion = gc.getPlayer(iOwner).getStateReligion()
        if iReligion == iStateReligion:
            iBuilding = gc.getInfoTypeForString("BUILDING_WALLS")
            if not pSpreadCity.isHasBuilding(iBuilding):
                pSpreadCity.setNumRealBuilding(iBuilding, 1)
        
        player = PyPlayer(iOwner)
        if (not self.__LOG_RELIGIONSPREAD):
            return
        CvUtil.pyPrint('%s has spread to Player %d Civilization %s city of %s'
            %(gc.getReligionInfo(iReligion).getDescription(), iOwner, player.getCivilizationName(), pSpreadCity.getName()))
 
Thank you, merijn_v1! That's awesome!

Is there also a way to add the building when the religion already exists in the city and that religion then becomes the State Religion. For example, let's say I don't have a State Religion, but I have two cities with Christianity in them, so I decide to make Christianity my State Religion. Is there a way to cause the game to give those two cities the building when Christianity becomes the State Religion?
 
Sure. It looks very similar. It is the same file, but a different function.

Code:
    def onPlayerChangeStateReligion(self, argsList):
        'Player changes his state religion'
        iPlayer, iNewReligion, iOldReligion = argsList
       
        if iNewReligion == gc.getInfoTypeForString("RELIGION_XXXX"):
            iBuilding = gc.getInfoTypeForString("BUILDING_WALLS")
            if not pSpreadCity.isHasBuilding(iBuilding):
                pSpreadCity.setNumRealBuilding(iBuilding, 1)
 
Thank you again, merijn_v1!

Unfortunately, I wasn't able to make the second change work.

Here's the change I made:
Code:
    def onPlayerChangeStateReligion(self, argsList):
        'Player changes his state religion'
        iPlayer, iNewReligion, iOldReligion = argsList

        if iNewReligion == gc.getInfoTypeForString("RELIGION_BUDDHISM"):
            iBuilding = gc.getInfoTypeForString("BUILDING_WALLS")
            if not pSpreadCity.isHasBuilding(iBuilding):
                pSpreadCity.setNumRealBuilding(iBuilding, 1)

The previous change had worked in both plain BTS and in BTS with BAT mod, so I tried the second change with both.

The second change did nothing in plain BTS and did not show an error message on the screen. In BTS with BAT mod, it also did nothing, but it showed the following error message on the screen:
Code:
Error in playerChangeStateReligion event handler <bound method BugEventManager.onPlayerChangeStateReligion of <BugEventManager.BugEventManager instance at 0x408F9B20>>

Any ideas?
 
I see what I did wrong. I forgot to loop over the cities of the civ. Try this:

Code:
    def onPlayerChangeStateReligion(self, argsList):
        'Player changes his state religion'
        iPlayer, iNewReligion, iOldReligion = argsList
        
        if iNewReligion == gc.getInfoTypeForString("RELIGION_XXXX"):
            for pCity in PyPlayer(iPlayer).getCityList():
                city = pCity.GetCy()
                iBuilding = gc.getInfoTypeForString("BUILDING_WALLS")
                if not city.isHasBuilding(iBuilding):
                    city.setNumRealBuilding(iBuilding, 1)
 
That almost works! It does create the building when a city has the specified religion and the civilization then adopts the specified religion as its State Religion. Unfortunately, however, it also creates the building in every city of the civilization, even if none of those other cities have the specified religion.

EDIT: I don't know if it's relevant, but I'm also using the first bit of code you provided me (in the onReligionSpread section).
 
Last edited:
Back
Top Bottom