1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Lua Reference Vault

Discussion in 'Civ5 - Modding Tutorials & Reference' started by Enginseer, Dec 14, 2016.

  1. Enginseer

    Enginseer Salientia of the Community Patch Supporter

    Joined:
    Nov 7, 2012
    Messages:
    3,217
    Gender:
    Male
    Location:
    Somewhere in California
    This thread fits the proper sub-forum because it's a reference of Lua code that many "inexperienced" coders lack at. It is highly RECOMMENDED that you DO NOT POST in this thread unless you are contributing Lua code or any alternative that suits for a reference that we don't have to flip to.

    In the OP, I'll answer some questions that may be asked.

    Q: What are dummy policies/buildings?
    A: Policies and buildings that output an effect desired to the modder, but (not necessarily) hidden from the player's view. An example would be simulating an increased resting point for a Civilization's UA. You would implement a dummy policy to do so. Hidden to the players, they would see the UA to be affected while to the modder and experienced players behind the framework is a dummy policy doing it essentially.

    Q: What are the limitation of dummy policies/buildings?
    A: Question was already answered. It's limited to what policies and buildings can do. This is where custom DLC scenarios can come in handy as they may have effects that the BNW package may not have, but still work. Alternatively, if you're willing to use a custom DLL, VMC and CP makes use of the "unified yield" element which can help you not use Lua to simulate effects.

    Q: What if I don't understand the Lua?
    A: It's not that hard to understand, it's plain English. You just need to substitute the VARIABLE(s) with what fits your XML entries.

    Q: What is this vault really?
    A: As there is a demand, a reference can be made so that other modders can reference to easily without having to look into other people's mods. If there are any errors, you should PM me personally or whoever made the reference rather than commenting here directly.
     
    Last edited: Dec 14, 2016
  2. Enginseer

    Enginseer Salientia of the Community Patch Supporter

    Joined:
    Nov 7, 2012
    Messages:
    3,217
    Gender:
    Male
    Location:
    Somewhere in California
    Making a Dummy Policy
    (This assumes that you know how to load a Lua and an XML file correctly!)
    Standard XML code. (SQL works well, if you know how to use it)
    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <GameData>
        <Language_en_US>
            <Row Tag="TXT_KEY_DUMMY_POLICY_VARIABLE">
                <Text>Variable Name</Text>
            </Row>
        </Language_en_US>
        <Policies>
            <Row>
                <Type>DUMMY_POLICY_VARIABLE</Type>
                <Description>TXT_KEY_DUMMY_POLICY_VARIABLE</Description>
                <Variable1>boolean/integer/textreference</Variable1>
            </Row>
        </Policies>
    </GameData>
    
    Variable1 is a setting of the Policies XML table, don't start pulling random settings like <Happiness> from the Building XML table.
    Lua for getting a dummy policy to work initially with a UA.
    Code:
        for iPlayerLoop = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
            local pPlayer = Players[iPlayerLoop]
            if (pPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_VARIABLE) then
                pPlayer:SetNumFreePolicies(1)
                pPlayer:SetNumFreePolicies(0)
                pPlayer:SetHasPolicy(GameInfoTypes.DUMMY_POLICY_VARIABLE, true)
            end
        end
    
    I've used an example here in this spoiler.
    Spoiler :

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <GameData>
        <Language_en_US>
            <Row Tag="TXT_KEY_DUMMY_POLICY_WOWLADS">
                <Text>Don't Ask, Don't Tell</Text>
            </Row>
        </Language_en_US>
        <Policies>
            <Row>
                <Type>DUMMY_POLICY_WOWLADS</Type>
                <Description>TXT_KEY_DUMMY_POLICY_WOWLADS</Description>
                <MinorFriendshipMinimum>30</MinorFriendshipMinimum>
            </Row>
        </Policies>
    </GameData>
    
    Code:
    function InitialWowLads()
        for iPlayerLoop = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
            local pPlayer = Players[iPlayerLoop]
            if (pPlayer:GetCivilizationType() == GameInfoTypes.CIVILIZATION_TOOFRIENDLYCIV) then
                pPlayer:SetNumFreePolicies(1)
                pPlayer:SetNumFreePolicies(0)
                pPlayer:SetHasPolicy(GameInfoTypes.DUMMY_POLICY_WOWLADS, true)
            end
        end
    end
    
    if (Modding.OpenSaveData().GetValue("GoodMemes") == nil) then
        InitialWowLads()
        Modding.OpenSaveData().SetValue("GoodMemes", 1)
    end
    
    This code adds in a UA, "Don't Ask, Don't Tell" that allows the resting point of city-states to increase toward 30(stacks with vanilla Consulates btw!). This code assumes that the UA text has been already preset and all this code provide is the necessary dummy policy coding to make it work.


    For experienced modders below..:
    "Wait a second this Lua code looks weird. Why isn't it a PlayerDoTurn GameEvent?"
    It's not supposed to be a PlayerDoTurn when the civilization only needs the policy changed one time. This saves much processing and makes your Lua optimized for the player! Since the code only runs once, you save lots of turn processing trying to add a dummy policy constantly every turn!
    "Don't I need more than just this?"
    This is the bare necessities. If you want to add a Help text to the Policy column, be my guest. It's a dummy policy however, so I doubt players will see it.
     
    Last edited: Dec 16, 2016
  3. Troller0001

    Troller0001 Not an actual Troll

    Joined:
    Mar 9, 2016
    Messages:
    732
    Gender:
    Male
    Location:
    The Netherlands
    To further elaborate on the 'Dummy Policies':

    'Dummy Policies' - Some more advanced tricks
    (This assumes that you understand the basic idea of 'Dummy Policies')
    The 'Rules of thumb'
    As you may already know, policies will become exponentially more expensive the more you adopt. This also applies to 'dummy policies'! However, we can use some 'trickery' to avoid this, using 2 'rules of thumb':

    Use this code (as already posted by Enginseer above) to grant a free dummy policy to a player:
    Code:
    [..]
    --pPlayer has been defined somewhere in the code above
    pPlayer:SetNumFreePolicies(1)
    pPlayer:SetNumFreePolicies(0)
    pPlayer:SetHasPolicy(GameInfoTypes.DUMMY_POLICY_VARIABLE, true)
    [..]
    
    Use this code to exchange one policy for another:
    NOTE: A social policy must first be removed before another one is given if you do not want the costs of other social policies to change! (as shown in the example below)
    Code:
    [..]
    --pPLayer has been defined somewhere in the code above
    pPlayer:SetHasPolicy(GameInfoTypes.DUMMY_POLICY_VARIABLE_1, false)
    pPlayer:SetHasPolicy(GameInfoTypes.DUMMY_POLICY_VARIABLE_2, true)
    [..]
    
    This Code removes DUMMY_POLICY_VARIABLE_1 and grants DUMMY_POLICY_VARIABLE_2


    'Removing' a Dummy Policy
    Note that (AFAIK) you are unable to remove dummy policies without costs of other social policies changing. A small workaround that modders can use is what I'd like to call 'the exchange trick' (not an official name!).
    This trick involves creating 2 dummy policies, one which contains the bonus you want, and the other one which is just a filler (and simply does not do anything when having it adopted).
    Let's assume that our two dummies are called DUMMY_POLICY_VARIABLE_EFFECT (which contains the bonus) and DUMMY_POLICY_VARIABLE (which is the filler); Define them using XML as Enginseer has shown in his post above

    Spoiler :

    First, grant the dummy policy without effects using the first trick:
    Code:
    [..]
    --pPlayer has been defined somewhere in the code above
    pPlayer:SetNumFreePolicies(1)
    pPlayer:SetNumFreePolicies(0)
    pPlayer:SetHasPolicy(GameInfoTypes.DUMMY_POLICY_VARIABLE, true)
    [..]
    
    Then, whenever you want the effect to apply, use 'the exchange trick' to swap out the dummy policy without the effect for the dummy policy with the effect:
    Code:
    [..]
    --pPLayer has been defined somewhere in the code above
    pPlayer:SetHasPolicy(GameInfoTypes.DUMMY_POLICY_VARIABLE, false)
    pPlayer:SetHasPolicy(GameInfoTypes.DUMMY_POLICY_VARIABLE_EFFECT, true)
    [..]
    
    When you want the effect to end, you simply use the exchange trick again to swap out the 'effect dummy policy' for the 'filler dummy policy'!

    Example:
    Spoiler :

    The use of dummy policies to apply a a boost in combat1 when your capital is conquered, so that you can quickly retake it!
    1 Spawn a Great General, have 10 units maintenance Free, extra Exp gain, GG's are earned faster

    XML (could also be done through SQL, depending on personal preference):
    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <GameData>
       <Language_en_US>
            <Row Tag="TXT_KEY_DUMMY_POLICY_COMBAT_FOR_LOST_CAPITAL">
                <Text>Combat bonus for Lost Capital</Text>
            </Row>
        </Language_en_US>
    
        <Policies>
            <!--The dummy Policy with the effect-->
           <Row>
                <Type>DUMMY_POLICY_COMBAT_FOR_LOST_CAPITAL_EFFECT</Type>
                <Description>TXT_KEY_DUMMY_POLICY_COMBAT_FOR_LOST_CAPITAL</Description>
                <IncludesOneShotFreeUnits>true</IncludesOneShotFreeUnits>
                <BaseFreeUnits>6</BaseFreeUnits>
                <ExpModifier>100</ExpModifier>
                <GreatGeneralRateModifier>100</GreatGeneralRateModifier>
            </Row>
             <!--The filler dummy Policy-->
            <Row>
                <Type>DUMMY_POLICY_COMBAT_FOR_LOST_CAPITAL</Type>
                <Description>TXT_KEY_DUMMY_POLICY_COMBAT_FOR_LOST_CAPITAL</Description>
            </Row>
        </Policies>
    
        <!-- an additional XML-table that is required for <IncludesOneShotFreeUnits> to work-->
        <Policy_FreeUnitClasses>
            <Row>
                <PolicyType>DUMMY_POLICY_COMBAT_FOR_LOST_CAPITAL_EFFECT</PolicyType>
                <UnitClassType>UNITCLASS_GREAT_GENERAL</UnitClassType>
                <Count>1</Count>
            </Row>
        </Policy_FreeUnitClasses>
    </GameData>
    
    Lua:
    Code:
    print('FILENAME.lua Loaded!');
    
    local iCiv = GameInfoTypes.CIVILIZATION_MY_AMAZING_CIV; --the civ which gains this as a UA
    local iPolicyEffect = GameInfoTypes.DUMMY_POLICY_COMBAT_FOR_LOST_CAPITAL_EFFECT;
    local iPolicy = GameInfoTypes.DUMMY_POLICY_COMBAT_FOR_LOST_CAPITAL;
    
    function GrantInitialDummy(iPlayer)
        local pPlayer = Players[iPlayer];
        if pPlayer:GetCivilizationType() == iCiv then
            if not pPlayer:HasPolicy(iPolicy) and not pPlayer:HasPolicy(iPolicyEffect) then
                pPlayer:SetNumFreePolicies(1)
                pPlayer:SetNumFreePolicies(0)
                pPlayer:SetHasPolicy(iPolicy, true)
           
                print("Initial dummy policy has been granted to"..pPlayer:GetName().." (ID="..iPlayer..")");
            end
        end
    end
    
    function TestCapitalCapturedPolicy(iPlayer)
        local pPlayer = Players[iPlayer];
    
        if pPlayer:GetCivilizationType() == iCiv then
            if pPlayer:IsHasLostCapital() then
                print(pPlayer:GetName().." (ID="..iPlayer..") lost his original capital. Super sayan buff activate!");
                pPlayer:SetHasPolicy(iPolicy, false)
                pPlayer:SetHasPolicy(iPolicyEffect, true)
            else
                print(pPlayer:GetName().." (ID="..iPlayer..") regained his original capital. Shutting buff down.. Please wait.. Done!");
                pPlayer:SetHasPolicy(iPolicyEffect, false)
                pPlayer:SetHasPolicy(iPolicy, true)
            end
        end
    end
    
    GameEvents.PlayerCityFounded.Add(GrantInitialDummy)
    GameEvents.PlayerDoTurn.Add(TestCapitalCapturedPolicy)
    



    Unwanted side effects of 'Dummy Policies'
    An unwanted side effect of dummy policies is that buildings using the '<HappinessPerXPolicies>' XML-tag (such as the Prora, which grants +1 Happiness per 2 adopted Social Policies) will grant more happiness than intended, since they consider 'dummy policies' as '"I need to grant happiness for this policy"-policies'!
    (IIRC VMC/the CP fixes this issue, but I'm not entirely sure).

    Furthermore, some Lua functions, such as 'pPlayer:GetNumPolicies()', also consider our 'dummy policies' as 'normal policies'. (Again, IIRC, VMC/the CP fixes this issue)

    Lastly, dummy policies also increase the score of the player a little, though this is the most minor issue of dummy policies.

    These issues are also a reason why modders might avoid using dummy policies. Sadly, this is not always possible though and sometimes you have to use dummy policies.



    tldr;
    Policy costs will increase and/or decrease if you do not implement the dummies in a correct way. Dummy Policies however have some unwanted side effects, regarding Lua functions, XML-tags. and even score.



    ------------------
    Anyhow, great idea to make such a reference page! :D :thumbsup:
    I'd love to contribute more if I ever encounter/think of other useful stuff!


    NOTE: I'll refine this a bit more within this day, just you wait!
     
    Last edited: Dec 28, 2016
  4. Troller0001

    Troller0001 Not an actual Troll

    Joined:
    Mar 9, 2016
    Messages:
    732
    Gender:
    Male
    Location:
    The Netherlands
    Ideas for paragraphs that could be added:
    - Stacking issues (explain using Tourism and Ultimate Potato's 'toBits' (or an equivalent version))
    - Removing redundant code/increasing Performance/reducing lag (or something like this). Explains things such as whoward's IsCivInPlay (or JFD"s equivalent)
    - Good habits (test regularly/in parts, using print-statements, etc.)
     
    Last edited: Dec 28, 2016
  5. Enginseer

    Enginseer Salientia of the Community Patch Supporter

    Joined:
    Nov 7, 2012
    Messages:
    3,217
    Gender:
    Male
    Location:
    Somewhere in California
    Restricting the Ability to Train a Unit
    (This assumes that you know some Lua.)​
    We're going to be using CityCanTrain to prohibits cities from training units.
    Sample Code
    Spoiler :

    Code:
    local iGDR = GameInfoTypes.UNIT_MECH
    local GDRhq2 = GameInfoTypes.BUILDINGCLASS_GDR_MILITARY_SECRET
    function GDRUnit(iPlayer, iCity, iUnit)
        local player = Players[iPlayer]
        if iUnit == iGDR and player:GetBuildingClassCount(GDRhq2) == 0 then
            return false
        end
        return true
    end
    GameEvents.CityCanTrain.Add(GDRUnit)
    
    This code adds in a limitation that once the ability to train the Giant Death Robot is available, the Giant Death Robot prohibits cities that do not have the building class of The Military Secret to train the Giant Death Robot and return false rendering the unit untrainable in that city. Otherwise, all other units and cities having The Military Secret return true and become trainable This code assumes that the Giant Death Robot exist and its dummy building class The Military Secret.


    For experienced modders below..:
    Can I add something more like for Scenarios?
    Yeah, you can use iCity to grab the ID of the city that you want to be able to train a certain unit and make sure that city is allowed to do so.
    How about PlayerCanTrain?
    Yeah same concept, this one prevents the blahblah civ from training the Giant Death Robot.
    Code:
    function spaghettio(iPlayer, iUnit)
       if Players[iPlayer]:GetCivilizationType() ~= GameInfoTypes.CIVILIZATION_BLAHBLAH and iUnit == GameInfoTypes.UNIT_MECH then
          return false
       end
       return true
    end
    GameEvents.PlayerCanTrain.Add(spaghettio)
    
     
    Last edited: Mar 22, 2017
  6. Lord_Baal

    Lord_Baal Chieftain

    Joined:
    Mar 27, 2018
    Messages:
    6
    Gender:
    Male
  7. Troller0001

    Troller0001 Not an actual Troll

    Joined:
    Mar 9, 2016
    Messages:
    732
    Gender:
    Male
    Location:
    The Netherlands
    I'm unsure if that technique works for Lua-files in the first place, but let me answer that question under the assumption that it would work.
    Dummy Policies work the exact same as normal policies. They share the same XML-tags and are stored in the same table. The only difference is that the Dummy Policies are hidden and are automatically granted/revoked to achieve effects for a Unique Component of a civ (or other mod component). Unlike normal policies though, they cannot be unlocked via culture (since they simply don't show up anywhere in the UI).

    tl;dr same as normal policies, just invisible to achieve effects for a mod component (which in many cases will be a civ's unique component)
     
  8. LeeS

    LeeS Imperator

    Joined:
    Jul 23, 2013
    Messages:
    6,517
    Location:
    Illinois, USA
    This code does not limit the construction of a unit to an individual city
    Code:
    local iGDR = GameInfoTypes.UNIT_MECH
    local GDRhq2 = GameInfoTypes.BUILDINGCLASS_GDR_MILITARY_SECRET
    function GDRUnit(iPlayer, iCity, iUnit)
        local player = Players[iPlayer]
        if iUnit == iGDR and player:GetBuildingClassCount(GDRhq2) == 0 then
            return false
        end
        return true
    end
    GameEvents.CityCanTrain.Add(GDRUnit)
    It allows all cities of a player with at least one BUILDINGCLASS_GDR_MILITARY_SECRET building anywhere within the empire to train or purchase the unit. Player:GetBuildingClassCount(eBuildingClass) is a Player method and therefore "counts" any and all buildings that belong to the specified building-class regardless of which city these buildings are located within.
     

Share This Page