Page 3 of 3

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

Posted: Sun Nov 25, 2012 11:24 pm
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


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

Posted: Mon Nov 26, 2012 7:32 am
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.

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

Posted: Thu Nov 29, 2012 7:39 am
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?

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

Posted: Thu Nov 29, 2012 11:59 am
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