This version is a more or less direct translation of the version done in Perl (See RCRPG/Perl) with some additional functionality added. Commands include attack, drop, take, equip, alias, name, inventory, and directions. The 'name' command can use a double-quoted string if spaces wanted to be included in the name (i.e. 'name "this room").

RCRPG/PureBasic is part of RCRPG. You may find other members of RCRPG at Category:RCRPG.

An additional command 'ask' was implemented for providing hints in finding the randomly placed Prize Room. The program also allows the stacking of commands if they are separated by a space (i.e. 'take all equip sledge a north n' will perform four actions: take all, equip sledge, [a]ttack north, [n]orth).

A simple outlay of the play strategy is: Take and equip a sledge. Get some gold to ask for hints (from the program) and move a ladder into a room to go up if necessary and attack walls to make exits.

;Here is a description of all of the commands:
;
;north
;south
;east
;west
;up
;down
;
;Move in the direction specified. The player won’t be able to move if there isn’t
;an exit in that direction.
;
;attack (direction)
;
;Attack in the direction specified. (Equip the sledge first.)
;
;drop {all|(item name)}
;
;Drop the item specified. Or drop everything the player is carrying.
;
;take {all|(item name)}
;
;Take the item specified. Or take everything in the room.
;
;inventory
;
;Display everything the player is carrying.
;
;name (name)
;
;The player can rename the room with this command.
;
;equip (item name)
;
;Equip the item in question.
;
;alias (existing command name) (new command name)
;
;Give an existsing command an alias. Starting aliases are n,s,e,w,u,d. i and inv
;are the same as inventory, a is the same as attack.
;
;At the start of the game, only two rooms exist, the Start and the Prize room.
;All other rooms the player creates by moving around.  The Prize room is randomly
;located each game.  If you need a hint just 'ask'.
;
;To move out of the start room, the player needs to break a hole in a wall,
;ceiling or floor. The sledge is needed to do this.
;
;There are three kinds of items in the different rooms: sledges, gold and
;ladders. A sledge is needed to gain access to rooms the player doesn’t have
;access to. A ladder is needed to move between levels.
;
;Every room, except the prize room, may randomly have gold, a sledge and/or a
;ladder. The player will have to leave the ladder behind when they go up a level,
;so they may have to hunt around a bit for a new ladder.
;
;When the player finds a ladder, they can either move up a level from that room,
;or they can take the ladder and drop it in a room that’s more convenient.
;
;The player can make their way to the Prize Room but there's nothing
;useful there; just gold.
;----------
Structure coord3D
  x.i
  y.i
  z.i
EndStructure

Structure room
  location.coord3D
  name.s
  description.s
  List items.i()
  exits.i ;bitmapped
EndStructure 

Structure player
  *curRoomPtr.room
  location.coord3D
  List inventory.i()
  equipped.i
EndStructure

Enumeration ;items
  #itm_any = -1
  #itm_nothing = 0
  #itm_sledge
  #itm_ladder
  #itm_gold
  #itm_count
EndEnumeration

Enumeration ;directions
  #dir_Nowhere
  #dir_North
  #dir_South
  #dir_East
  #dir_West
  #dir_Up
  #dir_Down
  #dir_count
EndEnumeration

Enumeration ;console colors
  #con_Black
  #con_Blue
  #con_Green
  #con_Cyan
  #con_Red
  #con_Magenta
  #con_Brown
  #con_Light_Grey
  #con_Dark_Grey
  #con_Bright_Blue
  #con_Bright_Green
  #con_Bright_Cyan
  #con_Bright_Red
  #con_Bright_Magenta
  #con_Yellow
  #con_White
EndEnumeration
#ConsoleWidth = 79 ;character width of console

Global NewMap *locations.room() ;"xx,yy,zz" hash of locations and their associated room data
Global NewList rooms.room() ;room data
Prototype.s command_prt(cmd.s) ;each command acts on an input string and returns the unused portion
Global NewMap *commands() ;hash of commands and their functions, all use the same prototype
Global quitNow = #False
Global isConsoleAvailable = #False
Global player.player
Global prizeRoom.coord3D
Global hintCount
Global foundPrizeRoom = #False

;==========================
DataSection
  dirData:
  Data.i #dir_Nowhere: Data.s "nowhere", "nowhere", "to nowhere": Data.i  0,  0,  0
  Data.i #dir_North  : Data.s "north", "south", "to the north"  : Data.i  0,  1,  0
  Data.i #dir_South  : Data.s "south", "north", "to the south"  : Data.i  0, -1,  0
  Data.i #dir_East   : Data.s "east", "west", "to the east"     : Data.i  1,  0,  0
  Data.i #dir_West   : Data.s "west", "east", "to the west"     : Data.i -1,  0,  0
  Data.i #dir_Up     : Data.s "up", "down", "in the ceiling"    : Data.i  0,  0,  1
  Data.i #dir_Down   : Data.s "down", "up", "in the floor"      : Data.i  0,  0, -1
  
  roomDescription:
  Data.s "featureless room", "cold dark room", "very stinky room", "small but comfortable room"
  Data.s "room with an incredible echo! Yahollaydoo!", "room resembling a window-less jail"
  Data.s "green room", "black room", "blue room", "brown sad room", "room which breathes pain"
  Data.s "mysterious room", "yellow room", "room with a think layer of dust"
EndDataSection
#count_roomDescriptions = 14 ;count of room Descriptions

Structure dirText
  name.s
  reverseName.s
  exitDesc.s
EndStructure

Global Dim dirText.dirText(#dir_count - 1) ;direction text for each direction index
Global NewMap dirIndex.i(#dir_count - 1) ;index for each name
Global NewMap directions.coord3D() ;coordinate offsets
Define i, x
For i = 0 To #dir_count - 1
  Read.i x
  Read.s dirText(x)\name
  Read.s dirText(x)\reverseName
  Read.s dirText(x)\exitDesc
  
  dirIndex(dirText(x)\name) = x
  
  Read.i directions(dirText(x)\name)\x
  Read.i directions(dirText(x)\name)\y
  Read.i directions(dirText(x)\name)\z
Next 

;============================
Global Dim itemName.s(#itm_count - 1) ;item names for each item index
itemName(#itm_nothing) = "nothing"
itemName(#itm_sledge) = "sledge"
itemName(#itm_ladder) = "ladder"
itemName(#itm_gold) = "gold"

;============================
Declare setLocation(*location.coord3D, x, y, z)

*locations("0,0,0") = AddElement(rooms())
rooms()\name = "The Start"
setLocation(rooms()\location, 0, 0, 0)
rooms()\description = "simple room"
AddElement(rooms()\items())
rooms()\items() = #itm_sledge

setLocation(prizeRoom, Random(6) - 3, Random(6) - 3, Random(5) + 2)
*locations(Str(prizeRoom\x) + "," + Str(prizeRoom\y) + "," + Str(prizeRoom\z)) = AddElement(rooms())
rooms()\name = "The Prize Room"
rooms()\location = prizeRoom
rooms()\description = "very bright and shiny metallic room"
For i = 1 To 9
  AddElement(rooms()\items())
  rooms()\items() = #itm_gold
Next 

Procedure setLocation(*location.coord3D, x, y, z)
  *location\x = x
  *location\y = y
  *location\z = z
EndProcedure

Procedure.s shift(cmd.s, count = 1, sep.s = " ")
  While count > 0
    Protected x = FindString(cmd, sep, 1)
    If x
      cmd = Right(cmd, Len(cmd) - x)
    Else
      cmd = ""
    EndIf
    count - 1
  Wend   
  ProcedureReturn Trim(cmd)
EndProcedure

Procedure display(text.s, textColor = #con_Bright_Cyan, backColor = #con_Black)
  Static lastPrintPos = 0
  If isConsoleAvailable
    Protected lineCount, curLine = 1, lineText.s, maxWidth, wrapPos, outputText.s
    ConsoleColor(textColor, backColor)
    
    lineCount = CountString(text, #CR$)
    Repeat
      lineText = StringField(text, curLine, #CR$)
      While (lastPrintPos + Len(lineText)) >  #ConsoleWidth
        maxWidth = #ConsoleWidth - lastPrintPos
        wrapPos = maxWidth - FindString(ReverseString(Left(lineText, maxWidth)), " ", 1) ;wrap at space
        outputText = Left(lineText, wrapPos)
        If wrapPos <> maxWidth
          ;find last of a group of spaces
          Repeat
            wrapPos + 1
          Until Mid(lineText, wrapPos + 1, 1) <> " "
        ElseIf maxWidth <> #ConsoleWidth And FindString(lineText, " ", 1) <= #ConsoleWidth
          wrapPos = 0
          outputText = ""
        EndIf 
        
        PrintN(outputText)
        lineText = Mid(lineText, wrapPos + 1)
        lastPrintPos = 0
      Wend 
      
      If lineCount > 0
        PrintN(lineText)
        lastPrintPos = 0
      Else
        Print(lineText)
        lastPrintPos + Len(lineText)
      EndIf 
      lineCount - 1: curLine + 1
    Until lineCount < 0
  EndIf 
  ProcedureReturn lastPrintPos
EndProcedure

Procedure displayN(text.s, textColor = #con_Bright_Cyan, backColor = #con_Black)
  ProcedureReturn display(text + #CR$, textColor, backColor)
EndProcedure

Procedure decodeExits(Array dir(1), exits)
  Protected i, count
  Dim dir(#dir_count - 1)
  
  For i = 1 To #dir_count
    If exits & 1
      dir(count) = i
      count + 1
    EndIf
    exits >> 1
  Next 
  If count = 0
    dir(count) = #dir_Nowhere
    count = 1
  EndIf 
  Redim dir(count - 1)
EndProcedure

Procedure parseItem(item.s)
  Protected i, type = #itm_nothing
  For i = 0 To #itm_count - 1
    If itemName(i) = item
      type = i
      Break
    EndIf
  Next
  ProcedureReturn type
EndProcedure

Procedure greet(*room.room)
  display(#CR$ + "You are in room (" + Str(player\location\x) + ", " +  Str(player\location\y) + ", " + Str(player\location\z) + "), ", #con_White)
  If player\location\x = prizeRoom\x And player\location\y = prizeRoom\y And player\location\z = prizeRoom\z
    display(*room\name, #con_Yellow, #con_Bright_Blue)
    If Not foundPrizeRoom
      display(".  It took you " + Str(hintCount) + " hints to find this room.  I bet your arms are tired!  After you've rested a bit you can start patching up all the holes..", #con_White)
      foundPrizeRoom = #True
    EndIf 
  Else
    display(*room\name, #con_Black, #con_White)
  EndIf 
  displayN(".  It is a " + *room\description + ".", #con_White)
 
  Dim dir_present(0)
  decodeExits(dir_present(), *room\exits)
  Protected i, count = ArraySize(dir_present()) + 1
  
  Select count
    Case 1
      If dir_present(0) = #dir_Nowhere
        displayN("There are no exits from this room. Perhaps you need to make one?", #con_Yellow)
      Else
        displayN("There is an exit " + dirText(dir_present(0))\exitDesc, #con_Yellow)
      EndIf 
    Default 
      display("There are exits ", #con_Yellow)
      For i = 0 To count - 3
        display(dirText(dir_present(i))\exitDesc + ", ", #con_Yellow)
      Next 
      displayN(dirText(dir_present(count - 2))\exitDesc + " and " + dirText(dir_present(count - 1))\exitDesc + ".", #con_Yellow)
  EndSelect
  
  count = ListSize(*room\items())
  If count > 0
    display("There is a ", #con_Yellow)
    FirstElement(*room\items())
    Select count
      Case 1
        display(itemName(*room\items()), #con_Yellow)
      Default 
        For i = 1 To count - 2
          display(itemName(*room\items()) + ", ", #con_Yellow)
          NextElement(*room\items())
        Next
        display(itemName(*room\items()) + " and a ", #con_Yellow)
        NextElement(*room\items())
        display(itemName(*room\items()), #con_Yellow)
    EndSelect
    displayN(" here.", #con_Yellow)
  Else
    displayN("There is nothing useful here you can take.", #con_Yellow)
  EndIf 
EndProcedure

Procedure mainloop()
  player\location\x = 0: player\location\y = 0: player\location\z = 0
  player\curRoomPtr = *locations(Str(player\location\x) + "," + Str(player\location\y) + "," + Str(player\location\z))
  displayN("Welcome to RCRPG, the PureBasic Edition.", #con_Yellow, #con_Bright_Blue)
  displayN("The aim is to find 'The Prize Room', good luck!", #con_Yellow)
  
  Repeat
    greet(player\curRoomPtr)
    displayN(#CR$ + "Try 'help' for help", #con_Bright_Green)
    display(#CR$ + ">")
    Protected cmd.s = Trim(Input())
    While cmd <> "" And quitNow = #False
      Protected command.s = StringField(cmd, 1, " ")
    
      If FindMapElement(*commands(), command)
        Protected function.command_prt = *commands()
        cmd = function(shift(cmd))
      Else
        displayN("'" + StringField(cmd, 1, " ") + "' didn't make any sense.  Try 'help'")
        cmd = ""
      EndIf 
    Wend 
  Until quitNow
EndProcedure

;Return pointer to room at the given coordinates, create it if it doesn't already exist.
Procedure roomcheck(x, y, z)
  Protected roomAddr.s = Str(x) + "," + Str(y) + "," + Str(z)
  If FindMapElement(*locations(), roomAddr)
    ProcedureReturn *locations()
  EndIf 
  
  *locations(roomAddr) = AddElement(rooms())
  With rooms()  
    \location\x = x: \location\y = y: \location\z = z
    \name = "Nameless"
    Protected i, newRoomDescript = Random(#count_roomDescriptions - 1) 
    Restore roomDescription
    For i = 0 To newRoomDescript
      Read.s \description
    Next 
    ;add items
    For i = 1 To Random(2)
      AddElement(\items())
      \items() = Random(#itm_count - 2) + 1
    Next 
  EndWith
  ProcedureReturn *locations()
EndProcedure

Procedure isLadderPresent(List items.i())
  ForEach items()
    If items() = #itm_ladder
      ProcedureReturn #True ;ladder present
    EndIf
  Next
  ProcedureReturn #False ;no ladder present
EndProcedure

;check if there is an exit from currentroom in the given direction (vector)
;and move to it if possible
Procedure move(dir.s)
  If player\curRoomPtr\exits & (1 << (dirIndex(dir) - 1))
    Protected curRoom.coord3D = player\curRoomPtr\location
    Protected VECTOR.coord3D = directions(dir)
    Protected *toRoom.room = roomcheck(curRoom\x + VECTOR\x, curRoom\y + VECTOR\y, curRoom\z + VECTOR\z)
    If dir = "up"
      ;check for ladder in room
      If Not isLadderPresent(player\curRoomPtr\items())
        displayN("There needs to be a ladder in the room before you can climb up.")
        ProcedureReturn
      EndIf 
    ElseIf dir = "down"
      ;check for ladder in lower room
      If Not isLadderPresent(*toRoom\items())
        displayN("There needs to be a ladder in that room before you can climb down.")
        ProcedureReturn
      EndIf 
    EndIf 
    player\curRoomPtr = *toRoom
    player\location = player\curRoomPtr\location
  Else
    displayN("Your way is blocked.")
  EndIf
EndProcedure

Procedure.s cmd_north(cmd.s)
  move("north")
  ProcedureReturn cmd.s
EndProcedure

Procedure.s cmd_south(cmd.s)
  move("south")
  ProcedureReturn cmd.s
EndProcedure

Procedure.s cmd_east(cmd.s)
  move("east")
  ProcedureReturn cmd.s
EndProcedure

Procedure.s cmd_west(cmd.s)
  move("west")
  ProcedureReturn cmd.s
EndProcedure

Procedure.s cmd_up(cmd.s )
  move("up")
  ProcedureReturn cmd.s
EndProcedure

Procedure.s cmd_down(cmd.s)
  move("down")
  ProcedureReturn cmd.s
EndProcedure

;connect two existing rooms via a related exit
Procedure link(*fromRoom.room, direction.s)
  ;calculate coord of toRoom
  Protected toPos.coord3D = directions(direction)
  toPos\x + *fromRoom\location\x:  toPos\y + *fromRoom\location\y :  toPos\z + *fromRoom\location\z 
  
  ;check if toRoom exists, if not create it (roomcheck)
  Protected *toRoom.room = roomcheck(toPos\x, toPos\y, toPos\z)
  
  ;place exit in fromRoom and corresponding exit direction in toRoom
  *fromRoom\exits | (1 << (dirIndex(direction) - 1))
  *toRoom\exits | (1 << (dirIndex(dirText(dirIndex(direction))\reverseName) - 1))
EndProcedure

Procedure.s cmd_attack(cmd.s)
  Protected direction.s = StringField(cmd, 1, " ")

  If direction = "help"
		displayN("Usage: attack (direction)", #con_Bright_Green)
    ProcedureReturn shift(cmd)
  EndIf 

	If direction <> ""
    If Not FindMapElement(directions(), direction)
      display("I don't now that direction.  Try: ")
      Protected output.s
 			ForEach directions()
        output + " " + MapKey(directions()) + ","
      Next
      displayN(Trim(output, ","))
      ProcedureReturn ""
    EndIf 
	Else
		displayN("Invalid syntax.  Try 'attack (direction)'")
    ProcedureReturn ""
  EndIf 
 
	If player\equipped = parseItem("sledge") 
    If dirIndex(direction) = #dir_Nowhere
      displayN("You destroyed a portion of the " + direction + " and the result is nothing.")
    ElseIf player\curRoomPtr\exits & (1 << (dirIndex(direction) - 1))
			displayN("You swing your sledge wildly.")
		Else
			displayN("You bash until the surface crumbles, leaving a hole you can crawl through.")
      link(player\curRoomPtr, direction)
		EndIf
	Else
		displayN("You accomplish nothing.")
	EndIf
  ProcedureReturn shift(cmd)
EndProcedure

Procedure.s cmd_name(cmd.s)
  Protected sep.s = " ", shiftCount = 1
  
  If Left(cmd, 1) = #DQUOTE$
    sep = #DQUOTE$  : shiftCount = 2
  EndIf 
  
  Protected newName.s = StringField(cmd, shiftCount, sep)
  
 	If newName = "help" Or newName = ""
    displayN("Usage: name (New name of room)", #con_Bright_Green)
    ProcedureReturn ""
  EndIf 
  
  Protected *room.room = player\curRoomPtr
  *room\name = newName 
  displayN("Room is now named '" + *room\name + "'.")
  ProcedureReturn shift(cmd, shiftCount, sep)
EndProcedure

Procedure.s cmd_equip(cmd.s)
  Protected toEquip.s = StringField(cmd, 1, " ")
  
	If toEquip = "help" Or toEquip = ""
    displayN("Usage: equip (itemname)", #con_Bright_Green)
    ProcedureReturn shift(cmd)
  EndIf 
  
  ;Find it
  Protected type = parseItem(toEquip)
  If player\equipped = type And type <> #itm_nothing
    displayN("You are already equipped with your " + toEquip + ".")
  ElseIf type = #itm_nothing
    player\equipped = type
    displayN("You are now equipped with " + toEquip + ".")
  Else
    Protected found
    ;Equip it.
    ForEach player\inventory()
      If player\inventory() = type
        found = 1
        player\equipped = type
        Break
      EndIf 
    Next 
    
    If found
      displayN("You equipped your " + toEquip + ".  Put it to good use.")
    Else 
      displayN("You don't have one of those.  Try 'i' to see what you have.")
    EndIf
  EndIf
  
  ProcedureReturn shift(cmd)
EndProcedure

Procedure move_items(List fromRef.i(), List toRef.i(), cmd.s)
  Protected item.s = StringField(cmd, 1, " ")
  Protected moveall, moved, type
  
  If item = "all"
    moveall = #True
    type = #itm_any
  Else 
    type = parseItem(item)
  EndIf 

  LastElement(toRef())
  ForEach fromRef()
    If type = #itm_any  Or fromRef() = type
      AddElement(toRef())
      toRef() = fromRef()
      DeleteElement(fromRef())
      moved + 1
      If Not moveall: Break: EndIf
    EndIf 
  Next 
    
  ProcedureReturn moved
EndProcedure

Procedure.s cmd_take(cmd.s)
  Protected item.s  = StringField(cmd, 1, " ")
  
 	If item = "help" Or Len(cmd) = 0
    displayN("Usage: take {all|(itemname)}", #con_Bright_Green)
    ProcedureReturn ""
  EndIf 

  Protected *room.room = player\curRoomPtr
  Protected moved = move_items(*room\items(), player\inventory(), cmd)
  Select moved
    Case 0
      displayN("There aren't any of those here.")
    Case 1
      displayN("You took 1 item.")
    Default 
      displayN("You took " + Str(moved) + " items.")
  EndSelect 
  ProcedureReturn shift(cmd)
EndProcedure

Procedure.s cmd_drop (cmd.s)
  Protected item.s = StringField(cmd, 1, " ")

	If item = "help" Or item = ""
    displayN("Usage: drop {all|(itemname)}", #con_Bright_Green)
    ProcedureReturn ""
  EndIf 
 
  Protected *room.room = player\curRoomPtr
  Protected moved = move_items(player\inventory(), *room\items(), cmd)
	Select moved
    Case 0
      displayN("You don't have any of those.")
    Case 1
      displayN("You dropped 1 item.")
    Default
      displayN("You dropped " + Str(moved) + " items.")
  EndSelect 
  
  ;Check to see if we dropped our equipped item.
  If moved And player\equipped
    Protected type = parseItem(item)
    Protected droppedEquipped = #True
    If type <> #itm_nothing
      ForEach player\inventory()
        If player\inventory() = player\equipped
          droppedEquipped = #False
          Break
        EndIf 
      Next 
    EndIf
    If droppedEquipped
      displayN("You dropped the item you were using.")
      cmd_equip("nothing")
    EndIf 
  EndIf 
  ProcedureReturn shift(cmd)
EndProcedure

Procedure.s cmd_inventory(cmd.s)
  Protected help.s = StringField(cmd, 1, " ")

	If help = "help"
    displayN("Usage: inventory", #con_Bright_Green)
  	ProcedureReturn ""
  EndIf 
 
  Protected count = ListSize(player\inventory())
	If count
    FirstElement(player\inventory())
    display("You have a ")
    Select count
      Case 1
        display(itemName(player\inventory()))
      Default
        Protected i
        For i = 1 To count - 2
          display(itemName(player\inventory()) + ", ")
          NextElement(player\inventory())
        Next
        display(itemName(player\inventory()) + " and a ")
        NextElement(player\inventory())
        display(itemName(player\inventory()))
    EndSelect
    displayN(".")
  Else
    displayN("You're not carrying anything.  Ask again later.")
  EndIf 
  ProcedureReturn shift(cmd)
EndProcedure

Procedure Max(x, y)
  If x < y
    ProcedureReturn y
  EndIf
  ProcedureReturn x
EndProcedure

Procedure.s cmd_hint(cmd.s)
  If StringField(cmd, 1, " ")
    displayN("Usage: hint", #con_Bright_Green)
    ProcedureReturn ""
  EndIf 
  
  ;check for gold
  Protected hasGold = #False 
  ForEach player\inventory()
    If player\inventory() = #itm_gold
      hasGold = #True
      Break
    EndIf 
  Next 
    
  ;if gold is not present then exit
  If Not hasGold
    displayN("You can't get a hint, you need gold.")
    ProcedureReturn cmd
  EndIf 
  
  display("Will you pay a gold for a hint (y/n)?")
  Protected Answer.s = Input()
  displayN("")
  If LCase(Left(Answer, 1)) <> "y"
    displayN("You must be saving your money for retirement, good luck!")
    ProcedureReturn cmd
  EndIf 
  DeleteElement(player\inventory())
  hintCount + 1
  
  ;calculate vector to prizeroom
  Protected VECTOR.coord3D, maxVector.coord3D, max
  VECTOR\x = prizeRoom\x - player\location\x
  VECTOR\y = prizeRoom\y - player\location\y
  VECTOR\z = prizeRoom\z - player\location\z
  If Abs(VECTOR\y) >= Max(Abs(VECTOR\x), Abs(VECTOR\z)): max = 1: EndIf
  If Abs(VECTOR\z) >= Max(Abs(VECTOR\x), Abs(VECTOR\y)): max = 2: EndIf
  
  Protected *ptrVec.Integer = @VECTOR + max * SizeOf(Integer)
  Protected *ptrMaxVec.Integer = @maxVector + max * SizeOf(Integer)
  If *ptrVec\i < 0
    *ptrMaxVec\i = -1
  ElseIf *ptrVec\i > 0
    *ptrMaxVec\i = 1
  EndIf 
  
  ForEach directions()
    With directions()
      If \x = maxVector\x And \y = maxVector\y And \z = maxVector\z
        Protected dir.s = MapKey(directions())
        Break
      EndIf
    EndWith
  Next 
  display("You place the gold into a small slot on the wall.  A message appears on the wall in bright letters that says '")
  display("Go " + dir, #con_Bright_Blue, #con_Yellow)
  displayN("'.  After a few moments it fades from view.")
   
  ProcedureReturn cmd.s
EndProcedure

Procedure.s cmd_quit(cmd.s)
  Protected help.s = StringField(cmd, 1, " ")
  If help = "help"
    displayN("Usage: quit", #con_Bright_Green)
    ProcedureReturn ""
  EndIf
  
  displayN("Goodbye!")
  quitNow = #True
  ProcedureReturn ""
EndProcedure

Procedure.s cmd_alias(cmd.s)
  Protected existing.s = StringField(cmd, 1, " ")
  Protected newCommand.s = StringField(cmd, 2, " ")
  
  If existing = "help" Or existing = "" Or newCommand = ""
    displayN("Usage: alias (existing command name) (additional name for command)", #con_Bright_Green)
    ProcedureReturn ""
  EndIf
  
	If FindMapElement(*commands(), newCommand)
    displayN( "Can't redefine an existing command!")
    ProcedureReturn ""
  EndIf 
  
  If Not FindMapElement(*commands(), existing)
    displayN("The command '" + existing + "' is not currently defined")
  Else 
    Protected function =  *commands()
  EndIf
  *commands(newCommand) = function
  displayN("alias '" + newCommand + "' defined.")
  ProcedureReturn shift(cmd, 2)
EndProcedure

Procedure.s cmd_help(cmd.s)
  Protected command.s = StringField(cmd, 1, " ")
  If command = "help"
    displayN("Usage: help (command name) ... But you apparently discovered that.", #con_Bright_Green)
    ProcedureReturn ""
  ElseIf FindMapElement(*commands(), command)
    Protected function.command_prt = *commands()
    function("help " + command)
  Else
    displayN("Valid commands are:" + #CR$, #con_Bright_Green)
    ResetMap(*commands())
    Protected i, count = MapSize(*commands())
    For i = count - 1 To 1 Step - 1
      NextMapElement(*commands())
      display(MapKey(*commands()), #con_Bright_Green)
      If i <> 1
        display(", ", #con_Bright_Green)
      EndIf 
    Next 
    displayN(".", #con_Bright_Green)
  EndIf 
  ProcedureReturn ""
EndProcedure

*commands("up") = @cmd_up()
*commands("down") = @cmd_down()
*commands("north") = @cmd_north()
*commands("south") = @cmd_south()
*commands("east") = @cmd_east()
*commands("west") = @cmd_west()
*commands("attack") = @cmd_attack()
*commands("name") = @cmd_name()
*commands("take") = @cmd_take()
*commands("drop") = @cmd_drop()
*commands("equip") = @cmd_equip()
*commands("inventory") = @cmd_inventory()
*commands("ask") = @cmd_hint()
*commands("quit") = @cmd_quit()
*commands("alias") = @cmd_alias()
*commands("help") = @cmd_help()

cmd_alias("north n")
cmd_alias("south s")
cmd_alias("east e")
cmd_alias("west w")
cmd_alias("up u")
cmd_alias("down d")
cmd_alias("attack a")
cmd_alias("inventory i")
cmd_alias("inventory inv")
cmd_alias("quit q")

isConsoleAvailable = OpenConsole()
If isConsoleAvailable
  mainloop()

  display(#CR$ + #CR$ + "Press ENTER to exit"): Input()
  CloseConsole()
EndIf