Jump to content

More details about triggers: Delay(I:Delay*), RandomNum(I:Range*,I:Value*)


Recommended Posts

0x4027 Delay(I:Delay*)
Delays the next check of the block of triggers where this trigger is, by the number of seconds specified. This value is not stored when the game is saved. 

Delay is applied immediately before first block execution of delayed script block if block could not be executed because of some different action eg. casting spell or movement , eg. if script block has Delay(60) and then it executes some action eg. casts a spell, before 1st execution game will wait 60 second and then casts a spell a repeats same every 60 seconds. It may happen delayed block will never be executed if another action is in progress, it looks like game gives some tolerance about 1 round if delay block is not executed within this period next chance to execute actions will be at next check in 60 sec. (the 1 round tolerance delay does exist if delayed block never been executed before)

What is missing in trigger description is: Delay is not executed for every block separately or better say delay changes time (interval for checking) for delayed blocks. This means delay should not be used like a cooldown for casting spells eg.

IF
	True()	//This is First script block with Sring 6 is notification - begining of script loop
THEN
	RESPONSE #100
		DisplayString(Myself,6)  // Then join us by all means. You are welcome here.
		Continue()
END

IF
	ActionListEmpty()
	Delay(3)
THEN
	RESPONSE #100
		DisplayString(Myself,2)  // You played Elminster?
END

IF
	ActionListEmpty()
	Delay(6)
THEN
	RESPONSE #100
		DisplayString(Myself,3)  // Uh, the yugoloth, was it? Yeah, you stole the show with that one, if I recall.
END

IF
	ActionListEmpty()
	Delay(3)
THEN
	RESPONSE #100
		DisplayString(Myself,4)  // And, who knows, we were rehearsing for Picoccio's "Three Days in the Ether." Perhaps we can give you a dress matinee.
END

Code above contains 4 blocks, 1st block is notification block to let us know when script loop begins, then 2nd block ticks every 3 second, 3rd block ticks every 6 seconds and 4th block every 3 seconds.

Result is only 2nd block script is executed, this means only "You played Elminster?" is displayed then script returns at beginning " Then join us by all means. You are welcome here." and continues checking blocks again, actions from blocks 3 and 4 are never executed.

1st block ticks always (approx. every 1 sec, this varies from script levels, override scripts and master scripts ticks much faster than class script, slowest is Default script)

2nd blocks ticks every 3 sec, 3,6,9,12,15,18,21,24

3rd blocks ticks every 6 sec, 6,12,18,24

4th blocks ticks every 3 sec, 3,6,9,12,15,18,21,24

Therefore script should not contain blocks with same Delay parameter or rest of blocks below are never executed. We could use Continue() to allow rest of scripts to be checked is such case delayed scripts which are checked in same time interval will be executed, but Continue() checks conditions of following block at once so if 1 block checks health eg.: HPLT(Myself,20) and then cast "CLERIC_HEAL", 2nd block checks HPLT(Myself,30) cast "CLERIC_CURE_MEDIUM_WOUNDS" the second healing is executed even target is already fully healed, because of a way how Continue() changes block checking.

 

***

0x4047 RandomNum(I:Range*,I:Value*)
Generates a random number between 1 and Range. Returns true only if the random number equals the 2nd parameter. 

Now about RandomNum, RandomNumGT, RandomNumLT, the problem seems to be similar to delay eg.:

IF
	ActionListEmpty()
	RandomNum(3,1)
THEN
	RESPONSE #100
		DisplayString(Myself,2)  // You played Elminster?
END

IF
	ActionListEmpty()
	RandomNum(3,1)
THEN
	RESPONSE #100
		DisplayString(Myself,3)  // Uh, the yugoloth, was it? Yeah, you stole the show with that one, if I recall.
END

IF
	ActionListEmpty()
	RandomNum(3,1)
THEN
	RESPONSE #100
		DisplayString(Myself,4)  // And, who knows, we were rehearsing for Picoccio's "Three Days in the Ether." Perhaps we can give you a dress matinee.
END

Similar script, 3 blocks with 33% chance to execute a block, result is 2nd and 3th block is never executed. I did not expect RandomNum works such way, so simply say if blocks contain same parameters as block above they are never executed. RandomNum is checked only once per loop for blocks with same parameters or better say RandomNum is checked at once for all blocks with same parameters?

 

If parameters are unique then each block is checked separately and actions in blocks 2 and 3 have chance to be executed.

IF
	ActionListEmpty()
	RandomNum(3,1)
THEN
	RESPONSE #100
		DisplayString(Myself,2)  // CharnameYou played Elminster?
END

IF
	ActionListEmpty()
	RandomNum(4,1)
THEN
	RESPONSE #100
		DisplayString(Myself,3)  // Uh, the yugoloth, was it? Yeah, you stole the show with that one, if I recall.
END

IF
	ActionListEmpty()
	RandomNum(5,1)
THEN
	RESPONSE #100
		DisplayString(Myself,4)  // And, who knows, we were rehearsing for Picoccio's "Three Days in the Ether." Perhaps we can give you a dress matinee.
END

example of script where RandomNum uses same parameters draconis.bcs

unique RandomNum parameters: ohryxtra.bcs

 

Edited by Gamemacik
Link to post

Delay: so it works like a modulo operator, a sieve.

Random: AFAIK all the triggers and actions share the random value (in the same tick).

Please just suggest changes or additions to the text on the site.

Link to post
Posted (edited)

i added to first post some more details to Delay trigger after more testing, now it is even more confusing, it seems to be very unreliable command for long delayed blocks because they may never be executed.


IF
	Delay(58)
THEN
	RESPONSE #100
		ForceSpell(Myself,WIZARD_GLOBE_OF_INVULNERABILITY)  // SPWI602.SPL (Globe of Invulnerability)
END

IF
	Delay(60)
THEN
	RESPONSE #100
		ForceSpell(Myself,CLERIC_HEAL)  // SPPR607.SPL (Heal)
END

IF
	Delay(18)
THEN
	RESPONSE #100
		ForceSpell(Myself,WIZARD_MAGIC_MISSILE)  // SPWI112.SPL (Magic Missile)
END

in short from testing of script above.

if spawned NPC is idle it will cast WIZARD_GLOBE_OF_INVULNERABILITY immediately but if eg. moves next check is in 58 sec

then is should cast 3x MAGIC_MISSILE that means about 54 seconds elapsed

NPC waits 4 sec and casts WIZARD_GLOBE_OF_INVULNERABILITY, NPC remains idle, after cast is time 58+6=64 seconds

CLERIC_HEAL is not casted because it is too late, required time was at 60 sec, long casting time of WIZARD_GLOBE_OF_INVULNERABILITY prevented NPC to heal self.

Edited by Gamemacik
Link to post

I imagine with long delays and interspersed blocking actions this is expected behaviour if it's just using game time to modulo against.

Link to post

Delay(intArg1) is just the total number script passes performed on the current creature, (including the one in progress), modulus intArg1. Very simple implementation in the engine:

return m_nExpectedProcessPendingTriggersCalls % intArg1 <= m_nMissedProcessPendingTriggerCalls

Unless an action specifically allows for itself to be interrupted, a currently executing action will block script passes for its duration, but not stop these blocked passes from being counted in m_nExpectedProcessPendingTriggersCalls.

TL;DR: Delay() should really be called something like "Interval()" — and this "interval" can be missed if the script is preoccupied with something else when it would otherwise be hit, as is standard behavior with IE scripting.

---

And yes, scripting uses the same random value to seed all RandomNum() triggers across a single tick; if you have multiple RandomNum() calls with the same parameters, they will all generate the same result.

Edited by Bubb
Link to post
Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...