onTechAcquired CustomCode not working correctly with Team/when giving Techs by Python

Cybah

Emperor
Joined
Jun 22, 2007
Messages
1,481
Hi.

It seems that the custom code at onTechAcquired (CvEventmanager.py) does not work if your teammate acquires the Tech instead of you or if you use sethastech on another python location.

Example:

With my custom code you should get a Great Person if you are researching Tech X.

- If you are researching Tech X, you will get the Great Person.

- If your teammate researches Tech X, that Tech will be given to you too, but you will not get the Great Person.

- If a vassal researches that Tech and a code snippet will give that Tech to you (with .sethastech), you will not get the Great Person either.


Why?
 
I know about the second part, but didn't try the first part before.

Thus, I never use setHasTech() so that my works will be compatible with other works with onTA codes.

Code:
pTeam.changeResearchProgress(iTech, pTeam.getResearchCost(iTech) - pTeam.getResearchProgress(iTech), iPlayer)
I use this instead to grant the tech so that onTA will be activated

Now that you mentioned the first part... this means there are some stuff for me to edit lol

P.S.
On a sidenote, setNumRealBuilding works like setHasTech()
It grants the building but onBuildingBuilt does not activate either
 
What do you mean with first/second part? //Edit: You mean the team, right? ;) A solution for this would be pretty nice too. :D

Thanks for that onTA Fix, and how do you handle onBuildingBuilt?
 
I mean, I know using setHasTech does not trigger onTA codes.
Thus I do not use that function at all.

However, I do not know about the part of team member getting the tech not triggering onTA for you, so probably have to do some loops to solve it.

As for setNumRealBuilding, although it does not trigger codes under onBB codes, XML effects such as Golden Age for Taj Mahal are triggered, so that didn't affect me much.
If there are python codes related to the building to be built with setNumRealBuilding, then I simply place the python codes directly in the same section after the line with setNumRealBuilding.

For instance, movie codes are triggered under onBB
Thus, if I use setNumRealBuilding to place a wonder at certain city, actually movie will not be displayed because onBB is not triggered.
Thus, I just copied the whole chunk of movie codes, do necessary modifications, and copy them after the setNumRealBuilding code

Example:
Spoiler :
Code:
	def onEndPlayerTurn(self, argsList):
		'Called at the end of a players turn'
		iGameTurn, iPlayer = argsList
## Crystal Palace Start ##
		if CyGame().getBuildingClassCreatedCount(gc.getInfoTypeForString("BUILDINGCLASS_CRYSTAL_PALACE")) == 0:
			if CyGame().getPlayerScore(iPlayer) > 4999:
				pPlayer = gc.getPlayer(iPlayer)
				capital = pPlayer.getCapitalCity()
				capital.setNumRealBuilding(gc.getInfoTypeForString("BUILDING_CRYSTAL_PALACE"), 1)
				if (not gc.getGame().isNetworkMultiPlayer()) and iPlayer == gc.getGame().getActivePlayer():
					popupInfo = CyPopupInfo()
					popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
					popupInfo.setData1(gc.getInfoTypeForString("BUILDING_CRYSTAL_PALACE"))
					popupInfo.setData2(capital.getID())
					popupInfo.setData3(0)
					popupInfo.setText(u"showWonderMovie")
					popupInfo.addPopup(iPlayer)
## Crystal Palace End ##
 
I guess we will have to modify the SDK to fix that team glitch right? Hm... should have something to do with ::updateTechShare in CvTeam.cpp.
 
I guess it depends what you do in onTA.

For me, I will just use loops to solve it.

Code:
## Cheomseongdae Start ##
		if pPlayer.getBuildingClassCount(gc.getInfoTypeForString("BUILDINGCLASS_CHEOMSEONGDAE")) == 1:
			if CyGame().getSorenRandNum(10, "Golden Age") == 0:
				pPlayer.changeGoldenAgeTurns(pPlayer.getGoldenAgeLength() /2)

This code under onTA gives a chance to trigger golden age for a player with Cheomseongdae wonder when a player researches a Tech, but since you mention about the team thingy, this means that when the team member researched the tech, this will not be triggered even if the Cheomseongdae player gets the tech as well.

Thus, what I can think of is use pTeam.getBuildingClassCount() instead, then use a loop to check who is the player with the wonder and do the same stuff.

So I guess it will be a case by case solution, but the idea is the same, loops should solve it if you do not want to use SDK
 
That is a permanent addition. What to do with single events like a GP? You cannot loop over it, you would get the GP every round. ;)

Also... I don't know why, but this does not work either:

onTechAcquired:

PHP:
# ZE: Israel 2/2 Start -----------------------------------------------------------------------------------------------
		if iTechType == gc.getInfoTypeForString("TECH_MONOTHEISM"):			
			if pZEPlayer.getCivilizationType() == gc.getInfoTypeForString("CIVILIZATION_ISRAEL"):
				iTechZE5 = gc.getInfoTypeForString("TECH_ISRAEL")
				if gc.getTeam(pZEPlayer.getTeam()).isHasTech(iTechZE5):
					capitalZE.createGreatPeople(gc.getInfoTypeForString( 'UNIT_PROPHET' ), False, False)
# ZE: Israel 2/2 End -----------------------------------------------------------------------------------------------


onBeginPlayerTurn:

PHP:
# Gameoption Hegemon/Vassal Shares Tech Start -----------------------------------------------------------------------------------------------

		if not gc.getGame().isOption(GameOptionTypes.GAMEOPTION_NO_VASSAL_STATES):
			if (gc.getGame().isOption(GameOptionTypes.GAMEOPTION_HEGEMON_SHARES_TECHS) or gc.getGame().isOption(GameOptionTypes.GAMEOPTION_VASSAL_SHARES_TECHS)):
				iTeam = pPlayer.getTeam()
				pTeam = gc.getTeam(iTeam)
				for iSharePlayer in xrange(gc.getMAX_PLAYERS()):
					vPlayer = gc.getPlayer(iSharePlayer)
					vTeam = gc.getTeam(vPlayer.getTeam())	
					if vPlayer.isAlive() and not vPlayer.isBarbarian():
						if gc.getTeam(vPlayer.getTeam()).isVassal(iTeam):
							for iTechType in xrange(gc.getNumTechInfos()):
								if gc.getTechInfo(iTechType).isTrade():
									if ((vTeam.isHasTech(iTechType)) and gc.getGame().isOption(GameOptionTypes.GAMEOPTION_VASSAL_SHARES_TECHS)):
										pTeam.changeResearchProgress(iTechType, pTeam.getResearchCost(iTechType) - pTeam.getResearchProgress(iTechType), iSharePlayer)
										# pTeam.setHasTech(iTechType, true, iSharePlayer, false, false)
									if ((pTeam.isHasTech(iTechType)) and gc.getGame().isOption(GameOptionTypes.GAMEOPTION_HEGEMON_SHARES_TECHS)):
										vTeam.changeResearchProgress(iTechType, vTeam.getResearchCost(iTechType) - vTeam.getResearchProgress(iTechType), iSharePlayer)
										# vTeam.setHasTech(iTechType, true, iSharePlayer, false, false)

# Gameoption Hegemon/Vassal Shares Tech End -----------------------------------------------------------------------------------------------


If my vassal has Monotheism, I will get it the next round (popup: wanna change to organized religion?).

But there is no tech screen and I don't get the Great Prophet. Hm? As you can see, I changed the code to changeResearchProgess. But same problem?!

Edit: Maybe because its the beginning of the vassal's round instead of mine? Do I need two different loops for that too options?
 
I did a simple test to confirm:

Code:
	def onEndPlayerTurn(self, argsList):
		'Called at the end of a players turn'
		iGameTurn, iPlayer = argsList
		
		pPlayer = gc.getPlayer(iPlayer)
		if pPlayer.getGold() > 20:
			pTeam = gc.getTeam(pPlayer.getTeam())
			iTech = gc.getInfoTypeForString("TECH_STEALTH")
			pTeam.changeResearchProgress(iTech, pTeam.getResearchCost(iTech) - pTeam.getResearchProgress(iTech), iPlayer)
Grants Stealth on next turn if player has more than 20 gold

Code:
	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
		
		if iTechType == gc.getInfoTypeForString("TECH_STEALTH"):
			pPlayer = gc.getPlayer(iPlayer)
			pPlayer.changeGoldenAgeTurns(5)
Activates 5 turns of GA if player researches stealth

Results:
The next turn after 20 gold, enters future era, gets splash screen of stealth, and GA of 5 turns start.

Thus, for your case, does the splash screen of monotheism activates? If it does, this means onTA codes have been activated. So then the problem will be part of your onTA codes
 
My code works if I am the vasall and my hegemon will research monotheism. But no splash screen the other way around (but I get the tech of cause). That makes no sense to me.
 
I believe the answer is because you use iSharePlayer for both cases.
Shouldn't the one for pTeam be iPlayer instead?

Anyway, if you use gc.getMAX_CIV_PLAYERS() instead, you can skip the barbarian check

By the way, reading your onTA codes, may I ask what pZEPlayer refers to?
I supposed it is meant to be:
If Isreal team gets Mono Tech, creates a GP at Isreal capital?
 
Omfg you are right. Thanks very much, did not see that.
 
Okay, now we have to get rid of the team problem, if possible.
 
By the way, reading your onTA codes, may I ask what pZEPlayer refers to?
I supposed it is meant to be:
If Isreal team gets Mono Tech, creates a GP at Isreal capital?

So I need to know how it is intended to function :D
 
pZEPlayer is just another pPlayer instance. ZE is a shortcut for "Civilization specific Traits" in German. ;) So yes, you are right.
 
See if this works
Code:
# ZE: Israel 2/2 Start ----------------------------------------------------------------------------------------------- 
		if iTechType == gc.getInfoTypeForString("TECH_MONOTHEISM"):
			if gc.getTeam(iTeam).isHasTech(gc.getInfoTypeForString("TECH_ISRAEL")):
				for iPlayerX in range(gc.getMAX_CIV_PLAYERS()):
					pPlayerX = gc.getPlayer(iPlayerX)
					if pPlayerX.isAlive() and pPlayerX.getTeam() == iTeam:
						if pPlayerX.getCivilizationType() == gc.getInfoTypeForString("CIVILIZATION_ISRAEL"):
							capitalZE = pPlayerX.getCapitalCity()
							capitalZE.createGreatPeople(gc.getInfoTypeForString( 'UNIT_PROPHET' ), False, False)
# ZE: Israel 2/2 End -----------------------------------------------------------------------------------------------
 
I've splitted the code now, so that always the active player will get the tech. Should be more accurate:

PHP:
# Gameoption Hegemon Shares Tech Start -----------------------------------------------------------------------------------------------

		if not gc.getGame().isOption(GameOptionTypes.GAMEOPTION_NO_VASSAL_STATES):
			if gc.getGame().isOption(GameOptionTypes.GAMEOPTION_HEGEMON_SHARES_TECHS):
				pPlayer = gc.getPlayer(iPlayer)
				iTeam = pPlayer.getTeam()
				pTeam = gc.getTeam(iTeam)
				if pTeam.isAVassal():				
					for iSharePlayer in xrange(gc.getMAX_CIV_PLAYERS()):
						vPlayer = gc.getPlayer(iSharePlayer)
						vTeam = gc.getTeam(vPlayer.getTeam())	
						if vPlayer.isAlive():
							if pTeam.isVassal(vPlayer.getTeam()):
								for iTechType in xrange(gc.getNumTechInfos()):
									if gc.getTechInfo(iTechType).isTrade():
										if vTeam.isHasTech(iTechType):
											pTeam.changeResearchProgress(iTechType, pTeam.getResearchCost(iTechType) - pTeam.getResearchProgress(iTechType), iPlayer)
											# pTeam.setHasTech(iTechType, true, iPlayer, false, false)

# Gameoption Hegemon Shares Tech End -----------------------------------------------------------------------------------------------
# Gameoption Vassal Shares Tech Start -----------------------------------------------------------------------------------------------

			if gc.getGame().isOption(GameOptionTypes.GAMEOPTION_VASSAL_SHARES_TECHS):
				pPlayer = gc.getPlayer(iPlayer)
				iTeam = pPlayer.getTeam()
				pTeam = gc.getTeam(iTeam)
				if not pTeam.isAVassal():				
					for iSharePlayer in xrange(gc.getMAX_CIV_PLAYERS()):
						vPlayer = gc.getPlayer(iSharePlayer)
						vTeam = gc.getTeam(vPlayer.getTeam())	
						if vPlayer.isAlive():
							if vTeam.isVassal(pPlayer.getTeam()):
								for iTechType in xrange(gc.getNumTechInfos()):
									if gc.getTechInfo(iTechType).isTrade():
										if vTeam.isHasTech(iTechType):
											pTeam.changeResearchProgress(iTechType, pTeam.getResearchCost(iTechType) - pTeam.getResearchProgress(iTechType), iPlayer)
											# pTeam.setHasTech(iTechType, true, iPlayer, false, false)

# Gameoption Vassal Shares Tech End -----------------------------------------------------------------------------------------------

Works.


If that works in python... we should find a SDK solution too.
 
See if this works
Code:
# ZE: Israel 2/2 Start ----------------------------------------------------------------------------------------------- 
		if iTechType == gc.getInfoTypeForString("TECH_MONOTHEISM"):
			if gc.getTeam(iTeam).isHasTech(gc.getInfoTypeForString("TECH_ISRAEL")):
				for iPlayerX in range(gc.getMAX_CIV_PLAYERS()):
					pPlayerX = gc.getPlayer(iPlayerX)
					if pPlayerX.isAlive() and pPlayerX.getTeam() == iTeam:
						if pPlayerX.getCivilizationType() == gc.getInfoTypeForString("CIVILIZATION_ISRAEL"):
							capitalZE = pPlayerX.getCapitalCity()
							capitalZE.createGreatPeople(gc.getInfoTypeForString( 'UNIT_PROPHET' ), False, False)
# ZE: Israel 2/2 End -----------------------------------------------------------------------------------------------


I understand. Nice idea. Will try it out and report back.
 
By the way, looking at the concept of the BeginPlayerTurn, it is looping through every player to check whether he is a vassal, then loop through the whole list of techs to see if there is a tech that vassal has that master does not and vice versa every single turn.

Why not rewrite the whole thing under onTA instead?
Such that, when a player gains a tech, check if he is a vassal or master, then gives the tech to the other player as well.
This way, it is only activated when tech is gained rather than every single turn. And you only check the new tech gained rather than loop through the whole list of techs

Also, since you are looping through every single tech, and granting to the other player, those techs that are not researchable like TECH_ISRAEL will be granted as well...
 
Top Bottom