[BNW] A new mod with timed wonders

yepzer

Chieftain
Joined
Jan 12, 2006
Messages
34
Location
Denmark
Here's a new mod where three wonders have been reworked to give a boost after some turns.

First I removed the existing El Dorado and Fountain of Youth wonders using a small mod developed by Erik Taurus. Then I add them back in with new names and wonder placement. Definition inspired by Natural Wonders Enhanced by Leo. The core LUA file and functions are inspired by the Fortress With Borders mod by conan.morris.

Discovering one of the updated natural wonders trickers a turn timer being counted down each turn. When the time is up a reward is given and the timer starts over. The timer restarting after the reward makes the player wait around before triggering the reward again.

AI doesn't use it, as it requires them to camp a unit for the duration. But they might own the wonder surroundings.

:shifty: Eventually it could be updated to give Faith (Player.SetFaith_(Civ5_API)) and Happiness (Player.SetHappiness_(Civ5_API)) and tech boosts. I'm not so sure of how to update the tech value (game upper left corner), would that be Player.ChangeScoreFromTechs_(Civ5_API)?
:shifty: If anyone would have a trick to "flatten" the wonders that would be neat. Currently they appear elevated/on a hill.

Find it on steam as Natural Wonder Timed Boost v5
Primary LUA functions below - full code on GitHub

GameEvents.UnitSetXY.Add( doUnitPositionChanged )
When a unit changes position, check if the plot is one of the wonders - exit as fast as possible if not. check for a timer in the database, if no timer is set, then set a timer (remaining turns, position, owner). if there is a timer notify how long time there is left.
Spoiler :
Code:
function doUnitPositionChanged(iPlayer,iUnit,iX,iY)
    -- Initialize --
    local pPlot = Map.GetPlot(iX,iY)
    if not pPlot then return end
    if (pPlot:IsCity()) then return end

    local pPlayer = Players[iPlayer]
    local pUnit = pPlayer:GetUnitByID(iUnit)
    if ( pUnit == nil ) then return end
    if ( pPlayer == nil ) then return end
        
    local iFeatureType = pPlot:GetFeatureType()   
    if ((iFeatureType ~= cFOC) and (iFeatureType ~= cGEE) and (iFeatureType ~= cGKS)) then return end
    local iTimer = getTimerActive(iFeatureType)
    
    -- print("doUnitPositionChanged: Plot OK, Unit OK, Feature OK")
    local sResult = ""
    local sFeature = GameInfo.Features[iFeatureType].Description

    -- Execute
    if (iTimer ~= nil) then
        -- there is an existing timer
        sResult = "Timer is on for "..sFeature.. ": "..iTimer
    else
        -- there is no existing timer
        local centerPlot = {}
        centerPlot.xPosition = iX
        centerPlot.yPosition = iY
        claimTerritoryAroundHex(centerPlot, iPlayer)
        setTimer(iFeatureType,iX,iY,iPlayer,cTURNS_TO_BOOST)
        sResult = "Hold "..sFeature.." for "..cTURNS_TO_BOOST.." turns"
    end
        
    -- Notify   
    if (sResult ~= "") then
        -- notify only if sResult has text
        local iNotifyType = NotificationTypes["NOTIFICATION_GOLDEN_AGE_BEGUN_ACTIVE_PLAYER"]
        pPlayer:AddNotification(iNotifyType, sResult, sResult, iX, iY)   
    end
end

GameEvents.PlayerDoTurn.Add(OnPlayerDoTurn)
When the turns end (and it does for every player human, minor Civ etc), check if there is a timer for either of the wonders. if there is an active timer, count it one down. If the time is up give a reward if the timer belongs to a player. After rewarding the player, clear the ownership of the surrounding plots. If the timer belongs to no player (-1), release the timer for recapture
Spoiler :

Code:
    if (iPlayer == 63) then return end --skip for barbarians turn
    updateTimer("NWTB_FOC",iPlayer)
    updateTimer("NWTB_GEE",iPlayer)
    updateTimer("NWTB_GKS",Player)

function updateTimer(sKey,iPlayer)
    -- initialize
    local sFullkey = sKey.."_timer"
    local db = Modding.OpenSaveData()
    local iTimer = db.GetValue(sFullkey)
    if (iTimer == nil) then return end

    local iOwner = db.GetValue(sKey.."_owner")
    if (iOwner == nil) then return end

    local iX = db.GetValue(sKey.."_x")
    local iY = db.GetValue(sKey.."_y")
    if ((iX == nil) or (iY == nil)) then return end

    local pPlot = Map.GetPlot(iX,iY)
    if (pPlot == nil) then return end
    local iFeatureType = pPlot:GetFeatureType()   
        
    -- print("updateTimer: Timer OK, Owner OK, Position OK, Player: "..iTimer..","..iOwner..","..iX..","..iY..","..iPlayer)

    -- Execute
    local sResult = ""
    local pUnit = pPlot:GetUnit()
    local centerPlot = {}
    centerPlot.xPosition = iX
    centerPlot.yPosition = iY

    if (iOwner == iPlayer) then
        -- if current player own the wonder
        if (pUnit == nil) then
            -- if no unit on the plot releases the spot totally
            claimTerritoryAroundHex(centerPlot, -1)
            setTimer(iFeatureType,nil,nil,nil,nil)
            sResult = "Wonder Lost"
        else
            -- there is a unit holding the spot           
            if (iTimer == 0 ) then
                -- time is up, reset spot, restart timer
                claimTerritoryAroundHex(centerPlot, -1)
                setTimer(iFeatureType,iX,iY,-1,cTURNS_TO_BOOST)
                sResult = giveTimedBoost(iPlayer,iFeatureType)
            end
    
            if (iTimer > 0) then
                -- time is not yet up, count down the timer
                setTimer(iFeatureType,iX,iY,iPlayer,iTimer-1)
                -- sResult = "Counting down to Boost "..iTimer-1
            end
        end
    end

    if ((iPlayer == 0) and (iOwner == -1)) then
        -- If Owner is -1 then count down timer to reset it again
        -- but only once (for player 0), not any others
        if (iTimer == 0 ) then
            setTimer(iFeatureType,nil,nil,nil,nil)
            sResult = "A Wonder is released for recapture"
        end
        if (iTimer > 0 ) then
            setTimer(iFeatureType,iX,iY,-1,iTimer-1)
            -- sResult = "Counting down for reset "..iTimer-1
        end
    end
        
    -- Notify
    if (sResult ~= "") then
        -- notify only if sResult has text
        local pPlayer = Players[iPlayer]
        local iNotifyType = NotificationTypes["NOTIFICATION_GOLDEN_AGE_ENDED_ACTIVE_PLAYER"]
        pPlayer:AddNotification(iNotifyType, sResult, sResult, iX, iY)   
    end
end
 
After tinkering long with the new wonders not rendering correctly, I realized that instead of creating new wonders in the database, I could just update the existing wonders. :cooool:

This enabled them to render nicely, and made the XML much simpler - and the LUA change was a simple config change. :woohoo:

I still used Natural Wonders Enhanced by Leo as an example and then the mod Really Advanced Setup by General Tsao to give me an exact occurrence of them all.

Code to update Natural Wonder below - the key for the LUA to work is really that the wonder is now passable (aka not impassable) and the proper TAG.

Spoiler :

Code:
    <Features>
        <Update>
            <Where Type="FEATURE_EL_DORADO"/>
            <Set
                Description="Golden Eras El Dorado (NWTB)"
                Help="Hold for a number of turns to receive Golden Eras. (NWTB)."
                OccurrenceFrequency="20"
                Impassable="false"
                InBorderHappiness="1"
                FirstFinderGold="0"
                AdjacentUnitFreePromotion=""
                NoCity="true"
                Defense="20"/>
        </Update>
    </Features>
 
Top Bottom