Timetabling events with the Advanced Clock Library

The Pixie
Nearly four years ago I created Clock_Lib.aslx. I now present a rather more advanced version, Adv_Clock_Lib.aslx (it mostly builds on Clock_Lib.aslx, but the long exits have been dropped and by default it only takes a minute to move to another room).

The new version allows you to timetable events, and includes a wait command that allows the player to wait until an event fires or a set time, whichever is first.

This post has been edited for version 2 of the Advanced Clock Library. Version 2 does not count mistyping as a turn, and it also has facilities for sequences, and other minor improvements.

If you want to upgrade from version 1, you will need to go to the "Set up the game attributes" and ensure you have all those attributes set up properly, and anywhere you use CreateEvent, you will need to add a second attribute, a string that identifies the event (however you want to do that).




The rest of this post is a tutorial for using it. It is fairly simple, but a bit of coding experience will be a big advantage.


Add the library

Add the file Adv_Clock_Lib.aslx to your game. Copy it to your game folder, then in the left pane, open up Advanced, go to Included Libraries, click Add, select from list, save, reload.


Set up the game attributes

On the Attributes tab of the game object, click the Add of Status attributes, type "clock" in the first box, leave the second blank. You can go in game now, and should see the clock attribute, it starts blank, but if you do stuff, time will increment from midnight.

Create two Boolean attributes, "notarealturn" and "beta". If "beta" is true, you will see some text printed out that might help you work out what the system is doing, and so fix any problems. Set it to false before releasing you game. Set "notarealturn" to false.

Now create a script attribute on the game object called "unresolvedcommandhandler". Set the script to this:
game.notarealturn = true



Set the start time

On the Script tab of the game object, in the Start script section, add this line:
SetTime ("1:19:50")

This will set the time to be ten to eight on the evening of day 1. You can use the SetTime function any where in your game if you want to jump to a different time, but be aware that you will skip any timetabled events if you do so.

Now when you go in game, the time starts from 7:50 pm.


Set the timetabled events

Each event is an object with a specific name. Each minute in game time Quest will search for the relevant event, and if it finds one, it will run it. You can only have one event set to run in a given minutes.

Events are named very specifically, according to this pattern:
event_dd_hh_mm

... where dd is the number of the day, hh is the hour and mm is the minutes. In each case you must use exactly two digits, padded with zeroes (this means you are limited to 99 days!).

You do not have to, but I suggest putting all events into a room the player cannot access called "events".

So let us now create an event. Inside the events room, create an object called "event_01_20_00". This will fire at 20:00 on day 1. In the alias field, it is a good idea to give the event a useful name, but this is optional.

In the Description, set this to "Run script". This is where the event is actually set up (it might seem strange to do it here, but it makes it easier to work with). Here is some example code to paste in.
if (player.parent = dining_room) {
msg("The butler sounds the dinner gong.")
}
else {
msg("You hear the dinner gong.")
}

Make sure you have a room called "dining_room" in your game, and then test it out. When the time gets to eight o'clock, you will hear the dinner gong.


Wait

But wait, try playing the game again, and this time type "WAIT" (or "Z"). Whenever the player types WAIT, the game time will move on 15 minutes or until something happens, whichever is first. In this case time will jump to when the dinner gong is sounded, whether that is ten minutes or two minutes.


Quiet

Let us create another event. Call this one "event_01_20_10", and paste in this code:
if (player.parent = dining_room) {
Quiet
}
else {
msg ("'You are late for dinner, sir,' says the butler.")
}

This will fire at ten past eight, to remind you to go to dinner. If you are already in the dining room, however, we do not want anything to happen, so there is the Quiet function. This ensures that WAIT will ignore this event.

Try it in game. Once the gong has sounded, if you type WAIT in the dining room, 15 minutes will pass, nothing happens. Type WAIT elsewhere, and the waiting will stop at 8:10 pm.


Creating Events On The Fly

Sometimes you want to create new events on the fly, scheduling them for a set number of minutes from now. Let us suppose dinner is served 5 minutes after the player gets to the dining room. On the Scripts tab of the dining_room, go to Entering the room for the first time, and paste in this code:
CreateEvent(5, "dinner") {
msg("Dinner is served.")
}

The delay is set to 5 minutes, and everything in the curly braces is the script that will be run. You can make that as complicated as you like, and it would certainly be a good idea to check if the player is actually present.

The second parameter, the string, is just to identify the event. When things are not going as expected, set game.beta to true, and you will see when each event happens, as idenfified by that name.


Sequences

An alternative approach to events is to define a sequence of steps.

Each step is an object, just like the events earlier. To link a step to the next one in the sequence, use the NextStep function in the "look at" script. For example, in the demo there is an object called soup_eaten, with this script:
msg ("'Did you enjoy the soup?' enquires the butler.")
NextStep (soup_rain, 4)

This will cause the object "soup_rain" to be done in 4 minutes.

To start a sequence, just call NextStep from any script, sending it the first object in your sequence.

You can also have sequences branch. One step can test conditions, and choose the next step accordingly.
msg ("'Did you enjoy the soup?' enquires the butler.")
if (player.cursed) {
NextStep (soup_rain, 4)
}
else {
NextStep (second_course, 10)
}

Branches can converge simply by pointing to the same step. You could also have steps running in a continuous cycle. It could be useful to have a step linking to itself until a condition is met. This example checs every three turns whether the player is in the dining room, only going to the next step once she is.

if (player.parent = dining_room) {
msg ("'Did you enjoy the soup?' enquires the butler.")
NextStep (soup_rain, 4)
}
else {
Quiet
NextStep (this, 3)
}


Note, however, that only one sequence can be running at a time (timed events and events created on the fly are not affected). The system only remembers a single event to do next, and if another sequence calls NextStep, that will get overwritten, and the sequence will terminate.


Is It After That Time?

Often you will want to know how much time has passed. The IsAfter function does just that. This example checks if it has gone five past eight.
if (IsAfter("1:20:05") {

To check if it is before, just use not.
if (not IsAfter("1:20:05") {


A better way to handle when dinner is served would be to set a flag on the room, and to move the script to the After entering the room section. Only create the event if the time is after eight o'clock, and use the flag to ensure it is only set once. Also have the event created in the first event, if the player is in the dining room at that time.


Taking Your Time

By default, all commands take 1 minute. If a command takes a long time, use the IncTime function, which takes an interger parameter, the number of minutes that passes. This will ensure that any intervening events will be triggered (but unlike WAIT, the full time will still pass).

Let us suppose it takes 5 minutes to get to or from the kitchen, you could put this code into your exits:
player.parent = this.to
SetInc(5)



Changing Defaults

You can change how long WAIT lasts. The default is fifteen minutes, to change it to 20, do this in your start script:
game_clock.waittime = 20


The player can type TIME, CLOCK or WATCH to see the time. To change the text at the start, you can do this in your start script:
game_clock.clockpreamble = "You look at your watch."

The Pixie
This is the game I built from the tutorial.
<!--Saved by Quest 5.6.5621.18142-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<include ref="Adv_Clock_Lib.aslx" />
<game name="turncount">
<gameid>7f84b598-f20f-4b84-b6e1-24b2d97a0458</gameid>
<version>1.0</version>
<firstpublished>2015</firstpublished>
<statusattributes type="stringdictionary">
<item>
<key>clock</key>
<value></value>
</item>
</statusattributes>
<notarealturn type="boolean">false</notarealturn>
<beta />
<start type="script">
SetTime ("1:19:50")
game_clock.clockpreamble = "You look at your watch."
game_clock.waittime = 20
</start>
<unresolvedcommandhandler type="script">
game.notarealturn = true
</unresolvedcommandhandler>
</game>
<object name="hall">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
<exit alias="south" to="dining_room">
<inherit name="southdirection" />
</exit>
</object>
<object name="events">
<inherit name="editor_room" />
<object name="event_01_20_00">
<inherit name="editor_object" />
<alias>dinner gong</alias>
<look type="script">
if (player.parent = dining_room) {
msg ("The butler sounds the dinner gong.")
dining_room.flag = true
CreateEvent (5, "dinner") {
msg ("Dinner is served.")
soup.parent = dining_room
prawn_cocktail.parent = dining_room
}
}
else {
msg ("You hear the dinner gong.")
}
</look>
</object>
<object name="event_01_20_10">
<inherit name="editor_object" />
<alias>late for dinner</alias>
<look type="script">
if (player.parent = dining_room) {
Quiet
}
else {
msg ("'You are late for dinner, sir,' says the butler.")
}
</look>
</object>
<object name="soup_eaten">
<inherit name="editor_object" />
<look type="script">
msg ("'Did you enjoy the soup?' enquires the butler.")
NextStep (soup_rain, 4)
</look>
</object>
<object name="prawns_eaten">
<inherit name="editor_object" />
<look type="script">
msg ("'Did you enjoy the prawns?' enquires the butler.")
NextStep (prawn_rain, 4)
</look>
</object>
<object name="soup_rain">
<inherit name="editor_object" />
<look type="script">
msg ("Suddenly it is raining soup!")
</look>
</object>
<object name="prawn_rain">
<inherit name="editor_object" />
<look type="script">
msg ("Suddenly it is raining prawns!")
</look>
</object>
</object>
<object name="dining_room">
<inherit name="editor_room" />
<flag type="boolean">false</flag>
<firstenter type="script">
</firstenter>
<enter type="script">
if (IsAfter("1:20:00") and not this.flag) {
CreateEvent (5, "dinner2") {
msg ("Dinner is served.")
}
this.flag = true
}
</enter>
<exit alias="north" to="hall">
<inherit name="northdirection" />
</exit>
<exit alias="east" to="kitchen">
<inherit name="eastdirection" />
<runscript />
<script type="script">
player.parent = this.to
SetInc (5)
</script>
</exit>
</object>
<object name="kitchen">
<inherit name="editor_room" />
<exit alias="west" to="dining_room">
<inherit name="westdirection" />
<runscript />
<script type="script">
player.parent = this.to
SetInc (5)
</script>
</exit>
</object>
<object name="nowhere">
<inherit name="editor_room" />
<object name="soup">
<inherit name="editor_object" />
<displayverbs type="stringlist">
<value>Look at</value>
<value>Take</value>
<value>Eat</value>
</displayverbs>
<eat type="script">
msg ("You eat the soup; thick vegetable - yum!")
NextStep (soup_eaten, 5)
soup.parent = nowhere
prawn_cocktail.parent = nowhere
</eat>
</object>
<object name="prawn_cocktail">
<inherit name="editor_object" />
<displayverbs type="stringlist">
<value>Look at</value>
<value>Take</value>
<value>Eat</value>
</displayverbs>
<eat type="script">
msg ("You eat the prawn cocktail; it tastes great.")
NextStep (prawns_eaten, 5)
soup.parent = nowhere
prawn_cocktail.parent = nowhere
</eat>
<alias>prawn cocktail</alias>
</object>
</object>
</asl>

jaynabonne
Great job! :)

The Pixie
I have updated the other posts for version 2 of the library.

HegemonKhan
Yet another library from Pixie, thanks again (saying it for all of us users of quest who're still learning to code, hehe) ! :D

DmNerd
Is it possible to set an event to fire the same time everyday?

The Pixie
Add a function to your game that uses CreateEvent to generate a new event in 24x60 minutes, and have that event call the function.

Say the function is called AlarmCall, it might look like this;
msg ("Your alarm clock goes off.")
CreateEvent (24 * 60, "daily alarm") {
AlarmCall
}

Talon
Is there a way to set the default movement time to a longer number rather than just doing it for every exit, tried copying the game_clock and changing the Inc on that, it seems to work on the first step then goes back to the default(tried to change it to five vs one for example)

The Pixie
Set the exit to run a script, with this as the script:

SetInt(5)
player.parent = this.to


Talon
I meant if there was some global effect i could use rather than setting each exit individually.

The Pixie
I guess the easiest way would be to put SetInt(5) in the "Script when entering a room"

This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums