Tutorial: Detecting a new Era through the TeamTechResearched event

Bobert13

Prince
Joined
Feb 25, 2013
Messages
346
I saw this method mentioned in a number of threads but I couldn't find a concrete example of it anywhere.
Code:
function OnResearched(iTeamID, eTech, iChange)
   local pPlayer   
   --this loop assigns the pPlayer object
   for iPlayer = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
       pPlayer = Players[iPlayer]
       if (pPlayer:GetTeam() == iTeamID) then
           break
       end
   end
   
   if pPlayer ~= nil and pPlayer:IsAlive() then
       
       --print(string.format("Some Player meeting the conditions has researched a new TECH!! =P"))
       local playerEra = pPlayer:GetCurrentEra()
       local techEra = GameInfoTypes[GameInfo.Technologies[eTech].Era]
       
       if techEra > playerEra then
           --print(string.format("Tech Era > Player Era. Giving out bonus points."))
           ###Your code here###
           
       elseif techEra == playerEra then
           --print(string.format("Tech Era = Player Era. Checking to see if it's the last tech to be researched for that Era."))
           local pTeam = Teams[iTeamID]
           local newEra = true
           for row in GameInfo.Technologies() do
               local techEra = GameInfoTypes[row.Era]
               --print(string.format("playerEra = %i, techEra = %i", playerEra, techEra))
               if techEra == playerEra then
                   if (pTeam:IsHasTech(row.ID) == false) then
                       --print(string.format("Bailing because the player hasn't finished all of the techs for the Era."))
                       newEra = false
                       break
                   end
               end
           end
           if newEra then
               --print(string.format("New Era Detected based on finishing all techs of an era."))
               ###Your code here###
           end
       end
   end
end
GameEvents.TeamTechResearched.Add(OnResearched)

It's best to include a third check for some conditional in the line where we ensure the player isn't nil (city-state/barbarian) and is alive. Where I've placed ###Your code here### is where you'd either assign your bonus (unit, yield, dummy policy/building etc.) or you could call a function.

This method is robust and takes effect immediately upon entering the Era unlike SerialEventEraChanged. It's also triggered when bulbing techs through Scientests and should a mod add techs that are out of sequence we're verifying those too.
 
What if the team has more than one player ? Theoretically for the human in a single-player game this would not be much of a problem, because they'd match the team ID 1st, but their AI team-mates would be ignored in such a case. People do play as teams apparently, tho except for a MP game I still don't understand why since the AI is so fundamentally stupid and quite irritating when part of the same team as the/a human player.
 

HEY! I made a thing and it works OK? :scan:
Coming in here with your common sense. But seriously, I only saw that mentioned once in a thread upon trying multiple searches for detecting when a civ's era changed and it also included no examples (it might've been the suggestion that required incorporating SaveUtils, I can't recall).

What if the team has more than one player ? Theoretically for the human in a single-player game this would not be much of a problem, because they'd match the team ID 1st, but their AI team-mates would be ignored in such a case. People do play as teams apparently, tho except for a MP game I still don't understand why since the AI is so fundamentally stupid and quite irritating when part of the same team as the/a human player.

This is the big exception and correct me if I'm wrong here but WHoward's event would have the same issue. I'm open to suggestions if you want to contribute (pPlayer:IsActivePlayer() maybe?).
 
Tho whether using TeamSetEra or TeamTechResearched won't effect the logic of running through the list of players, here's a frankensteined-down version of TeamSetEra I've used
Code:
function UponEraAdvance(teamId, eEra)
	local pTeam = Teams[teamId]
	if pTeam:IsBarbarian() or pTeam:IsMinorCiv() then return end
	if not pTeam:IsAlive() then return end
		--tho I'm not sure how we ever get a dead team advancing in era
	for iPlayer = 0, GameDefines.MAX_MAJOR_CIVS - 1, 1 do
		local pPlayer = Players[iPlayer]
		if (pPlayer ~= nil) and (pPlayer:GetTeam() == teamId) and pPlayer:IsAlive() then
			--do stuff here
		end
	end
end
GameEvents.TeamSetEra.Add(UponEraAdvance)
The issue I was bringing up was with this part of your code
Code:
local pPlayer   
--this loop assigns the pPlayer object
for iPlayer = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
    pPlayer = Players[iPlayer]
    if (pPlayer:GetTeam() == iTeamID) then
        break
    end
end
Which only "fetches" and therefore only implements for the 1st player found who matches to the Team ID#. Granted in 95% of all conditions people are playing games where each team is composed of only one player, there's always that issue where more than one player belongs to the same team, esp in Scenarios people create.
 
So I just need to move the body of the code into the for loop so it's applied to all players?
 
That would be the way I would do it. Just be sure you create and localize your pPlayer object within the loop for each successive player being examined because otherwise the pPlayer object might give bizarro results related to what localization scope you are in when you try to refer to it, with data "hanging on" from the last time you updated the pointer-variable.
 
Top Bottom