Lua Objects

Is there a way to do the equivalent of City:IsOriginalCapital() in the Gameplay context?
 
Is there a way to do the equivalent of City:IsOriginalCapital() in the Gameplay context?
City:IsOriginalCapital() can be used for both Gamplay and UI Script (). (ChimpanG has updated the Modding companion sheet)
City:IsCapital() can only be used in UI Script
Otherwise you can use: Player:GetCities():GetCapitalCity(), or use Exposed.Members Methode.
 
Hello,
I have a bit of trouble understanding what exactly "Game.GetEras():HasDarkAge" and its golden counterpart do and how it works.
My goal is to give cities amenities for each darkAge it went through, so I am using "if Game.GetEras():HasDarkAge(iPlayer) then" to build a dummy building with entertainment each time there's a new era starting. I assumed that the function returns true if current era of "Players[iPlayer]" is a dark age. However, I get a "function expected instead of nil" error on the if statement.
Can anyone explain to me what I did wrong?
 
the function is called in a Lua file from the script/gameplay context ?
 
Indeed it is, I mean, it wouldn't appear in the logs if it wasn't anyway, right?

here's the code in case:
Code:
function NephilimEras(iOldEra, iNewEra)
    for iPlayer = 0, 63 do
        if PlayerConfigurations[iPlayer]:GetCivilizationTypeName() == 'CIVILIZATION_HOLOEN_NEPHILIM' then
            for i,city in Players[iPlayer]:GetCities():Members() do
                if Game.GetEras():HasDarkAge(Players[iPlayer].Index) then
                    PlaceBuildingInCityCenter(i, GameInfo.Buildings["BUILDING_TWOAMEN"].Index)
                elseif not Game.GetEras():HasGoldenAge(iPlayer) then
                    PlaceBuildingInCityCenter(i, GameInfo.Buildings["BUILDING_ONEAMEN"].Index)
                end
            end
        end
    end
end

function PlaceBuildingInCityCenter(pCity, iBuilding)
    local iCityPlotIndex = Map.GetPlot(pCity:GetX(), pCity:GetY()):GetIndex()
    if not pCity:GetBuildings():HasBuilding(iBuilding) then
        pCity:GetBuildQueue():CreateIncompleteBuilding(iBuilding, iCityPlotIndex, 100);
    end
end

Events.GameEraChanged.Add(NephilimEras)
 
the function should not be nil if the file is loaded in gameplay/script context AFAIK.

are you sure the file is not loaded in UI context ? (check the .modinfo)
 
Indeed, it is properly in the script part. I would also like to say that it's not the only custom function in this script and the others works.
That why I was thinking it might be my use of HasDarkAge that might be wrong.
Is my first guess of the function returning true when the player is in a Dark Age currently right? Or is it used some way else?
 
Code:
Players[iPlayer].Index

HasDarkAge wants a Player ID # (ie, just iPlayer) and not a player object method. And certainly not an invalid one as there is to my knowledge no such thing as
Code:
PlayerObject.Index

Players[iPlayer] creates a PlayerObject from which player object methods can be executed, but they are not usually static methods (ie, "dot" rather than "colon" syntax). "Index" is not a player object method of either kind so far as I am aware. ".Index" is used with database GameInfo data for game tables like "Units" or "Buildings", but not with player objects. The nearest equivalent for a player to an "Index" value is the player ID #, which your code already has as variable "iPlayer".

------------------

And so far as I am aware
Code:
Game.GetEras():HasDarkAge(playerID)
is only valid in a UI context, which is what Gedemon was trying to get at. You cannot use it in any lua file activated by a AddGameplayScript type of action.
 
Eh?
Isn't that the reverse of what Gedemon was saying? I would also be really surprised if it was just an UI thing?

the function should not be nil if the file is loaded in gameplay/script context AFAIK.
So it should work as an added Gameplay Script?

For the index thing, it was just me trying to see if I didn't mess up somewhere so I just tried doing a random thing in hope it might have been my error. The problem really happened for both "Players[iPlayer].Index" AND "playerID".

So my lua file containing various other functions is in a <AddGameplayScripts id="NewAction"> tag. All the other functions properly work.
 
I interpretted what Gedemon was saying as needing to check if it is nil or not in a gameplay script. But that looks to have just have been my bad interpretation of what he was saying.

---------------------------------------------

Code:
function expected instead of nil
pretty much always means that the method (ie, function) is not valid in the side of the lua engine where you are attempting to use it.

For the several hits that came up when searching the game's lua files (all that generated hits were UI files: none of the scenario gameplay scripts tried to use it) the argument data Firaxis used was always a Player ID #.

The data I have (and ChimpanG's spreadsheets) shows the method to be invalid in a GameplayScript.

API methods are entirely hit or miss as to which side of the lua "engine" they are valid in. An object like City:GetBuildings() might have any number of methods available within it which are valid in both sides of the lua engine, as well as those which are only valid in one or the other. It's the sort of thing that drives modders crazy but at which Firaxis excels, mosty because the Civ6 lua system is a truncated implementation that only really has those portions available which Firaxis needed at one point or another, or which they thought they might need. Civ6 lua really does not much go beyond that.
 
Yep, I misread, seems to be nil in gameplay.
 
I see, so adding amenities depending on the Age is impossible in the current state of the game using LUA...
Thanks for your help anyway.
 
I've already shared this elsewhere, but I thought I'd post it here as well, I'm working on a place to document Lua modding for Civ 6, and hopefully in a more comprehensive way than the Google Sheet linked on the first page, since many of the methods have little quirks.

For instance:
Spoiler :

upload_2021-8-2_22-58-45.png


upload_2021-8-2_23-0-22.png


upload_2021-8-2_23-0-52.png


The website is actually just generated from a series of markdown files (an Obdisian Vault to be exact), hosted on Github (https://github.com/Sukritact/Civilization-VI-Modding-Knowledge-Base). So anyone can fork it and make changes.
 
Thanks, I've edited and cleaned the OP.

I'm not active so don't plan to contribute directly ATM, but the DealManager tab of my old spreadsheets may interest you, I've edited it recently while looking at diplomacy control, to list the methods of the pDeal and pItem object, returned from DealManager.GetWorkingDeal(DealDirectionType, fromPlayerID, toPlayerID) and from pDeal:AddItemOfType (DealItemTypes, playerID)

example of usage:

Make Open Border for 10 turns
Code:
    DealManager.ClearWorkingDeal(DealDirection.OUTGOING, iPlayer1, iPlayer2);
    local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, iPlayer1, iPlayer2);
    if pDeal then
        pDealItem = pDeal:AddItemOfType(DealItemTypes.AGREEMENTS, iPlayer1);
        if pDealItem then
            pDealItem:SetSubType(DealAgreementTypes.OPEN_BORDERS);
            pDealItem:SetValueType(-1);
            pDealItem:SetFromPlayerID(iPlayer1);
            pDealItem:SetToPlayerID(iPlayer2);
            pDealItem:SetDuration(10);
            pDealItem:SetLocked(true);
        end
        pDeal:Validate();
        DealManager.EnactWorkingDeal(iPlayer1, iPlayer2);
    end

Stop Open Border
Code:
    DealManager.ClearWorkingDeal(DealDirection.OUTGOING, iPlayer1, iPlayer2);
    local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, iPlayer1, iPlayer2);
    if pDeal then
        pDealItem = pDeal:AddItemOfType(DealItemTypes.AGREEMENTS, iPlayer1);
        if pDealItem then
            pDealItem:SetSubType(DealAgreementTypes.OPEN_BORDERS);
            pDealItem:SetValueType(-1);
            pDealItem:SetFromPlayerID(iPlayer1);
            pDealItem:SetToPlayerID(iPlayer2);
            pDealItem:SetDuration(0);
            pDealItem:SetLocked(true);
        end
        pDeal:Validate();
        DealManager.EnactWorkingDeal(iPlayer1, iPlayer2);
    end

Make Military Alliance
Code:
    DealManager.ClearWorkingDeal(DealDirection.OUTGOING, iPlayer1, iPlayer2);
    local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, iPlayer1, iPlayer2);
    if pDeal then
        pDealItem = pDeal:AddItemOfType(DealItemTypes.AGREEMENTS, iPlayer1);
        if pDealItem then
            pDealItem:SetSubType(DealAgreementTypes.ALLIANCE);
            pDealItem:SetValueType(DB.MakeHash("ALLIANCE_MILITARY"));
            pDealItem:SetLocked(true);
        end
        pDeal:Validate();
        DealManager.EnactWorkingDeal(iPlayer1, iPlayer2);
    end

Stop Military Alliance
Code:
    DealManager.ClearWorkingDeal(DealDirection.OUTGOING, iPlayer1, iPlayer2);
    local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, iPlayer1, iPlayer2);
    if pDeal then
        pDealItem = pDeal:AddItemOfType(DealItemTypes.AGREEMENTS, iPlayer1);
        if pDealItem then
            pDealItem:SetSubType(DealAgreementTypes.ALLIANCE);
            pDealItem:SetValueType(DB.MakeHash("ALLIANCE_MILITARY"));
            pDealItem:SetDuration(0);
            pDealItem:SetLocked(true);
        end
        pDeal:Validate();
        DealManager.EnactWorkingDeal(iPlayer1, iPlayer2);
    end

(I'm still wondering how many things I've thought impossible were in fact possible since a long time... and why they never released at least a minimal API)
 
(I'm still wondering how many things I've thought impossible were in fact possible since a long time... and why they never released at least a minimal API)
yeah, me too. One can even make shared visibility if you tie it (via alliance database modifiers) to an AllianceType or to a dummy Alliance (would need a DiploDealScreen UI rework if you want to hide it tho, but you're already overhauling everything in your Mod, so no big deal for you I guess). Except defensive Pacts I think.
 
note for myself: I still need to try to manually lock peace for x turns by using those methods with DealAgreementTypes.MAKE_PEACE for Civilizations already at peace, as the Open Borders method works for expanding the duration of an existing agreement for example.
 
Back
Top Bottom