How do you catch an era change event in Lua?

isau

Deity
Joined
Jan 15, 2007
Messages
3,071
I'm trying to use Lua to catch an event when a particular player changes eras. I'm not very experienced with Lua and don't have any really good ideas on how to use Firetuner or figure out what parameters each Event uses. I mainly rely on code I see in the existing scenarios which I repurpose (very painfully).

I ventured out a little and tried this:

Code:
local function fnQuo_FreeCivicBoostOnEraChange( pPlayer )

    print ('ERA CHANGED.') ;
end
GameEvents.PlayerEraChanged.Add(fnQuo_FreeCivicBoostOnEraChange);


But it doesn't seem to work as far as I can tell. Any ideas on what I'm doing wrong or how I could improve the process so I can better tell what parameters the event listener functions need?
 
PlayerEraChanged is defined in the "Events" table by the game, try

Code:
local function fnQuo_FreeCivicBoostOnEraChange( iPlayer )

    print ('ERA CHANGED.') ;
end
Events.PlayerEraChanged.Add(fnQuo_FreeCivicBoostOnEraChange);

Also I've not tested it, but AFAIK the arguments are index, not object in Events, the exception being Events.Combat which returns a table.

there are not a lot of predefined "GameEvents", I think this is the complete list:
CityBuilt
CityConquered
OnCityPopulationChanged
OnFaithEarned
OnGameTurnStarted
OnGreatPersonActivated
OnNewMajorityReligion
OnPillage
OnUnitRetreated
PlayerTurnStartComplete
PlayerTurnStarted

(Note that you can add new "GameEvents" to that table, like the "LuaEvents" table.)


Moderator Action: I've also moved the thread to Mod Creation Help
 
PlayerEraChanged is defined in the "Events" table by the game, try

Code:
local function fnQuo_FreeCivicBoostOnEraChange( iPlayer )

    print ('ERA CHANGED.') ;
end
Events.PlayerEraChanged.Add(fnQuo_FreeCivicBoostOnEraChange);

Also I've not tested it, but AFAIK the arguments are index, not object in Events, the exception being Events.Combat which returns a table.

there are not a lot of predefined "GameEvents", I think this is the complete list:
CityBuilt
CityConquered
OnCityPopulationChanged
OnFaithEarned
OnGameTurnStarted
OnGreatPersonActivated
OnNewMajorityReligion
OnPillage
OnUnitRetreated
PlayerTurnStartComplete
PlayerTurnStarted

(Note that you can add new "GameEvents" to that table, like the "LuaEvents" table.)


Moderator Action: I've also moved the thread to Mod Creation Help


Thanks Gedemon! I tried it and it mostly works, altho I'm getting a Lua error somewhere in my code. At least the event is triggering now.

This may be a really basic question, but I'm still really struggling with Lua in the Civ 6 context. Is there some way to reload the Lua scripts without exiting/starting reloading a whole game? It takes forever to test. I've tried the "Refresh Lua States" in the Firetuner drop-down box, but its not clear to me what that feature does. I've coded in other languages (C++, C# in particular) and trying to get used to Lua has been hard, in part because I don't understand what tools we have available. The lack of type safety has also led me to many crashes to desktop, enough so that I've probably removed more Lua codes from my mods than I have included.
 
I use quick save / quick load a lot when debugging, I don't know if there is another way.

AFAIK only the files of a mod replacing one of the game's UI files reload automatically when they are saved.
 
I use quick save / quick load a lot when debugging, I don't know if there is another way.

AFAIK only the files of a mod replacing one of the game's UI files reload automatically when they are saved.


Awesome. Unfortunately with PlayerEraChanged the event occurs and calls the listener function, but doesn't appear to return any indication of which player triggered it (iPlayer enters the listener function as nil). Is there some obvious way to figure that out? All this stuff with the _G table and which variables are available when leaves me very confused.


EDIT: Nix that. I did some more testing and it turns out I am catching the iPlayer! It does lead to another question tho. How, other than trial and error, can you test a function to find out what variables it returns/feeds into listener functions?
 
Last edited:
Strange, I've checked the last time I tried all the events, it was returning playerID and EraID.
 
example:
Code:
local sRequiredPlayerCivName = "CIVILIZATION_AMERICA"

function PlayerProgressedEras(iPlayer, iPlayerEra)
	--fires on game start / game load so needs to be delayed to LoadScreenClose activation
	print("Events.PlayerEraChanged fired for function PlayerProgressedEras")
	if PlayerConfigurations[iPlayer]:GetCivilizationTypeName() == sRequiredPlayerCivName then
		local pPlayer = Players[iPlayer]
		local pCities = pPlayer:GetCities();
		if pCities:GetCount() > 0 then
			print("[PlayerProgressedEras] Player # " .. iPlayer .. " has some cities")
			for i, pCity in pCities:Members() do
				--do stuff for each city here such as call a function like the one here:
				UpdateEraBuildingsLockersAndProgresses(pCity, iPlayer, iPlayerEra)
			end
		else
			print("[PlayerProgressedEras] Player # " .. iPlayer .. " has no cities")
		end
	end
end
function OnLoadScreenClose()
	Events.PlayerEraChanged.Add(PlayerProgressedEras)
end
Events.LoadScreenClose.Add(OnLoadScreenClose)
The era change listener would only execute the first-level conditional if the player who progressed eras was playing as America, whether human or AI.
 
I think Events.PlayerEraChanged does not work in Rise and Fall any more. You can use it without errors, but it seems like it never triggers in R&F.

Edit: However, you can use a workaround like this code:

Code:
local iLastShownEraIndex = Game.GetEras():GetCurrentEra()
function OnPlayerTurnActivated( iPlayerID ) 
    local iCurrentEraIndex = Game.GetEras():GetCurrentEra()
    local bGameEraHasChanged
    if( iLastShownEraIndex ~= iCurrentEraIndex ) then
        bGameEraHasChanged = true
    else
        bGameEraHasChanged = false
    end
    iLastShownEraIndex = iCurrentEraIndex0    
    print("Era Change: " .. tostring(bGameEraHasChanged))
    if( bGameEraHasChanged ) then
        --your code...
    end
end
Events.TurnBegin.Add(OnPlayerTurnActivated);
 
Last edited:
Back
Top Bottom