[HELP] Timers and waiting in scripts

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
flatline

[HELP] Timers and waiting in scripts

Post by flatline »

If I want to add an amount of protection with a spell and after 30 seconds return protection to its original value, how can I accomplish that in a script?

Say I want a "mana shield" spell where I get the casters current mana, and adds that amount of armor to all champions for 30 seconds. What is the way to achieve a 30 second wait inside that spell?
User avatar
cromcrom
Posts: 549
Joined: Tue Sep 11, 2012 7:16 am
Location: Chateauroux in a socialist s#!$*&% formerly known as "France"

Re: [HELP] Timers and waiting in scripts

Post by cromcrom »

You can spawn timers. I advise you to check grimwold's very nice spells that do this.
viewtopic.php?f=14&t=3475
A trip of a thousand leagues starts with a step.
User avatar
Komag
Posts: 3658
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: [HELP] Timers and waiting in scripts

Post by Komag »

You could spawn a timer for it, and that's a good way to do it because if you place a timer in the editor beforehand and the party is on a different level when they cast the spell, the timer won't count at the right speed due to engine optimizations.

Here is an example:

Code: Select all

function manaShield()
--cast mana shield code
  spawn("timer",party.level,0,0,0,"manaShieldTimer")
   :addConnector("activate", "manaScript", "resetProtection")
   :setTimerInterval(30)
   :activate()
end

function resetProtection()
--reset the armor settings code
  manaShieldTimer:destroy()
end
Finished Dungeons - complete mods to play
flatline

Re: [HELP] Timers and waiting in scripts

Post by flatline »

Thanks a bunch!

One thing struck me:
Say Champion 1 have 20 protection, spell is cast, adding 20 protection. During the spell effect, the hero equips or unequips armor, altering his protection value. Does this affect the base protection value when the spell is destroyed. IE, is the original protection value calculated as normal when the Mana shield turns off? I guess I'll try and see.
User avatar
Grimwold
Posts: 511
Joined: Thu Sep 13, 2012 11:45 pm
Location: A Dungeon somewhere in the UK

Re: [HELP] Timers and waiting in scripts

Post by Grimwold »

Komag wrote:You could spawn a timer for it, and that's a good way to do it because if you place a timer in the editor beforehand and the party is on a different level when they cast the spell, the timer won't count at the right speed due to engine optimizations.

Here is an example:

Code: Select all

function manaShield()
--cast mana shield code
  spawn("timer",party.level,0,0,0,"manaShieldTimer")
   :addConnector("activate", "manaScript", "resetProtection")
   :setTimerInterval(30)
   :activate()
end

function resetProtection()
--reset the armor settings code
  manaShieldTimer:destroy()
end
This is very good, but I would suggest adding a little 'protection' into the script to avoid problems if the spell is cast again before the previous spell has finished. When the spell is cast, I would search for the timer and if it exists destroy it.. then go on to spawn a new timer.

Code: Select all

local mana_timer_entity = findEntity("manaShieldTimer")
if mana_timer_entity ~= nil then
  mana_timer_entity:destroy()
end
User avatar
JohnWordsworth
Posts: 1397
Joined: Fri Sep 14, 2012 4:19 pm
Location: Devon, United Kingdom
Contact:

Re: [HELP] Timers and waiting in scripts

Post by JohnWordsworth »

Just a quick question about using the timer method. If you create a timer manually (in script) is it immune to running at a different speed when you go down stairs? Or, if I cast a spell which spawns a timer to give me a buff and then jump down a pit - will it last twice as long?

I don't suppose we have access to any of the lua os.time() methods. In fact, a gameTicks() or gameTime() method that counts the in game seconds since the start of the game (not including pause mode etc) would be really, really useful. It wouldn't matter if the time fire every second, or every frame - you could always accurately measure the time an effect has been active and disable it round about after the right time.
My Grimrock Projects Page with links to the Grimrock Model Toolkit, GrimFBX, Atlas Toolkit, QuickBar, NoteBook and the Oriental Weapons Pack.
flatline

Re: [HELP] Timers and waiting in scripts

Post by flatline »

Ok, I can't get this to work due to stupidity, tiredness and being away from modding for a few weeks.
I want to avoid having to place timers and lua scripts into the dungeon, if possible.

SpoilerShow
defineSpell{
name = "ManaShield",
uiName = "Holy Shield",
skill = "spellcraft",
level = 1,
runes = "GHI",
manaCost = 1,
onCast = function(Champ)
function spellcheck()
local mana_timer_entity = findEntity("manaShieldTimer")
if mana_timer_entity ~= nil then
mana_timer_entity:destroy()
end
--cast mana shield code
function manashield(Champ)
local base_energy = Champ.getStat("energy")
spawn("timer",party.level,0,0,0,"manaShieldTimer")
:addConnector("activate", "manaScript", "resetProtection")
:setTimerInterval(30)
:activate()
end

function manaScript()
for slot=1,4 do
if party:getChampion(slot) ~= nil then
party:getChampion(slot):modifyStat("protection", base_energy)
Champ:setStat("energy", 0)
end

function resetProtection()
--reset the armor settings code
manaShieldTimer:destroy()
end
end
}
User avatar
Grimwold
Posts: 511
Joined: Thu Sep 13, 2012 11:45 pm
Location: A Dungeon somewhere in the UK

Re: [HELP] Timers and waiting in scripts

Post by Grimwold »

Although I haven't tested it, I'm pretty sure that timers spawned in script behave the same as timers placed using the editor... and hence would suffer from the time-dilation effects of being on a different level to the party.

If needed, you could probably implement a script to transfer active party_timer_'s to the party's current level.. maybe as part of the onMove hook using a variable that stores the level the party was on last time it moved.


Also, I don't think we have access to the lua os library..
User avatar
Komag
Posts: 3658
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: [HELP] Timers and waiting in scripts

Post by Komag »

timers spawned via script are exactly the same, and suffer the same dilation. You can instead start a ticker that ticks a script counter every second and that way you can detect each second whether the timer and the party are still on the same level, and if not destroy the timer and spawn a new on on the party level to continue the tick
Finished Dungeons - complete mods to play
User avatar
Grimwold
Posts: 511
Joined: Thu Sep 13, 2012 11:45 pm
Location: A Dungeon somewhere in the UK

Re: [HELP] Timers and waiting in scripts

Post by Grimwold »

flatline wrote:I want to avoid having to place timers and lua scripts into the dungeon, if possible.
I'm pretty sure that for a complex spell like this, that uses multiple functions, you will be unable to manage without using a script entity in the dungeon. The spell definition can only handle a fire-once piece of code. That's why all my more complex spells (Push Monster; Hold Monster; Burn Monster) required a script entity in the dungeon for any ongoing effects.

You wouldn't need to manually place any timers in the dungeon, and would only need a single script entity, say called mana_shield_script.

Your spell definition would look something like this in spells.lua:

Code: Select all

defineSpell{
name = "ManaShield",
uiName = "Holy Shield",
skill = "spellcraft",
level = 1,
runes = "GHI",
manaCost = 1,
onCast = function(champ)
  return mana_shield_script.manashield(champ)
end,
}
and your script entity called mana_shield_script in the dungeon would be something like this:

Code: Select all

    -- set initial base_energy value (this variable used for 'resetting' the protection)
    base_energy = 0

    -- modify protection value
    function modifyProtection(modifier)
      hudPrint("modifying by " .. modifier)
      for slot=1,4 do
        if party:getChampion(slot) ~= nil then
          party:getChampion(slot):modifyStatCapacity("protection", modifier)
          party:getChampion(slot):modifyStat("protection", modifier)
          -- hudPrint("max protection " .. tostring(party:getChampion(slot):getStatMax("protection")))
        end
      end
    end

    -- check for and destroy mana timer
    function checkManaTimer()
      local mana_timer_entity = findEntity("manaShieldTimer")
      if mana_timer_entity ~= nil then
        mana_timer_entity:destroy()
      end
    end

    -- cast mana shield code
    function manashield(Champ)
      checkManaTimer()
      base_energy = Champ:getStat("energy")
      -- hudPrint("base energy = " .. tostring(base_energy))
      spawn("timer",party.level,0,0,0,"manaShieldTimer")
        :addConnector("activate", "mana_shield_script", "resetProtection")
        :setTimerInterval(30)
        :activate()
      Champ:setStat("energy", 0)
      modifyProtection(base_energy)
    end

    function resetProtection()
      modifyProtection(-base_energy)
      checkManaTimer()
    end
I haven't tested this code, and it's pretty late as I'm typing so I may have made the odd mistake, but the principle should be sound... if I get chance I'll plug it into a test dungeon and see what happens.

EDIT - When I tested the code I originally wrote, I ran into a problem regarding Max Stat value.. but once I found out that's why protection was not increasing I was able to modify the script and it now works as expected. the above code has been corrected, so should work.
Post Reply