Elevator and stairs (Hugo example)
From IFWiki
I didn't make this quite as efficient as I'd like, but oh well...
!::
! Elevator and stairs by Roody Yogurt
!::
constant GAME_TITLE "ELEVATOR ACTION"
!:: Flags
#set VERBSTUBS ! Include the grammar and routines from verbstubs.g
! and verbstubs.h, respectively
!:: Grammar Library Inclusions (grammar must come first)
! put your new grammar here
verb "take"
* (stairs) "up"/"down" DoTakeStairs
! * multi DoGet
#include "verblib.g"
#include "hugolib.h" ! Standard Hugo Library
!:: Game Initialization routine
routine init
{
word[1] = ""
MAX_SCORE = 0 ! ready to change for a scored game
STATUSTYPE = 1 ! 0 = none :: 1 = score/turns :: 2 = time
counter = -1 ! 1 step before first turn
verbosity = 2
!\ VERBOSITY -
! 1 = normal (rooms described only if not previously described)
! 2 = full (rooms described every time they are entered)
\!
#if defined GAME_TITLE
display.title_caption = GAME_TITLE !
! display.title_caption - used for GUI clients for title bar text.
#endif
prompt = ">"
window 0 ! resets the windows in case the player is restarting a game
cls
DEFAULT_FONT = PROP_ON
Font(DEFAULT_FONT)
Font(BOLD_ON)
"Elevator Action"
Font(BOLD_OFF)
player = you
location = groundfloor
old_location = location
MovePlayer(location)
CalculateHolding(player)
#ifset USE_PLURAL_OBJECTS
InitPluralObjects
#endif
}
!:: Main game loop
routine main
{
counter = counter + 1
run location.each_turn
runevents
RunScripts
if speaking not in location
speaking = 0
PrintStatusLine
}
!\ I also used PreParse to allow "go up stairs" and "go stairs" (which I
would redirect to "take stairs" \!
player_character you "you"
{
before
{
actor PreParse
{
if word[1] = "go","climb","walk"
{
if word[2] = "stairs"
{
word[1] = "take"
return true
}
elseif (word[2] = "up","down") and word[3] = "stairs"
{
DeleteWord(3, 1) ! delete "stairs" and reparse
return true
}
}
return false
}
}
}
!\ For readability, I made some constants to represent the different floors.
GROUND = 1, SECOND = 2, THIRD = 3 \!
enumerate start = 1
{
GROUND, SECOND, THIRD
}
property floor_number alias misc
room groundfloor "Ground Floor"
{
floor_number GROUND
long_desc
{
"You are on the ground floor. The ";
OpenOrClosed
" door to the elevator is north, and stairs lead up."
}
u_to {
if verbroutine = &DoGo
Trudge
return secondfloor
}
cant_go
{
if object = d_obj
{
"The stairs only lead up."
}
elseif object = n_obj, in_obj
"The elevator doors are closed."
else
return false
}
n_to
{
if location.floor_number = doors.current_open_door
{
if verbroutine = &DoGo
{
"You step into the elevator."
}
return elevator
}
else
return false
}
in_to
return self.n_to
}
room secondfloor "Second Floor"
{
floor_number SECOND
long_desc
{
"You are on the second floor. The ";
OpenOrClosed
" door to the elevator is north, and stairs go both up and down from
here."
}
u_to {
if verbroutine = &DoGo
Trudge
return thirdfloor
}
d_to {
if verbroutine = &DoGo
Trudge
return groundfloor
}
cant_go
{
if object = n_obj, in_obj
"The elevator doors are closed."
else
return false
}
n_to
{
if location.floor_number = doors.current_open_door
{
if verbroutine = &DoGo
{
"You step into the elevator."
}
return elevator
}
else
return false
}
in_to
return self.n_to
}
room thirdfloor "Third Floor"
{
floor_number THIRD
long_desc
{
"You are on the ground floor. The ";
OpenOrClosed
" door to the elevator is north, or you can take the stairs
down."
}
d_to {
if verbroutine = &DoGo
Trudge
return secondfloor
}
cant_go
{
if object = u_obj ! if player tries to go up
{
"The stairs only lead down."
}
elseif object = n_obj, in_obj
"The elevator doors are closed."
else
return false
}
n_to
{
if location.floor_number = doors.current_open_door
{
if verbroutine = &DoGo
{
"You step into the elevator."
}
return elevator
}
else
return false
}
in_to
return self.n_to
}
!\ This routine is called when the player takes the stairs. the "main" routine
is called twice. it'll be called again when the turn is over, making 3 turns
pass to get between floors. I also temporarily clear the location global
so event text isn't printed while the player is moving. \!
routine Trudge
{
local a
a = location
location = 0
"You trudge ";
print object.noun #2;
" the stairs."
main : main
location = a
}
routine OpenOrClosed
{
if location.floor_number = doors.current_open_door or
(location = elevator and doors.current_open_door)
"open";
else
"closed";
return
}
scenery stairs "stairs"
{
noun "stairs"
article "the"
found_in groundfloor secondfloor thirdfloor
long_desc
{
select location
case groundfloor : "They go up."
case secondfloor : "They go up and down."
case thirdfloor : "They go down."
}
before
{}
}
attribute glowing alias special
scenery callbutton "call button"
{
current_floor 0
noun "button"
adjective "call"
article "the"
found_in groundfloor secondfloor thirdfloor
long_desc
{
if self is glowing
"The call button is lit."
else
"The call button is dark."
}
before
{
object DoPush
{
if self is glowing
{
"The call button has already been pressed."
}
elseif location.floor_number ~= elevator.current_floor
{
"The call button begins to glow."
self is glowing
self.current_floor = location.floor_number
Activate(moving_elevator)
}
elseif location.floor_number = elevator.current_floor and
not doors.current_open_door
{
Activate(door_close,3)
"The doors slide open."
doors.current_open_door = location.floor_number
}
elseif location.floor_number = doors.current_open_door
"Nothing happens."
}
}
}
daemon moving_elevator
{}
! moving elevator event
event in moving_elevator
{
if doors.current_open_door
{
if location = elevator or (elevator.current_floor = location.floor_number)
{
Deactivate(door_close)
"\nThe doors slide closed."
}
doors.current_open_door = 0 ! clear it
return ! takes up one turn
}
elseif elevator.current_floor ~= callbutton.current_floor
{
if location = elevator
{
"\nYou feel the elevator going ";
if callbutton.current_floor > elevator.current_floor
{
"up";
if callbutton.current_floor - 1 = elevator.current_floor
{
" (and then come to a stop)";
}
"."
}
else
{
"down";
if callbutton.current_floor + 1 = elevator.current_floor
{
" (and then come to a stop)";
}
"."
}
}
elseif location
"\nYou hear the hum of the elevator moving."
if callbutton.current_floor > elevator.current_floor
elevator.current_floor++ ! go up
else
elevator.current_floor-- ! go down
return
}
elseif elevator.current_floor = callbutton.current_floor
{
if location = elevator or location.floor_number = elevator.current_floor
{
""
"The elevator door opens.";
Activate(door_close,3)
if location ~= elevator
" The call button blinks off."
else
""
event_flag = 2
}
doors.current_open_door = elevator.current_floor
callbutton.current_floor = 0
callbutton is not glowing
Deactivate(self)
}
}
fuse door_close
{}
event in door_close ! the "in" is optional
{
if not doors.current_open_door
{
Deactivate(self)
}
! any code that executes each turn the fuse is running
if not self.tick
{
if location.misc = doors.current_open_door
{
"\nThe elevator doors slide closed."
}
doors.current_open_door = 0
}
}
property current_open_door alias misc
scenery doors "elevator doors"
{
noun "doors" "door"
adjective "elevator"
article "the"
is openable
current_open_door 0
found_in groundfloor secondfloor thirdfloor elevator
long_desc
{
"The elevator door is ";
OpenOrClosed
if location = elevator
", and there's a panel of buttons next to it."
else
", and there's a call button beside it."
}
before
{
object DoOpen
{
if self.current_open_door = location.floor_number or
(location = elevator and self.current_open_door)
{
"The elevator door is already open."
}
elseif location = elevator
"Try pushing a floor number."
else
"Try pushing the call button."
}
object DoClose
{
if self.current_open_door = location.floor_number or
(location = elevator and self.current_open_door)
{
"The elevator door will close automatically when it needs to."
}
else
"The elevator door is already closed."
}
}
}
property current_floor alias misc
room elevator "Elevator"
{
current_floor GROUND ! starts on the ground floor
long_desc
{
"You are inside the elevator. The door to the south is ";
OpenOrClosed
", and there's the usual panel of buttons beside it."
}
s_to
{
if self.current_floor = doors.current_open_door
{
if verbroutine = &DoGo
{
"You step out of the elevator."
}
select doors.current_open_door
case GROUND : return groundfloor
case SECOND : return secondfloor
case THIRD : return thirdfloor
}
else
return false
}
out_to
return self.s_to
cant_go
{
if object = s_obj
"The elevator doors are closed."
else
return false
}
}
scenery panel "panel of buttons"
{
noun "buttons" "panel"
adjective "panel" "of"
article "the"
in elevator
long_desc
{
"The panel has three buttons: G, 2, and 3. There is also a LED display that reads ";
SelectFloor
""
}
before
{
object DoPush
{
"You can only push one button at a time."
}
}
}
!\ I made the buttons and display components so trying to get them
would get the "that is part of the panel of buttons" response \!
component LED_display "LED display"
{
adjective "led"
noun "display"
article "the"
part_of panel
long_desc
{
"The LED display is showing a large red ";
SelectFloor
""
}
}
component g_button "G button"
{
article "the"
adjective "g"
noun "button"
part_of panel
long_desc
{
"The G button is ";
LitorDark(self)
}
before
{
object DoPush
{
ElevatorPush(self)
}
}
}
component 2_button "2 button"
{
long_desc
{
"The 2 button is ";
LitorDark(self)
}
article "the"
adjective "2"
noun "button"
part_of panel
before
{
object DoPush
{
ElevatorPush(self)
}
}
}
component 3_button "3 button"
{
long_desc
{
"The 3 button is ";
LitorDark(self)
}
article "the"
adjective "3"
noun "button"
part_of panel
before
{
object DoPush
{
ElevatorPush(self)
}
}
}
routine LitorDark(obj)
{
local a
select obj
case g_button : a = GROUND
case 2_button : a = SECOND
case 3_button : a = THIRD
if a = callbutton.current_floor
"lit."
else
"dark."
}
routine SelectFloor
{
"\"";
select elevator.current_floor
case GROUND : "G.\"";
case SECOND : "2.\"";
case THIRD : "3.\"";
}
routine ElevatorPush(obj)
{
local a
select obj
case g_button : a = GROUND
case 2_button : a = SECOND
case 3_button : a = THIRD
if callbutton.current_floor = a
{
print CThe(obj) ; " is already lit."
return
}
if a = elevator.current_floor
{
if doors.current_open_door = a ! doors are already open
{
"Nothing happens."
Activate(door_close, 3) ! extend door-open length by two turns
return
}
else
{
if callbutton.current_floor and
callbutton.current_floor ~= a
{
callbutton.current_floor = 0
"The elevator abruptly stops, and the doors slide open."
doors.current_open_door = a
Deactivate(moving_elevator)
return
}
else
{
Deactivate(moving_elevator)
"The doors slide open again."
doors.current_open_door = a
Activate(door_close,3)
return
}
}
}
else
{
print "You push "; The(obj) ;"."
}
Deactivate(moving_elevator)
callbutton.current_floor = a
Activate(moving_elevator)
}
routine DoTakeStairs
{
if word[3] ~= "up", "down"
{
select location.floor_number
case 1 : word[3] = "up"
case 3 : word[3] = "down"
}
select word[3]
case "up" : return Perform(&DoGo,u_obj)
case "down" : return Perform(&DoGo,d_obj)
case else
{
"Do you want to take the stairs up, or take the stairs down?"
return false ! Don't take up a turn
}
}
!\ If the player tries "take stairs" from the second floor, I didn't want the
"which stairs did you mean?" response to take up a turn. The easiest way to do
this was to replace DoGet and add my own code. If I didn't care about taking a
turn, I could have easily handled it with a before routine in the stairs object.
\!
replace DoGet
{
local b, p
if object = stairs and word[1] = "take"
{
select location
case groundfloor : return Perform(&DoGo, u_obj)
case secondfloor
{
"Do you want to take the stairs up, or take the stairs down?"
return false ! Don't take up a turn
}
case thirdfloor : return Perform(&DoGo, d_obj)
}
if object in player
VMessage(&DoGet, 1) ! "You already have that."
elseif object = player
{
VMessage(&DoGet, 2) ! player trying to get player
return false
}
elseif object is living and object is static
{
VMessage(&DoGet, 3) ! player trying to get character
return false
}
elseif parent(object) is living and parent(object) is unfriendly
VMessage(&DoGet, 4) ! "X doesn't want to give it to you."
elseif (parent(object) is openable, not open) and
parent(object) is container:
{
VMessage(&DoGet, 5) ! "X is closed."
return false
}
elseif Contains(object, player)
{
if object is static
VMessage(&DoGet, 7) ! "You can't take that."
else
VMessage(&DoGet, 6) ! "Not while you're in/on it..."
return false
}
else
{
if not CheckReach(object)
return false
elseif object is static
{
VMessage(&DoGet, 7) ! "You can't take that."
return true
}
! Because the engine calls location.before
if (parent(object)~=location)
b = parent(object).before
if not b
{
xobject = parent(object)
if object not in location
{
CalculateHolding(xobject)
p = xobject
}
if Acquire(player, object)
{
object is not hidden
if not object.after
{
! Again, to avoid duplication or
! echoing:
!
b = 0
if xobject ~= location
b = xobject.after
if b = false
! "Taken."
VMessage(&DoGet, 8)
}
}
else
! "You're carrying too much to take that."
VMessage(&DoGet, 9)
}
}
return true
}