!::
! NEWMENU.H Version 3.4 by Roody Yogurt
!::
!\
For a nice overview of this contribution, check out:
http://hugo.gerynarsabode.org/index.php?title=NewMenu.h
version 3.4 - got rid of the array usage for setting up menus (a legacy
from the original menu routines). now it's completely based
on object hierarchy. added some stuff to sort menus by priority
property the first time they are opened
version 3.3 - changed some "press a key" stuff
version 3.2 - Got rid of extra screen clears and other code cleaning
version 3.1 - added alt_title property for option objects. if provided,
the name property is still used as a menu choice, but alt_title
is used to title the actual page.
added NEW_FUSE code
fixed ShowPage "returning to game" printed text
removed DESCFORM_I code
changed cheap code to be keypress-based, not input-based
version 3.0 - Added USE_EXTENSION_CREDITING object stuff
version 2.9 - Fixed some flags so the default menu works without Roodylib
Cleaned up command-printing page in default menu; added
PrintCommands routine
version 2.8 - Rewrote how "cheap"-mode works and looks. Now glk menus that
are over a certain size are automatically drawn as cheap
menus. Other little changes.
version 2.7 - Added an argument to ShowPage so it can be called at the
end of a game and won't expect to go back to gameplay
Added it to MakeMenu so authors have the option of calling
up menus after the game, too
version 2.6 - common_commands array was being overwritten by MenuInit
Changed the default printing behavior of MenuPause
Changed text in the Special Commands page
MenuPause with top pause message now always one line window
(instead of current display.status_window height)
version 2.5 - added some code for dealing with changing window sizes
mid-menu
version 2.4 - changed it so newmenu always compiles with a main_menu object,
default menu still only displays with #USE_DEFAULT_MENU switch. you can
change the name of the main_menu object easily with:
main_menu.name = "Your New Name"
version 2.3 - fixed some cheaplib/color stuff. added a #USE_DEFAULT_MENU
switch so the built-in menu only shows up when wanted. got rid of extra
array.
version 2.2 - added a "priority" property for the option objects. higher
numbers are listed first in menu lists (only works when newmenu is used in
conjunction with "roodylib". Fixed some clearscreen stuff; tidied up the
messages to be shown during transcripts.
version 2.0 - took out jumps, hid a cursor, fixed some pauses, made Glk.h
no longer necessary for menus to work with interpreters like Gargoyle
version 1.9 - fixed a bug in non-glk games, added Kent Tessman's
cursor-hiding pause code
version 1.8 - fixed something where hidden transcript notes were
being printed in BGCOLOR, BGCOLOR instead of MENU_BGCOLOR, MENU_BGCOLOR
version 1.7 - better support for menu colors. Now choosing specific
menu colors results in the colors being used for the whole page, instead
of a colored menu option "island" on a normal TEXTCOLOR/BGCOLOR background
in some circumstances.
Also, I added some color properties for menu_category options, so different
menu pages can have different color schemes. The new properties are:
page_text_color
page_bg_color
title_color
title_bg
version 1.5 - fixed message routines
New in version 1.2- added "options_gap" property for menucategory objects.
Controls spaces between "[N]ext item..." text and menu options, giving more
configurability.
New in version 1.1- added "title_gap" property to menucategory object. Put in
a true value if you want that menu to have a blank line between the title and
"[N]ext item..." text
This is an update to Kent Tessman's menu routine in the Hugo Library.
Differences in this version:
- Adds some "hidden" text so transcripts look better.
- Adds asterisk-highlighting when used with glk interpreters
- Adds support to cheapglk interpreters
- Has built-in support for Guilty Bastards style hints
As it is based on the original menu routine and Guilty Bastards hint routine,
this extension draws on those two things a fair amount, despite having been
worked around, si this thing couldn't have been written without Kent's original
work.
First things first-
Include this file after "hugolib.h".
This extension *expects* a menu_category object named main_menu. One is
provided by newmenu.h, but if you need to replace it, do the following:
replace main_menu "TITLE OF YOUR MAIN MENU"
{
inherits menu_category
}
Now, calling MakeMenu from a DoAbout or DoHelp routine will automaticaly bring
up that menu. (if you have several different menus that can be called by
different commands, call MakeMenu([other_menu_object]).
Now let's fill that menu with choices. For this, we use option objects.
option contact_choice "Contact"
{
in main_menu ! which menu it is
menu_text
{
""
"\_ Feel free to send me your thoughts and suggestions at
[email protected]! What an amazing discourse we will have!"
! MenuPause will be called automatically
}
}
The menu_text property holds the text you want on the page. After the menu_text
property is printed, the MenuPause routine automatically prints a "press a key"
message and waits for a pause. Change the MenuPause messages in NewMenuMessages
if you'd like to change the text.
You can change when an option is available by changing its option_available
value.
Of course, return true when you want it available:
option helicopter_choice "Whoa, a Helicopter!"
{
in main_menu
option_available
{
if helicopter is known
return true
else
return false
}
menu_text
{
! helicopter text
}
}
If you want an option to lead to *another* menu, give it a menu_link property:
option submenu_choice "CHOICE LEADING TO SUBMENU"
{
in main_menu
menu_link [submenu menucategory object]
}
Hints!
So yeah, this thing also supports hints. Just make a hint menucategory object,
and fill it with hint_options like this:
hint_option studiopass_hints "How do I get on the studio lot?"
{
in hint_menu
hints_available
{
if studio_lot is visited
return true
else
return false
}
hint1
{
"Movie studio security is on par with Area 51. To get on
the lot, you'll need a pass."
}
hint2
{
"There's a studio pass in the envelope that was slipped
under the door of your hotel room."
}
hint3
{
"Drive to the studio lot. Make sure you've got the pass
handy. Get out of the car and go north."
}
}
Notice the hints_available property (which does pretty the same
thing as the option_available property). Now, the player will
have to type 'H' for each additional hint on this hint page.
Hmmm, that should be everything! E-mail me if you have any questions!
Roody Yogurt
[email protected]
\!
#ifclear _NEWMENU_H
#set _NEWMENU_H
#ifset VERSIONS
#message "NewMenu.h Version 3.4"
#endif
#ifset USE_EXTENSION_CREDITING
#ifclear _ROODYLIB_H
#message error "Extension crediting requires \"roodylib.h\". Be sure to include
it first!"
#endif
version_obj newmenu_version "NewMenu Version 3.4"
{
in included_extensions
desc_detail
" by Kent Tessman and Roody Yogurt";
}
#endif
#ifset _ROODYLIB_H
object menulib "menu"
{
! if roodylib.h has been included before newmenu.h, nothing needs to be
! added to the init routine
type settings
in init_instructions
execute
{
local i
#ifset USE_DEFAULT_MENU
if word[LAST_TURN] ~= "undo"
{
for i in init_instructions
{
if &i.usage_desc
break
}
if i
special_choice.option_available = true
else
special_choice.option_available = false
}
#endif
#ifset DEBUG
if word[LAST_TURN] ~= "undo","restore"
{
for (i=(menu_category + 1);i<=objects ;i++ )
{
if i.type = menu_category and parent(i) = nothing and
i ~= menu_category
move i to menu_pages
}
}
#endif
return i ! just to avoid a warning if DEBUG and DEFAULT_MENU are
! turned off
}
}
#endif ! _ROODYLIB_H
#ifset USE_DEFAULT_MENU
#if undefined usage_desc
property usage_desc alias short_desc ! some text describing what commands turn
! a library's function on/off
! (ex: CHEAPMODE ON)
#endif
!routine MenuInit
!{
! local i
! for i in init_instructions
! {
! if &i.usage_desc
! {
! move special_choice to main_menu
! break
! }
! }
!}
#if undefined TOTAL_COMMANDS
constant TOTAL_COMMANDS 16
#endif
#ifset _ROODYLIB_H
array verblib_commands[TOTAL_COMMANDS] = "OPEN","CLOSE","LOCK","UNLOCK", \
"WEAR", "REMOVE","TURN ON","TURN OFF", "DRINK", "EAT", \
"SIT" , "MOVE", "INSERT", "SEARCH"
#ifset _VERBSTUB_G
array verbstub_commands[TOTAL_COMMANDS] = "PUSH", "PULL", "YELL", "JUMP", \
"THROW","SLEEP", "KISS", "WAVE", "CLIMB", "WAKE", "SWIM", \
"DIG", "TIE", "BURN", "CUT"
#endif
#else
array verblib_commands[TOTAL_COMMANDS] = "OPEN","CLOSE","LOCK","UNLOCK", \
"WEAR", "REMOVE","TURN ON","TURN OFF", "DRINK", "EAT", \
"SIT" , "MOVE", "INSERT"
#ifset _VERBSTUB_G
array verbstub_commands[TOTAL_COMMANDS] = "SEARCH","PUSH", "PULL", "YELL", \
"JUMP", "THROW","SLEEP", "KISS", "WAVE", "CLIMB", "WAKE", "SWIM", \
"DIG", "TIE", "BURN", "CUT"
#endif
#endif
#endif ! USE_DEFAULT_MENU
attribute sorted alias special
! menu_category properties
property title_gap alias initial_desc
property options_gap alias reach
property page_text_color alias holding
property page_bg_color alias exclude_from_all
property title_color alias list_contents
property title_bg alias capacity
! option/hint_option properties
property menu_text alias long_desc
property menu_link alias door_to
property hint1 alias n_to
property hint2 alias ne_to
property hint3 alias e_to
property hint4 alias se_to
property hint5 alias s_to
property hint6 alias sw_to
property hint7 alias w_to
property hint8 alias nw_to
property hint9 alias u_to
property hint10 alias d_to
property alt_title alias misc
property alt_name alias misc ! just because I think I'm going to forget the
! name of the property from time to time
property option_available alias in_to
property hints_available alias in_to
property hints_revealed alias out_to
property priority alias parse_rank
#ifset DEBUG
object menu_pages
{}
#endif
class menu_category
{
type menu_category
title_gap 0 ! lines between menu title and "[N]ext key"
options_gap 1 ! lines between "[N]ext key" and menu options
option_available true
page_bg_color 0
page_text_color 0
title_color 0
title_bg 0
}
class option
{
type option
option_available true
priority 0
}
option hint_option "(hint_option)"
{
type hint_option
menu_text
Help_Hints(self)
hints_available 1
hints_revealed 0
}
routine MakeMenu(menu_title, recurse)
{
local glktest, count, category, old_category, cos
local simple_port
cos = CheaporSimple
if not menu_title
menu_title = main_menu
if not cos
SetPageColors(menu_title)
if display.windowlines > (display.screenheight + 100)
glktest = true
if not glktest and system(61)
simple_port = true
if not recurse
{
if verbroutine = &EndGame
""
MenuOpen(menu_title)
}
local revisit
while true
{
if not cos and revisit
SetPageColors(menu_title)
revisit++
if not cos
color MENU_TEXTCOLOR, MENU_BGCOLOR
count = 0
local c
! for category in menu_title
! {
! if category.option_available
! {
! menuitem[++count] = category !.name
! if category.priority
! c = true
! }
! }
for category in menu_title
{
if category.option_available
{
++count
if category.priority and menu_title is not sorted
c = true
}
}
if c
SortMenu(menu_title)
if not (cos = 2 or simple_port)
{
window 0
cls
}
! menuitem[0] = menu_title
category = Menu(menu_title, count, 0, old_category,menu_title.title_gap,menu_title.options_gap)
old_category = category
if category
{
local chosen, n = 1
chosen = child(menu_title)
while not chosen.option_available
{
chosen = younger(chosen)
}
while true
{
if n = category
break
else
{
chosen = younger(chosen)
if chosen.option_available
n++
}
}
if chosen.type = menu_category
MakeMenu(chosen,(recurse + 1))
elseif chosen.menu_link
MakeMenu(chosen.menu_link,(recurse + 1))
else
{
if not cos
{
SetPageColors(chosen)
color MENU_TEXTCOLOR, MENU_BGCOLOR
}
do
{
if display.needs_repaint and cos ~= 2
{
color MENU_BGCOLOR, MENU_BGCOLOR
MenuMessage(&MakeMenu,4) ! "[WINDOW RESIZED]"
color TEXTCOLOR, BGCOLOR, INPUTCOLOR
""
}
display.needs_repaint = false
if not cos
color MENU_BGCOLOR, MENU_BGCOLOR
if cos ~= 2
MenuMessage(&MakeMenu,3,chosen.name)
color TEXTCOLOR, BGCOLOR, INPUTCOLOR
if not (cos = 2 or simple_port)! simple_port
{
if chosen.alt_title
CenterTitle(chosen.alt_title)
else
CenterTitle(chosen.name)
}
else
{
Indent
print "\_ ";
Font(BOLD_ON)
if chosen.alt_title
print chosen.alt_title
else
print chosen.name
Font(BOLD_OFF)
""
}
if not cos
locate 1,TopPageMargin
! elseif CheapOrSimple = 2
! ""
run chosen.menu_text
print newline
! if not (cos = 2 and menuitem[category].type = hint_option)
""
if chosen.type ~= hint_option
MenuPause(chosen)
}
while (display.needs_repaint = true )
}
}
else
{
if not recurse
{
if not (cos = 2 or simple_port)
{
! color MENU_BGCOLOR, MENU_BGCOLOR
! MenuMessage(&MakeMenu,5) ! "[LEAVING MENU]"
! if verbroutine ~= &EndGame
! ""
#ifset _ROODYLIB_H
InitScreen
#else
color TEXTCOLOR, BGCOLOR, INPUTCOLOR
if not cos ! system(61)
window 0
cls
#endif
}
if not verbroutine ~= &EndGame
{
! if CheapOrSimple = 2
! ""
AfterMenu
}
else
PrintStatusLine
}
return
}
}
}
routine MenuOpen(menu_title)
{
if not (system(61) or CheapOrSimple = 2)
color BGCOLOR, BGCOLOR
MenuMessage(&MenuOpen,1,menu_title) ! "Opening menu..."
""
color TEXTCOLOR, BGCOLOR, INPUTCOLOR
}
routine AfterMenu
{
#ifset CHEAP
if not (cheap & CHEAP_ON)
#endif
PrintStatusline
Font(DEFAULT_FONT) ! just in case
MenuMessage(&AfterMenu,1) ! "...and now returning to the story."
#ifset _ROODYLIB_H
if (FORMAT & DESCFORM_I)
""
#endif
DescribePlace(location, true)
#ifset NEW_FUSE
fake_runevents
#endif
}
routine TopPageMargin
{
if not display.hasvideo
return display.windowlines
else
return 2
}
!#ifset _ROODYLIB_H
!routine MenuPriority(obj1,obj2)
!{
! return (obj1.priority < obj2.priority)
!}
!#endif
replace Menu(menu_par,num, width, selection,titlegap,optionsgap)
{
local i, column, cos ! , oldselection
local simple_port, glktest,n
local sel = 1
simple_port = not (display.windowlines > (display.screenheight + 100)) and system(61)
cos = CheapOrSimple
if system(61)
{
titlegap = 0
optionsgap = 1
}
if width = 0: width = 20
for i in menu_par
{
if i.option_available
{
n = string(_temp_string,i.name)
if n > width : width = n
}
}
! for (i=1; i<=num; i++) ! determine appropriate width
! {
! n = string(_temp_string, menuitem[i].name)
! if n > width: width = n
! }
if width > (display.linelength-1): width = display.linelength-1
! Default selection is 1 if not otherwise given
if selection = 0: selection = 1
if selection > num: selection = num
glktest = display.windowlines > (display.screenheight + 100)
if cos = 2 or
( glktest and
( num + 5 + titlegap + optionsgap ) >= (display.screenheight/3*2))
{
while true
{
if not (cos = 2 or simple_port)
cls
if not simple_port
CenterTitle(menu_par.name)
if display.needs_repaint
display.needs_repaint = false
print newline
! if cos = 2
! ""
Indent
print "\_ ";
Font(BOLD_ON)
print menu_par.name
Font(BOLD_OFF)
""
i = child(menu_par)
while i
{
if i.option_available
{
Indent
print number sel++;". ";
print i.name
}
i = younger(i)
}
! while sel <= num ! menuitem[sel]
! {
! Indent
! print number sel;". ";
! print menuitem[sel++].name
! }
print ""
MenuMessage(&Menu, 2) ! "Select the number of your choice"
! local numb
if num > 9
{
GetInput
if word[1] = "q"
{
""
return 0
}
if word[1]
selection = StringToNumber(word[1])
else
selection = StringToNumber(parse$)
}
else
{
pause
if word[0] = 'q','Q', '0', ESCAPE_KEY
{
printchar word[0]
print newline
if not (cos = 2 or simple_port)
cls
""
return 0
}
else
selection = word[0] - 48
}
if selection>0 and (selection <= num) ! sel)
{
if num <= 9
{
printchar word[0]
print newline
}
""
if not (cos = 2 or simple_port)
cls
return selection
}
else
{
if num <= 9
{
printchar word[0]
print newline
}
"\nNot a valid option.\n"
}
}
}
else
{
Font(BOLD_OFF | ITALIC_OFF | UNDERLINE_OFF | PROP_OFF)
while true
{
local selected
column = display.linelength/2 - width/2
if not system(61)
{
color MENU_BGCOLOR, MENU_BGCOLOR
if display.needs_repaint
{
window 0
display.needs_repaint = false
}
cls
}
window ( num + 5 + titlegap + optionsgap )
{
if glktest ! system(61) and not simple_port
cls
! local m
! This section "fakes" CenterTitle, so it appears to be
! a regular title window, when in actuality, the whole menu
! is in the status window
if not simple_port
locate 1,1
Font(PROP_OFF)
n = string(_temp_string, menu_par.name)
color MENU_SELECTCOLOR, MENU_SELECTBGCOLOR ! shouldn't affect glk
print to (display.linelength/2 - n/2);
print menu_par.name;
print to display.linelength ! make sure we color the line completely
for (i=0; i<titlegap;i++)
{
""
}
color MENU_TEXTCOLOR, MENU_BGCOLOR
! end of fake CenterTitle
Font(BOLD_OFF|ITALIC_OFF|UNDERLINE_OFF|PROP_OFF) ! shouldn't affect
! glk
MenuMessage(&Menu, 1) ! print key commands
for (i=0; i<optionsgap;i++)
{
""
}
! if selection ~= oldselection ! glk code that *shouldn't*
! { ! affect normal execution
! if oldselection ~= 0 ! (hopefully)
! selection = oldselection
! }
sel = 1
i = child(menu_par)
while i
{
if i.option_available
{
if sel = selection
{
selected = i
if system(61) ! glk or minimum port
print to (column - 2);"* ";
else
locate (column + 1), display.cursor_row
color MENU_SELECTCOLOR, MENU_SELECTBGCOLOR ! shouldn't affect
! glk?
print i.name; to (column+width) !;
color MENU_TEXTCOLOR, MENU_BGCOLOR
}
else
{
locate (column + 1), display.cursor_row !print to column;
print i.name ; to (column+width)
}
sel++
}
i = younger(i)
}
! for (i=1; i<=num ; i++)
! {
! if i = selection
! {
! if system(61) ! glk or minimum port
! print to (column - 2);"* ";
! else
! locate (column + 1), display.cursor_row
! color MENU_SELECTCOLOR, MENU_SELECTBGCOLOR ! shouldn't affect
! ! glk?
! print menuitem[selection].name; to (column+width) !;
! color MENU_TEXTCOLOR, MENU_BGCOLOR
! }
! else
! {
! locate (column + 1), display.cursor_row !print to column;
! print menuitem[i].name ; to (column+width)
! }
! }
}
word[0] = PressKey
select word[0]
case 'N', 'n', DOWN_ARROW, RIGHT_ARROW
{
while true
{
if not younger(selected)
{
selection = 1
break
}
else
{
selected = younger(selected)
selection++
if selected.name ~= ""
break
}
}
! if menuitem[++selection].name = ""
! ++selection
! if selection > num : selection = 1
}
case 'P', 'p', UP_ARROW, LEFT_ARROW
{
while true
{
if not elder(selected)
{
selection = num
break
}
else
{
selected = elder(selected)
selection--
if selected.name ~= ""
break
}
}
! if menuitem[--selection].name = ""
! --selection
! if selection < 1 : selection = num
}
case 'Q', 'q', ESCAPE_KEY
{
if not cos ! system(61)
{
window !0
cls
}
return 0
}
case ENTER_KEY
{
if not cos ! system(61)
{
window !0
cls
}
return selection
}
if word[0] >= '0' and word[0] <= '9'
{
i = word[0] - '0'
if i = 0: i = 10
! oldselection = selection
if selection ~= i and i <= num
{
selected = child(menu_par)
selection = 1
while true
{
if selection = i and selected.name ~= ""
break
if younger(selected)
{
selected = younger(selected)
selection++
}
! else
! {
! selection = oldselection
! break
! }
}
}
! selection = 1
! while --i
! {
! selection++
! if menuitem[selection].name = ""
! selection++
! }
! if selection > num or menuitem[selection].name = ""
! selection = oldselection
}
}
}
}
routine MenuPause(page,no_newline)
{
local simple_port, cos
simple_port = not (display.windowlines > (display.screenheight + 100)) and system(61)
cos = CheapOrSimple
Indent
if (cos = 2 or simple_port)
MenuMessage(&MenuPause,1,page) ! "[PRESS A KEY TO CONTINUE]"
else
MenuMessage(&MenuPause,2,page) ! "\Ipress a key to continue\i"
PressKey
Font(DEFAULT_FONT)
! print newline
if not no_newline
""
}
routine CheaporSimple
{
#ifset CHEAP
if cheap
return 2
#endif
if system(61)
return 3
}
routine Help_Hints(obj)
{
local i
for (; i<=obj.hints_revealed; i++)
{
if i
""
run obj.(hint1+i)
print newline
! ""
}
""
while &obj.(hint1+i) ~= 0 ! i.e., no more topics
{
Font(BOLD_ON)
MenuMessage(&Help_Hints,1) ! "[Press 'H' for another hint, or 'Q' to
! quit]";
Font(BOLD_OFF)
print newline
word[0] = PressKey
if word[0] = 'Q', 'q', ESCAPE_KEY
return
if word[0] = 'H', 'h'
{
obj.hints_revealed++
run obj.(hint1+i++)
print newline
""
}
}
Font(BOLD_ON)
if CheapOrSimple ~= 2
{
MenuMessage(&Help_Hints,2) ! "[No more hints. Press any
! key...]";
Font(BOLD_OFF)
PressKey
}
else
{
MenuMessage(&Help_Hints,3) ! "[No more hints. Leaving page.]";
Font(BOLD_OFF)
}
return
}
routine PressKey
{
local key
key = system(11) ! READ_KEY
if not system_status
system(32) ! PAUSE_100TH_SECOND
if system_status or CheaporSimple ! system(61) ! MINIMAL_INTERFACE
{
pause
key = word[0]
}
else
{
while true
{
key = system(11) ! READ_KEY
system(32) ! PAUSE_100TH_SECOND
if key:break
}
}
return key
}
routine ShowPage(page)
{
local simple_port,glktest, reset_indent, cos
if display.windowlines > (display.screenheight + 100)
glktest = true
cos = CheapOrSimple ! so we only call it once
if not glktest and system(61)
simple_port = true
if not cos ! (CheaporSimple = 2 or system(61))
window 0
if verbroutine = &EndGame
""
if not (cos = 2 or simple_port)
{
color BGCOLOR, BGCOLOR
MenuMessage(&ShowPage,1,page) ! "[OPENING PAGE]"
""
cls
}
do
{
if display.needs_repaint and cos ~= 2
{
color BGCOLOR, BGCOLOR
MenuMessage(&MakeMenu,4) ! "[WINDOW RESIZED]"
! color TEXTCOLOR, BGCOLOR, INPUTCOLOR
""
! if not (cos = 2 or simple_port)
! color BGCOLOR, BGCOLOR
! if cos ~= 2
! MenuMessage(&MakeMenu,3,page.name)
}
display.needs_repaint = false
color TEXTCOLOR, BGCOLOR, INPUTCOLOR
if not (cos = 2 or simple_port)
{
if page.alt_title
CenterTitle(page.alt_title)
else
CenterTitle(page.name)
}
if not cos
locate 1,TopPageMargin
elseif cos = 2
{
if not (FORMAT & NOINDENT_F)
{
reset_indent = true
FORMAT = FORMAT | NOINDENT_F
}
}
run page.menu_text
if reset_indent
FORMAT = FORMAT & ~NOINDENT_F
print newline
if cos ~= 2 and
not (page.type = hint_option and verbroutine = &EndGame) ! or page.type = hint_option)
""
if page.type ~= hint_option and not (CheaporSimple = 2 or simple_port)
MenuPause(page,(verbroutine = &EndGame))
}
while (display.needs_repaint = true )
if not (cos = 2 or simple_port)
{
! color BGCOLOR, BGCOLOR
! MenuMessage(&ShowPage,2) ! "[CLOSING PAGE]"
! if verbroutine ~= &EndGame
! ""
#ifset _ROODYLIB_H
InitScreen
#else
color TEXTCOLOR, BGCOLOR, INPUTCOLOR
if not cos ! system(61)
window 0
cls
#endif
}
if verbroutine ~= &EndGame and
not (cos = 2 or simple_port) ! and page.type ~= hint_option)
AfterMenu
else
PrintStatusLine
}
routine SetPageColors(page)
{
if not (MENU_TEXTCOLOR or MENU_BGCOLOR) and ! must not have been set
not (main_menu.page_text_color or main_menu.page_bg_color)
{
MENU_TEXTCOLOR = TEXTCOLOR
MENU_BGCOLOR = BGCOLOR
}
if not( MENU_SELECTCOLOR or MENU_SELECTBGCOLOR) and
not (main_menu.title_color or main_menu.title_bg)
{
MENU_SELECTCOLOR = SL_TEXTCOLOR
MENU_SELECTBGCOLOR = SL_BGCOLOR
}
if not (main_menu.page_text_color or main_menu.page_bg_color)
{
main_menu.page_text_color = MENU_TEXTCOLOR
main_menu.page_bg_color = MENU_BGCOLOR
}
if not (main_menu.title_color or main_menu.title_bg)
{
main_menu.title_color = MENU_SELECTCOLOR
main_menu.title_bg = MENU_SELECTBGCOLOR
}
if page.page_text_color or page.page_bg_color
{
MENU_TEXTCOLOR = page.page_text_color
MENU_BGCOLOR = page.page_bg_color
}
else
{
MENU_TEXTCOLOR = main_menu.page_text_color
MENU_BGCOLOR = main_menu.page_bg_color
}
if page.title_color or page.title_bg
{
MENU_SELECTCOLOR = page.title_color
MENU_SELECTBGCOLOR = page.title_bg
}
else
{
MENU_SELECTCOLOR = main_menu.title_color
MENU_SELECTBGCOLOR = main_menu.title_bg
}
}
routine MenuMessage(r, num, a, b)
{
if NewMenuMessages(r, num, a, b): return
select r
case &MakeMenu
{
select num
case 1 : "[OPENING MENU]"
case 2
{
if a
""
print "[MENU NAME: \""; b ; "\"]"
}
case 3
{
! local l,i
! l = string(_temp_string, a)
! print to (40 - l/2-1);
! print "+";
! for (i=1;i<=l ;i++ )
! {
! print "-";
! }
! print "+"
! print to (40 - l/2-1);
! print "|";
! print a;
! print "|"
! print to (40 - l/2 - 1);
! print "+";
! for (i=1;i<=l ;i++ )
! {
! print "-";
! }
! print "+"
!\ The previous code is this experimental thing I wrote to make transcripts
look nicer, but it looks kind of crappy in scrollback (which is shown in
proportional font). Out for now. \!
! print "[";a;"]"
Indent
print "\_ "; a
""
}
case 4 : "Window resized. Redrawing screen."
case 5 : "[LEAVING MENU]"
case 6 : "Opening the menu..."
}
case &Menu
{
select num
case 1
{
if system(61)
locate 2, display.cursor_row
else
locate 1, display.cursor_row
print "[N]ext item"; to (display.linelength - 11); \
"[Q]uit menu"
if system(61)
locate 2, display.cursor_row
print "[P]revious item"; to (display.linelength - 17);
print "[Enter] to select"
}
case 2
{
! The CheapGlk version now works off numbers to make
! navigation as easy as possible in simple terps
print "Select the number of your choice or \"Q\" to exit: ";
}
}
case &MenuOpen
{
select num
case 1:"Opening menu..."
}
case &MenuPause
{
select num
case 1 ! default cheapglk "press a key"
"[PRESS A KEY TO CONTINUE]" ! ;
case 2 ! default normal "press a key"
"\Ipress a key to continue\i" ! ;
}
case &Help_Hints
{
select num
case 1
"[Press 'H' for another hint, or 'Q' to quit]"; !;
case 2
print "[No more hints. Press any key...]";
case 3
print "[No more hints. Leaving page.]";
}
case &ShowPage
{
select num
case 1
{
! "[OPENING PAGE]"
if a.alt_name
print "(Opening \""; a.alt_name;"\")"
else
print "(Opening \""; a.name;"\")"
}
case 2
"[CLOSING PAGE]"
}
case &AfterMenu
{
select num
case 1: print "\I...and now returning to the story.\i"
}
}
!\ The NewMenuMessages routine may be REPLACED and should return
true if a replacement message exists for routine <r> \!
routine NewMenuMessages(r, num, a, b)
{
select r
! case
! {
! select num
! case 1:
! }
case else : return false
return true ! this line is only reached if we replaced something
}
object menu_bowl
{}
routine SortMenu(menu_title)
{
local resort,x, prio, old_prio = 200
x = child(menu_title)
while x
{
if x.priority
prio = x.priority
if prio > old_prio
{
resort = true
break
}
old_prio = prio
x = younger(x)
}
if not resort
return
while child(menu_title)
{
move child(menu_title) to menu_bowl
}
while child(menu_bowl)
{
prio = 0
x = child(menu_bowl)
while x
{
if x.priority and x.priority > prio
prio = x.priority
x = younger(x)
}
x = child(menu_bowl)
if prio
{
while x
{
if prio = x.priority
{
move x to menu_title
break
}
x = younger(x)
}
}
else
{
while x
{
move child(menu_bowl) to menu_title
x = child(menu_bowl)
}
}
}
menu_title is sorted
return true ! means we resorted
}
menu_category main_menu
{
name
{
#if defined GAME_TITLE
return GAME_TITLE
#endif
#if undefined GAME_TITLE
return "Help Menu"
#endif
}
}
#ifset USE_DEFAULT_MENU
option hugo_choice "About Hugo"
{
in main_menu
priority 10
menu_text
{
Indent
"Hugo is a system created by Kent Tessman for developing and playing sophisticated computer adventure games (or \"interactive fiction\").\n"
Indent
"The complete system comprises a high-level programming language, world-simulation library, compiler, runtime engine, debugger, and other tools. Games can be designed for player input keyboard and/or mouse in addition to using Hugo's full-sentence natural-language parsing capabilities, and can make extensive use of graphics, sound, music, and video playback.\n"
Indent
"Hugo is powerful and versatile enough to have been used not only for games such as ";
Font(ITALIC_ON)
#if defined GAME_TITLE
print GAME_TITLE;
#else
print "Future Boy!";
#endif
Font(ITALIC_OFF)
", but also for presentations and tutorials, prototyping, and other applications.\n"
Indent
"Hugo's cross-platform support is broad, including official implementations for Windows, Macintosh, Linux/Unix, Windows Mobile/Pocket PC, and Palm, with additional versions available for other platforms. The source code for all components is available.\n"
Indent
"\BHugo's official website:\b"
Indent
"\I
http://www.generalcoffee.com/index_noflash.php?content=hugo\i"
""
Indent
"\BHugo By Example, a Hugo code repository:\b"
Indent
"\I
http://hugo.gerynarsabode.org\i\n"
Indent
"\BThe joltcountry Hugo forum:\b"
Indent
"\I
http://www.joltcountry.com/phpBB2/viewforum.php?f=8\i\n"
Indent
"Also! If you are a screenwriter or would like to support
Kent Tessman in his current endeavors, check out his fantastic
program, Fade In Professional Screenwriting Software R
(\B
http://www.fadeinpro.com\b)!"
}
}
menu_category how_play "How To Play Interactive Fiction"
{
in main_menu
priority 8
}
!option if_choice "How To Play Interactive Fiction"
!{
! in main_menu
!#ifset _ROODYLIB_H
! priority 9
!#endif
! menu_link how_play
!}
option where_choice "Where To Get More IF"
{
in main_menu
priority 6
menu_text
{
Indent
"\BMore Hugo games can be found at:\b"
Indent
"\I
http://ifarchive.org/indexes/if-archiveXgamesXhugo.html\i"
Indent(true)
"\BOther sites of interest:\b"
Indent
"The Brass Lantern (\I
http://brasslantern.org/\i)"
Indent
"The People's Republic of Interactive Fiction
(\I
http://pr-if.org/play/\i)"
Indent
"The IF Database (\I
http://ifdb.tads.org/\i)"
Indent
"IF Reviews (\I
http://www.ifreviews.org/\i)"
Indent
"The IF Archive (\I
http://ifarchive.org/\i)"
! "\I
http://www.joltcountry.com/phpBB2/viewforum.php?f=8\i\n"
}
}
#ifset _ROODYLIB_H ! Only roodylib-using games can do Special Commands
option special_choice "Special Commands"
{
in main_menu ! (should be added to main_menu by menulib object
menu_text
{
Indent
"\BAdditional commands:\b\n"
SpecialCommands
}
}
routine SpecialCommands
{
local i, sum, nl
i = child(init_instructions)
while i
{
if &i.usage_desc
{
if nl
{
""
nl = false
}
if i.usage_desc
{
nl = true
! if i ~= youngest(init_instructions)
! ""
sum++
}
}
i = younger(i)
}
if not sum
{
Indent
"Sorry, it appears that there are no special features supported by your
interpreter. Try the official Hugo interpreter or Hugor TODAY!"
}
}
#endif
!menu_category how_play "How To Play Interactive Fiction"
!{}
option what_is "What is \"interactive fiction\"?"
{
in how_play
priority 10
menu_text
{
Indent
"In interactive fiction, you, the player, will be appraised of
your surroundings and happenings in the game by largely textual means.
You get the chance to interact with these surroundings by typing
commands (read the other entries in this menu for examples of the kind
of commands that are accepted). Hopefully, you are rewarded for your
efforts with engaging puzzles and entertaining prose!"
}
}
option move_around "Moving around"
{
in how_play
priority 8
menu_text
{
Indent
"Everything described in your current location should be available to
interact with (unless it is explicitly out-of-reach), so rest assured, you
should almost never have to \B>WALK OVER TO THING\b. This is a common
misunderstanding.\n"
Indent
"That said, you \Ido\i need to move from room to room. Most of the time,
this will involve going in compass directions (\BGO SOUTH. GO NORTHWEST.\b). Such directions can be abbreviated further (\BS. NW.\b).\n"
Indent
"All in all, eight compass directions are usually accepted (\BNORTH\b, \BNORTHEAST\b, \BEAST\b, \BSOUTHEAST\b, \BSOUTH\b, \BSOUTHWEST\b, \BWEST\b, AND \BNORTHWEST\b), along with the directions \"\BUP\b\",\"\BDOWN\b\",\"\BIN\b\", and \"\BOUT\b\".\n"
Indent
"Some games will demand shipboard directions like \"\BAFT\b\",\"\BFORE\b\",\"\BSTARBOARD\b\", and \"\BPORT\b\" for certain areas, while some
games \Iwill\i accept a simple \B>GO TO <ROOM>\b. In both cases, it is
expected that the game will adequately inform you of your options.\n"
"Sometimes, you'll want to \BENTER\b, \BCLIMB\b, or \BGET ON\b something.
Later on, you may want to \BGET OFF\b, \BGET UP\b, or \BEXIT\b \Ithat
same object\i!"
}
}
option look_around "Looking around"
{
in how_play
priority 6
menu_text
{
Indent
"Getting a good look at things is important in interactive fiction. If
you've forgotten what the room looks like, you can always \B>LOOK\b or
\B>LOOK AROUND\b again to get another peek.\n"
Indent
"To get a closer look at objects (including yourself), you'll want to
\BEXAMINE\b or \BLOOK AT\b the object, like:\n"
Indent
"\B>EXAMINE FOOTPRINT\b\n"
Indent
"(To save time, \BEXAMINE\b can be shortened down to \BX\b.)\n"
Indent
"Some things can be \BSEARCH\bed or \BLOOK\b \BIN\b, too. In tougher
games, you may even need to \BLOOK BEHIND\b or \BLOOK UNDER\b something."
}
}
option talk_chars "Talking to characters"
{
in how_play
priority 4
menu_text
{
Indent
"In \"traditional\" IF, charactes can be interacted with using four major
commands:\n"
Indent
"\BASK <CHARACTER> ABOUT <SUBJECT>\b"
Indent
"\BTELL <CHARACTER> ABOUT <SUBJECT>\b"
Indent
"\BSHOW <OBJECT> TO <CHARACTER>\b"
Indent
"\BGIVE <OBJECT> TO <CHARACTER>\b\n"
Indent
"Additionally, sometimes characters can be given commands, using this
syntax:\n"
Indent
"\BDETECTIVE, FOLLOW ME\b"
Indent
"\BCLOWN, JUMP THROUGH HOOP\b\n"
Indent
"In newer games, though, it is common that a simple \"\BTALK TO
<CHARACTER>\b\" will handle all of your character-interacting needs."
}
}
option manip_objects "Manipulating objects"
{
in how_play
priority 2
menu_text
{
Indent
"Knowing how to work with object is very important to IF. To begin with,
sometimes your character will start off with objects in his or her
possession. To see what items you possess, try \B>TAKE INVENTORY\b. This
can be shortened down to \"\BINVENTORY\b\", \"\BINV\b\", or just
\"\BI\b\".\n"
Indent
"Now that you know what items you've got, you want MORE, right? To acquire
objects, try \BPICK UP <object>\b or \BGET <object>\b. To let it go, try
\BDROP <object>\b. Sometimes you'll even want to \BPUT <object> IN
<another object>\b or \BPUT <object> ON <another object>\b. Conversely,
you may want to \BTAKE <object> FROM\b or \BEMPTY\b objects.\n"
Indent
"A well-implemented game might cover lots of sensory verbs (like
\BSMELL\b, \BTASTE\b, \BLISTEN TO\b, or even \BTOUCH\b), but that can't
always be expected.\n"
Indent
"Here are some other common commands:\n"
local a ! ,b
while true ! checking how many possible columns we can write
{ ! (although we end up using, at max, 5 since 5 looks nice
if (a*12 + INDENT_SIZE) >= display.linelength
{
break
}
a++
}
PrintCommands(verblib_commands,a)
! b++
#ifset _VERBSTUB_G
Indent
"Less commonly, you might use the following:\n"
PrintCommands(verbstub_commands,a)
#endif ! VERBSTUB_G
Indent
"Hopefully, that gives you some ideas!"
}
}
routine PrintCommands(arr,columns)
{
local i, n
local max = 5 ! -1
if CheaporSimple ~= 2
Font(BOLD_ON|PROP_OFF)
if display.windowlines < (display.screenheight + 100)
columns--
while array arr[n] ~= 0 and n < (array arr[])
{
print to (INDENT_SIZE + i++ * 12);
print array arr[n++];
if i >= columns or array arr[n] = 0 or i = max
{
i = 0
""
}
}
""
Font(BOLD_OFF|PROP_ON)
! return start
}
option do_nothing "Doing nothing at all"
{
in how_play
priority 0
menu_text
{
Indent
"Sometimes the best thing to do is to do nothing and watch how things
play out. Since game time doesn't pass when one isn't typing commands,
you have to type \BWAIT\b. This will automatically make 1-3 turns pass
by, depending on what the game defaults to.\n"
Indent
"Alternatively, you can type \BWAIT <some number>\b to wait a specified
number of turns. \BWAIT\b can be shortened to \"\BZ\b\"."
}
}
#ifclear NO_XVERBS
option saving_loading "Saving, restoring, and other \"meta\" commands"
{
in how_play
priority -2
menu_text
{
Indent
"Some commands don't affect the game world itself. They exist solely for
playing convenience. Some of them include-\n"
Indent
"\BSCORE\b- In a score-tracking game, this prints the current score."
Indent
"\BSAVE\b- Saves the game state to a file."
Indent
"\BRESTORE\b- Restores a saved game."
Indent
"\BQUIT\b- Ends a play session."
Indent
"\BRESTART\b- Restarts the game."
Indent
"\BUNDO\b- Undoes the previous turn."
Indent
"\BSCRIPT ON/OFF\b- Writes the prose (with commands) of your game to a
text file."
Indent
"\BRECORD ON/OFF\b- Writes only \Icommands\i to a file."
Indent
"\BPLAYBACK\b- Inserts commands from a recording (see previous command)
into the game."
Indent
"\BVERBOSE\b- Gives full description every time a room is entered."
Indent
"\BBRIEF\b- Full room description is only printed on the first visit (or
when LOOK is called)."
Indent
"\BSUPERBRIEF\b- Short room descriptions every time."
Indent
"\BDISPLAY WIDE/TALL\b- Forces listings (such as inventory) to be wide
or tall, depending.\n"
Indent
"Lastly, if you happen to misspell a word in a command, you can use the
\BOOPS\b command to fix it:\n"
Font(BOLD_ON)
">X MEF"
"You don't need to use the word \"mef.\"\n"
">OOPS ME"
"Looking good.\n"
Font(BOLD_OFF)
Indent
"So, how about that?"
}
}
#endif ! ifclear NO_XVERBS
#endif ! USE_DEFAULT_MENU
#endif ! _NEWMENU_H