Page 1 of 1

Delay Timer in Script

Posted: Mon Apr 29, 2013 9:36 am
by Damonya
I try to have a delay in a script without using a timer already built into the editor, but I am faced with many difficulties. I have some ideas but I'm not an expert with script.

Initially the script is very simple:

the herderondie.onDieOne function runs when the herder die:

Code: Select all

cloneObject{
	name = "herder_dying",
	baseObject = "herder",
	onDie = function(self)		
      return herderondie.onDieOne(self)
   end,
}

herderondie script:

Code: Select all

function onDieOne(self)
     spawn("herder",self.level,self.x,self.y,self.facing)
end
But I want a delay between when the first herder die and when the other herder spawn.
if I simply put a timer in the editor, the problem is with the "self" in the function, because the herder spawn where the timer is placed in the editor. So not possible.

So my idea was to spawn a timer where the first herder dies:

Code: Select all

herder_ondieone_sequence = 0
function onDieOne(self)
	
	if herder_ondieone_sequence == 0 then
		t = spawn("timer", self.level, self.x,self.y,self.facing, "timer_herder_ondie_one"..self.id)
		t:setTimerInterval(0.25)
		t:addConnector("activate", "herderondie", "onDieOne")
		t:activate()
		herder_ondieone_sequence = 1
	
	elseif herder_ondieone_sequence == 1 then
		spawn("herder",self.level,self.x,self.y,self.facing)
		herder_ondieone_sequence = 0
		t:deactivate()
		t:destroy()
	end		

end
But I am not satisfied with this code. For example, if I destroy several herders in the same time? The function collapse. And I intend to use in addition, several sequences with such longer period to create visual effects with particle, so this function is not suitable with many herders in the same room. There is probably another method, more efficient and more general, but I don't see.

Re: Delay Timer in Script

Posted: Mon Apr 29, 2013 11:22 am
by alois
Since you actually call the function exactly two times for every herder maybe it is easier to do as follows:

Code: Select all

function onDieOne(self)
   if (self.id:find("timer")) then -- in this case, the timer has already been set -> we have to spawn a monster
      spawn("herder",self.level,self.x,self.y,self.facing)
      self:deactivate()
      self:destroy()
   else -- in the id of the monster the word "timer" is missing -> it is the first time -> let's spawn the timer
      local t = spawn("timer", self.level, self.x,self.y,self.facing, "timer_"..self.id)
      t:setTimerInterval(0.25)
      t:addConnector("activate", "herderondie", "onDieOne")
      t:activate()
   end      
end
Of course, you have to be careful to spawn the 'standard' herder the second time (not the modified one with the onDie hook) or otherwise you are going to have a tough ( = infinite) battle! :)

alois :)

Re: Delay Timer in Script

Posted: Mon Apr 29, 2013 12:06 pm
by Damonya
Thank you once again alois.

The way you see the script is very interesting. :)

Code: Select all

self.id:find("timer")
This is what I was missing

EDIT:

However, still a problem if I want with the same method a herder_3 who spawn herder_2 who spawn herder when dying: error duplicate ID
But I bypassed the problem, finally abandoning the delay timer, for the same result

Re: Delay Timer in Script

Posted: Mon Apr 29, 2013 10:47 pm
by Torquemada
Edit: I see now that you've already solved it, too eager to help I guess :D

I believe I've found the solution you were looking for.
- Place a Timer and a Counter in the editor (call them spawn_timer and spawn_counter).
- Give the counter an initial value (I gave it 4)
- Connect the timer to the counter with decrement action
- Place two script entities:

- herderondie

Code: Select all

function onDieOne(self)
     spawning_script.setX(self.x)
     spawning_script.setY(self.y)
     spawning_script.setLevel(self.level)
     spawning_script.setFacing(self.facing)
     spawn_counter:reset()
     spawn_timer:activate()
end
- spawning_script

Code: Select all

spawnX = 0
spawnY = 0
spawnFacing = 0
spawnLevel = 0
function spawnHerder()
  if spawn_counter:getValue() == 0 then
     spawn_timer:deactivate()
     spawn("herder_dying",spawnLevel,spawnX,spawnY,spawnFacing)
  end
end

function setX(value)
  spawnX = value
end

function setY(value)
  spawnY = value
end

function setLevel(value)
  spawnLevel = value
end

function setFacing(value)
  spawnFacing = value
end
- Connect the counter to spawning_script

Now when a herder_dying dies it stores it's position and facing in spawning_script and starts the timer.
When the counter hits zero it fires the spawning script which contains the positional values of the last herder.

Re: Delay Timer in Script

Posted: Tue Apr 30, 2013 5:16 am
by Diarmuid
Well, don't you know, exsp comes with a delay function (powered by LoG framework extended timers): https://sites.google.com/site/exspwiki/ ... arguments-

So you can simply write:

Code: Select all

onDie = function(self)

	exsp.delay(4, 	
		function(self, name, level, x, y, facing)
			spawn(name, level, x, y, facing)
		end,		
		{self.name, self.level, self.x, self.y, self.facing}
	)
	
end
There, this respawns the same monster in 4s, no timers, counters, or whatever to deal with.

Re: Delay Timer in Script

Posted: Tue Apr 30, 2013 8:30 am
by Damonya
Torquemada wrote:Edit: I see now that you've already solved it, too eager to help I guess :D
No no, thanks for help. And this can be useful for other scripts and other people. Your method is original and very interesting.
Well, don't you know, exsp comes with a delay function (powered by LoG framework extended timers)
I didn't know. :D

I will test both your methods. ;) Thank you to all

Re: Delay Timer in Script

Posted: Tue Apr 30, 2013 9:14 am
by Damonya
Ok I tested. Thanks to all.


Method alois:
perfect but works with only 2 monster: herder_2_dying-->herder_1 . No with herder_3_dying-->herder_2_dying-->herder
Otherwise, no problem with massive killings herder at the same time.

Method Torquemada :
perfect and works with several spawning monsters. herder_n_dying --> herder_2_dying --> herder
Otherwise problem with massive killing herder at the same time. But I think you can surely add timer and counter for each spawning herder with specific ID for bypass this. (problem: if you have a lot of this type monster, you have a lot of timer and counter). So if it's only for one boss or if there is not several of this type monster in one room, it's not a problem (only one counter and one timer are good enough).

My method
works with several spawning monsters but problem with massiv killings herder at the same time. No solution

Diarmuid Method
Perfect. No problem and short scripting. But you must download LOG and EXSP framework. (But I recommend them ;) )

Re: Delay Timer in Script

Posted: Tue Apr 30, 2013 2:44 pm
by Diarmuid
Damonya wrote: Diarmuid Method
Perfect. No problem and short scripting. But you must download LOG and EXSP framework. (But I recommend them ;) )
No need for exsp actually, only LoG framework is required. You can paste the following in any script entity:
SpoilerShow

Code: Select all

function delay(delay, funct, args)

	local delayId = randomTimerId("delay")
	local delayTimer = timers:create(delayId)

	delayTimer:setTimerInterval(delay)
	delayTimer:addCallback(funct,args)
	delayTimer:setTickLimit(1,true)
	delayTimer:activate()

	return delayId

end


function randomTimerId(prefix)

	local numId = math.random(10000,99999)

	while timers:find(prefix.."."..numId) do
		numId = math.random(10000,99999)
	end

	return prefix.."."..numId

end
and then just call that_script_entity.delay(delayInterval, functionToCall, argumentsToPassToTheFunction).


EDIT: If you need that, here's also a cancelDelay() function to which you can pass the timer id returned by delay(), and it will prevent the delayed function from exectuing. For example, you could step on a pressure plate, trigger a deadly poison trap in the room in 20s, unless the player solves the puzzle, in which case you cancel the delay.
SpoilerShow

Code: Select all

function cancelDelay(delayId)
	local delayTimer = timers:find(delayId)
	delayTimer:deactivate()
	delayTimer:destroy()
end
Example usage:
SpoilerShow

Code: Select all

trapDelay = nil

function activateTrap()

	trapDelay = delayScript.delay(20,
		function()
			launchPoisonClouds()
		end
	)

end

function deactivateTrap()

	delayScript.cancelDelay(trapDelay)
	
end

function launchPoisonClouds()

	poisonSpawner1:activate()
	poisonSpawner2:activate()
	poisonSpawner3:activate()
	poisonSpawner4:activate()
	poisonSpawner5:activate()
	poisonSpawner6:activate()

end

Re: Delay Timer in Script

Posted: Tue Apr 30, 2013 3:49 pm
by JKos
actually I added delayCall-method to timers-script entity a while ago (thanks to Diarmuid for the idea). So you don't need that delayScript either, just download the latest version of LoG framework and you can do this:

Code: Select all

timers.delayCall(2,function() 
		print('test') 
	end
)

I also added repeatCall and sequenceCall-methods.

Code: Select all

timers.repeatCall(2,10,true,function() 
		print('test') 
	end
)
Calls that function 10 times with 2 seconds interval, and first call is instant(no delay)

Code: Select all

timers.sequenceCall('1,2,2.5',function() 
		print('test') 
	end
)
calls function 3 times, 1st call is executed after 1 seconds, 2nd call is executed 2 seconds after the previous call and the last call is executed 2.5 seconds after the previous call.

Re: Delay Timer in Script

Posted: Tue Apr 30, 2013 9:03 pm
by Damonya
Thanks for the update and the examples. I still can not understand totally your frameworks ;)