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

C++/Lua Request Thread

Discussion in 'Civ5 - SDK / LUA' started by Nefliqus, Jun 11, 2012.

  1. Troller0001

    Troller0001 Watching from a safe distance

    Joined:
    Mar 9, 2016
    Messages:
    753
    Gender:
    Male
    Location:
    The Netherlands
    Most of your variable names have correct syntax but many modders have adopted Hungarian Notation.
    Basically, since a variable can have any type (E.g. integer, string, table, etc.), it can make code more readable to explicitly mention this type in the variable name.
    For instance, a variable named pUnit will contain a pointer to a unit (i.e. you can use methods such as :GetName() or :GetUnitType() on such a variable).
    sUnit will contain a string related to a unit (for instance a name)
    iUnit will contain an integer related to a unit (for instance an ID)
    tUnit will contain a table related to a unit, etc.
    Therefore, following Hungarian Notation, your variable can rename the following variables:
    Code:
    iCivilisationID = GameInfoTypes["CIVILIZATION_SERTAO"]
    iUAPromotion = GameInfoTypes["PROMOTION_SERTAO_RELIGION_PROMOTION"]
    bHasCreatedReligion = pPlayer:HasCreatedReligion()
    iPlayerReligion = pPlayer:GetReligionCreatedByPlayer()
    iCityReligion = pCity:GetReligiousMajority()
    pUnit = pPlayer:GetUnitByID(UnitID)
    pPlot = pUnit:GetPlot()
    iCity = pPlot:GetCityPurchaseID()
    
    What is a problem is that you try to define several variables outside of the methods:
    Code:
    local HasCreatedReligion = player:HasCreatedReligion()
    local PlayerReligion = player:GetReligionCreatedByPlayer()
    local CityReligion = City:GetReligiousMajority()
    local Unit = player:GetUnitByID(UnitID)
    local Plot = Unit:GetPlot()
    local City = Plot:GetCityPurchaseID()
    
    However, at this point, it is unknown to the game what the value for say, player, actually is (as this has not been defined)

    If we move some of these variables of your original function, we obtain the following.
    At this point, the game knows which values (most of) these variables have
    Code:
    function CombatBonus(iPlayer, iUnit)
        local pPlayer = Players[iPlayer]
        if pPlayer:GetCivilizationType() == iCivilisationID then
            if pPlayer:HasCreatedReligion() then
                -- Note that this will not work as pCity is not defined!
                if pPlayer:GetReligionCreatedByPlayer() == pCity:GetReligiousMajority() then
                    -- Note that pUnit is not defined!
                    pUnit:SetHasPromotion(UAPromotion, true)
                else
                    pUnit:SetHasPromotion(UAPromotion, false)
                end
            end
        end
    end
    

    Your base logic seems good, though you're attempting to look at a city that has not been used anywhere before.
    Hence, we need a way to obtain a city, which we can do based on the plot the unit is currently standing on:
    Code:
    -- This assumes we know pUnit
    local pPlot = pUnit:GetPlot()
    local iCity = pPlot:GetCityPurchaseID() -- I do not know for sure what :GetCityPurchaseID(..) will return if standing on neutral lands (I assume it's either nil or -1)
    if iCity and iCity > 0 then
        local pCity = pPlayer:GetCityByID(iCity)
        -- Do logic with pCity here
    end
    
    The same goes for a unit, which we can obtain by:
    Code:
    -- This assumes we have pPlayer and iUnit
    local pUnit = pPlayer:GetUnitByID(iUnit)
    
    Combining the things gives us the following (along with a small trick to avoid code repetition):
    Code:
    iCivilisationID = GameInfoTypes["CIVILIZATION_SERTAO"]
    iUAPromotion = GameInfoTypes["PROMOTION_SERTAO_RELIGION_PROMOTION"]
    
    function CombatBonus(iPlayer, iUnit)
        local pPlayer = Players[iPlayer]
        local pUnit = pPlayer:GetUnitByID(iUnit)
        local bGrantPromotion = false -- Indicates whether the unit will gain/lose the promotion
       
        if pPlayer:GetCivilizationType() == iCivilisationID then
            if pPlayer:HasCreatedReligion() then
                local pPlot = pUnit:GetPlot()
                local iCity = pPlot:GetCityPurchaseID() -- I do not know for sure what :GetCityPurchaseID(..) will return if standing on neutral lands (I assume it's either nil or -1)
                if iCity and iCity > 0 then
                    local pCity = pPlayer:GetCityByID(iCity)
                    if pCity and pPlayer:GetReligionCreatedByPlayer() == pCity:GetReligiousMajority() then
                        -- A small print-statement that is useful for testing purposes.
                        -- Probably a good idea to comment out or remove upon release, as it'll get printed MANY times
                        print("Adding promotion since "..pCity:GetName().." and "..pPlayer:GetName().." share their religion")
                        bGrantPromotion = true
                    end
                end
            end
            pUnit:SetHasPromotion(iUAPromotion, bGrantPromotion)
        end
    end
    
    if IsCivActive(civilisationID) then
        GameEvents.UnitSetXY.Add(CombatBonus)
    end
    
     
  2. KyubeyD3

    KyubeyD3 Chieftain

    Joined:
    Oct 6, 2019
    Messages:
    17
    Gender:
    Male
    Thank you so much!
    Now the only thing I still have to do is pedia and diplomacy text, and I'll have finished my first mod!
     
    Troller0001 likes this.
  3. KyubeyD3

    KyubeyD3 Chieftain

    Joined:
    Oct 6, 2019
    Messages:
    17
    Gender:
    Male
    Hi again!
    I'm making another civ and I'm trying to make an Unique Unit with the following ability:
    "When starting a turn while standing on friendly territory, gain +1 Movement and ignore enemy Zone of Control."
    By looking at some threads here and at the Lua of some other mods, I made this:

    Code:
    local iDummyPromotion = GameInfoTypes["PROMOTION_QB_FRIENDLY_TURF_DUMMY"]     -- has no attributes and is given to the UU for free
    local iTruePromotion = GameInfoTypes["PROMOTION_QB_FRIENDLY_TURF_ACTIVATED"]  -- contains the actual attributes
    --
    function FriendlyTurfBonus(iPlayer)
        local pPlayer = Players[iPlayer]
       
        if iPlayer < iMaxCivs then
           for pUnit in pPlayer:Units() do
                if pUnit:IsHasPromotion(iDummyPromotion) then
                   if pUnit:GetPlot():GetOwner() == iPlayer then
                     pUnit:SetHasPromotion(iTruePromotion, true)
                   else
                     pUnit:SetHasPromotion(iTruePromotion, false)
                   end        
                end
            end  
        end
    end
    --
    GameEvents.PlayerDoTurn.Add(FriendlyTurfBonus)
    Would this be correct?

    edit: I tested it and it didn't work lmao, then I fixed it
    might as well post my fixed code here

    Code:
    function FriendlyTurfBonus(iPlayer)
        local pPlayer = Players[iPlayer]
        
        if pPlayer:IsAlive() then
           for pUnit in pPlayer:Units() do
                if pUnit:IsHasPromotion(iDummyPromotion) then
                   if pUnit:GetPlot():GetOwner() == iPlayer then
                     pUnit:SetHasPromotion(iTruePromotion, true)
                     pUnit:ChangeMoves(1 * GameDefines.MOVE_DENOMINATOR) -- wtf why does pUnit:SetMoves(pUnit:GetMoves() + 1) work differently Lua is so weird
                   else
                     pUnit:SetHasPromotion(iTruePromotion, false)
                   end         
                end
            end   
        end
    end
    --
    GameEvents.PlayerDoTurn.Add(FriendlyTurfBonus)
     
    Last edited: Jan 11, 2020
  4. Lyokoheros

    Lyokoheros Chieftain

    Joined:
    Mar 1, 2020
    Messages:
    15
    Gender:
    Male
    (I hope I write this in correct thread...)
    I'm quite new to Lua modding (I have some experience with XML files and in programming in general, though I never write anything in Lua) but there is a think I start to wonder about lua scripts... how (well WHEN would be better word) are they executed and how to make the game run such script. I want to make mountain workable - even without carrying on using mod for that, so more like alltime game modification. (Because honestly mountain aren't useless in real life, can be source of various resources etc... so why they should be useless in civ?)

    I found two mods, which add special hidden feature to all mounaints(FEATURE_MOUNTAIN_YIELD), which enable to reffer tomountain in XML files, to easily and flexibly set its yield. The script (which was part of this mod) look like this:
    Code:
    Events.SequenceGameInitComplete.Add(function()
        for i = 0, Map:GetNumPlots() - 1, 1 do
            local fPlot = Map.GetPlotByIndex( i );
            if fPlot:IsMountain() then
                if fPlot:GetFeatureType() == -1  then
                    fPlot:SetFeatureType(GameInfoTypes.FEATURE_MOUNTAIN_YIELD,-1);
                end
            end
        end
    end)
    and in the second it was:
    Code:
    function Mountaineering(iPlayer)
        print("Assigning ski slopes");
        -- loop through all plots
        for iPlot = 0, Map.GetNumPlots() - 1 do
            local plot = Map.GetPlotByIndex(iPlot);
            if plot:IsMountain() and plot:GetFeatureType() == -1 then
                plot:SetFeatureType(GameInfoTypes.FEATURE_SKI);
            end
        end
    end
    Events.SequenceGameInitComplete.Add( Mountaineering );
    
    But I noticed (in the first case at least) that it's file wasn't mentioned in modinfo file, and also that simply put script file (WorkableMountain.lua) into proper Lua folder (I mean [gamefolder]\Assets\DLC\Expansion2\Gameplay\Lua) won't be enough so I considered to add that part to some of the scripts there (FeatureGenerator.lua seems the most suitable)... but just my knowing of the game and general-programming knowledge isn't enough to say where exactly I should put it. Or maybe just the part between "(funtction()" and "end)"... I'm also not sure whit one would be better, though difference seems minimal(but there could be some details of Lua programming that are unknown to me)

    EDIT:
    After some test I come up with the following solution(not exactly working yet...):
    In the file "FeatureGenerator.lua" inside function "function FeatureGenerator:AddFeaturesAtPlot(iX, iY)"
    At the end I added followind code:
    Code:
        if (plot:GetFeatureType() == FeatureTypes.NO_FEATURE) and plot:IsMountain()  then
            plot:SetFeatureType(GameInfoTypes.FEATURE_MOUNTAIN_YIELD);
            print("Assigning mountain feature(once)");
        end
    I know it would kinda trash my log file with many instance of that communicate (1 for every mountain which isn't already a nature wonder).
    Then in "CIV5Features_Expansion2.xml" I put the following entries:
    Code:
    <Features>
          <Row>
                <Type>FEATURE_MOUNTAIN_YIELD</Type>
                <Description>Góry</Description>
                <Civilopedia>Mountains will provide +3 [ICON_production]</Civilopedia>
                <ArtDefineTag>NULL</ArtDefineTag>
                <Movement>2</Movement>
                <Impassable>true</Impassable>
                <PortraitIndex>8</PortraitIndex>
                <IconAtlas>NW_ATLAS</IconAtlas>
            </Row>
        </Features>
    <Feature_YieldChanges>
            <Row>
                <FeatureType>FEATURE_MOUNTAIN_YIELD</FeatureType>
                <YieldType>YIELD_PRODUCTION</YieldType>
                <Yield>3</Yield>
            </Row>
    </Feature_YieldChanges>
    
    ...but in game (though i get this lot of "Assigning mountain feature(once)" in Lua file, and there seemengly isn't any error (excluding missing refference, but considering I just hardcoded the description I can simply skip this warning)) the mountain still have no yields, are not workable.
    What have I missing here?
     
    Last edited: Mar 20, 2020
  5. Ohura196

    Ohura196 Chieftain

    Joined:
    Apr 17, 2020
    Messages:
    16
    Gender:
    Male
    Location:
    Japan
    Can change flevors in lua?
    For Example, if Golden age MAJOR_CIV_APPROACH_WAR 5 >>> 10 etc.
     
  6. Clarkimedes

    Clarkimedes Chieftain

    Joined:
    Aug 23, 2019
    Messages:
    3
    Was wondering if there is a way to create a new mission and have its effects defined in lua. I'd love to hear how to do it as I've been searching through posts and lua references trying to figure it all out.

    I've noticed that some missions in the CIV5Missions.xml file are linked to EntityEventTypes. It seems to me that the entity events just link the action to its animations through the Civ5EntityEvents.xml file. I guess the xml files just link the mission to its art and animation.

    I have found no reference to entity events in the lua reference, but have found several references to missions, such as Unit:pushMission or Unit:CanStartMission. I'm just lost as to how to add new missions into the game.

    For reference, my hope is to revamp air combat a bit by adding new air missions and disabling the old versions. Is this possible with lua or is this something I'd have to dive into the dll to accomplish?

    Many Thanks!
     

Share This Page