Merging BUG with other Mods

That block is only skipped with cheating enabled (which I have for debugging purposes) but yeah, jdog also did his thing a few lines below. And no, I don't think he's using the OtherRelationsString, you have 1 line of code there for war/worst enemy where he has over 50.
I guess I can leave the Deals thing in though, I just won't see them there.

So much for the scoreboard hover.
What interests me a bit more is the new Actual Buildings Effect part, Defence. Where is this new feature supposed to be visible and what values should it display? I fear something isn't working as it should, for me at least.

---
 
There was an existing empty hover for the City Defense shown at the top-center of the City Screen. Afforess built one for his mod, so I added on to BULL to support BTS and other modders. It shows the effects of culture, buildings, wonders (Chichen Itza) and bombardment (damage). It also shows what buildings you can build to affect it.

The building hover's Actual Effects now includes the defense as well.

Are you asking why the defense is +0% in one place and +10% in another? That's because defense = max(buildings, culture) + wonders, so Walls won't provide a benefit for a city with culture level 60% and only 10% to one at 40%. The Defense hover on the City Screen makes this a little clearer.

Note that the effect to Bombard Defense isn't shown on the building hover yet because I need a new icon to represent it. It is shown on the Defense hover in a separate section.
 
One more detail about game mechanics I still had to learn then. Slowly but surely BUG still keeps teaching me :)
For the icon, couldn't you just use 2? The tower icon for defence plus one more, catapult/explosion/imact themed. For a single icon solution, I envision the tower in the foreground and the explosion in the background.
Someone would still have to create those icons though.
 
I maybe should ask this quesiton in the Python/SDK forums, but I'm sure someone on the BUG team has a better idea anyway, and also BUG might change it (and RevDCM uses a RevDCM base). I'd like to add a the UnitKilled sound you hear when a unit with an attached GG dies to units that are over level 10 and also to units that are WorldWonderClass units. Where is this function handled, the one that adds the sound to Warlord led units?
 
oops...wrong thread
 
OK, I've merged my EventsManager wrong...

I've got a couple of different mods comp'd into what I play. As a result, I've got bits from all over the place. There're two in particular that require mods in the EventManager though.

So, here's the contents of what is currently called "CvRichModEventManager.py" in BtS\Mods\BUG & BULL Mod\Assets\Python\Contrib\RichModUtils:

Spoiler :
Code:
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

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


# globals
# ##################################################
class CvEventManager:
	def __init__(self):
		# ######################
		# ### RichMod Worker Forest Fix ###
		# ######################
                self.pPlot_remembered = [-1,""]
		# ###############
		# ### RichMod ends ###
		# ###############
				
	def onBeginPlayerTurn(self, argsList):
		'Called at the beginning of a players turn'
		iGameTurn, iPlayer = argsList
		# ########################
		# ### RichMod Worker Forest Fix ###
		# is checking all tiles whether some of them had the forest planted in last turn and then removes improvement
		# ########################
		if (self.pPlot_remembered[0] != -1):
			self.pPlot_remembered[0] += 1
			if (self.pPlot_remembered[0] > 3):
				self.pPlot_remembered[1].setImprovementType(-1)
				self.pPlot_remembered = [-1,""]
				# ##############
				# ### RichMod ends ###
				# ##############

	def onImprovementBuilt(self, argsList):
		'Improvement Built'
		iImprovement, iX, iY = argsList

		# ##############################################################
		# ### RichMod : when improvement finished then remove improvement(delayed) and create a feature	###
		# ##############################################################
		pPlot = CyMap().plot(iX,iY)
		if(iImprovement==gc.getInfoTypeForString('IMPROVEMENT_NEW_FOREST')):
			pPlot.setFeatureType(4, 0)
			CyInterface().addMessage(CyGame().getActivePlayer(),True,25,'A new forest has been planted!','AS2D_DISCOVERBONUS',1,'Art/Interface/Buttons/TerrainFeatures/Forest.dds',ColorTypes(8),iX,iY,True,True)
			self.pPlot_remembered = [1,pPlot]		
		if(iImprovement==gc.getInfoTypeForString('IMPROVEMENT_NEW_FORESTW')):
			pPlot.setFeatureType(4, 1)
			CyInterface().addMessage(CyGame().getActivePlayer(),True,25,'A new forest has been planted!','AS2D_DISCOVERBONUS',1,'Art/Interface/Buttons/TerrainFeatures/Forest.dds',ColorTypes(8),iX,iY,True,True)
			self.pPlot_remembered = [1,pPlot]
			# ################
			# ### RichMod ends ###
			# ################

	def onBuildingBuilt(self, argsList):
		'Building Completed'
		pCity, iBuildingType = argsList
		game = gc.getGame()

# #############################
# ## RichMod - The School of Confucius Start ###
# #############################
		if ( iBuildingType == gc.getInfoTypeForString("BUILDING_PALACE_CHINA") ):

			pPlayer = gc.getPlayer(pCity.plot().getOwner())
			iPID = pPlayer.getID()
			iTID = pPlayer.getTeam()
			iX = pCity.getX()
			iY = pCity.getY()
			b_school = gc.getInfoTypeForString("BUILDING_PALACE_CHINA")
			u_prophet = gc.getInfoTypeForString( 'UNIT_PROPHET' )
			u_artist = gc.getInfoTypeForString( 'UNIT_ARTIST' )
			u_scientist = gc.getInfoTypeForString( 'UNIT_SCIENTIST' )
			u_merchant = gc.getInfoTypeForString( 'UNIT_MERCHANT' )
			u_engineer = gc.getInfoTypeForString( 'UNIT_ENGINEER' )
			u_general = gc.getInfoTypeForString( 'UNIT_GREAT_GENERAL' )
			u_spy = gc.getInfoTypeForString( 'UNIT_GREAT_SPY' )

			self.iGreatPeopleNumberOne = self.getRandomNumber( 6 )
			self.iGreatPeopleNumberTwo = self.getRandomNumber( 6 )

			for i in range(1):
				if self.iGreatPeopleNumberOne == 0:
					pNewUnit = pPlayer.initUnit( u_prophet, iX, iY, UnitAITypes.UNITAI_PROPHET, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_PROPHET", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberOne == 1:
					pNewUnit = pPlayer.initUnit( u_artist, iX, iY, UnitAITypes.UNITAI_ARTIST, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_ARTIST", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberOne == 2:
					pNewUnit = pPlayer.initUnit( u_scientist, iX, iY, UnitAITypes.UNITAI_SCIENTIST, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_SCIENTIST", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberOne == 3:
					pNewUnit = pPlayer.initUnit( u_merchant, iX, iY, UnitAITypes.UNITAI_MERCHANT, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_MERCHANT", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberOne == 4:
					pNewUnit = pPlayer.initUnit( u_engineer, iX, iY, UnitAITypes.UNITAI_ENGINEER, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_ENGINEER", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberOne == 5:
					pNewUnit = pPlayer.initUnit( u_general, iX, iY, UnitAITypes.UNITAI_GENERAL, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_GENERAL", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberOne == 6:
					pNewUnit = pPlayer.initUnit( u_spy, iX, iY, UnitAITypes.UNITAI_MERCHANT, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_SPY", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)

			for i in range(1):
				if self.iGreatPeopleNumberTwo == 0:
					pNewUnit = pPlayer.initUnit( u_prophet, iX, iY, UnitAITypes.UNITAI_PROPHET, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_PROPHET", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberTwo == 1:
					pNewUnit = pPlayer.initUnit( u_artist, iX, iY, UnitAITypes.UNITAI_ARTIST, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_ARTIST", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberTwo == 2:
					pNewUnit = pPlayer.initUnit( u_scientist, iX, iY, UnitAITypes.UNITAI_SCIENTIST, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_SCIENTIST", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberTwo == 3:
					pNewUnit = pPlayer.initUnit( u_merchant, iX, iY, UnitAITypes.UNITAI_MERCHANT, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_MERCHANT", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberTwo == 4:
					pNewUnit = pPlayer.initUnit( u_engineer, iX, iY, UnitAITypes.UNITAI_ENGINEER, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_ENGINEER", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberTwo == 5:
					pNewUnit = pPlayer.initUnit( u_general, iX, iY, UnitAITypes.UNITAI_GENERAL, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_GENERAL", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
				if self.iGreatPeopleNumberTwo == 6:
					pNewUnit = pPlayer.initUnit( u_spy, iX, iY, UnitAITypes.UNITAI_MERCHANT, DirectionTypes.NO_DIRECTION )
					szTitle = localText.getText( "TXT_KEY_SCHOOL_SPY", ( ) )
					CyInterface().addImmediateMessage( szTitle , None)
# ############################
# ## RichMod - The School of Confucius End ###
# ############################

# ################### TRIGGERED EVENTS ##################	
				
# #####################
# RichMod: The School of Confucius Start ###
# #####################

	def getRandomNumber(self, int):
		return CyGame().getSorenRandNum(int, "Gods")
# #####################
# RichMod: The School of Confucius End ###
# #####################

And here's the "RichMod.xml" file from \BtS\Mods\BUG & BULL Mod\Assets\Config:
Spoiler :
Code:
<mod id="RichMod" 
	 name="RichMod" 
	 author="Richard" 
	 version="1.0" 
	 date="10/30/2008"
	 url="http://forums.civfanatics.com/showthread.php?t=241801">
	 
	<events module="CvRichModEventManager">
		<!--arg type="key" value="Alt Ctrl N"/-->
	</events>
</mod>

Now, the intended effect of the Python above is that when a certain Wonder is built, two random Great People appear in the city in which it was built. Also, the Events file is supposed to take care of replacing a certain tile improvement, once built, with a Forest feature. Neither effects work.

It just occurred to me: could my problem be that I've got two things trying to run from the same Event's file? That doesn't make any sense, does it?
 
If you don't specify a class attribute for your <events> element, it is assumed to be the same name as the module. Change it to this:

Code:
<events module="CvRichModEventManager" class="CvEventManager"/>
		[s]<!--arg type="key" value="Alt Ctrl N"/-->[/s]
	[s]</events>[/s]

The stuff I scratched out after it isn't needed here, so remove it. Make sure you use "/>" at the end of that <events> element, too. Finally, while not mandatory, it's not a great idea to use the same name CvEventManager as the one from the module with the same name. It's okay, just a little confusing.

Instead of the above you could rename your class and leave the XML as-is:

Code:
class CvRichModEventManager:

The choice is yours.
 
Ok, I must have done something worng, because it still doesn't work at all...

My CvRichModEventManager.py now has this after the import list:
Code:
class [B]CvRichModEventManager[/B]:
	def __init__(self):

And my XML looks like this now:
Code:
<mod id="RichMod" 
	 name="RichMod" 
	 author="Richard" 
	 version="1.0" 
	 date="10/30/2008"
	 url="http://forums.civfanatics.com/showthread.php?t=241801">
	[B]<events module="CvRichModEventManager"/>[/B]
</mod>

I thought your advice about changing the name of the class in Python was the better to follow. Did I misunderstand what you were trying to say? Or have I just got the code written wrong? It's not possible to include the entire original EventsManager is it? That screws everything up, doesn't it?

Also, I've added Sevo's MasteryVictory to my mod. And so now I get the Events alerts every turn about exceeding the land and population minimums for a Domination victory. How would I turn that alert off? Oh, and while I'm at it, do you know if it's possible to extend how many lines the alerts list has? I'd like to extend the list to 9 lines instead of the current 6 (the benefits of having a nice big screen... ;)).
 
Yes, you did that correctly. Do not include the original CvEventManager. Change the __init__ line to this:

Code:
def __init__(self[B][COLOR="Red"], eventManager[/COLOR][/B]):

Note the comma. And now for every onXXX() function you need to tell eventManager to add your handler for the event. Unfortunately I didn't automate this part in BUG. :(

Code:
class CvRichModEventManager:
	def __init__(self, eventManager):
		[B][COLOR="Red"]eventManager.addEventHandler("BeginPlayerTurn", self.onBeginPlayerTurn)[/COLOR][/B]

You need one line as above for each onXXX() you have. Look up the event type (part in quotes--"xxx") to use for each function in BTS's CvEventManager.

You can turn off the domination alerts on the Alerts tab of the BUG Options screen (ALT + CTRL + O). I have no idea how to expand the message area. :(
 
So, I have four def statements (and the __init__ of course) in my RichModEventManager. They should look like this?
Code:
class CvRichModEventManager:
	def __init__(self, eventManager):
		blah blah

	def onBeginPlayerTurn(self, argsList):
		eventManager.addEventHandler("BeginPlayerTurn", self.onBeginPlayerTurn)
		blah blah

	def onImprovementBuilt(self, argsList):
		eventManager.addEventHandler("ImprovementBuilt", self.onImprovementBuilt)
		blah blah

	def onBuildingBuilt(self, argsList):
		eventManager.addEventHandler("BuildingBuilt", self.onBuildingBuilt)
		blah blah

	def getRandomNumber(self, int):
		return CyGame().getSorenRandNum(int, "Gods")
 
No, you need to add those lines to the __init__() function as I showed in my post. Move all those addEventHandler() calls up into __init__().
 
Actually, I just finished comparing my RichModEventMngr to the old GGfBCEventMngr file, and discovered just that. Fixed where things are listed, and tried again. Unfortunately, it still doesn't work... :eek:

Do the addEventHandler() entries need to be listed in reverse order from how they written in file? Just noticing that they happen to be in the GGfBCEM. Going to try having the RichMod file in my CustomAssets directiry. That shouldn't make any difference, I know, but I've come across such weirdness in my mod before... :crazyeye:
 
No, the order of the addEventHandler() calls only affects the order in which those handlers are called if there is more than one handler registered for a single event type. In this case, it won't matter between those three functions. If you turn on BUG's logging on the System tab (set File Log Level to DEBUG), you can see as each handler is registered and called in Logs/PythonDbg.log. Just do find on the name of your class.
 
No, the order of the addEventHandler() calls only affects the order in which those handlers are called if there is more than one handler registered for a single event type. In this case, it won't matter between those three functions. If you turn on BUG's logging on the System tab (set File Log Level to DEBUG), you can see as each handler is registered and called in Logs/PythonDbg.log. Just do find on the name of your class.
 
OK, that file shows that BUG is finding the directory of where my mod is, but it's not being loaded. Although, GGfBC loads just fine...

Spoiler PythonDbg.log :
8. Using moduleSearchDirs: python\
9. Using moduleSearchDirs: python\contrib\ggfbc modutils\
10. Using moduleSearchDirs: python\contrib\richmodutils\
11. Using moduleSearchDirs: python\pywb\

blah blah

01:40:19 DEBUG: BUG: looking up BugCreditsOptionsTab.BugCreditsOptionsTab
load_module BugCreditsOptionsTab

01:40:19 DEBUG: BugConfig - loading mod file GGfBC Mod
01:40:19 DEBUG: BugInit - loading mod GGfBC Mod...
01:40:19 INFO : BugCore - creating uninitialized mod GGfBC Mod
01:40:19 DEBUG: BUG: looking up CvGGfBCModEventManager.CvGGfBCModEventManager
load_module CvGGfBCModEventManager

load_module CvConfigParser

load_module ConfigParser

load_module CvPath

01:40:20 DEBUG: Timer - load mod [GGfBC Mod] took 249 ms
01:40:20 DEBUG: Timer - load mod [init] took 2993 ms
01:40:20 DEBUG: Timer - BUG init [read configs] took 2993 ms
01:40:20 DEBUG: BugInit - calling init functions...
load_module BugFinanceAdvisor


I guess my error is more basic... I'm sure I haven't made a stoopid spelling mistake...

EDIT (02:30 EST): Ok, the module gets loaded now. I hadn't listed RichMod in the init.xml file in Assets\Config. Still doesn't work though. :wallbash:
 
Do you see anything interesting in the logs (Dbg or Err)? Can you be more specific than "it doesn't work"?
 
I'm sorry EF, I wish I could... :(

The Dbg log shows both modules being loaded (RichMod & GGfBC). But, whereas GGfBC works as expected, I get no functionality from RichMod at all. The effects of it should be, that upon construction of a certain improvement (New Forest in this case) the game should then delete that improvement and replace it with the actual Feature, Forest. The other effect is that upon building a certain Wonder, two random Great People should be created.

  • I've double-checked to make sure the code as written is the same as original mods I D/L'd.
  • I've confirmed no spelling errors.
  • I've fixed the "Class" name of RichMod, as you instructed.
  • I've listed the addEvent lines in RichMod, also as instructed.
  • I've corrected Init.xml, so the RichMod module is now loaded (confirmed in PythonDbg.log).
  • The Python error logs show nothing suspicious (PythonErr.log is empty, Err2 shows the usual long list of stuff, no references to either of my modules there).
  • All the other Log files look normal too, no references to either of my modules in any of them.

I don't know how else to troubleshoot this error. How to you go about finding something that isn't firing? If it were firing wrong, that'd be easy. But this module doesn't fire at all. No error messages, no logs, no "strange" behaviour, nadda. There is simply no effect from the module. It's like it doesn't exist, and I just have a neat Build order and pretty Wonder button.

An idea :think:: Could the problem be that I have two separate effects in one file? Should I have one file for the Forest and a different one for the GP's?
 
Sorry I didn't reply earlier. The forum seems to be on-and-off for me right now.

No, you shouldn't need to split apart your module at all. I bet the problem is that the events are not being registered for some reason. Can you post PythonDbg.log? Open it up and look for your mod's ID (the id="..." in the <mod> element). Also look for the name of your class. BUG will report as each event handler is registered and again when they fire. Also post the whole Python module (file).
 
Civ4 is very particular about its event IDs. You must use the strings from CvEventManager exactly, including case. From the log file I see

Code:
02:22:25 DEBUG: BugEventManager - adding event '[B]ImprovementBuilt[/B]'
02:22:25 DEBUG: BugEventManager - adding event '[B]BuildingBuilt[/B]'

but looking in CvEventManager I see

Code:
'[B]i[/B]mprovementBuilt' 		: self.onImprovementBuilt,
'[B]b[/B]uildingBuilt' 		: self.onBuildingBuilt,

The first letter of each should be lowercase.
 
Back
Top Bottom