1. We have added the ability to collapse/expand forum categories and widgets on forum home.
    Dismiss Notice
  2. All Civ avatars are brought back and available for selection in the Avatar Gallery! There are 945 avatars total.
    Dismiss Notice
  3. To make the site more secure, we have installed SSL certificates and enabled HTTPS for both the main site and forums.
    Dismiss Notice
  4. Civ6 is released! Order now! (Amazon US | Amazon UK | Amazon CA | Amazon DE | Amazon FR)
    Dismiss Notice
  5. Dismiss Notice
  6. Forum account upgrades are available for ad-free browsing.
    Dismiss Notice

Lua Objects

Discussion in 'Civ6 - Modding Tutorials & Reference' started by Gedemon, Oct 23, 2016.

  1. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    7,436
    Location:
    France
    Also related, damage from combat are applied before the combat event is called.
     
  2. Infixo

    Infixo Warlord

    Joined:
    Jan 9, 2016
    Messages:
    2,088
    Gender:
    Male
    Location:
    Warsaw
    @cromcrom You mean standard game healing? If so, that's ok because it must happen within player's turn, after you move, etc. So, it will be before PlayerTurnDectivate and TurnEnd, since they are called after the player's done its things. If you want to apply attrition before healing, then:
    A) hook into unit movement
    B) hook into PlayerTurnAcfivate which could be really a logical choice since you will be able to apply attrition to,initial warrior and settler as well if they spawn in bad terrain. Otherwise, they will have a chance to escape.
     
  3. LeeS

    LeeS Imperator

    Joined:
    Jul 23, 2013
    Messages:
    5,289
    Location:
    Illinois, USA
  4. isau

    isau Warlord

    Joined:
    Jan 15, 2007
    Messages:
    2,642
    I apologize if this has been answered already. I'd like to be able to pinpoint the Hex a player clicked on. I assume there is some way to do this since Firetuner lets you select a hex to drop units/features/etc on. Is this replicable with Lua? I don't see any obvious Firaxis code that pinpoints how, but I assume it has to exist given its such a core game requirement.
     
  5. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    7,436
    Location:
    France
    try this
    Code:
            local plotX:number, plotY:number = UI.GetCursorPlotCoord();
    There are also a lot of other function related to plot/world/screen coordinate in the UI table
     
  6. isau

    isau Warlord

    Joined:
    Jan 15, 2007
    Messages:
    2,642

    This is perfect, thanks. I'm still struggling a bit with the Civ 6 object model and Lua. Hoping I can use this to good ends. :)
     
  7. StandardGaussian

    StandardGaussian Chieftain

    Joined:
    Mar 8, 2017
    Messages:
    13
    Does anyone have info related to manipulating districts specifically through Lua? The documentation you guys have uncovered so far is great, but I'm stuck at WorldBuilder.CityManager(), which I assume would be my portal for changing all things about cities, but I can't find any functions to set anything related to districts anywhere (eg. change an adjacency bonus).

    I've detailed what I'm trying to do in this topic.

    I feel genuinely stuck at the moment. I have plenty of experience with other languages, but not Lua, particularly with switching contexts and using the FireTuner console to cajole data out of the game at runtime. I don't really know how to "select" a district in-game, seems like it would be under the city manager.
     
  8. Chrisy15

    Chrisy15 Limmu

    Joined:
    Jul 9, 2015
    Messages:
    1,879
    I'd have thought that WorldBuilder would operate solely with, well, WorldBuilder...

    As for Set functions, then yea they're pretty thin on the ground :/
     
  9. StandardGaussian

    StandardGaussian Chieftain

    Joined:
    Mar 8, 2017
    Messages:
    13
    The reason I brought up WorldBuilder is that it appears able to assign plot ownership to specific cities at runtime through WorldBuilder.CityManager(), which gives me the impression that it does more than simply construct the game world before the game starts. I imagine the function I'm looking for is somewhere inside the City Manager, possibly after multiple layers of indirection. I'm attempting to use the debug dump functions created by @Gedemon / @LeeS to expose more functions, but I'm having trouble getting them to work. I have no experience with Lua and it doesn't appear to be similar enough to other scripting languages I'm comfortable with, like Python, to just jump in without a primer. I don't mind sitting down some evening and doing a "Lua for Dummies"-style tutorial, but I don't know if that'll end up getting me very much closer to finding the setter functions we would need to make truly interesting mods.

    A few have been found, like the aforementioned "SetPlotOwner", which is why I have hope that many more exist.
     
  10. Chrisy15

    Chrisy15 Limmu

    Joined:
    Jul 9, 2015
    Messages:
    1,879
    If you just wanna practice Lua, then I'd highly recommend playing around in Civ 5; Civ 6's Lua capabilities are abysmal, so if you wanna play around and actually be able to do stuff then I'd just sit down with Bane_'s tutorial and be able to actually do stuff.
     
  11. CivilizationAce

    CivilizationAce Chieftain

    Joined:
    Jan 17, 2017
    Messages:
    236
    Gender:
    Male
    I'm going to need examples that work in actual .lua code, because the very first one I tried in Lua Console in FireTuner didn't work: print(_G.Players[0]:GetName()) produces just an error message. It seems that _G.Players is nil, which leaves me pretty much up a creek without a paddle to the point where further testing, not that I haven't done any, is pointless, because if I can't even tell which player is which my civilization specific lua is stillborn.

    Has any of the output been tested or is it just some arbitrary readout from a DLL with no provenance, no reliability, no practical use. Yes, I'm angry, but not at the OP. I'm disappointed that the best that we can do is lists of three values that don't seem to work and don't come with descriptions to indicate what they should do if they did work. I'm angry at Firaxis for treating us like mushrooms — They told us Civ VI was designed to be modded not designed to be reverse engineered. I appreciate attempts to do the latter and at the same time I deplore the need.
     
  12. Infixo

    Infixo Warlord

    Joined:
    Jan 9, 2016
    Messages:
    2,088
    Gender:
    Male
    Location:
    Warsaw
    _G is not available for modding. Player object doesn't have GetName() function. You can use PlayerConfigurations[0]:GetPlayerName() or PlayerConfigurations[0]:GetCivilizationShortDescription().
    If you are referring to the list of Lua functions in Excel - I can assure you that all of them are working (at least I have not encountered a situation where they would not). The problem is only with parameters - you need to look in the code provided by Firaxis. If a function is not used anywhere (many cases, unfortunately).. well, that's a real pickle.
    And the other thing. I did a little of Civ5 modding, but I can say that Civ6 is much better designed, both DB and Lua interface. There's a lot of logic that can help you actually discover how how some of functions are working.
     
  13. LeeS

    LeeS Imperator

    Joined:
    Jul 23, 2013
    Messages:
    5,289
    Location:
    Illinois, USA
    Code:
    local sPlayerCivName = PlayerConfigurations[0]:GetCivilizationTypeName()
    local sPlayerLeaderName = PlayerConfigurations[0]:GetLeaderTypeName()
    print(Locale.Lookup(GameInfo.Civilizations[sPlayerCivName].Name)
    print(Locale.Lookup(GameInfo.Leaders[sPlayerLeaderName].Name)
    That will print into the lua log file the name of the human-player's civilization and leader (assuming a single-player game) as seen in-game.

    Civ6 lua is workable and has much room for improvement but I cannot say I agree it is better designed or implemented at the moment. But Vanilla civ5 was also kind of kludgey in some degree: for example there was no hook event for a city completing a building or wonder, or a city training a unit, or purchasing a tile: these were added in the Fall'14 patch, along with a whole series of other lua event hooks.
     
  14. CivilizationAce

    CivilizationAce Chieftain

    Joined:
    Jan 17, 2017
    Messages:
    236
    Gender:
    Male
    Thank you both. I can see that it's going to take a lot more digging than I'd expected, let alone hoped, to achieve even simple things :(
     
  15. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    7,436
    Location:
    France
    Adding GameEvents to the google doc:

    CityBuilt
    CityConquered
    OnCityPopulationChanged
    OnFaithEarned
    OnGameTurnStarted
    OnGreatPersonActivated
    OnNewMajorityReligion
    OnPillage
    OnUnitRetreated
    PlayerTurnStartComplete
    PlayerTurnStarted

    thanks @Gleb Bazov
     
    Gleb Bazov likes this.
  16. Gleb Bazov

    Gleb Bazov Chieftain

    Joined:
    Feb 13, 2017
    Messages:
    176
    Gender:
    Male
    I am posting here a few of the function arguments and event parameters that I have sleuthed out. They may have already been posted, but, if not, here they are. I have more, and I'll keep on posting them here for everyone's convenience. Cheers,

    UnitManager.RestoreMovement(pUnit)

    UnitManager.MoveUnit( pUnit, iPlotX, iPlotY )

    UnitManager.PlaceUnit( pUnit, iPlotX, iPlotY )

    NOTE: In order to move or place a unit after a move that exhausts its movement points. the unit's movement points must first be restored. If this is not done, and PlaceUnit is used, error artifacts appear on the game screen, where the game treats the unit as being at the new location, but the graphics do not update. I.e. visually it remains at the old location, but, in actuality, it is at the new location.

    If MoveUnit is used to move a unit that has exhausted its movement points, no move takes place. The function fires successfully, but has no effect.

    -- where:

    local pPlayer = Players[ iPlayerID ]

    local pUnit = pPlayer:GetUnits():FindID( iUnitID )

    On a separate note, I have determined the following parameters for the following event:

    function OnUnitGreatPersonCreated( iPlayerID, iUnitID, igpType, igpID )
    -- main chunk --
    end
    Events.UnitGreatPersonCreated.Add(OnUnitGreatPersonCreated);

    -- where:

    igpType is an integer, from 0 to 8, corresponding to the index of the GreatPersonClasses table

    -- and:

    igpID is an integer, corresponding to the index of the GreatPersonIndividuals table
     
    Gedemon likes this.
  17. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    7,436
    Location:
    France
    thanks you for finding those, they are new, I was waiting since release for something allowing control over movement of AI units :)

    (and now I'll have to test if it allows to initialize combat)
     
    Gleb Bazov likes this.
  18. Gleb Bazov

    Gleb Bazov Chieftain

    Joined:
    Feb 13, 2017
    Messages:
    176
    Gender:
    Male
    My pleasure :) ! @Infixo suggested that I try them, and they worked well for me. If they work for initializing combat, please let me know!

    I spent a couple of hours tonight sleuthing out a few more events and parameters that might be missing from the excel table. Here they are:

    Code:
    function OnNationalParkAdded( iPlayerID, iParkRootX, iParkRootY )
    -- main chunk --
    Events.NationalParkAdded.Add( OnNationalParkAdded );
    
    -- iParkRootX: coordinate X of the National Park's tower (the lower end of the vertical diamond)
    -- iParkRootX: coordinate Y of the National Park's tower (the lower end of the vertical diamond)
    
    --====================================================================================================================
    
    function OnPlotYieldChanged( iPlotX, iPlotY )
    -- main chunk --
    Events.PlotYieldChanged.Add( OnPlotYieldChanged );
    
    --====================================================================================================================
    
    function OnTreasuryChanged( iPlayerID, iGoldPerTurn, iCurrentTreasury)
    -- main chunk --
    Events.TreasuryChanged.Add( OnTreasuryChanged );
    
    -- iGoldPerTurn refers to the player's gold income per turn, and not to the change in the player's treasury
    -- event fires every time there is a change in the player's treasury, but does not yield the quantum of the change itself
    
    --====================================================================================================================
    
    function OnUnitFormCorps( iPlayerID, iUnitID )
    -- main chunk --
    Events.UnitFormCorps.Add( OnUnitFormCorps );
    
    --====================================================================================================================
    
    function OnUnitFormArmy( iPlayerID, iUnitID )
    -- main chunk --
    Events.UnitFormArmy.Add( OnUnitFormArmy );
    
    --====================================================================================================================
    
    function UnitGreatPersonActivated( iUnitOwnerID, iUnitID, iGreatPersonClass, iGreatPersonType)
    -- main chunk --
    Events.UnitGreatPersonActivated.Add( UnitGreatPersonActivated );
    
    -- iGreatPersonType refers to the index of the GreatPersonIndividuals table
    -- iGreatPersonClass refers to the index of the GreatPersonClasses table
    
    --====================================================================================================================
    
    function UnitGreatPersonChanged( iPlayerID, iUnitID)
    -- main chunk --
    Events.UnitGreatPersonChanged.Add( UnitGreatPersonChanged );
    
    --====================================================================================================================
    
    function UnitMoveComplete( iPlayerID, iUnitID, iTerminusX, iTerminusY)
    -- main chunk --
    Events.UnitMoveComplete.Add( UnitMoveComplete );
    
    -- fires every time a unit stops moving
    -- for a multi-plot movement path, will fire only for the final destination plot on which the unit stops for that turn
    
    --====================================================================================================================
    
    function CityCommandStarted( iPlayerID, iCityID, iIntegerA, iIntegerB, Hash, iIntegerC )
    -- main chunk --
    Events.CityCommandStarted.Add( CityCommandStarted );
    
    -- in the case of the human player's capital city, iIntegerB = iCityID
    -- for other human player cities, iIntegerB differs from iCityID
    -- in all fired events, iIntegerA and iIntegerC consistently print as 0
    -- Hash appears to refer to the hash of the city command that triggers the event
    -- The events does not seem to fire for non-human player cities where the human player has no visibility (or,
    -- alternatively, the event does not fire for non-human player cities at all).
    
    --====================================================================================================================
    
    function CityTileOwnershipChanged( iPlayerID, iCityID )
    -- main chunk --
    Events.CityTileOwnershipChanged.Add( CityTileOwnershipChanged );
    
    function DiplomacyDealEnacted( iFirstPlayerID, iSecondPlayerID )
    -- main chunk --
    Events.DiplomacyDealEnacted.Add( DiplomacyDealEnacted );
    
    -- it is assumed that iFirstPlayerID refers to the player initiating the deal, while iSecondPlayerID is the player
    -- accepting the deal, but insufficient testing done to rule out the possibility of it being the reverse in certain cases
    
    function DiplomacyDeclareWar( iFirstPlayerID, iSecondPlayerID )
    --    iFirstPlayerID = player declaring war
    --    iSecondPlayerID = player subject to the declaration of war
    Events.DiplomacyDeclareWar.Add( DiplomacyDeclareWar );
    
    function DiplomacySessionClosed( iPlayerID )
    -- iPlayerID = player that responds to the diplomatic interaction
    -- event fires on conclusion of a diplomatic exchange (refusal/acceptance of a deal, acknowledgement of war declaration)
    Events.DiplomacySessionClosed.Add( DiplomacySessionClosed );
    
    --DISTRICTS
    
    function DistrictUnitsChanged( iPlayerID, iDistrictID )
    -- iDistrictID refers to the district's object ID in the game
    Events.DistrictUnitsChanged.Add( DistrictUnitsChanged );
    
    function DistrictAddedToMap( iPlayerID, iDistrictID, iCityID, iDistrictX, iDistrictY, iDistrictType, HashA, HashB, iPercentComplete, iAppealRating, iIntegerB )
    -- iCityID = 65536 is the same for the capital city ID of every player (major and minor)
    -- iCityID = iDistrictID for any City Center District
    -- iDistrictType refers to the index of the Districts table
    -- iPercentComplete is always 100 for City Centers and DISTRICT_WONDERs, and 0 for all other newly-placed districts
    -- HashA is always the same: 440626330 for the human player and -1851407529 for non-human players
    -- HashB remain the same and constant for any district of a given player
    -- iAppealRating is the appeal of the district's tile
    -- iIntegerB always prints as 0 in all (limited) tests
    Events.DistrictAddedToMap.Add( DistrictAddedToMap );
    
    function DistrictBuildProgressChanged( iPlayerID, iDistrictID, iCityID, iDistrictX, iDistrictY, iDistrictType, HashA, HashB, iPercentComplete, iAppealRating, iIntegerB )
    -- iCityID = 65536 is the same for the capital city ID of every player (major and minor)
    -- iCityID = iDistrictID for any City Center District
    -- iDistrictType refers to the index of the Districts table
    -- iPercentComplete changes as district build progress advances
    -- HashA is always the same: 440626330 for the human player and -1851407529 for non-human players
    -- HashB remain the same and constant for any district of a given player
    -- iAppealRating is the appeal of the district's tile
    -- iIntegerB always prints as 0 in all (limited) tests
    Events.DistrictBuildProgressChanged.Add( DistrictBuildProgressChanged );
    
    --POLICIES
    
    function GovernmentPolicyChanged( iPlayerID, iPolicyID )
    -- iPolicyID refers to the index of the Policies table
    -- fires when changes are made to a player's policies and accepted
    -- fires on acceptance of policy changes for the old (removed) and the new (adopted) policies
    Events.GovernmentPolicyChanged.Add( GovernmentPolicyChanged );
    
    function GovernmentChanged( iPlayerID, iGovernmentID )
    -- iGovernmentID refers to the index of the Governments table
    Events.GovernmentChanged.Add( GovernmentChanged );
    
    -- GPs
    
    function GreatPeopleTimelineChanged()
    -- no parameters --
    Events.GreatPeopleTimelineChanged.Add( GreatPeopleTimelineChanged );
    
    function GreatWorkCreated( iPlayerID, iGreatWorkID, iLocationX, iLocationY, iMuseumID, iIndexOfGreatWorkInGame )
    -- iLocationX and iLocationY refer to the location cooredinates of the Great Work
    -- iIndexOfGreatWorkInGame refers to great work's order of appearance in the game
    -- iMuseumID identifies the museum where the great work is placed
    Events.GreatWorkCreated.Add( GreatWorkCreated );
    
    function GreatWorkMoved( iOldPlayerID, iOldCityID, iNewPlayerID, iNewCityID, iMuseumID, iIndexOfGreatWorkInGame )
    -- iMuseumID identifies the museum where the great work is placed
    -- iIndexOfGreatWorkInGame refers to great work's order of appearance in the game
    Events.GreatWorkMoved.Add( GreatWorkMoved );
    
    --====================================================================================================================
    --====================================================================================================================
    
    -- GAME EVENTS --
    
    function OnGreatPersonActivated( iUnitOwnerID, iUnitID, iGreatPersonType, iGreatPersonClass )
    -- main chunk --
    GameEvents.OnGreatPersonActivated.Add( OnGreatPersonActivated );
    
    -- iGreatPersonType refers to the index of the GreatPersonIndividuals table
    -- iGreatPersonClass refers to the index of the GreatPersonClasses table
     
    Last edited: Apr 13, 2017
    Infixo likes this.
  19. LeeS

    LeeS Imperator

    Joined:
    Jul 23, 2013
    Messages:
    5,289
    Location:
    Illinois, USA
    Code:
    function GetArgumentDatas(sOrigin, tTable)
    	print("============================================================================================")
    	print("[" .. sOrigin .. "]: Dumping Event Hook Argument Data")
    	print("............................................................................................")
    	for k,v in pairs(tTable) do
    		local sKeyType = type(k)
    		local sValueType = type(v)
    		print("[" .. sOrigin .. "]: Key is of type " .. sKeyType .. " = " .. tostring(k) .. ", Value is of type " .. sValueType .. " = " .. tostring(v))
    	end
    	print("............................................................................................")
    	print("[" .. sOrigin .. "]: dump completed for this firing of the event")
    	print("============================================================================================")
    end
    function OnDistrictAddedToMap(...)
    	--OnDistrictAddedToMap(iPlayer, iDistrict, iCity, iX, iY, iDistrictIndex, iUnknownEventSubType1, iUnknownEventSubType2, iPercentComplete, iPlotAppeal, iUnknown3)
    		--above was for city center district
    		--for human player (Cleopatra, Egypt)
    			--iUnknownEventSubType1 == -1851407529
    			--iUnknownEventSubType2 == -1155553852
    		--for Montezuma, Aztecs:
    			--iUnknownEventSubType1 == -1851407529
    			--iUnknownEventSubType2 ==  1347583174
    		--iDistrict == iCity for founding a city and plopping the City Center District
    	--OnDistrictAddedToMap(iPlayer, iDistrict, iCity, iX, iY, iDistrictIndex, iUnknownEventSubType1, iUnknownEventSubType2, iPercentComplete, iPlotAppeal, iUnknown3)
    		--for adding Holy Site to the build qeue in human player's capital city: 0, 131073, 65536, 66, 30, 1, -1851407529, -1155553852, 0, 2, 0
    	--the event only appears to fire when the district is placed for construciton, not when it is completed.
    	--OnDistrictAddedToMap(iPlayer, iDistrict, iCity, iX, iY, iDistrictIndex, iUnknownEventSubType1, iUnknownEventSubType2, iPercentComplete, iPlotAppeal, iUnknown3)
    		--for adding Hanging Gardens to the map on save reload next to human player's capital city: 0, 196610, 65536, 21, 59, 13, -1851407529, -1806906687, 100, -4, 0
    		--"13" matches to the index # within table <Districts> for "DISTRICT_WONDER"
    	--Event fires as part of saved-game reloading for all districts and wonders placed on the map
    	print("Events.DistrictAddedToMap fired for function OnDistrictAddedToMap")
    	GetArgumentDatas("OnDistrictAddedToMap", {...})
    end
    Events.DistrictAddedToMap.Add(OnDistrictAddedToMap)
     
    Gleb Bazov likes this.
  20. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    7,436
    Location:
    France
    I've attached new dumps from script and UI context in the second post.
     

Share This Page