adapt a script

globosud

Warlord
Joined
Jul 7, 2017
Messages
109
Is there anyone so kind who could edit this script for me for bug mods? I tried, but it always gives me errors. the script is at this link
thanks
 
I've just done a search for a tutorial on integrating mod components with BUG, and, actually, there used to be one, plus extensive HTML documentation, but it all disappeared in the late 2010s. These are the only traces I can find through the Wayback Machine: Tutorial | References
I had always assumed that the BUG modders had just not gotten around to documentation beyond the technical comments throughout the scripts, i.e. that they implemented this carefully designed and neatly extensible framework, and failed to educate fellow modders in its use. It does seem that the documentation didn't receive much attention even when it was available. Maybe, even then, the problem was that the modders wishing to add a mod component to a BUG-based modpack were not the ones who originally wrote that component and had hardly any experience with Python themselves.

I can't research and write a new tutorial, but I'll try to demonstrate how this simple mod – WarNPeaceScript – can be integrated with BUG. Based on how it's done for some of the components that come with BUG. Apparently,
Code:
<load mod="WarNPeace"/>
needs to be added to Config\init.xml; probably best to add it after the last of the existing load elements. Also in the Config folder, a corresponding XML file WarNPeace.xml needs to be added with contents such as:
Spoiler :
Code:
<?xml version="1.0" encoding="ISO-8859-1" ?>

<mod id="WarNPeace"
	 name="WarNPeaceScript"
	 module="WarNPeace"
	 author="The_J (apart from BUG integration)"
	 version="1.0" 
	 date="06/02/2024"
	 dll="0">

	<init/>

</mod>
I assume that many of those metadata attributes like author are optional. I think the module attribute needs to match the name of our main Python module. And the (empty) init element is probably necessary so that the init function in our module receives a call when the BUG core gets initialized. Then WarNPeace.py can be placed directly in the BUG-based mod's Python folder, I think, or in any subfolder. To that module, we'll add an init function that will register the event handlers of the WarNPeace mod, i.e. the WarNPeace changes in CvEventManager.py get moved into WarNPeace.py (and the modified CvEventManager.py gets discarded):
Spoiler :
Code:
import BugEventManager

def init():
       em = BugEventManager.g_eventManager
       em.addEventHandler('LoadGame', loadCustomXML)
       em.addEventHandler('GameStart', loadCustomXML)
       em.addEventHandler('BeginGameTurn', onBeginGameTurn)

def loadCustomXML(argsList):
        loadEvents("Mods/MyModPack/Assets/XML/CustomXML/WarNPeace.xml")

def onBeginGameTurn(argsList):
        iGameTurn = argsList[0]
        triggerEvents(iGameTurn)
This chunk of code should go right above the first original function definition, i.e. above def triggerEvents(iTurn):. I've adopted the peculiar 7-space indents of the original code because indentation has to be consistent within a Python module. The mod name is contained in one of the paths here. This isn't nice, but it's already the case in the original mod. I've put "MyModPack" in the path, will need to be changed to whatever the BUG-based mod is named.

To elaborate: In the init function, em is defined as a local shorthand for the global BUG event manager – just for brevity. Then handlers for the three event types LoadGame, GameStart and BeginGameTurn are added. Since the original WarNPeace code (in CvEventManager.py) did the same thing at game start as upon loading a savegame, I've added a single handler function loadCustomXML for both. BeginGameTurn gets its own mini handler onBeginGameTurn. Both of my handler functions simply call pre-existing WarNPeace functions. One of those functions loads the custom XML file that specifies which wars are supposed to be declared and ended.
I've copied that file along with its containing "CustomXML" folder into the BUG-based mod.

Lastly, the game text file WarNPeace_GameText.xml can simply be copied to XML\Text. For a test with the WB file that comes with the mod, I had to explicitly assign France and England to AI civs on the Custom Scenario screen. Then, as intended, a DoW happened between those two at the start of turn 2 and peace was signed at the start of turn 5. That's all the testing I've done. I hope I haven't forgotten any step.

Edit: Linking to this thread for another, very similar example.
 
Last edited:
first of all thanks for the help. :)
at this link I copied the files as I tried to modify them, at the beginning it doesn't give me errors but then nothing happens, if you can take a look, it will make it easier for me to understand the changes you recommended ., Thank you
 
It looks like you made no changes to WarNPeace.py, and added WarNPeaceUtil.py. I don't think that latter module is referenced anywhere, so I assume that it never gets called, I guess not even loaded. That's what the entry in init.xml (along with the mod definition in XML) is supposed to accomplish. You could register the handlers in WarNPeaceUtil – and invoke that module from XML – but a separate module isn't really needed and seems a little more complicated than letting WarNPeace.py do everything. Putting the Python stuff in the Contrib folder as you've done should be fine.
 
I made the changes as you wrote, I linked the files, if you can look at them, to see if I did it right. Thank you
 

Attachments

  • WarNPeace.rar
    5.6 KB · Views: 5
basically this script, I need it to create a civilization, with two cities,

which I will name a "panama canal"
and a Suez Canal, to which I can change cityartstyle, and which always remains at peace with everyone, so as to be a kind of customs house, of the canal, which will allow ships and units to cross the land, It would be nice if I could then put a toll on the passage, but I think it's too complicated for me
I created this mega map that I use in my games, for patch 3.6 and now I'm transferring it to 3.4, it's a gigantic map of 44196 tiles, wid 340 height 127, it took me 6 months of hard work, in the scenario there are 65 factions, and I tested it for 1200 turns, so it has no bugs. to make you understand the scale, Europe is as large as the Europe of the Europe of R.I. scenario,consider that from Spain to America there are 70 ocean tiles approximately,
after about 1000 turns the save file is about 8kb
for the resources I also based myself on the R.I. scenarios, but it is very balanced.
 

Attachments

  • Screenshot 2024-02-02 155419.png
    Screenshot 2024-02-02 155419.png
    247 KB · Views: 7
Last edited:
It looks like you made no changes to WarNPeace.py, and added WarNPeaceUtil.py. I don't think that latter module is referenced anywhere, so I assume that it never gets called, I guess not even loaded. That's what the entry in init.xml (along with the mod definition in XML) is supposed to accomplish. You could register the handlers in WarNPeaceUtil – and invoke that module from XML – but a separate module isn't really needed and seems a little more complicated than letting WarNPeace.py do everything. Putting the Python stuff in the Contrib folder as you've done should be fine.
thank you with all my heart. Everything works perfectly. Without your help I would never have succeeded. And for people like you, that civilization 4 after 17 years still remains one of the best games ever
 
I made the changes as you wrote, I linked the files, if you can look at them, to see if I did it right. Thank you
It looks like it should work. Though I wonder if WarNPeace can actually prevent a civ from declaring war on a canal owner and immediately conquering the canal city. It seems that, at best, the mod can force everyone to make peace with the canal owners once per game turn. I'll post a reply to your original question – enforcing peace – in your other thread. Quite an effort to ultimate just have a kind of intersection that both ships and land units can pass. I guess complicated solutions to simple problems is the charm of Python modding. ;) The transit fee, on that note, also sounds difficult to do through Python. There is a unit-move callback that can be enabled through XML and then the same technique as discussed in this thread can be used to register an event handler for unit moves. My main concern would be the extra time spent on a DLL-to-Python call each time that any unit moves on the map. But it could also be that the time overhead is actually negligible.

Edit: Didn't see your last post. Great, at least the BUG integration stuff works. Happy to help.
 
Last edited:
It looks like it should work. Though I wonder if WarNPeace can actually prevent a civ from declaring war on a canal owner and immediately conquer the canal city. It seems that, at best, the mod can force everyone to make peace with the canal owners once per game turn. I'll post reply to your original question – enforcing peace – in your other thread. Quite an effort to ultimate just have a kind of intersection that both ships and land units can pass. I guess complicated solutions to simple problems is the charm of Python modding. The transit fee, on that note, also sounds difficult to do through Python. There is a unit-move callback that can be enabled through XML and then the same technique as discussed in this thread can be used to register an event handler for unit moves. My main concern would be the extra time spent on a DLL-to-Python call each time that any unit moves on the map. But also be that the time overhead is actually negligible.

Edit: Didn't see your last post. Great, at least the BUG integration stuff works. Happy to help.
i have to think about it, you're right, this script doesn't make the city/canal unassailable, perhaps another type of script would be needed
 
Overriding a DLL-to-Python call that is not an event – like canDeclareWar – in a BUG-based mod turns out to be rather easy. With the above already in place, it suffices to add BugGameUtils.addHandler(canDeclareWar) to the init function of the WarNPeace module. Then, a function
Code:
def canDeclareWar(argsList):
       iAttackingTeam, iDefendingTeam = argsList
       return True
can be declared in the same module. That function can then check the teams' IDs or some property of the warring teams and return True or False accordingly. And import BugGameUtils is needed somewhere at the top. And USE_CAN_DECLARE_WAR_CALLBACK needs to be enabled in PythonCallbackDefines.xml. In a test with standard game settings, I see canDeclareWar called a few hundred times per turn in the early game. Regrettable wrt. performance to make a Python call each time, but I doubt that it'll make a noticeable difference. Edit: Missing word. Happens to me more and more often with age.
 
Last edited:
you mean it like that
 

Attachments

  • Screenshot 2024-02-06 194931.jpg
    Screenshot 2024-02-06 194931.jpg
    106.9 KB · Views: 7
then I add this function,
def canDeclareWar(argsList):
iAttackingTeam, iDefendingTeam = argsList
return True
but for the team's choice?
 
Yes, that looks good. Indentation will have to be in line with the rest of the file. Not sure how you want to identify the war-immune teams. If by ID is sufficient then something like
Code:
if iAttackingTeam == 4 or iDefendingTeam == 4:
       return False
above the return True.
 
I did it like this, it's ok to try
 

Attachments

  • Screenshot 2024-02-06 201259.png
    Screenshot 2024-02-06 201259.png
    33.9 KB · Views: 12
The above. It's a different design pattern than for the event manager. BugEventManager is a class with a global instance, BugGameUtils isn't a class at all. The attachment looks like it could work. Or maybe just always return False for a test. Should then be impossible to declare any wars.
 
But no "self" in the parameters of canDeclareWar. The self parameter is only for methods, i.e. functions that are part of a class.
 
Quanto sopra. È un modello di progettazione diverso rispetto a quello del gestore eventi. BugEventManager è una classe con un'istanza globale, BugGameUtils non è affatto una classe. Sembra che l'allegato possa funzionare. O forse restituisci sempre False per un test. Dovrebbe quindi essere impossibile dichiarare guerre.
Scusa ,
i try in this way?

correct, removed self
 
you are genius. thxxx

I can't declare war on team 4
 

Attachments

  • Screenshot 2024-02-06 202352.png
    Screenshot 2024-02-06 202352.png
    240.1 KB · Views: 10
thank you, you are a wonderful and helpful person, thanks to you I can continue my scenario
 
HI. I wanted to know if a further condition could be added to this script, in addition to "I can't declare war on team 4", also that team 4 cannot move to another civilization, due to cultural conquest, and that if it is possible, it cannot grow culturally. I hope it's possible, thanks
 

Attachments

  • Screenshot 2024-02-16 181123.png
    Screenshot 2024-02-16 181123.png
    46.8 KB · Views: 9
Top Bottom