Merging BUG with other Mods

I'm back, now I'm trying to merge a mod that uses CvEventManager.py with BUG (merging Thomas' War python with LoR python). EF, you said
Next we need to know how the mod your merging in was built itself. Some provide a modified copy of CvEventManager.py. This is the toughest to work with because you need to extract the changes they made into a new module and ditch CvEventManager.

I can find the changes in there, but what do you mean, extract them into a "new module"?

And while a lot of the changes I need are in the CvEventManger.py file, as well as CvGameUtils.py, this mod also has a CvCustomEventManger.py. As for that, I'm trying to just do what you had me do last time, telling the init file to recognize the custom python, but I wonder if I'll have more luck with that once I get the contents of CvEventManager.py to work.

Thanks in advance
 
Basically what you need to do is move the stuff in CvEventManager that isn't in the original BTS file to a new custom event manager, similar in style to the one it is already using. Okay, lots of duplicate words for different things in there. Lemme try with letters.

BTS's CvEventManager = B
mod's CvEventManager = E
CvCustomEventManager = C
<custom event manager that C points to> = M

You need to extract the stuff that's in E but not in B (E - B) and move it to a new module that looks just like M. Throw out C.

You've already learned how to use M with BUG by adding an <events> call to an XML config file pointing to M, right? You need to do this again for a new module you will create.

Did that help at all? This is going to require a little bit of Python knowledge, so I highly recommend doing some reading on the subject. There's an excellent free online book on Python and programming in general called How to Think Like a Computer Scientist.
 
Thanks tons, I think that clears it up! The letters did help a lot, lol. I'll give it a shot. Thanks for the book link too; I really just need to dive into some python tutorials at some point here.
 
Great! While I learned Python from docs.python.org and the tutorial there because I already had lots of experience with many languages, I did skim that book a bit when someone asked for a book recommendation here, and it looked really good. If you know other languages well, just go to docs.python.org and look up what you need, but if you are new to programming that book is excellent.

The same author (I think) wrote versions for Java and other languages as well. Python is a great language for learning to code.
 
Bleh, still having issues. I've been having fun (no, really) reading up on some python tutorials, but I get the feeling that my problem is something simple. I just can't get BUG's init.xml to load my attempted modules. When I load Civ, it gives me this error:
BugConfig - failure parsing D:\Program Files\Civ4\Beyond The Sword\Mods\WoH 0.5\Assets\Config\init.xml at line 119
Line 118 (or 120, or 124, as the case may be) is where I've tried to direct init.xml to my modules, by typing:
Spoiler :
<!-- Mods -->
<events module="CvCultureBombEventManager"/>
<events module="MongolCamp"/>
<events module="CvMercEventManager"/>
<events module="ThomasWarEvents"/>
<events module="AbandonRazeDemolish"/>
<events module="CvCrossroadsEvents"/>
<events module="GodsOfOld"/>

I'm not sure if the problem is somewhere in my attempted python modules. The first module, CvCultureBombEventManager, works fine (remember helping me with that one a few weeks back?), but I haven't pinpointed what makes BUG accept that one but none of the others. ThomasWarEvents.py is the only one I've made myself, the others are all downloaded (and I've seen most of them work in their native mods).

Just for reference, here's the top bit of my ThomasWarEvents.py. Don't laugh:
Spoiler :
# ThomasWarEvents.py
#

from CvPythonExtensions import *
import CvUtil
import CvScreensInterface
import CvDebugTools
import CvWBPopups
import PyHelpers
import Popup as PyPopup
import CvCameraControls
import CvTopCivs
import sys
import CvWorldBuilderScreen
import CvAdvisorUtils
import CvTechChooser
import CvEventManager

# globals
gc = CyGlobalContext()
localText = CyTranslator()
PyPlayer = PyHelpers.PyPlayer
PyInfo = PyHelpers.PyInfo

class ThomasWarEvents:
def __init__(self, eventManager):


## Mercantile Victory ##

g_iCaptureHeadquartersGold = 50

## Mercantile Victory ##

# Gods variables
# private
self.clearGodsVariables()


self.DemoCount = 0

#Net Messages
self.m_iNetMessage_Inquisitor = 0
self.m_iNetMessage_ProphetKi = 1
self.m_iNetMessage_ProphetEnki = 2
self.m_iNetMessage_ProphetEnlil = 3
self.m_iNetMessage_ProphetNanna = 4
self.m_iNetMessage_ProphetUtu = 5
self.m_iNetMessage_ProphetAn = 6

# Next War tracks cities that have been razed
self.iArcologyCityID = -1

#Inquisitor's Effect on a City
if ( iMessageID == self.m_iNetMessage_Inquisitor ):

iPlotX = iData2
iPlotY = iData3
iOwner = iData4
iUnitID = iData5

pPlot = CyMap( ).plot( iPlotX, iPlotY )
pCity = pPlot.getPlotCity( )
pPlayer = gc.getPlayer( iOwner )
pUnit = pPlayer.getUnit( iUnitID )

self.doInquisitorPersecution( pCity, pUnit )

# Social Reform
 
The XML and your module look fine. In PythonErr.log should be the cause of the "failure parsing" message. While loading the module (the module level code is run when Python loads a module) or when creating your event manager--e.g. ThomasWarEvents.ThomasWarEvents(bugEventManager)--a Python error occurs. BugConfig detects this error, logs it to PythonErr.log, and then reports the place in the XML where it was when the error occurred.

If it's not there, check PythonDbg.log. These two files are your real source of information. The on-screen message is just to let you know that there was a problem so you know to look in those files.
 
Well, I feel like I've been making good progress by using PythonErr.log, but more recently I've ended up going in circles. Thanks, btw, for working with me through all this. I've been looking all around for anything else that might help me figure this out, and it's amazing how many search results turn up an old thread of you working someone through their own python issues. No luck solving my particular problem, though. Man, if I can just bust past this, this is one of the last stumbling blocks in the way of this mod!

Anyway, my PythonErr.log is presently always blank, which is a big improvement but it's baffling because the ThomasWar python still isn't having any effect. This is stuff by tsentom1, if that helps at all - I've noticed you've helped other people who've tried to merge his stuff with BUG. So, uh, here I'm posting a link to the whole of the ThomasWarEvents.py that I made. I know, it's a lot (that's why I had to make a link instead of just a spoiler here), but I figured I'd give it all to you in case it helps you see anything wrong with it. I had to make it a txt file, cause google docs wouldn't let my upload python for some reason.

http://docs.google.com/Doc?docid=0AYHTOL7pFZn9ZGY0Y2ozd3FfMGZoenRtNWNk&hl=en

Thanks for taking all this trouble, I seriously want to figure out what's stopping this.

EDIT: Oh, and PythonDbg looks good too, I think. The only thing it says about the merging stuff is:
PY:Initializing MongolCamp
01:56:55 DEBUG: BUG: looking up ThomasWarEvents.ThomasWarEvents
load_module ThomasWarEvents
 
It's really hard to read code without the indentation, so I skimmed only a small bit of it. I didn't see anywhere that you call addEventHandler() to hook this event manager up to BUG. Does this one give you a warning in BugConfig or does it just do nothing?

You need to tell BUG, "when event type X is fired, call function Y." I would expect to see lines that look like this:

Code:
eventManager.addEventHandler("OnLoad", self.onLoad)

in the "__init__(self, eventManager)" constructor (function).
 
Oh, duh, indentation, right. Sorry about that. I'll take a look at the EventHandler stuff, thanks! And no, it doesn't give me any warning that I've seen, it just does nothing.
 
Yeah, I'm really just feeling around in the dark at this juncture. Here's what I've added near the beginning of the problem file:
class ThomasWarEvents:

def __init__(self, eventManager):
# initialize base class
eventManager.addEventHandler("OnLoad", self.onLoad)

def onLoad(self, argsList):
ThomasWarEvents.onLoad(argsList)

I satisfied all the complaints of PythonErr.log again, but still the mod doesn't have an effect :P

As always, thanks lots for this
 
What does this part of code do:

# **********************************
# GJD modifications start here
# **********************************

import BugEventManager

eventManager = BugEventManager.BugEventManager()

def getEventManager():
return eventManager

# **********************************
# GJD modifications end here
# **********************************

It's from the BUG CvEventInterface file.

I am looking for a way to integrate it with the equivalent RFC file that contains:

import CvUtil
import CvRFCEventManager
from CvPythonExtensions import *

normalEventManager = CvRFCEventManager.CvRFCEventManager()

def getEventManager():
return normalEventManager
 
That code you posted already has an onLoadGame() function. Are you adding an onLoad() function? You can just point to onLoadGame() directly. I hadn't looked far enough to see which event handlers you needed; I just picked one I knew existed. :)

Code:
class ThomasWarEvents:

    def __init__(self, eventManager):
        eventManager.addEventHandler("OnLoad", self.onLoadGame)
        eventManager.addEventHandler("PreSave", self.onPreSave)
        ...

You need to find all of the onFoo(self, argsList) functions in that class and add an event handler for each one. Look in CvEventManager from BTS to see the event type (e.g. "OnLoad") that goes with the function (e.g. onLoadGame). The function name must match what is in ThomasWarEvents, and the event type must match what's in CvEventManager. By match I mean exactly, upper/lower case included. The function name and event type don't have to look anything alike, but each must match what I've stated just previously. You can do

Code:
eventManager.addEventHandler("OnLoad", self.ohPleaseLoadMyMod)

as long as you define a function called ohPleaseLoadMyMod in ThomasWarEvents.

@PPQ_Purple - The first block of code you posted is how BUG sets up its event manager. You cannot replace it with your own (as the code in the second block does) or BUG will cease to function. To hook up your own events or those from an existing mod, start by reading the chapter BUG Core: Events.

It looks like CvRFCEventManager is designed to replace CvEventManager just as BUG does. Sadly, this is the hardest type of mod to retrofit into BUG because you need to separate CvRFCEventManager from the CvEventManager code on which it is based.

However, it's possible that CvRFCEventManager extends CvEventManager. If that's the case, it will be a lot easier. If you post CvRFCEventManager, I'll take a quick peak to see which type it is.
 
Okay, this is weird. Now PythonErr keeps saying
ConfigError: No such module 'ThomasWarEvents'
Thanks for slogging through this with me. I can't believe it's being this hard, but at least I'm learning lots as I go! The python book you linked me too is really good so far, btw. Anyway, here's the top portion of ThomasWarEvents.py right now:

Spoiler :
# ThomasWarEvents.py
#

from CvPythonExtensions import *
import CvUtil
import CvScreensInterface
import CvDebugTools
import CvWBPopups
import PyHelpers
import Popup as PyPopup
import CvCameraControls
import CvTopCivs
import sys
import CvWorldBuilderScreen
import CvAdvisorUtils
import CvTechChooser
import GodsOfOld
import pickle

# globals
gc = CyGlobalContext()
localText = CyTranslator()
PyPlayer = PyHelpers.PyPlayer
PyInfo = PyHelpers.PyInfo


class ThomasWarEvents(CvEventManager.CvEventManager):
def __init__(self, eventManager):
eventManager.addEventHandler("ModNetMessage", self.onModNetMessage)
eventManager.addEventHandler("OnPreSave", self.onPreSave)
eventManager.addEventHandler("OnLoad", self.onLoadGame)
eventManager.addEventHandler("GameStart", self.onGameStart)
eventManager.addEventHandler("GameEnd", self.onGameEnd)
eventManager.addEventHandler("BeginGameTurn", self.onBeginGameTurn)
eventManager.addEventHandler("plotPicked", self.onPlotPicked)


#Net Messages
self.m_iNetMessage_Inquisitor = 0
self.m_iNetMessage_ProphetKi = 1
self.m_iNetMessage_ProphetEnki = 2
self.m_iNetMessage_ProphetEnlil = 3
self.m_iNetMessage_ProphetNanna = 4
self.m_iNetMessage_ProphetUtu = 5
self.m_iNetMessage_ProphetAn = 6

# Next War tracks cities that have been razed
self.iArcologyCityID = -1

def onModNetMessage(self, argsList):
'Called whenever CyMessageControl().sendModNetMessage() is called - this is all for you modders!'

iData1, iData2, iData3, iData4, iData5 = argsList

print("Modder's net message!")

CvUtil.pyPrint( 'onModNetMessage' )

iMessageID = iData1

#Inquisitor's Effect on a City
if ( iMessageID == self.m_iNetMessage_Inquisitor ):

iPlotX = iData2
iPlotY = iData3
iOwner = iData4
iUnitID = iData5

pPlot = CyMap( ).plot( iPlotX, iPlotY )
pCity = pPlot.getPlotCity( )
pPlayer = gc.getPlayer( iOwner )
pUnit = pPlayer.getUnit( iUnitID )

self.doInquisitorPersecution( pCity, pUnit )

# Social Reform


Sorry, no indents again, I hope that's not where the problem is...don't think it is, tho
 
To get indentation, put your code inside [code][/code] tags.
 
Ahhh, thanks! Okay, for your pleasure EF:

Code:
# ThomasWarEvents.py
#

from CvPythonExtensions import *
import CvUtil
import CvScreensInterface
import CvDebugTools
import CvWBPopups
import PyHelpers
import Popup as PyPopup
import CvCameraControls
import CvTopCivs
import sys
import CvWorldBuilderScreen
import CvAdvisorUtils
import CvTechChooser
import GodsOfOld
import pickle

# globals
gc = CyGlobalContext()
localText = CyTranslator()
PyPlayer = PyHelpers.PyPlayer
PyInfo = PyHelpers.PyInfo


class ThomasWarEvents(CvEventManager.CvEventManager):
	def __init__(self, eventManager):
		eventManager.addEventHandler("ModNetMessage", self.onModNetMessage)
		eventManager.addEventHandler("OnPreSave", self.onPreSave)
		eventManager.addEventHandler("OnLoad", self.onLoadGame)
		eventManager.addEventHandler("GameStart", self.onGameStart)
		eventManager.addEventHandler("GameEnd", self.onGameEnd)
		eventManager.addEventHandler("BeginGameTurn", self.onBeginGameTurn)
		eventManager.addEventHandler("plotPicked", self.onPlotPicked)
		

#Net Messages
		self.m_iNetMessage_Inquisitor = 0
		self.m_iNetMessage_ProphetKi = 1
		self.m_iNetMessage_ProphetEnki = 2
		self.m_iNetMessage_ProphetEnlil = 3
		self.m_iNetMessage_ProphetNanna = 4
		self.m_iNetMessage_ProphetUtu = 5
		self.m_iNetMessage_ProphetAn = 6
		
# Next War tracks cities that have been razed
		self.iArcologyCityID = -1

	def onModNetMessage(self, argsList):
		'Called whenever CyMessageControl().sendModNetMessage() is called - this is all for you modders!'
		
		iData1, iData2, iData3, iData4, iData5 = argsList
		
		print("Modder's net message!")
		
		CvUtil.pyPrint( 'onModNetMessage' )

		iMessageID = iData1
		
#Inquisitor's Effect on a City
		if ( iMessageID == self.m_iNetMessage_Inquisitor ):
			
			iPlotX = iData2
			iPlotY = iData3
			iOwner = iData4
			iUnitID = iData5
			
			pPlot = CyMap( ).plot( iPlotX, iPlotY )
			pCity = pPlot.getPlotCity( )
			pPlayer = gc.getPlayer( iOwner )
			pUnit = pPlayer.getUnit( iUnitID )
			
			self.doInquisitorPersecution( pCity, pUnit )
			
# Social Reform

btw phungus, any ideas on my predicament? You've never tried merging tsentom's stuff with LoR, have you?
 
Honestly the couple of functions I imported from Tsentom I moved over to the SDK, and it took alot of help. I think it's best to avoid python except in cases where you are manipulating the interface (in which case the UI of Civ is written in Python for the most part anyway, so it just makes sense to build off of that, as BUG has done). And No, sorry, no ideas, I'm not a programmer, I just bumble along, and try to get things working that I know are needed for LoR.
 
That error is saying the module is either not in the right place (somewhere in the Python folder hierarchy) or is misnamed--case matters.

Also, change this line

Code:
class ThomasWarEvents[s][COLOR="Red"](CvEventManager.CvEventManager)[/COLOR][/s]:

to this

Code:
class ThomasWarEvents:

BugEventManager is the only class that should subclass CvEventManager. The rest looks okay so far. Give this change a try and double-check your module placement/name. It was finding it before. Also check the init.xml where you load it to make sure you don't have extra spaces (I don't think that would matter) or odd characters.
 
@PPQ_Purple - The first block of code you posted is how BUG sets up its event manager. You cannot replace it with your own (as the code in the second block does) or BUG will cease to function. To hook up your own events or those from an existing mod, start by reading the chapter BUG Core: Events.

It looks like CvRFCEventManager is designed to replace CvEventManager just as BUG does. Sadly, this is the hardest type of mod to retrofit into BUG because you need to separate CvRFCEventManager from the CvEventManager code on which it is based.

However, it's possible that CvRFCEventManager extends CvEventManager. If that's the case, it will be a lot easier. If you post CvRFCEventManager, I'll take a quick peak to see which type it is.
So basically this block of code will determen if the two mods can be merged at all or not.

Alright, here is the RFC Event Menager:
 

Attachments

Really, really weird... I've tried a number of things, including trying to make a new .py file with only some of the elements of ThomasWarEvents.py, but no matter what, the game still says "ConfigError: No such module." I even took one module that has been working, CvCultureBombEventsManager, and replaced its contents with some ThomasWar stuff. Once I do that, the game says "ConfigError: No such module 'CvCultureBombEventManager'" The file has been neither moved nor renamed, but once I change its contents, the game says it doesn't even exist.

Here's the little bit of ThomasWar code I've been trying to get to work for starters:
Code:
# Agr_Nat
#

from CvPythonExtensions import *
import CvUtil
import CvScreensInterface
import CvDebugTools
import CvWBPopups
import PyHelpers
import Popup as PyPopup
import CvCameraControls
import CvTopCivs
import sys
import CvWorldBuilderScreen
import CvAdvisorUtils
import CvTechChooser
import GodsOfOld
import pickle

# globals
gc = CyGlobalContext()
localText = CyTranslator()
PyPlayer = PyHelpers.PyPlayer
PyInfo = PyHelpers.PyInfo
PyCity = PyHelpers.PyCity
PyGame = PyHelpers.PyGame


class Agr_Nat:
	def __init__(self, eventManager):


## Agr & Nat Trait Start ##

		player = PyPlayer(city.getOwner())
		pPlayer = gc.getPlayer(city.getOwner())

		iTrait = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_AGR')
		iTrait2 = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_NAT')

		if (pPlayer.hasTrait(iTrait)):
			city.changePopulation(1)

		NBuilding = "BUILDING_NAT_BONUS"
		AgrBuilding = "BUILDING_AGR_BONUS"

		if (pPlayer.hasTrait(iTrait2)):
			city.setNumRealBuilding(gc.getInfoTypeForString(NBuilding), 1)

		if (pPlayer.hasTrait(iTrait)):
			city.setNumRealBuilding(gc.getInfoTypeForString(AgrBuilding), 1)

## Agr & Nat Trait End ##

# Agr & Nat Trait Start #

		pPlayer = gc.getPlayer(iNewOwner)
		iX = pCity.getX()
		iY = pCity.getY()
		pPlot = CyMap().plot(iX +0, iY +0)

		iTrait = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_NAT')
		iTraitAgr = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_AGR')
		iBuildingMagLev = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_NAT_BONUS')
		iAgrTraitBonus = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_AGR_BONUS')
		iAqueduct = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_AQUEDUCT')
		iBerber = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_BERBER')
		iKalanBonus = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_KALAN_BONUS')

		if (pPlayer.hasTrait(iTrait)):
			pCity.setNumRealBuilding(iBuildingMagLev, 1)
		else:
			if pCity.getNumActiveBuilding(iBuildingMagLev) == true:
				pCity.setNumRealBuilding(CvUtil.findInfoTypeNum(gc.getBuildingInfo, gc.getNumBuildingInfos(), "BUILDING_NAT_BONUS"), False)

		if (pPlayer.hasTrait(iTraitAgr)):
			pCity.setNumRealBuilding(iAgrTraitBonus, 1)
		else:
			if pCity.getNumActiveBuilding(iAgrTraitBonus) == true:
				pCity.setNumRealBuilding(CvUtil.findInfoTypeNum(gc.getBuildingInfo, gc.getNumBuildingInfos(), "BUILDING_AGR_BONUS"), False)

		if pCity.getNumActiveBuilding(iKalanBonus) == true:
			pCity.setNumRealBuilding(CvUtil.findInfoTypeNum(gc.getBuildingInfo, gc.getNumBuildingInfos(), "BUILDING_KALAN_BONUS"), False)

# Agr & Nat Trait End #

## Agr Trait Start ##

		player = PyPlayer(pCity.getOwner())
		pPlayer = gc.getPlayer(pCity.getOwner())
		iTrait = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_AGR')

## Temp Disabled ##
#
#		if (pPlayer.hasTrait(iTrait)):
#
#			estiEnd = CyGame().getEstimateEndTurn()
#			if ( estiEnd >= 1000 ):
#				pCity.changeFood( +12 )
#			elif ( estiEnd >= 700 ):
#				pCity.changeFood( +8 )
#			elif ( estiEnd >= 500 ):
#				pCity.changeFood( +6 )
#			elif ( estiEnd >= 300 ):
#				pCity.changeFood( +4 )
#
## Agr Trait End ##

Thanks, I seriously hope we can find whatever the problem is here. Thanks so much for taking all this time and trouble
 
Back
Top Bottom