Custom Perk: Night Person - melindil/FTSE GitHub Wiki

In this example, we will recreate the Night Person trait as a perk, with the following differences:

  • The perk will work as described, giving -1 to PE and IN during daytime and +1 to PE and IN during night time.
  • The perk will apply the +1/-1 stats as temporary modifiers rather than permanent ones. Among other things, this will result in them being highlighted in blue or red, and will make it so that the character's perk selection is (correctly) not affected by the bonus/penalty.

ACTOR_TABLE_PERM = 0
ACTOR_TABLE_DERIVED = 1
ACTOR_TABLE_TEMPORARY = 2
ACTOR_TABLE_CURRENT = 3

-- Use the default implementations for converting the millisecond timer
-- to in-game time. These need to be in Lua for the perk code to correctly
-- determine the game timer hour. 

month_end_days = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}

function MsecToDayHMS(ms,scale)
    if scale > 0 then
      ms = ms * 3
    end
    d = (ms // 86400000)
    h = (ms // 3600000)%24
    m = (ms // 60000)%60
    s = (ms // 1000)%60
    ms = ms % 1000
    gametime = {
      year = 0,
      month = 0,
      day = d,
      hour = h,
      minute = m,
      second = s,
      msec = ms
    }
    return gametime
end

function AddBaseToGameTime(gametime)

    -- add base days, hours and minute
    -- default start time is Jan 1 2197 06:29:00
    gametime["minute"] = gametime["minute"] + 29
    gametime["hour"] = gametime["hour"] + 6
    gametime["day"] = gametime["day"] + 2197*365

    -- normalize hours and minutes
    if gametime["minute"] > 59 then
      gametime["minute"] = gametime["minute"] - 60
      gametime["hour"] = gametime["hour"] + 1
    end
    if gametime["hour"] > 23 then
      gametime["hour"] = gametime["hour"] - 24
      gametime["day"] = gametime["day"] + 1
    end
    
    -- calculate year and day within year
    gametime["year"] = gametime["day"]//365
    gametime["day"] = gametime["day"] % 365 + 1

    -- Get month and day within month
    mo = gametime["day"] // 30
    if mo == 0 or gametime["day"] > month_end_days[mo] then
      mo = mo + 1
    end
    if mo > 1 then
      gametime["day"] = gametime["day"] - month_end_days[mo-1]
    end
    gametime["month"] = mo
    return gametime
end

function OnStart ()
  -- Very simple requirement for testing, level 3 only
  newperk = {name = "nightPersonPerk",
               minlevel = 3,
               maxperktaken = 1
              }
  -- Replace unused perk 18 "fortuneFinder"
  hookexecutor:ReplacePerk(newperk, 18)

end

function OnLocaleLoad()
    hookexecutor:AddLocaleString("name_nightPersonPerk","Night Person")
    hookexecutor:AddLocaleString("desc_nightPersonPerk","Perk demonstrating game timer routines")

end

function OnLongTick(e)

  if e:GetAttribute("nightPersonPerk", ACTOR_TABLE_CURRENT) > 0 then
    -- use perk entry in temporary table to save info about
    -- penalty (=1), bonus (=2), or neither (=0) is applied.
    curr = e:GetAttribute("nightPersonPerk", ACTOR_TABLE_TEMPORARY)
    now = world:GetTime()
    if now["hour"] < 8 or now["hour"] > 19 then
      -- night time: apply bonus if none yet or on penalty
      if curr == 0 then
        bonus = { perception=1, intelligence=1 }
        e:ApplyBonus(bonus,false)
        e:SetAttribute("nightPersonPerk", ACTOR_TABLE_TEMPORARY, 2)
      elseif curr == 1 then
        bonus = { perception=2, intelligence=2 }
        e:ApplyBonus(bonus,false)
        e:SetAttribute("nightPersonPerk", ACTOR_TABLE_TEMPORARY, 2)
      end
    else
      -- day time: apply penalty if none yet or on bonus
      if curr == 0 then
        bonus = { perception=1, intelligence=1 }
        e:RemoveBonus(bonus,false)
        e:SetAttribute("nightPersonPerk", ACTOR_TABLE_TEMPORARY, 1)
      elseif curr == 2 then
        bonus = { perception=2, intelligence=2 }
        e:RemoveBonus(bonus,false)
        e:SetAttribute("nightPersonPerk", ACTOR_TABLE_TEMPORARY, 1)
      end
    end
  end
end