Making Actions Take Time

I figured some people might have interest in making different actions take different amounts of time. It turned out to not be very difficult. Here’s the gameplay:

Train Station
You are here.

> examine cheap digital watch
You examine your cheap digital watch. Apparently it is now 12:00:10.

> wait
A moment slips away.

> jump
You enjoy a bit of jumping on the spot.

> dance
You practise your moves.

> examine watch
You examine your cheap digital watch. Apparently it is now 12:00:50.

And here’s the code:

%% Default action takes 10 seconds.
(delay after $ is 10 seconds)

(global variable (current hour 12))
(global variable (current minute 0))
(global variable (current second 0))
(global variable (current delay 0))

(after $Action)
	(delay after $Action is $Delay seconds)
	(now) (current delay $Delay)

(progress time one second)
	(current delay $OldDelay)
	(if) ($OldDelay > 0) (then)
		($OldDelay minus 1 into $NewDelay)
		(now) (current delay $NewDelay)
	(endif)
	(current second $OldSecond)
	($OldSecond plus 1 into $NewSecond)
	(if) ($NewSecond > 59) (then)
		(now) (current second 0)
		(current minute $OldMinute)
		($OldMinute plus 1 into $NewMinute)
		(if) ($NewMinute > 59) (then)
			(now) (current minute 0)
			(current hour $OldHour)
			($OldHour plus 1 into $NewHour)
			(if) ($NewHour > 23) (then)
				(now) (current hour 0)
			(else)
				(now) (current hour $NewHour)
			(endif)
		(else)
			(now) (current minute $NewMinute)
		(endif)
	(else)
		(now) (current second $NewSecond)
	(endif)

(tick)
	(if) (inhibiting next tick) (then)
		(now) ~(inhibiting next tick)
	(else)
		(update environment around player)
		(progress time one second)
		(exhaust) *(early on every tick)
		(exhaust) *(on every tick)
		(exhaust) *(late on every tick)
	(endif)

(read-parse-act)
	(rebuild scope)
	(if) (current delay 0) (then)
		(if) (deferred commandline $Words) (then)
			(now) ~(deferred commandline $)
			(stoppable) {
				(parse commandline $Words with choices [])
			}
		(else)
			(par)
			(stoppable) {
				(if)
					(scoring enabled)
					(score notifications are on)
				(then)
					(report score change)
				(endif)
	
				(if) (current node $DispObj) (then)
					(collect $Choice)
						*($DispObj offers $Choice)
						(available $Choice)
					(into $ChoiceListWithDup)
					(remove duplicates $ChoiceListWithDup $ChoiceList)
					(if) (empty $ChoiceList) (then)
						(now) ~(current node $)
						(now) ($DispObj is choice-exhausted)
						(if) ($DispObj flows to $Fallback) (then)
							(activate node $Fallback)
						(else)
							(activate parser)
						(endif)
					(endif)
					(redraw status bar)
					(get choice of $ChoiceList into $Words)
				(else)
					(redraw status bar)
					($ChoiceList = [])
					(prompt and input $Words)
				(endif)
	
				(parse commandline $Words with choices $ChoiceList)
			}
		(endif)
	(else)
		(tick)
	(endif)

#station
(room *)
(singleton *)
(name *)
	Train Station

#player
(current player *)
(* is #in #station)

#watch
(item *)
(* is #wornby #player)
(name *)
	cheap digital watch
(your *)
(descr *)
	You examine your cheap digital watch. Apparently it is now
	(current hour $Hour)
	$Hour:
	(current minute $Minute)
	(no space) (if) ($Minute < 10) (then) 0 (no space) (endif) $Minute:
	(current second $Second)
	(no space) (if) ($Second < 10) (then) 0 (no space) (endif) $Second.

What’s needed now for this to be useful is some way to schedule events to happen at specific time X, or every Y ticks, and such.

4 Likes

I’ve switched to an American-style time, since that’s what I’m used to, and now the day of the week is tracked as well. Because the small range of the Dialog integer I’ve split up the delay counter into separate delays for hours, minutes and seconds. Still no event queuing system, predicates aren’t first class in Dialog to the best of my knowledge so I think I’m going to have to abuse the action system somehow to make it work.

You are here.

> examine watch
You spend some time examining your watch; it is now 12:01:00 pm.

> examine calendar
You spend some time examining your calendar. It is Sunday.

> examine watch
You spend some time examining your watch; it is now 12:03:00 pm.

Here’s the code:

%% Arbitrarily start at noon on Sunday.
(global variable (current day #sunday))
(global variable (current meridiem #pm))
(global variable (current hour 0))
(global variable (current minute 0))
(global variable (current second 0))

%% Counters for how long until the actor may act again.
(global variable (delay hours 0))
(global variable (delay minutes 0))
(global variable (delay seconds 0))

%% The default action takes 1 minute.
(delay after $ is 0 hours)
(delay after $ is 1 minutes)
(delay after $ is 0 seconds)

%% Apply a time delay after the player acts.
(after $Action)
        (delay after $Action is $Hours hours)
        (now) (delay hours $Hours)
	(delay after $Action is $Minutes minutes)
	(now) (delay minutes $Minutes)
	(delay after $Action is $Seconds seconds)
	(now) (delay seconds $Seconds)

%% Every tick, progress time and reduce delay.
(tick)
	(if) (inhibiting next tick) (then)
		(now) ~(inhibiting next tick)
	(else)
		(update environment around player)
		(delay hours $DelayHours)
		(progress $DelayHours hours)
		(delay minutes $DelayMinutes)
		(progress $DelayMinutes minutes)
		(delay seconds $DelaySeconds)
		(progress $DelaySeconds seconds)
		(exhaust) *(early on every tick)
		(exhaust) *(on every tick)
		(exhaust) *(late on every tick)
	(endif)

%% Almost unchanged from the standard library, if there is a delay tick it away.
(read-parse-act)
	(rebuild scope)
	(if) (delay hours 0) (delay minutes 0) (delay seconds 0) (then)
		(if) (deferred commandline $Words) (then)
			(now) ~(deferred commandline $)
			(stoppable) {
				(parse commandline $Words with choices [])
			}
		(else)
			(par)
			(stoppable) {
				(if)
					(scoring enabled)
					(score notifications are on)
				(then)
					(report score change)
				(endif)
	
				(if) (current node $DispObj) (then)
					(collect $Choice)
						*($DispObj offers $Choice)
						(available $Choice)
					(into $ChoiceListWithDup)
					(remove duplicates $ChoiceListWithDup $ChoiceList)
					(if) (empty $ChoiceList) (then)
						(now) ~(current node $)
						(now) ($DispObj is choice-exhausted)
						(if) ($DispObj flows to $Fallback) (then)
							(activate node $Fallback)
						(else)
							(activate parser)
						(endif)
					(endif)
					(redraw status bar)
					(get choice of $ChoiceList into $Words)
				(else)
					(redraw status bar)
					($ChoiceList = [])
					(prompt and input $Words)
				(endif)
	
				(parse commandline $Words with choices $ChoiceList)
			}
		(endif)
	(else)
		(tick)
	(endif)

%% Increment time while reducing delay.
(progress 0 days)
(progress $NumberOfDays days)
	(current day $Yesterday)
	(day after $Yesterday is $Today)
	(now) (current day $Today)
	(delay hours $OldHoursDelay)
	(if) ($OldHoursDelay > 23) (then)
		($OldHoursDelay minus 24 into $NewHoursDelay)
		(now) (delay hours $NewHoursDelay)
	(else)
		(now) (delay hours 0)
		(now) (delay minutes 0)
		(now) (delay seconds 0)
	(endif)
	($NumberOfDays minus 1 into $RemainingDays)
	(progress $RemainingDays days)
(progress 0 meridiems)
(progress $NumberOfMeridiems meridiems)
	(current meridiem $PastMeridiem)
	(meridiem after $PastMeridiem is $PresentMeridiem)
	(now) (current meridiem $PresentMeridiem)
	(if) (current meridiem #am) (then)
		(current day $Yesterday)
		(day after $Yesterday is $Today)
		(now) (current day $Today)
	(endif)
	(delay hours $OldHoursDelay)
	(if) ($OldHoursDelay > 11) (then)
		($OldHoursDelay minus 12 into $NewHoursDelay)
		(now) (delay hours $NewHoursDelay)
	(else)
		(now) (delay hours 0)
		(now) (delay minutes 0)
		(now) (delay seconds 0)
	(endif)
	($NumberOfMeridiems minus 1 into $RemainingMeridiems)
	(progress $RemainingMeridiems meridiems)
(progress 0 hours)
(progress $NumberOfHours hours)
	(current hour $PastHour)
	(hour after $PastHour is $PresentHour)
	(now) (current hour $PresentHour)
	(if) (current hour 0) (then)
		(current meridiem $PastMeridiem)
		(meridiem after $PastMeridiem is $PresentMeridiem)
		(now) (current meridiem $PresentMeridiem)
		(if) (current meridiem #am) (then)
			(current day $Yesterday)
			(day after $Yesterday is $Today)
			(now) (current day $Today)
		(endif)
	(endif)
	(delay hours $OldHoursDelay)
	(if) ($OldHoursDelay > 0) (then)
		($OldHoursDelay minus 1 into $NewHoursDelay)
		(now) (delay hours $NewHoursDelay)
	(else)
		(now) (delay minutes 0)
		(now) (delay seconds 0)
	(endif)
	($NumberOfHours minus 1 into $RemainingHours)
	(progress $RemainingHours hours)
(progress 0 minutes)
(progress $NumberOfMinutes minutes)
	(current minute $PastMinute)
	(minute after $PastMinute is $PresentMinute)
	(now) (current minute $PresentMinute)
	(if) (current minute 0) (then)
		(current hour $PastHour)
		(hour after $PastHour is $PresentHour)
		(now) (current hour $PresentHour)
		(if) (current hour 0) (then)
			(current meridiem $PastMeridiem)
			(meridiem after $PastMeridiem is $PresentMeridiem)
			(now) (current meridiem $PresentMeridiem)
			(if) (current meridiem #am) (then)
				(current day $Yesterday)
				(day after $Yesterday is $Today)
				(now) (current day $Today)
			(endif)
		(endif)
	(endif)
	(delay minutes $OldMinutesDelay)
	(if) ($OldMinutesDelay > 0) (then)
		($OldMinutesDelay minus 1 into $NewMinutesDelay)
		(now) (delay minutes $NewMinutesDelay)
	(else)
		(delay hours $OldHoursDelay)
		(if) ($OldHoursDelay > 0) (then)
			($OldHoursDelay minus 1 into $NewHoursDelay)
			(now) (delay hours $NewHoursDelay)
			(now) (delay minutes 59)
		(else)
			(now) (delay seconds 0)
		(endif)
	(endif)
	($NumberOfMinutes minus 1 into $RemainingMinutes)
	(progress $RemainingMinutes minutes)
(progress 0 seconds)
(progress $NumberOfSeconds seconds)
	(current second $PastSecond)
	(second after $PastSecond is $PresentSecond)
	(now) (current second $PresentSecond)
	(if) (current second 0) (then)
		(current minute $PastMinute)
		(minute after $PastMinute is $PresentMinute)
		(now) (current minute $PresentMinute)
		(if) (current minute 0) (then)
			(current hour $PastMinute)
			(hour after $PastMinute is $PresentMinute)
			(now) (current hour $PresentMinute)
			(if) (current hour 0) (then)
				(current meridiem $PastMeridiem)
				(meridiem after $PastMeridiem is $PresentMeridiem)
				(now) (current meridiem $PresentMeridiem)
				(if) (current meridiem #am) (then)
					(current day $Yesterday)
					(day after $Yesterday is $Today)
					(now) (current day $Today)
				(endif)
			(endif)
		(endif)
	(endif)
	(delay seconds $OldSecondsDelay)
	(if) ($OldSecondsDelay > 0) (then)
		($OldSecondsDelay minus 1 into $NewSecondsDelay)
		(now) (delay seconds $NewSecondsDelay)
	(else)
		(delay minutes $OldMinutesDelay)
		(if) ($OldMinutesDelay > 0) (then)
			($OldMinutesDelay minus 1 into $NewMinutesDelay)
			(now) (delay minutes $NewMinutesDelay)
		(else)
			(delay hours $OldHoursDelay)
			(if) ($OldHoursDelay > 0) (then)
				($OldHoursDelay minus 1 into $NewHoursDelay)
				(now) (delay hours $NewHoursDelay)
				(now) (delay minutes 59)
				(now) (delay seconds 59)
			(else)
				(now) (delay seconds 0)
			(endif)
		(endif)
	(endif)
	($NumberOfSeconds minus 1 into $RemainingSeconds)
	(progress $RemainingSeconds seconds)

				

%% Days of the week.
#sunday
(name *) Sunday
(proper *)
(day after * is #monday)
#monday
(name *) Monday
(proper *)
(day after * is #tuesday)
#tuesday
(name *) Tuesday
(proper *)
(day after * is #wednesday)
#wednesday
(name *) Wednesday
(proper *)
(day after * is #thursday)
#thursday
(name *) Thursday
(proper *)
(day after * is #friday)
#friday
(name *) Friday
(proper *)
(day after * is #saturday)
#saturday
(name *) Saturday
(proper *)
(day after * is #sunday)

%% Meridiems of the day.
#am
(name *) am
(proper *)
(meridiem after * is #pm)
#pm
(name *) pm
(proper *)
(meridiem after * is #am)

%% Succession of the hours.
(hour after 11 is 0)
(hour after $OldHour is $NewHour)
	($OldHour plus 1 into $NewHour)

%% Succession of the minutes.
(minute after 59 is 0)
(minute after $OldMinute is $NewMinute)
	($OldMinute plus 1 into $NewMinute)

%% Succession of the seconds.
(second after 59 is 0)
(second after $OldSecond is $NewSecond)
	($OldSecond plus 1 into $NewSecond)

%% Print helpers.
(print day)
	(current day $Time)
	(name $Time)
(print meridiem)
	(current meridiem $Time)
	(name $Time)
(print hour)
	(current hour $Time)
	(if) ($Time = 0) (then)
		12
	(else)
		$Time
	(endif)
(print minute)
	(current minute $Time)
	$Time
(print second)
	(current second $Time)
	$Time
(print time)
	(print hour):(no space)
	(if)(current minute $Minute)($Minute < 10)(then)0(no space)(endif)(print minute):(no space)
	(if)(current second $Second)($Second < 10)(then)0(no space)(endif)(print second)
	(print meridiem)

%% Example scene.
#kitchen
(room *)
(singleton *)
(name *)
	Kitchen
#player
(current player *)
(* is #in #kitchen)
#watch
(item *)
(* is #wornby #player)
(name *)
	watch
(your *)
(descr *)
	You spend some time examining your watch; it is now (print time).
#calendar
(* is #in #kitchen)
(name *)
	calendar
(your *)
(descr *)
	You spend some time examining your calendar. It is (print day).

Predicates aren’t first class, but Dialog still has closures, so it’s possible to do something like the following. (Untested, and I’m still quite new to Dialog, but it shows the idea.)

(schedule $Closure at [$H $M $S])
    %% Handle the closure somehow, like storing it into a list or something.
    %% Here, we'll just fire it right away for the sake of the example.
    (query $Closure)

(instead of [jump])
    ($SomeVar = #my-obj)
    %% Closures can capture variables.
    (schedule { (my rule with $SomeVar) } at [18 42 0])

(I’s possible to pass one argument to the closure when querying it, should the need arise. If you need multiple arguments, you can use a list.)

I’d link to the relevant section of the documentation, but Dialog’s site seems down at the time of writing. Seems to be up again, here’s the link:

https://linusakesson.net/dialog/docs/control.html#closures

1 Like