-- menu.ala
-- version 1.0
--
-- Alan source code example demonstrating
-- a few techniques for implementing a menu
-- in an Alan game.
--
-- Written in Alan 2.8 (Works fine in 2.6 and 2.7)
--
-- [email protected]
-- February 1999

---------------------------------------------------

-- An object to hold the menu status information

OBJECT menu_system
   HAS level 0 .
   HAS selection_bad "no" .
END OBJECT.

---------------------------------------------------

-- Normal game commands aren't disabled while the menu is on-screen
-- If player selects a non-menu command - eg:'north' or 'attack troll'
-- then the game will continue so this event is scheduled to run one turn
-- after a menu is entered to return the game to 'not-in-menu' status.
-- If the player continues to use menu commands then the event is
-- cancelled and re-scheduled to run on the next turn.

EVENT not_in_menu
   SET level OF menu_system TO 0 .
   SET selection_bad OF menu_system TO "no".
END EVENT.

---------------------------------------------------

-- Add a 'using the menu?' check to the normal quit
-- command as the same command will now be used to
-- quit a menu as well as quit the whole game.

SYNTAX 'quit' = 'quit'.

SYNONYMS q = 'quit'.

VERB 'quit'
DOES
   IF level OF menu_system > 0 THEN
       "Ok.  Back to the game ...."
       SET level OF menu_system TO 0 .
       SET selection_bad OF menu_system TO "no" .
       LOOK. -- debatable whether want this 'look' or not.
   ELSE
       QUIT.
   END IF.
END VERB 'quit'.

---------------------------------------------------

-- Command to start the menu system and display the 'menu_1' object which
-- contains the text for the main menu.

SYNTAX menu = menu.

SYNONYMS help = menu.

VERB menu
CHECK level OF menu_system = 0
   ELSE "You are already in the menu system."
DOES
   SET level OF menu_system TO 1.
   SCHEDULE not_in_menu AfTER 1.
   "$p$p(The purpose of this program is to provide source code which
   demonstrates how to program menus in 'Alan'.
   This program demonstrates two different menu-selection methods
   which may be a little confusing. Also the menus
   are not very well laid out, sorry, as I had trouble thinking of
   enough menu topics to adequately illustrate
   the programming techniques in the source code.)"
   DESCRIBE menu_1.
END VERB.

---------------------------------------------------

-- Menu verbs
--
-- Note that the IF statements in these verbs must be customised to
-- reflect the actual menu structure.
-- eg: if there's no option c on the 'menu_111' menu then the author needs
-- to remove the section of the IF statement in the 'c' verb that refers
-- to menu_1113
--
-- Note that there's two different item-selection methods used in this
-- demo - the 'a,b,c..' and 'topic n' methods. In a real game you'd only
-- need one or the other system as you'd want all your menus to work in a
-- consistent way for the player's convenience.


SYNTAX
   a = a.
   b = b.
   c = c.
   d = d.
   p = p.

VERB a
CHECK level OF menu_system > 0
   ELSE "That command is only valid within the menu system."
DOES
   CANCEL not_in_menu.
   SCHEDULE not_in_menu AfTER 1.

   IF level OF menu_system = 1 THEN
       DESCRIBE menu_11.
   ELSIF level OF menu_system = 11 THEN
       DESCRIBE menu_111.
   ELSIF level OF menu_system = 111 THEN
       DESCRIBE menu_1111.
   ELSIF level OF menu_system = 112 THEN
       DESCRIBE menu_1121.
   ELSE
       "'a' is not a valid option."
       SET selection_bad OF menu_system TO "yes".
   END IF.

   -- if the player's selection was valid then
   -- display the 'footer' text for the new menu and update the menu
   -- level number otherwise do nothing except turn the 'bad' flag
   -- off again ready for the player's next attempt.
   IF selection_bad OF menu_system = "yes" THEN
       SET selection_bad OF menu_system TO "no".
   ELSE
       "$p(Enter P for previous menu, Q to quit menu and return to game.)"
       SET level OF menu_system TO (level OF menu_system * 10) + 1.
   END IF.
END VERB a.

VERB b
CHECK level OF menu_system > 0
   ELSE "That command is only valid within the menu system."
DOES
   CANCEL not_in_menu.
   SCHEDULE not_in_menu AfTER 1.

   IF level OF menu_system = 1 THEN
       DESCRIBE menu_12.
   ELSIF level OF menu_system = 11 THEN
       DESCRIBE menu_112.
   ELSIF level OF menu_system = 111 THEN
       DESCRIBE menu_1112.
   ELSIF level OF menu_system = 112 THEN
       DESCRIBE menu_1122.
   ELSE
       "'b' is not a valid option."
       SET selection_bad OF menu_system TO "yes".
   END IF.

   IF selection_bad OF menu_system = "yes" THEN
       SET selection_bad OF menu_system TO "no".
   ELSE
       "$p(Enter P for previous menu, Q to quit menu and return to game.)"
       SET level OF menu_system TO (level OF menu_system * 10) + 2.
   END IF.
END VERB b.

VERB c
CHECK level OF menu_system > 0
   ELSE "That command is only valid within the menu system."
DOES
   CANCEL not_in_menu.
   SCHEDULE not_in_menu AfTER 1.

   IF level OF menu_system = 111 THEN
       DESCRIBE menu_1113.
   ELSIF level OF menu_system = 112 THEN
       DESCRIBE menu_1123.
   ELSE
       "'c' is not a valid option."
       SET selection_bad OF menu_system TO "yes".
   END IF.

   IF selection_bad OF menu_system = "yes" THEN
       SET selection_bad OF menu_system TO "no".
   ELSE
       "$p(Enter P for previous menu, Q to quit menu and return to game.)"
       SET level OF menu_system TO (level OF menu_system * 10) + 2.
   END IF.
END VERB c.

VERB d
CHECK level OF menu_system > 0
   ELSE "That command is only valid within the menu system."
DOES
   CANCEL not_in_menu.
   SCHEDULE not_in_menu AfTER 1.

   IF level OF menu_system = 111 THEN
       DESCRIBE menu_1114.
   ELSE
       "'d' is not a valid option."
       SET selection_bad OF menu_system TO "yes".
   END IF.

   IF selection_bad OF menu_system = "yes" THEN
       SET selection_bad OF menu_system TO "no".
   ELSE
       "$p(Enter P for previous menu, Q to quit menu and return to game.)"
       SET level OF menu_system TO (level OF menu_system * 10) + 2.
   END IF.
END VERB d.

VERB p
CHECK level OF menu_system > 0
   ELSE "That command is only valid within the menu system."
DOES
   CANCEL not_in_menu.
   SCHEDULE not_in_menu AfTER 1.

   IF level OF menu_system = 1 THEN
       "No 'previous' menu - you are at the top level of the menu."
   ELSE
       -- "/" in Alan means 'integer division' - ie result of division
       -- is the whole number portion - the decimal part is thrown away
       -- so "/10" effectively moves the digits one place to the right
       -- and throws away the rightmost digit
       -- eg 132 /10 = 13
       SET level OF menu_system TO (level OF menu_system / 10).

       IF level OF menu_system = 1 THEN
           DESCRIBE menu_1.
       ELSIF level OF menu_system = 11 THEN
           DESCRIBE menu_11.
       ELSIF level OF menu_system = 12 THEN
           DESCRIBE menu_12.
       ELSIF level OF menu_system = 111 THEN
           DESCRIBE menu_111.
       ELSIF level OF menu_system = 112 THEN
           DESCRIBE menu_112.
       ELSIF level OF menu_system = 123 THEN
           DESCRIBE menu_123.
       ELSIF level OF menu_system = 126 THEN
           DESCRIBE menu_126.
       ELSE
           "Oops, there's a problem! $nMenu"
           SAY level OF menu_system.
           "isn't a valid menu screen.
           $pExiting menu now - type 'menu' to re-enter the menu system
           at the top level."
           SET selection_bad OF menu_system TO "yes".
       END IF.

       IF selection_bad OF menu_system = "yes" THEN
           SET selection_bad OF menu_system TO "no".
           SET level OF menu_system TO 0.
       ELSE
           IF level OF menu_system > 1 THEN
               "$p(Enter P for previous menu, Q to quit
               menu and return to game.)"
           END IF.
       END IF.
   END IF.
END VERB p.

---------------------------------------------------

SYNTAX choose = choose (opt)
   WHERE opt ISA INTEGER
       ELSE "You must enter a number - eg: 'c 3'"

SYNONYMS
   topic, t = choose.  -- usually would use 'c' as the synonym

VERB choose
CHECK level OF menu_system > 0
   ELSE "That command is only valid within the menu system."
DOES
   CANCEL not_in_menu.
   SCHEDULE not_in_menu AfTER 1.

   IF opt = 1 THEN
       IF level OF menu_system = 12 THEN
           DESCRIBE menu_121.
       ELSIF level OF menu_system = 123 THEN
           DESCRIBE menu_1231.
       ELSIF level OF menu_system = 126 THEN
           DESCRIBE menu_1261.
       ELSE
           SET selection_bad OF menu_system TO "yes".
       END IF.
   ELSIF opt = 2 THEN
       IF level OF menu_system = 12 THEN
           DESCRIBE menu_122.
       ELSIF level OF menu_system = 123 THEN
           DESCRIBE menu_1232.
       ELSIF level OF menu_system = 126 THEN
           DESCRIBE menu_1262.
       ELSE
           SET selection_bad OF menu_system TO "yes".
       END IF.
   ELSIF opt = 3 THEN
       IF level OF menu_system = 12 THEN
           DESCRIBE menu_123.
       ELSIF level OF menu_system = 123 THEN
           DESCRIBE menu_1233.
       ELSIF level OF menu_system = 126 THEN
           DESCRIBE menu_1263.
       ELSE
           SET selection_bad OF menu_system TO "yes".
       END IF.
   ELSIF opt = 4 THEN
       IF level OF menu_system = 12 THEN
           DESCRIBE menu_124.
       ELSE
           SET selection_bad OF menu_system TO "yes".
       END IF.
   ELSIF opt = 5 THEN
       IF level OF menu_system = 12 THEN
           DESCRIBE menu_125.
       ELSE
           SET selection_bad OF menu_system TO "yes".
       END IF.
   ELSIF opt = 6 THEN
       IF level OF menu_system = 12 THEN
           DESCRIBE menu_126.
       ELSE
           SET selection_bad OF menu_system TO "yes".
       END IF.
   ELSIF opt = 7 THEN
       IF level OF menu_system = 12 THEN
           DESCRIBE menu_127.
       ELSE
           SET selection_bad OF menu_system TO "yes".
       END IF.
   ELSE
       SET selection_bad OF menu_system TO "yes".
   END IF.

   IF selection_bad OF menu_system = "yes" THEN
       SAY opt. "is not a valid option."
       SET selection_bad OF menu_system TO "no".
   ELSE
       "$p(Enter P for previous menu, Q to quit menu and return to game.)"
       SET level OF menu_system TO (level OF menu_system * 10) + opt.
   END IF.

END VERB choose.

---------------------------------------------------

-- menu objects
--
-- These are used rather than including menu text within verbs as
-- several verbs may actually display the same text - eg 'menu' and
-- 'p' (for previous menu) may both display the main menu text.
-- Using objects means just need 'DESCRIBE <object>' statements repeated
-- in the relevant verbs.

OBJECT menu_1
DESCRIPTION
   "$pMain Menu
   $pSelect an option:"
   "$p
   $n$tA$t-$tPlaying, & writing, I.F.$t(uses 'a,b,c' verbs)
   $n$tB$t-$tMiscellaneous Notes.$t(uses 'choose topic' verb)
   $n$tQ$t-$tQuit this menu."
END OBJECT menu_1.

----

OBJECT menu_11
DESCRIPTION
   "$pGeneral Interactive Fiction Information
    $pSelect an option:"
   "
   $p$tA$t-$tCommons Commands used to play I.F. games
   $n$tB$t-$tWriting I.F. games with the 'Alan' system
   "
END OBJECT menu_11.

OBJECT menu_12
DESCRIPTION
   "$pNotes are available on the following topics:"
   "$pEnter 'topic n' or 't n'
   $nwhere 'n' is the number of your choice"
   "
   $p$t1$t-$tWhy doesn't this menu use a,b,c options.
   $n$t2$t-$tWhy have a 'topic' verb?
   $n$t3$t-$tLimitations of this menu system.
   $n$t4$t-$tA third item selection method.
   $n$t5$t-$tNon-text 'action' items.
   $n$t6$t-$tWho wrote this program?
   $n$t7$t-$tWhy?
   "
END OBJECT menu_12.

----

OBJECT menu_111
DESCRIPTION
   "$pStandard Interactive Fiction Commands
    $pSelect an option:"
   "
   $p$tA$t-$tMoving around.
   $n$tB$t-$tInteracting with objects.
   $n$tC$t-$tInteracting with characters.
   $n$tD$t-$tMiscellaneous commands.
   "
END OBJECT menu_111.

OBJECT menu_112
DESCRIPTION
   "$pWhere to obtain the Alan I.F. Authoring System
    $pSelect an option:"
   "
   $p$tA$t-$tThe Alan Web Site.
   $n$tB$t-$tThe I.F. Archive ftp Site.
   $n$tC$t-$tVia Internet Email.
   "
END OBJECT menu_112.

----

OBJECT menu_1111
DESCRIPTION
   "$pMoving around.
   $pnorth,south,southwest,etc (abbreviate as n,s,sw,etc)
   $nalso enter or exit in some locations
   $ngo north, etc also works
   "
END OBJECT menu_1111.

OBJECT menu_1112
DESCRIPTION
   "$pObjects
   $pexamine or look at 'object' (abbr. x 'object')
   $ntake or get 'object'
   $ndrop or throw 'object'
   $nput 'object' in (or on) 'another object'
   $ngive 'object' to 'character'
   "
END OBJECT menu_1112.

OBJECT menu_1113
DESCRIPTION
   "$pCharacters
   $pask 'character' about 'subject'
   $ntell 'character' about 'subject'
   $ngive 'object' to 'character'
   "
END OBJECT menu_1113.

OBJECT menu_1114
DESCRIPTION
   "$pGame Status
   $pinventory (abbr. i ) - list objects being carried
   $nlook (abbr. l ) - repeat description of current location
   $nscore - display game points currently earned

   $pStopping and starting game
   $psave - save current game state to a disk file
   $nrestore - restore previously saved game from disk file
   $nrestart - start playing game again
   $nquit - exit the game

   $pMiscellaneous
   $pbrief - only describe a location when first visit it
   $nverbose - display description each time visit a location
   $nwait (abbr. z ) - do nothing for a turn
   "
END OBJECT menu_1114.

----

OBJECT menu_1121
DESCRIPTION
   "$pThe Alan Web Site.
   $ihttp://www.pp.softlab.se/thomas.nilsson/alan/
   "
END OBJECT menu_1121.


OBJECT menu_1122
DESCRIPTION
   "$pThe I.F. Archive ftp Site.
   $iftp://ftp.gmd.de/if-archive/
   $ihttp://www.if_archive.org/"
END OBJECT menu_1122.


OBJECT menu_1123
DESCRIPTION
   "$pVia Internet Email.
   $iSend a message containing the text SEND INFO to
   [email protected]"
END OBJECT menu_1123.

----

OBJECT menu_121
DESCRIPTION
   "
   $iThe use of a,b,c etc for menu items runs into a problem if there's
   more than three items because 'd' might already be defined as a
   synonym for the direction 'down' and almost certainly 'e' will be
   short for 'east'.
   This menu demonstrates another way the player can specify their
   item choice.
   "
END OBJECT menu_121.

OBJECT menu_122
DESCRIPTION
   "
   $iYou can't use 1,2,3 etc as Alan verbs because a command can't start
   with a number. So you can define a command like 'choose n'
   abbreviated to 'c n' where n is the number of the option required. (In
   this demo the verb is 'topic n' coz the abbreviation 'c' is already
   defined as a verb for the a,b,c style of menu-selection.
   Of course, in a real game you wouldn't mix and match the two selection
   methods as this demonstration does.
   "
END OBJECT menu_122.

OBJECT menu_123
DESCRIPTION
   "Inherent Restrictions within this Menu System"
   "$pChoose a topic by entering 't n' where n is the number of your
   choice:"
   "$p$t1$t-$tNine Items per menu"
   "$n$t2$t-$tNine levels of menus"
   "$n$t3$t-$tFree Letters available for item labels"
END OBJECT menu_123.

OBJECT menu_124
DESCRIPTION
   "Third Alternative Menu Selection Method"
   "$n$t
   (Not implemented in this example program.)
   $pThere's no reason (except that its easier to program) why you must
   use one-letter verbs to select menu items.  For example you could have ....
   $pAuthor's Notes
   $n$tAUTHOR$t-$tAbout the author.
   $n$tCREDITS$t-$tBeta-testers.
   $n$tALAN$t-$tAbout the authoring system used to write this game.
   $n$tHISTORY$t-$tFootnotes about the era this game is set in.
   $n$tLEGAL$t-$tCopyright notice and Disclaimer.
   $pWith this sort of menu you could allow the player to access the items
   directly during game-play as well as from a menu. You can then have the
   verbs keep track of whether the menu was active or not to control if
   the player is returned to the menu or the game after the menu item is
   executed."
END OBJECT menu_124.

OBJECT menu_125
DESCRIPTION
   "Note that in this demo all the menu items simply display bits of
   text. But they could also perform actions just as well. So you could
   do 'choose your own adventure' games with menus like
   $p$tDo you want to....
   $p$t$tA$t-$tAttack Troll
   $n$t$tB$t-$tKiss Troll
   $n$t$tC$t-$tGo North
   $p$tThe 'a' verb would then have in its statement something like...
   $iELSIF level OF menu_system = 14 THEN
   $i$t""You kill the troll with your trusty sword. Now you can
   $i$tfinally cross the eastern bridge.""
   $i$tLOCATE hero AT eastern_kingdom.
   $i$tSCORE 5."
END OBJECT menu_125.

OBJECT menu_126
DESCRIPTION
   "Who wrote this demo?"
   "$pChoose a topic by entering 't n' where n is the number of your
   choice:"
   "$p$t1$t-$tAuthor email address"
   "$n$t2$t-$tFeedback requested"
   "$n$t3$t-$tWhy is this info split up into three submenus?"
END OBJECT menu_126.

OBJECT menu_127
DESCRIPTION
   "I wrote this program because I hoped that other Alan programmers
   would find it useful. You're welcome to use this code as a basis
   for your own menus. I hope you'll share any improvements and new ideas
   for the benefit of the Alan programming 'community.'"
END OBJECT menu_127.

----

OBJECT menu_1231
DESCRIPTION
   "$pNine Items per menu
   $pThis limitation is because of the menu level numbering scheme
   within the program. Each menu screen seen by the player is a
   separate Alan object identified by an id number. The first menu is
   called menu_1. Menu screens off that are called menu_1x (where x
   can be 1 to 9). The menu screens off each one of those screens are
   labelled menu_1xx.

   $pmenu_1 ----> menu_11 --> menu_111
   $n$t$t$t$t$t$t               menu_112
   $n$t$t$t$t$t$t                  etc
   $n$t$t$t        menu_12 --> menu_121
   $n$t$t$t$t$t$t                menu_122
   $n$t$t$t$t$t$t                   etc
   $n$t$t$t$t           :
   $n$t$t$t$t           :
   $n$t$t$t        menu_18
   $n$t$t$t        menu_19"

   "$pTake menu_12 as an example. Menu_12 is the second menu off the main
   menu. (The player selects if off the main menu by entering 'b' or 't 2'
   or whatever other verb you might program to do it.) Menu_12 could have
   up to nine submenus off it which would be labelled menu_121, menu_122,
   menu_123, ... , menu_129.  A tenth menu off menu_12 would have to be
   called menu_130 or something. That wouldn't work coz the program would
   see the '13' bit and relate it to the _third_ submenu off the main menu
   not the second one. Or you could try menu_1210 but that wouldn't work
   either because that would signify (if you could had a menu 0 under this
   naming scheme) the zero'th menu off the first submenu off the second
   submenu off the main menu! :-)"
END OBJECT menu_1231.

OBJECT menu_1232
DESCRIPTION
   "$pNine Levels of menus
   $pWell about nine levels. I haven't worked it out exactly but it looks
   like the largest number you can have in Alan is measured in the billions
   so you could perhaps have a menu_1999999999. Hopefully you'd never need
   to go nine menu levels deep anyway. That'd be pretty confusing for the
   player. As would having nine options on one menu. So hopefully these
   limitations won't be a problem in practice."
END OBJECT menu_1232.


OBJECT menu_1233
DESCRIPTION
   "$pFree Letters available for item labels
   $pWith the 'a,b,c...' method of selection you're further limited to the
   number of letters you can think of that aren't used for other
   player verbs or exits. (d,e,g,i,l,n,p,q,s,u,x,z are standard
   abbreviations traditionally defined for something.)
   $pBut you could use two letter commands or whatever (see menu
   item 'A third menu selection alternative' for an example.)
   "
END OBJECT menu_1233.
----

OBJECT menu_1261
DESCRIPTION
   "$pThis program was written by Stephen Griffiths. Email address
   is [email protected]"
END OBJECT menu_1261.

OBJECT menu_1262
DESCRIPTION
   "$pI would really welcome feedback on this demo program. Let me know
   if you find it useful, discover bugs, have a better way of doing menus
   or whatever. I look forward to hearing from other users of 'Alan'"
END OBJECT menu_1262.

OBJECT menu_1263
DESCRIPTION
   "$pYes I know all these dinky little submenus are annoying but I needed
   to have at least two submenus off the 'topic n' submenu to make the
   choose/topic verb example in the source more informative."
END OBJECT menu_1263.

---------------------------------------------------

-- A dummy location to have somewhere to start this demo game

LOCATION somewhere NAME somewhere 'in' a hypothetical game
DESCRIPTION
   "$iYou are in a room dimly lit only by the full moon shining through a small
   window high on the eastern wall. A thick swirling mist several inches
   thick cloaks the floor. Many fascinating objects and items of furniture
   festooned with cobwebs fill the room.
   $iWell, no, not really! Actually this location is empty and exists for no
   reason other than to have a place to start from in this demonstration."

   EXIT north,south,east,west TO somewhere
      CHECK "You can't go anywhere. You can only look at the menu
               or quit, sorry."
   END EXIT.

END LOCATION.

START AT somewhere.
"----------------------------------------------------------------------"
"$pMenu demonstration"
"$n------------------"
"$pAn Alan IF System coding example$iBy Stephen Griffiths"
"$p
Player Commands available in this 'game':
$n$tmenu$t$t$t-$tsee the demonstration
$n$tnorth,east etc$t-$tjust there so you've got some non-menu commands
$n$tquit$t$t$t-$texit the program"
"$p----------------------------------------------------------------------"