Lua Objects

Ok, I've ran some tests, it seems it changes the in memory DB, but does not change debug DB dump on disk. But the problem is that the changes are ignored by the game so for the test I've added 2 civilization traits for Russia and then run the select query to check if the DB changed:

Code:
local sqls = {
"insert into CivilizationTraits (CivilizationType, TraitType)  values ('CIVILIZATION_RUSSIA', 'TRAIT_CIVILIZATION_DISTRICT_SEOWON');",
"insert into CivilizationTraits (CivilizationType, TraitType)  values ('CIVILIZATION_RUSSIA', 'TRAIT_CIVILIZATION_ROYAL_NAVY_DOCKYARD');"
}

--******************************************************************************
function Initialize()
    for i = 1, 2 do
        local q = DB.Query(sqls[i]);
        tprint(q, 8);
        print( " Exec query", sqls[i], q );
        dumpAAA(q);
    end
    local q = DB.Query("SELECT CivilizationType, TraitType from CivilizationTraits where CivilizationType = ?", "CIVILIZATION_RUSSIA");
    tprint(q, 8);
    dumpAAA(q);
end

I had no Seowon district and Royal Dockyard playing Russia. But the console output shows that DB was changed:
Spoiler console :

Code:
 LuaScript1:  Exec query    insert into CivilizationTraits (CivilizationType, TraitType)  values ('CIVILIZATION_RUSSIA', 'TRAIT_CIVILIZATION_DISTRICT_SEOWON');    table: 0000000050E27750
 LuaScript1:  Exec query    insert into CivilizationTraits (CivilizationType, TraitType)  values ('CIVILIZATION_RUSSIA', 'TRAIT_CIVILIZATION_ROYAL_NAVY_DOCKYARD');    table: 0000000050E277A0
 LuaScript1:                 1:
 LuaScript1:                   TraitType: TRAIT_CIVILIZATION_DISTRICT_LAVRA
 LuaScript1:                   CivilizationType: CIVILIZATION_RUSSIA
 LuaScript1:                 2:
 LuaScript1:                   TraitType: TRAIT_CIVILIZATION_DISTRICT_SEOWON
 LuaScript1:                   CivilizationType: CIVILIZATION_RUSSIA
 LuaScript1:                 3:
 LuaScript1:                   TraitType: TRAIT_CIVILIZATION_MOTHER_RUSSIA
 LuaScript1:                   CivilizationType: CIVILIZATION_RUSSIA
 LuaScript1:                 4:
 LuaScript1:                   TraitType: TRAIT_CIVILIZATION_ROYAL_NAVY_DOCKYARD
 LuaScript1:                   CivilizationType: CIVILIZATION_RUSSIA
 LuaScript1:                 5:
 LuaScript1:                   TraitType: TRAIT_CIVILIZATION_UNIT_RUSSIAN_COSSACK
 LuaScript1:                   CivilizationType: CIVILIZATION_RUSSIA


I think that it maybe useful for the runtime Civilopedia edits which seems to use SQL queries to fill the content (Base\Assets\UI\Civilopedia\CivilopediaSupport.lua) and maybe in some cases for the in-mod data exchanges. Maybe if it was possible to run the lua script during UpdateDatabase phase?
 
Last edited:
-- initialize events - starting events
Events.LocalPlayerChanged.Add( OnLocalPlayerChanged ); -- fires in-between TurnEnd and TurnBegin
Events.PreTurnBegin.Add( OnPreTurnBegin ); -- fires ONCE at start of turn, before actual Turn start
Events.TurnBegin.Add( OnTurnBegin ); -- fires ONCE at the start of Turn
Events.PhaseBegin.Add( OnPhaseBegin ); -- engine?
Events.LocalPlayerTurnBegin.Add( OnLocalPlayerTurnBegin ); -- event for LOCAL player only (i.e. HUMANS), fires BEFORE PlayerTurnActivated
Events.PlayerTurnActivated.Add( OnPlayerTurnActivated ); -- main event for any player start (AIs, including minors), goes for playerID = 0,1,2,...
-- these events fire AFTER custom PlayerTurnActivated()
Events.CivicBoostTriggered.Add( OnCivicBoostTriggered );
Events.TechBoostTriggered.Add( OnTechBoostTriggered );
Events.CityProductionCompleted.Add( OnCityProductionCompleted );
Events.CityProjectCompleted.Add( OnCityProjectComplete );
-- HERE YOU PLAY GAME AS HUMAN
-- initialize events - finishing events
Events.LocalPlayerTurnEnd.Add( OnLocalPlayerTurnEnd ); -- fires only for HUMANS
Events.PlayerTurnDeactivated.Add( OnPlayerTurnDeactivated ); -- main event for any player end (including minors)
Events.PhaseEnd.Add( OnPhaseEnd ); -- engine?
Events.TurnEnd.Add( OnTurnEnd ); -- fires ONCE at end of turn
Events.EndTurnDirty.Add( OnEndTurnDirty ); -- engine event, triggers very often
This fine table of firing sequence is very helpful to understand the fundamental structure!

I'm looking for the locations of optional Events, which are not happening every turn, eg. Events.CityTileOwnershipChanged(iPlayerID, iCityID).
The point is, that this call doesn't provide the plotID, whose Ownership has Changed and one has to find out in which context it is used.

So I suppose, while conquering a city (or using cultureBomb) Events.CityTileOwnershipChanged(iPlayerID==0) will happen multiple times during "-- HERE YOU PLAY GAME AS HUMAN".
But when the human player receives a new tile from the "city manager" CityTileOwnershipChanged happens only once and I would think earlier, because it is an effect of culture in Events.CityProductionCompleted. Where?

Do you know, where in the sequence eg. CityTileOwnershipChanged is fired in those 2 different cases above for an AIplayer (ie. conquering a city or receiving a new tile)?
.
 
Do you know, where in the sequence eg. CityTileOwnershipChanged is fired in those 2 different cases above for an AIplayer (ie. conquering a city or receiving a new tile)?
Sorry, I don't. Write a Lua script that has this framework I posted and add the events you want to check. Run several turns of the game until you get an event and you can see when it was triggered.
 
Updated script to get Lua objects. Includes RiverManager, ImprovementBuilder, TerrainBuilder, GameClimate, MapFeatureManager, TerrainManager, Territories, MapManager, WorldBuilder, ResourceBuilder.
Spoiler :

Code:
local function Initialize()
    dumpAll()
end
Events.LoadScreenClose.Add(Initialize);

local player = Players[0]
local unit = nil
local playerUnits = player:GetUnits()
for i, u in playerUnits:Members() do
    if u then
        unit = u
    end
end
local pConfig = PlayerConfigurations[0]
local city = nil
local playerCities = player:GetCities()
for i, c in playerCities:Members() do
    if c then
        city = c
    end
end
local Plot = Map.GetPlot(0,0)
local GetBarbarianManager = nil
local GetFalloutManager = nil
local GetGossipManager = nil
local GetQuestsManager = nil
local GetTradeManager = nil
if Game.GetBarbarianManager then GetBarbarianManager = Game.GetBarbarianManager() end
if Game.GetFalloutManager then GetFalloutManager = Game.GetFalloutManager() end
if Game.GetGossipManager then GetGossipManager = Game.GetGossipManager() end
if Game.GetQuestsManager then GetQuestsManager = Game.GetQuestsManager() end
if Game.GetTradeManager then GetTradeManager = Game.GetTradeManager() end
local seenO = {}
local seenT = {}
listDump = {
    Achievements = Achievements,
    AutoplayManager = AutoplayManager,
    Calendar = Calendar,
    Cities = Cities,
    CityManager = CityManager,
    City = city,
    CombatManager = CombatManager,
    ContextPtr = ContextPtr,
    DealManager = DealManager,
    DiplomacyManager = DiplomacyManager,
    Game = Game,
    GameConfiguration = GameConfiguration,
    GameEffects = GameEffects,
    GetUnitStats = GetUnitStats,
    GameGetBarbarianManager = GetBarbarianManager,
    GameGetFalloutManager = GetFalloutManager,
    GameGetGossipManager = GetGossipManager,
    GameGetQuestsManager = GetQuestsManager,
    GameGetTradeManager = GetTradeManager,
    IconManager = IconManager,
    InstanceManager = InstanceManager,
    Locale = Locale,
    MapConfiguration = MapConfiguration,
    Map = Map,
    NotificationManager = NotificationManager,
    Options = Options,
    PlayerConfigurations = pConfig,
    PlayerManager = PlayerManager,
    PlayerVisibilityManager = PlayerVisibilityManager,
    Players = player,
    Plot = Plot,
    TTManager = TTManager,
    UIManager = UIManager,
    UITutorialManager = UITutorialManager,
    Unit = unit,
    UnitManager = UnitManager,
    Units = Units,
    UserConfiguration = UserConfiguration,
    RiverManager = RiverManager,
    ImprovementBuilder = ImprovementBuilder,
    TerrainBuilder = TerrainBuilder,
    GameClimate = GameClimate,
    MapFeatureManager = MapFeatureManager,
    TerrainManager = TerrainManager,
    Territories = Territories,
    MapManager = MapManager,
    WorldBuilder = WorldBuilder,
    ResourceBuilder = ResourceBuilder
    }
listExceptionStr = {
    "IsNone",
    "ToPlot",
    "ToArea",
    "GetDiplomaticState",
    "HasProductionProgress",
    "ToolTip",
    "HasBeenPlaced",
    "GetAvailableProductionType",
    "GetTurnsLeft",
    "GetName",
    "GetScienceYieldToolTip",
    "GetPlayerName",
    "GetLeaderName",
    "Name",
    "Description",
    "Text",
    "Password",
    "GetNextEscapingSpyID",
    "Advice",
    "IsResourceExtractableAt",
    "Tooltip",
    "GetNextPursuedSpyID",
    "GetTurnFromIndex",
    "GetTurn",
    "GetNthOffMapSpy",
    "GetPlayerFromIndex",
    "FromIndex",
    "GetDiplomaticActionCost",
    "Turn",
    "Level",
    "GetDiplomatic",
    "GetCities",
    "GetStartingPlot",
    "GetActiveQuestReward",
    }
function canTest(functionName)
    local bCanTest = false
    local get = string.find(functionName, "Get")
    --local is = string.find(functionName, "Is")
    --local has = string.find(functionName, "Has")
    if get == 1 or is == 1 or has == 1 then
        bCanTest = true
    end
    for k, str in pairs(listExceptionStr) do
        if string.find(functionName, str) then
            return false
        end
    end
    return bCanTest
end
function dumpO(object,i)
    seenO[object]=true
    local s={}
    local n=0
    local meta = getmetatable(object).__index
    if type(meta)=="function" then meta = getmetatable(object).__index() end
    if not meta then return end
    for k, v in pairs(meta) do
        print(i,k)
        if type(v)=="table" and not seenT[v] then
            dumpT(v,i.."\t")
        end
        if type(v)=="function" then
            object.f = object[k]
            local value = nil
            if canTest(tostring(k)) then
                value = object:f()
                --print(i.."\t - ".."return value :", value)
            end
            if getmetatable(v) and getmetatable(v).__index and not seenO[v] then
                dumpO(v,i.."\t")
            end
            if value and getmetatable(value) and getmetatable(value).__index and not seenO[value] then
                dumpO(value,i.."\t")
            end
            if value and type(value)=="table" and not seenT[value] then
                dumpT(value,i.."\t")
            end
        end
    end;
end
function dumpT(table,i)
    seenT[table]=true
    local s={}
    local n=0
    for k in pairs(table) do
        n=n+1 s[n]=k
    end
    for k,v in ipairs(s) do
        print(i,v)
        v=table[v]
        if type(v)=="table" and not seenT[v] then
            dumpT(v,i.."\t")
        end
    end
end
function dumpAll()
    local contextName = "Script"
    if ContextPtr and ContextPtr.GetID then contextName = ContextPtr:GetID() end
    print("-----------------------------------------------------------------------------------------------------")
    print("-----------------------------------------------------------------------------------------------------")
    print("-- STARTING DUMP FROM CONTEXT = ".. Locale.ToUpper(contextName))
    print("-----------------------------------------------------------------------------------------------------")
    print("-----------------------------------------------------------------------------------------------------")
    local a = {}
    for n in pairs(listDump) do table.insert(a, n) end
    table.sort(a)
    for i,k in ipairs(a) do
        local v = listDump[k]
        local i = ""
        if type(v)=="function" then
            local value = v()
            print("return value :" .. value)
            if getmetatable(v) and getmetatable(v).__index then
                dumpO(v,i.."\t")
            end
            if getmetatable(value) and getmetatable(value).__index then
                dumpO(value,i.."\t")
            end
            if type(value)=="table" then
                dumpT(value,i.."\t")
            end
        end
        if getmetatable(v) and getmetatable(v).__index then
            print("--- object:", k)
            dumpO(v,i)
            print("--- ")
            print("--------------------------------------")
        end
        if type(v)=="table" then
            print("--- table:", k)
            dumpT(v,i)
            print("--- ")
            print("--------------------------------------")
        end
    end
end



Does anyone know why this command
Code:
WorldBuilder.MapManager():SetAllRevealed(true, 0);
is not printed?
 
Last edited:
This fine table of firing sequence is very helpful to understand the fundamental structure!

I'm looking for the locations of optional Events, which are not happening every turn, eg. Events.CityTileOwnershipChanged(iPlayerID, iCityID).
The point is, that this call doesn't provide the plotID, whose Ownership has Changed and one has to find out in which context it is used.

So I suppose, while conquering a city (or using cultureBomb) Events.CityTileOwnershipChanged(iPlayerID==0) will happen multiple times during "-- HERE YOU PLAY GAME AS HUMAN".
But when the human player receives a new tile from the "city manager" CityTileOwnershipChanged happens only once and I would think earlier, because it is an effect of culture in Events.CityProductionCompleted. Where?

Do you know, where in the sequence eg. CityTileOwnershipChanged is fired in those 2 different cases above for an AIplayer (ie. conquering a city or receiving a new tile)?
.
Code:
	--Firing Order: (all functions subscribed to these events fire in this order as part of a city conquest)
	--	GameEvents.CityConquered
	--	Events.CityRemovedFromMap
	--	Events.CityAddedToMap
	--	Events.CityPopulationChanged
	--	Events.CityTileOwnershipChanged (fires in succession for each tile whose ownership was altered)
	--	Events.CityInitialized
	--	Events.CityProductionCompleted
	--	Events.CityPopulationChanged	(you seem to get two firings of this event as part of a city-capture)
	--	Events.CityProductionCompleted	(you seem to get two or more firings of this event as part of a city-capture)
CityTileOwnershipChanged fires whenever tile ownerships are alterred. It is not a subset of CityProductionCompleted and has no relation to it for acquisition of tiles via the normal cultural expansion mechanics. Tile acquisition by normal cultural border expansion occurs as part of each player's turn processing, but whether tile ownserhip expansion occurs before or after the game assesses whether a city has completed its current production item, for example, I like @Infixo am not sure since I have never specifically run a monitoring test to determine which elements of a turn process occur before or after certain others.
 
  • Like
Reactions: cvb
I love the new sequence you provided for city conquest :love: ...
Tile acquisition by normal cultural border expansion occurs as part of each player's turn processing, but whether tile ownserhip expansion occurs before or after the game assesses whether a city has completed its current production item, for example, I like Infixo am not sure since I have never specifically run a monitoring test to determine which elements of a turn process occur before or after certain others.
I simply figured, that his list of cities is processed during each player's turn and every city after collecting its yields would generate the possible results on the same turn [tile(culture) like building(production) -- visual: civ1 production box full of shields -> unit/building completed ). But of course you are right, one can never be sure about such things without testing.
CityTileOwnershipChanged fires whenever tile ownerships are alterred.
Yeah, originally I wanted to use this event to grant coastal cities extra (FREE) water tiles (cities with ALOTOF coast, ocean tiles can gain ALOT - cities with only a few ie. barely "coastal cities" not so!!). Narration: a "real" coastal city with focus on sea has a lot of ships, hence water tiles quicker than "normal". So they develop altogether quicker (also on land, because their 2nd & 3rd ring are filled sooner).

But there are way too many CityTileOwnershipChanged occurrences to be viable [***]: New tile granted via accumulated culture by "city manager" /// TilesCultureBombed(Cree-trader) / City flips because lack of loyality / CityConquered militarily / CitySwapped in trade-deal / TilesCultureBombed(improvement Poland, Australia, Maori ...) / New tile bought with gold ...

Right now I plan to store & compare City:GetCulture():GetCurrentCulture in Events.TurnBegin respective Events.TurnEnd
or just check for City:GetCulture():GetTurnsUntilExpansion==1in Events.TurnBegin or Events.TurnEnd


Edit: [*** Back then I expected to find easily ANY events, which are reproducible near before & after my wanted occurrence, and set /reset within them a flag in order to mask out the other occurrences.]

.
 
Last edited:
Just be aware that tiles given via lua scripts have some problems associated with them. The Plot:SetOwner(args) method results in tiles that can never be worked.

The method
Code:
 WorldBuilder.CityManager():SetPlotOwner(pGrabPlot, pCity);
Works in RaF and GS but not currently in Vanilla (GS broke it for Vanilla). The
Code:
WorldBuilder.CityManager():SetPlotOwner(args)
method can accept the two arguments as shown or an alternative set of arguments I cannot remember off the top of my head at the moment. Regardless of the argument set you use, the WorldBuilder method will result in plots that can be worked by the city but which do not reflect modifiers that source from the city or the player, from World Wonders the player owns, or the player's religion, pantheon, etc., until the game is saved and reloaded.
 
  • Like
Reactions: cvb
WorldBuilder.CityManager is available again since last patch in vanilla.
 
  • Like
Reactions: cvb
The Plot:SetOwner(args) method results in tiles that can never be worked.
I suppose, that is the method to immerse any tile on the map in a civ's colours. ;)
The WorldBuilder.CityManager():SetPlotOwner(args) method [...] will result in plots that can be worked by the city but which do not reflect modifiers that source from the city or the player, from World Wonders the player owns, or the player's religion, pantheon, etc., until the game is saved and reloaded.
I am a patient player. So I will use this workaround (and use pickle/unpickle to avoid further problems).

.
 
pUnit:GetAbility() is new ?

Code:
GameCore_Tuner:     GetAbility
GameCore_Tuner:         GetAbilityCount
GameCore_Tuner:         RemoveAbilityCount
GameCore_Tuner:         GetAbilities
GameCore_Tuner:             1
GameCore_Tuner:                 Count
GameCore_Tuner:                 Ability
GameCore_Tuner:             2
GameCore_Tuner:                 Count
GameCore_Tuner:                 Ability
GameCore_Tuner:             3
GameCore_Tuner:                 Count
GameCore_Tuner:                 Ability
GameCore_Tuner:         TypeName
GameCore_Tuner:         __instances
GameCore_Tuner:             userdata: 000000017376F990
GameCore_Tuner:                 f
GameCore_Tuner:                 __instance
GameCore_Tuner:         CanHaveAbility
GameCore_Tuner:         ChangeAbilityCount
GameCore_Tuner:         HasAbility
GameCore_Tuner:         AddAbilityCount

interesting, can be used for adding/removing modifiers for units I suppose...

from CivRoyaleScenario_StartScript.lua
Code:
function RefreshAllWMDAbility(iPlayerID :number)
    local pPlayer = Players[iPlayerID];
    if(pPlayer == nil) then
        print("Error: No Player!");
        return;
    end
    local playerWMDs = pPlayer:GetWMDs();
    local grantWMDAbility :boolean = playerWMDs:GetWeaponCount(GameInfo.WMDs["WMD_THERMONUCLEAR_DEVICE"].Index) > 0;
    print("Setting WMD Ability to " .. tostring(grantWMDAbility) .. " playerID: " .. tostring(iPlayerID));
    local pPlayerUnits : object = pPlayer:GetUnits();
    for i, pUnit in pPlayerUnits:Members() do
        local unitInfo:table = GameInfo.Units[pUnit:GetType()];
        if(unitInfo ~= nil and unitInfo.FormationClass ~= "FORMATION_CLASS_CIVILIAN") then
            local pUnitAbility = pUnit:GetAbility();
            local iCurrentCount = pUnitAbility:GetAbilityCount("ABILITY_WMD_STRIKE");
            pUnitAbility:ChangeAbilityCount("ABILITY_WMD_STRIKE", grantWMDAbility and 1 or -iCurrentCount);
        end
    end
end
 
Ah. So long as we define an ability with it's attendant UnitAbilityModifier rather than directly define a modifier we can add and remove a modifier from a unit via the UnitAbility.
 
Hello. Is there any way to get correct production per turn values? City:GetYield() returns production values without different modificators. The only call that calculates production values with all modificators that I could find is City:GetBuildQueue():GetTurnsLeft(). But of course it returns rounded values of turns only and can't be used to get production.
 
@Infixo I forgot to write it, GetBuildQueue():GetProductionYield() returns the same values as City:GetYield().
 
Like when someone is dropping from a game for instance?

I am specifically trying to find a way to prevent MP game from halting at the end of a turn when a player becomes an observer (like with your autoplay mod).
 
Back
Top Bottom