Delay Timer in Script

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
Post Reply
User avatar
Damonya
Posts: 134
Joined: Thu Feb 28, 2013 1:16 pm
Location: France
Contact:

Delay Timer in Script

Post 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.
Orwak - MOD - Beta version 1.0
alois
Posts: 112
Joined: Mon Feb 18, 2013 7:29 am

Re: Delay Timer in Script

Post 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 :)
User avatar
Damonya
Posts: 134
Joined: Thu Feb 28, 2013 1:16 pm
Location: France
Contact:

Re: Delay Timer in Script

Post 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
Orwak - MOD - Beta version 1.0
Torquemada
Posts: 25
Joined: Fri Apr 05, 2013 10:52 pm

Re: Delay Timer in Script

Post 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.
User avatar
Diarmuid
Posts: 807
Joined: Thu Nov 22, 2012 6:59 am
Location: Montreal, Canada
Contact:

Re: Delay Timer in Script

Post 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.
User avatar
Damonya
Posts: 134
Joined: Thu Feb 28, 2013 1:16 pm
Location: France
Contact:

Re: Delay Timer in Script

Post 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
Orwak - MOD - Beta version 1.0
User avatar
Damonya
Posts: 134
Joined: Thu Feb 28, 2013 1:16 pm
Location: France
Contact:

Re: Delay Timer in Script

Post 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 ;) )
Orwak - MOD - Beta version 1.0
User avatar
Diarmuid
Posts: 807
Joined: Thu Nov 22, 2012 6:59 am
Location: Montreal, Canada
Contact:

Re: Delay Timer in Script

Post 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
User avatar
JKos
Posts: 464
Joined: Wed Sep 12, 2012 10:03 pm
Location: Finland
Contact:

Re: Delay Timer in Script

Post 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.
- 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
Damonya
Posts: 134
Joined: Thu Feb 28, 2013 1:16 pm
Location: France
Contact:

Re: Delay Timer in Script

Post by Damonya »

Thanks for the update and the examples. I still can not understand totally your frameworks ;)
Orwak - MOD - Beta version 1.0
Post Reply