[script] Extended timer (setConstant, tickLimit, callbacks)

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
User avatar
JKos
Posts: 464
Joined: Wed Sep 12, 2012 10:03 pm
Location: Finland
Contact:

Re: [script] Extended timer (setConstant, tickLimit, callbac

Post by JKos »

Yeah the getStatistics('play_time') could render the clock example useless, but it doesn't make the extended timer useless. You can do all kinds of crazy stuff with it :) Because the extended timer can be extended dynamically and it's passed to called event-functions instead of native timer it's possible to do things like this:

Code: Select all

function activateTimer()
    local timer = timers:create('test')
    timer.message = "Hello"
    timer:addConnector('activate','this_script','print_message')
    timer:setTimerInterval(1)
    timer:activate()

   local timer2 = timers:create('test2')
   timer2.message = "Hi"
   timer2:addConnector('activate','this_script','print_message')
   timer2:setTimerInterval(2)
   timer2:activate()
end

print_message(timer)
    print(timer.message)
end

- LoG Framework 2http://sites.google.com/site/jkoslog2 Define hooks in runtime by entity.name or entity.id + multiple hooks support.
- cloneObject viewtopic.php?f=22&t=8450
User avatar
Diarmuid
Posts: 807
Joined: Thu Nov 22, 2012 6:59 am
Location: Montreal, Canada
Contact:

Re: [script] Extended timer (setConstant, tickLimit, callbac

Post by Diarmuid »

Ok, I got it to work.

I modified JKos excellent script and wrapper to map functions to a counter instead of a timer. I had to study it a bit to understand how it worked and it had taught me a lot, thanks.

So here's the modified timers script:

Code: Select all

objects = {}
debug = true

-- new absoluteTimerCode

function createAbsolute(self,id)
 local timerEntity = spawn('counter',1,0,0,0,id)
 self.objects[id] = aWrap(timerEntity)
 timerEntity:addConnector('activate','timers','callCallbacksAbs')
 globalTimer:addConnector('toggle',timerEntity.id,'decrement')
 return self.objects[id]
end

function aWrap(timer)
 local wrapper = {
    id = timer.id,
    interval = 0,
    connectors = {},
   active = false,
   callbacks = {},
   tick = 0,

   addConnector = function(self,paction,ptarget,pevent)
      self:addCallback(
         function(self,scriptId,functionName) 
            findEntity(scriptId)[functionName](self)
         end,
         {ptarget,pevent}
      )
   end,
   activate = function(self)
      self.active = true
      findEntity(self.id):setValue(self.interval*20)
   end,
   deactivate = function(self)
      self.active = false
      findEntity(self.id):setValue(2000000)
   end,
   toggle = function(self)
      if (self.active) then 
         self:deactivate()
      else
         self:activate()
      end
   end,   
   isActivated = function(self)
      return self.active
   end,      
   setTimerInterval = function(self,interval)
      self.interval = interval
      if self.active == true then
          findEntity(self.id):setValue(interval*20)
      else
          findEntity(self.id):setValue(2000000)
      end
   end,
   destroy = function(self)
      findEntity(self.id):destroy()
      timers.objects[self.id] = nil
   end,   
   addCallback = function(self,callback,callbackArgs)
      callbackArgs = callbackArgs or {}
      self.callbacks[#self.callbacks+1] = {callback,callbackArgs}
      
   end,
   callCallbacksAbs = timers.callCallbacksAbs,
   setTickLimit = function(self,limit,destroy)
      self:addCallback(
         function(self,limit,destroy)
            if timers.debug then 
               print('tick count:'..self.tick) 
            end
            if self.tick >= limit then
               self:deactivate()
               if timers.debug then print('timer '..self.id..' deactivated: tick limit '..limit) end
               if (destroy) then
                  self:destroy() 
               end
            end
         end,
         {limit,destroy}
      )
   end   
 }
 return wrapper
end

function find(self,id)
   return self.objects[id]
end

function callCallbacksAbs(timerEntity)
   --print(timerEntity.id..' callbacks called')
   local extTimer = objects[timerEntity.id]
   extTimer.tick = extTimer.tick + 1
   for _,callback in ipairs(extTimer.callbacks) do
      callback[1](extTimer,unpack(callback[2]))
   end
   if extTimer.active == true then
       extTimer:setTimerInterval(extTimer.interval)
   end
   if (extTimer.destroyed) then
      if timers.debug then print('timer '..extTimer.id..' destroyed') end
      extTimer:destroy()
   end
end
As you see, I've changed functions from create to createAbsolute, wrap to aWrap and callCallbacks to callCallbacksAbs, to allow coexistence of this script with the original one. Essentially, the createAbsolute creates a timer which will always be in sync at the same rate at all levels anywhere, so I got rid of all the isConstant and levels elements.

The required setup to use this is:
1) create a script_entity with this code inside (name doesn't matter).

Code: Select all

spawn('wall_button',1,0,0,1,"globalTimer")

function globalTick(sourceTimer)
	if sourceTimer.level == party.level then
		globalTimer:push()
	end
end
2) connect a 0.04 timer to this function on each level.

I've tested this resolution of 1/20th of a second and it's not performance noticeable in any way. This also means that, in terms of decimals, your extended timers will need to be either: 0.05 (1/20), 0.625 (1/16), 0.1(1/10), 0.125(1/8), 0.2(1/5), 0.25(1/4) or 0.5(1/2). So a value of 3.1 works.

Apart from that, all the syntax that JKos developped is intact, so you should use these absolute timers in the exact same way as his timers. You just call createAbsolute instead of create, and the rest is handled internally. I tried for example JKos's example just above with Hello/Hi, and it worked fine with just the createAbsolute change. Now, I probably made a typo somewhere or I missed something, so please test and feedback.
User avatar
msyblade
Posts: 792
Joined: Fri Oct 12, 2012 4:40 am
Location: New Mexico, USA
Contact:

Re: [script] Extended timer (setConstant, tickLimit, callbac

Post by msyblade »

You guys just BLEW my mind. Follow me here. Doesn't this mean, that if I were a coding ninja like you guys, (Which I am NOT.)I could set up an actual "Game Clock"? Maybe even am/pm, But!!! I could call that timer result, and make my mod know what time of day it is? Sooooo, I could make Zombies come out of "The Crypt" From midnight to 4am, but they "Retreat" before dawn?
Currently conspiring with many modders on the "Legends of the Northern Realms"project.

"You have been captured by a psychopathic diety who needs a new plaything to torture."
Hotel Hades
User avatar
Komag
Posts: 3659
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: [script] Extended timer (setConstant, tickLimit, callbac

Post by Komag »

I don't see why not! But then you have to deal with all the design issues that come with that - how long to make the player way, is there a way to fast-forward time, etc
Finished Dungeons - complete mods to play
Post Reply