Elevator and stairs (Dialog example)
From IFWiki
(current player #player)
(#player is #in #ground)
(story author) IF Community
%% Creating the right predicates makes for simple, elegant code.
(level #ground 1)
(level #external-button-ground 1)
(level #internal-button-g 1)
(level #ground-door 1)
(level #second 2)
(level #external-button-second 2)
(level #second-door 2)
(level #internal-button-2 2)
(level #third 3)
(level #external-button-third 3)
(level #third-door 3)
(level #internal-button-3 3)
($Button is button of $Room)
*(button $Button)
*(room $Room)
(level $Room $N)
(level $Button $N)
($Door is door of $Room)
*(door $Door)
*(room $Room)
(level $Door $N)
(level $Room $N)
%% Floors
#ground
(room *)
(name *) ground floor
(singleton *)
(ordinal *) ground
%% Instead of creating three separate stairs objects, we will create one and
%% specify that each of the three floors attracts it.
(* attracts #stairs)
(look *)
(look at *) and the stairs are up.
(from * go #north through #ground-door to #elevator)
(#elevator is on *)
(from * go #up to #second)
#second
(room *)
(name *) second floor
(singleton *)
(ordinal *) second
(* attracts #stairs)
(look *)
(look at *) and stairs go both up and down from here.
(from * go #north through #second-door to #elevator)
(#elevator is on *)
(from * go #up to #third)
(from * go #down to #ground)
#third
(room *)
(name *) third floor
(singleton *)
(ordinal *)
(* attracts #stairs)
(look *)
(look at *) or you can take the stairs down.
(from * go #north through #third-door to #elevator)
(#elevator is on *)
(from * go #down to #second)
(look at $Room)
($Door is door of $Room)
You are on the (ordinal $Room) floor. The
(if)($Door is open)(then)
open
(else)
closed
(endif)
door to the elevator is north,
%% Call Buttons
#external-button-ground
(external button *)
(* is #in #ground)
#external-button-second
(external button *)
(* is #in #second)
#external-button-third
(external button *)
(* is #in #third)
(name (external button $Button))
(external button $Button)
call button
(descr (external button $Button))
(current room $Room)
($Button is button of $Room)
Pushing this button summons the elevator to this floor. It's currently
(if)($Button is lit)(then)
lit
(else)
dark
(endif)
.
(perform [push (button $Button)])
(push $Button)
%% When the elevator is already on the floor and the door is closed
(push $Button)
(#elevator is on $Origin)
($Button is button of $Dest)
($Origin = $Dest)
($Door is door of $Origin)
($Door is closed)
(now)($Door is open)
(now)($Door closes in 2)
(The $Door) opens.
%% When the elevator is already on the floor and the door is already open
(push $Button)
(#elevator is on $Origin)
($Button is button of $Dest)
($Origin = $Dest)
($Door is door of $Origin)
($Door is open)
Nothing happens.
($Door closes in $Old)
($Old plus 1 into $New)
(now)($Door closes in $New)
%% When the elevator is on a different floor and all the doors are closed
(push $Button)
*(external button $External)
($Button is button of $Room)
($External is button of $Room)
(#ground-door is closed)
(#second-door is closed)
(#third-door is closed)
(now)(#elevator has destination $Room)
(now)~(#external-button-ground is lit)
(now)~(#external-button-second is lit)
(now)~(#external-button-third is lit)
(now)($External is lit)
(if)(current room $Room)(or)(current room #elevator)(then)
The call button lights up.
(endif)
(move elevator)
%% When the elevator is on a different floor and at least one door is open
(push $Button)
*(external button $External)
($Button is button of $Dest)
($External is button of $Dest)
(now)(#elevator has destination $Dest)
(now)~(#external-button-ground is lit)
(now)~(#external-button-second is lit)
(now)~(#external-button-third is lit)
(now)($External is lit)
(if)(current room $Dest)(or)(current room #elevator)(then)
The call button lights up.(par)
(endif)
(#elevator is on $Room)
($Door is door of $Room)
(if)($Door is open)(then)
(if)(current room $Room)(or)(current room #elevator)(then)
(The $Door) closes.
(endif)
(endif)
(now)(#ground-door is closed)
(now)(#second-door is closed)
(now)(#third-door is closed)
(now)~(#ground-door closes in $)
(now)~(#second-door closes in $)
(now)~(#third-door closes in $)
(stop)
%% Elevator Doors
#ground-door
(door *)
(openable *)
(* is closed)
(* is #in #ground)
#second-door
(door *)
(openable *)
(* is closed)
(* is #in #second)
#third-door
(door *)
(openable *)
(* is closed)
(* is #in #third)
(name (door $Door))
elevator door
(descr (door $Door))
(current room $Room)
($Door is door of $Room)
The elevator door is
(if)($Door is open)(then)
open,
(else)
closed,
(endif)
and there's a call button beside it.
(prevent [open (door $Door)])
($Door is open)
(The $Door) is already open.
(prevent [open (door $Door)])
Try pushing the call button.
(prevent [close (door $Door)])
($Door is closed)
(The $Door) is already closed.
(prevent [close (door $Door)])
(The $Door) will close automatically when it needs to.
%% Elevator
#elevator
(name *) elevator
(room *)
(singleton *)
(* is on #ground)
(look *)
You are inside the elevator. The door to the south is
(#elevator is on $Room)
($Door is door of $Room)
(if)($Door is open)(then)
open
(else)
closed
(endif)
, and there's the usual panel of buttons beside it.
(from * go #south through #ground-door to #ground)
(* is on #ground)
(from * go #south through #second-door to #second)
(* is on #second)
(from * go #south through #third-door to #third)
(* is on #third)
%% As a kindness to the player we remap OUT to SOUTH.
(from * go #out to #south)
(on every tick)
($Door closes in $Old)
($Door is door of $Room)
(if)($Old = 0)(then)
(now)~($Door closes in $)
(now)($Door is closed)
(if)(current room $Room)(or)(current room #elevator)(then)
(par)The door closes.
(endif)
(else)
($Old minus 1 into $New)
(now)($Door closes in $New)
(endif)
%% If the elevator is already on the right floor
(on every tick)
(#elevator is on $Current)
(#elevator has destination $Dest)
($Current = $Dest)
($Door is door of $Current)
(now)($Door is open)
(now)~(#elevator has destination $)
(now)($Door closes in 2)
($Button is button of $Current)
(now)~($Button is lit)
(current room $Room)
(if)($Room = $Current)(or)($Room = #elevator)(then)
(par)(The $Door) opens. The call button blinks off.
(endif)
(on every tick)
(move elevator)
%% If the elevator is below the destination
(move elevator)
(#elevator is on $Current)
(#elevator has destination $Dest)
(level $Current $CurrentLevel)
(level $Dest $DestLevel)
($CurrentLevel < $DestLevel)
($CurrentLevel plus 1 into $NextLevel)
(level $Room $NextLevel)
(now)(#elevator is on $Room)
(if)(current room #elevator)(then)
(par)You feel the elevator going up
(if)($Dest = $Room)(then)
, and then it comes to a stop
(endif)
.
(endif)
(stop)
%% If the elevator is above the destination
(move elevator)
(#elevator is on $Current)
(#elevator has destination $Dest)
(level $Current $CurrentLevel)
(level $Dest $DestLevel)
($CurrentLevel > $DestLevel)
($CurrentLevel minus 1 into $NextLevel)
(level $Room $NextLevel)
(now)(#elevator is on $Room)
(if)(current room #elevator)(then)
(par)You feel the elevator going down
(if)($Dest = $Room)(then)
, and then it comes to a stop
(endif)
.
(endif)
(stop)
%% Panel
#panel
(name *) panel
(* is #in #elevator)
(descr *)
The panel has three buttons: G, 2, and 3. There is also a LED display that
reads (display floor).
#internal-button-g
(name *) g button
(dict *)
(plural dict *) buttons
(internal button *)
(* is #partof #panel)
#internal-button-2
(name *) 2 button
(dict *) two
(plural dict *) buttons
(internal button *)
(* is #partof #panel)
#internal-button-3
(name *) 3 button
(dict *) three
(internal button *)
(plural dict *) buttons
(* is #partof #panel)
%% We make external buttons and internal buttons members of the same
%% class. This allows us to make our code more concise elsewhere.
(button $Obj) *(external button $Obj)
(button $Obj) *(internal button $Obj)
%% Instead of creating a distinct "buttons" object, we create a means to refer
%% to multiple already existing objects.
(action [examine $] may group (internal button $) with (internal button $))
(group-perform [examine $List])
*(internal button $Obj)
($Obj is one of $List)
(try [examine #panel])
(instead of [examine (internal button $)])
(try [examine #panel])
%% Display
#display
(name *) LED display
(singleton *)
(descr *)
The LED display is showing a large red (display floor).(par)
(* is #in #elevator)
(display floor)
(#elevator is on #ground)
G
(display floor)
(#elevator is on #second)
2
(display floor)
3
%% Stairs
#stairs
(name *) stairs
(plural *)
(singleton *)
(descr *)
(current room $Room)
(if)($Room = #ground)(then)
They go up.(par)
(elseif)($Room = #second)(then)
They go up and down.(par)
(else)
They go down.(par)
(endif)
(instead of [take/climb #stairs])
(current room $Room)
($Room is one of [#ground #second #third])
(if)($Room = #ground)(then)
(try [go #up])
(elseif)($Room = #third)(then)
(try [go #down])
(else)
Which way do you want to go?(par)
1. Up.(line)
2. Down.(par)
(get key $Key)
(handle keypress $Key)
(endif)
(handle keypress $Key)
($Key is one of [1 @\u])
(try [go #up])
(handle keypress $Key)
($Key is one of [2 @\d])
(current room $Room)
(try [leave $Room #down])
(perform [take #stairs])
There are no stairs here.(par)
%% As per our instructions, we make going up or down stairs take three ticks.
(after [go $Dir])
($Dir is one of [#up #down])
(tick)(tick)
%% TAKE <obj> <dir>
(grammar [take [object] [direction]] for [take $ $])
(instead of [take $Obj $Dir])
($Obj = #stairs)
($Dir is one of [#up #down])
(try [go $Dir])