Modules and the Eventmanager

In that event handler, it is assigning one of the values from argsList (passed from the DLL) to a temporary variable called iGameTurn. You don't have the same argsList in the canDeclareWar() callback, so you must get it from the CyGame:

Code:
iGameTurn = gc.getGame().getGameTurn()

Now you can use your own variable holding the current game turn called iGameTurn. You could call it iBob if you wanted--variable names only have significance to humans--but that would be misleading. iGameTurn sounds like a good name. :)
 
Okay, I ran into another problem. I got the GameUtils set up fine, but there is a problem with my Python code from the Warlords version. It seems BtS changed the declareWar function:
Code:
VOID declareWar (TeamType eTeam, BOOL bNewDiplo, WarPlanType eWarPlan)
void (int /*TeamTypes*/ eTeam, bool bNewDiplo, int /*WarPlanTypes*/ eWarPlan) - Forces your team to declare War on iTeam
Which adds the WarPlanTypes integer. I'm just wondering what that does before I go stick an arbitrary value in without knowing what it does.
 
Just pass in -1 or WarPlanTypes.NO_WARPLAN. This is used by the AI in some way which you can find by digging into the SDK code.
 
Okay thanks for that. I have yet another question though, which I find really odd. I'm trying to use the setPythonModule function so that I can place the popup function in the same module rather than in CvScreensInterface. I tried using this line:
Code:
popupInfo.setPythonModule("CvHastingsEvents")
but the game complained that it couldn't find the module. I checked the spelling over, and anything else I could think of, but it doesn't work. Any suggestions?

Here is the whole function
Code:
def walesAttackNormandy():
	WALES_TEAM.declareWar(NORMANDY_TEAM_ID, false, -1) ## Sets Wales at war with Normandy
	if NORMANDY_PLAYER.isHuman(): ## gives the human a popup in playing as Normandy
		popupInfo = CyPopupInfo()
		popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON) ## set popup type
		popupInfo.setText(CyTranslator().getText("TXT_KEY_CIV_POPUP_WELSH_ATTACK",())) ## set text
		popupInfo.setData1(NORMANDY_PLAYER_ID)
		popupInfo.setOnClickedPythonCallback("walesPopup") ## call walesPopup function below
		popupInfo.setPythonModule("CvHastingsEvents") ## allows walesPopup to exist in a different module
		popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_CIV_POPUP_WELSH_ATTACK_R1", ()), "") ## Do nothing
		popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_CIV_POPUP_WELSH_ATTACK_R2", ()), "") ## Send units to Wales for 100 gold
		popupInfo.addPopup(NORMANDY_PLAYER_ID) ## Adds Popup
	else:
		williamToWales() ## AI chooses to send the units
		
def walesPopup(argsList):
	iButtonId = argsList[0]
	iData1 = argsList[1]

	pPlayer = gc.getPlayer(iData1)
	if iButtonId == 0:
		pass
	if iButtonId == 1:
		williamToWales()
	
## Sends units to Wales
def williamToWales():
	iKnight = gc.getInfoTypeForString("UNIT_NORMANKNIGHT")
	iXBow = gc.getInfoTypeForString("UNIT_NORMANCROSSBOW")
	## 2 Knights and 3 crossbows to Wales
	NORMANDY_PLAYER.initUnit(iKnight, 50, 24, UnitAITypes.NO_UNITAI)
	NORMANDY_PLAYER.initUnit(iKnight, 50, 24, UnitAITypes.NO_UNITAI)
	NORMANDY_PLAYER.initUnit(iXBow, 50, 24, UnitAITypes.NO_UNITAI)
	NORMANDY_PLAYER.initUnit(iXBow, 50, 24, UnitAITypes.NO_UNITAI)
	NORMANDY_PLAYER.initUnit(iXBow, 50, 24, UnitAITypes.NO_UNITAI)

	NORMANDY_PLAYER.changeGold(-100) ## Remove 100 gold
 
From what I can tell, the SDK and EXE can only call functions in the modules in the EntryPoints folder, and even further only those that already exist in the original BTS EntryPoints. It will use the new module you have in your mod folder, but it must be a module name that was already in BTS's EntryPoints folder.

However, I think there's a slick way around this due to the coolness that is Python. Try this out and lemme know how it works:

Code:
		...
		popupInfo.setOnClickedPythonCallback("walesPopup") ## call walesPopup function below
		[B][COLOR="Red"][s]popupInfo.setPythonModule("CvHastingsEvents") ## allows walesPopup to exist in a different module[/s][/COLOR][/B]
		popupInfo.addPythonButton(CyTranslator().getText("TXT_KEY_CIV_POPUP_WELSH_ATTACK_R1", ()), "") ## Do nothing
		...

def walesPopup():
	...
		williamToWales()

[COLOR="DarkGreen"]import CvScreensInterface
CvScreensInterface.walesPopup = walesPopup[/COLOR][/B]

## Sends units to Wales
...

This will make BTS think that your walesPopup() function exists in CvScreensInterface. Please let me know if this works.
 
Thats really interesting, it seems to work. :D I'm getting a new problem though, there is a new argument in the initUnit function called DirectionTypes. I thought it was an integer, but apparently not since I stuck a -1 in and it still threw an error. I tried looking through the source code, but that didn't seem to get me anywhere.

What kind of value should I put in there, and how do I find what the code does in the source if I don't understand C++ really at all?
 
It takes a DirectionTypes which is an enumeration--a constrained integer value in C++. The Python API should accept an integer as well, but -1 won't work. You need to give it one of the 8 directions to face your new unit, and DirectionTypes.DIRECTION_SOUTH (facing the player) should work.
 
Great thanks. Where can I find these sorts of things though? I seem to get hung up on the values, and if its in the SDK I get lost trying to find it. I can find the argument itself (i.e. DirectionTypes) but I can't ever find what values are acceptable. :(
 
Greetings,
I'm a new poster in this forum, but I've been lurking around this site for quite some time. I learned how to deal with XML files, however Python for me is still a huge pain in the ass. I absolutely suck at it. Anyway, I've been trying to merge two different CvEventManager files: one from Limited Religions and other from Female Great People ModComp. Separated, they both work well, but I couldn't find a way to make them work at the same time. After some failed experiments, I found this topic and decided to follow EmperorFool's advice on the second post. It was the closest I could get to success, but something's gone wrong and I can't figure what it is. I put the following text on the alternate CvEventManager file:
Spoiler :
PHP:
# HolyCityEventManager.py

import CvEventManager

class HolyCityEventManager(CvEventManager):

	def __init__(self):
		CvEventManager.__init__(self)

	def onBeginPlayerTurn(self, argsList):
		'Called at the beginning of a players turn'
		iGameTurn, iPlayer = argsList
		
		# Limited Religions	
		if LimitedReligions.NonStateHolyCityReligionSpreadCheck(iPlayer):
			LimitedReligions.doNonStateHolyCityReligionSpread(iPlayer)
		# Limited Religions	
		
	def onTechAcquired(self, argsList):
		'Tech Acquired'
		iTechType, iTeam, iPlayer, bAnnounce = argsList
		# Note that iPlayer may be NULL (-1) and not a refer to a player object
		# Limited Religions		
		game = CyGame()
		pPlayer = gc.getPlayer(iPlayer)
		FoundRel = False
				
		if iPlayer > -1:
			# Is this a religious Tech?
			if LimitedReligions.isReligiousTech(iTechType):
				# Is the game option selected for Limited Religions?
				if LimitedReligions.isOC_LIMITED_RELIGIONS():
					# Skip dead players and Barbarions
					if pPlayer.isAlive() and not pPlayer.isBarbarian():
						# Must not already have a Holy City
						if not LimitedReligions.OwnsHolyCity(iPlayer):
							# Loop through all religions
							for iSlot in range(gc.getNumReligionInfos()):
								# Does the player have the prerequisite tech for this religion slot?
								if gc.getTeam(pPlayer.getTeam()).isHasTech(gc.getReligionInfo(iSlot).getTechPrereq()):
									# Must be at least one religion slot available
									if not game.isReligionSlotTaken(iSlot):
										# The number of religious techs discovered must be greater than total religions founded.
										if LimitedReligions.RelTechsGreaterThanReligions:
											# PreConditions are met to found a religion.
											# If the active player is Human
											if iPlayer == gc.getGame().getActivePlayer() and pPlayer.isHuman:
												# Choose religions option on?												
												if game.isOption(GameOptionTypes.GAMEOPTION_PICK_RELIGION):
													# If Autoplay is running, Let the game pick the religion.
													if( game.getAIAutoPlay() > 0 ):
														FoundRel = True
														break
														
													else:
														#Display the popup to pick a religion
														#CyInterface().addImmediateMessage("Pick Religion", "")
														popupInfo = CyPopupInfo()
														popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_FOUND_RELIGION)
														popupInfo.setData1(iSlot)
														popupInfo.addPopup(iPlayer)
														break
														
												else:
													# Not Playing Choose Religions, So let the game pick the religion.
													#CyInterface().addImmediateMessage("C", "")
													FoundRel = True
													break
											
											else:												
												# Not Human, So let the game pick the religion.
												#CyInterface().addImmediateMessage("Found a Religion", "")
												FoundRel = True
												break
							
							if FoundRel:
								if game.isOption(GameOptionTypes.GAMEOPTION_PICK_RELIGION):
									# Get Civ's Favorite religion or random pick if favorite religion is not available.
									iNewReligion = LimitedReligions.AI_chooseReligion(iPlayer)
									if iNewReligion != -1:
										# Found the religion.
										#CyInterface().addImmediateMessage("Found Favorite Religion", "")
										pPlayer.foundReligion(iNewReligion, iSlot, True)
								
								else:
									for i in range(gc.getNumReligionInfos()):
										if gc.getReligionInfo(i).getTechPrereq() == iTechType:
											if not gc.getGame().isReligionFounded(i):
												# Found the religion.
												#CyInterface().addImmediateMessage("Found Prerequisit Religion", "")
												pPlayer.foundReligion(i,i,True)
# End Limited Religions Mod
		
		# Show tech splash when applicable
		if (iPlayer > -1 and bAnnounce and not CyInterface().noTechSplash()):
			if (gc.getGame().isFinalInitialized() and not gc.getGame().GetWorldBuilderMode()):
				if ((not gc.getGame().isNetworkMultiPlayer()) and (iPlayer == gc.getGame().getActivePlayer())):
					popupInfo = CyPopupInfo()
					popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
					popupInfo.setData1(iTechType)
					popupInfo.setText(u"showTechSplash")
					popupInfo.addPopup(iPlayer)
				
		if (not self.__LOG_TECH):
			return
		CvUtil.pyPrint('%s was finished by Team %d' 
			%(PyInfo.TechnologyInfo(iTechType).getDescription(), iTeam))
And I kept Female Great People ModComp's CvEventManager as the basis. But then, when I play the mod, I can't found a religion, nor can the AI.
Could someone please help me? I thank you beforehand.
 
Because LimitedReligions is not imported?
Anyway, enable python exceptions to tell you what went wrong.

And personally I never liked the idea of separating python into modules.
Although it makes merging and deletion easier, it clouds your overall vision of what is going on.

If you have 10 chunks of codes being activated onUnitBuilt for instance, when they are all in the same CvEventManager file, you can tell exactly what is going on and the end result.

1) Separating them into 10 modules, you cannot tell what is gonna happen unless you open all the module folder one by one and look at 10 CvEventManager to try and figure out what is going on.
2) And worse, when you want to change something in onCityBuilt for instance, there is nothing to inform you whether those 10 modules made a change to it, unless you open them again, whereas if I only have 1 CvEventManager, I can tell straightaway there is no code there, while there are 10 codes onUnitBuilt.
3) Ordering of codes is important as it is usually top down basic. Good luck when they are in 10 modules.
 
I didn't import LimitedReligions because, in this extension - or module, if you will - I put all the customized info I found in the LimitedReligions file in order to complement the CvEventManager file I used as a basis (sorry, I don't know the jargons, but then, as I said, I'm a total noob at Python). Anyway, at least that's what I understood from Emperor's suggestion.

I tried to put both custom infos in the same files (because one deals with "onTechAcquired" and other with "onGreatPersonBorn", I believe there isn't a conflict), but it turned out worse than when I tried the compilation. The new tech announcements wouldn't even show up. So, I don't know if it's possible. Probably is, but certainly there's something more than replacing codes, I guess...

What would you suggest, then?
 
By now, this python exception should be stickied somewhere...

You can switch these on in your CivilizationIV.ini file
Code:
; Set to 1 for no python exception popups
HidePythonExceptions = 0

Activate it and see what error messages you get.

As for my suggestion, I always place all my python codes in same file rather than in 1000 different modules.
It is actually destructive rather than constructive when I want to modify a particular area and end up having to open 1000 modules just to see if there is any conflict with another module.

Placing them all in the same file, I can see exactly which of the 1000 modules modify the area I intended to modify and I can immediately see if there is any conflict.
 
Amazing how such a small detail can screw everything up...
Worked like a charm. Or at least it seems. LimitedReligions works fine, but I guess it will take further gaming to see if the Great People configuration is working as well. And I have to agree, it's definitely easier to deal with the main file only. Anyway, thank you very much for your help!
 
Back
Top Bottom