!::
! 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
		roody.yogurt@gmail.com! 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
                                 roody.yogurt@gmail.com
\!
#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
		"\Ihttp://www.generalcoffee.com/index_noflash.php?content=hugo\i"
		""
		Indent
		"\BHugo By Example, a Hugo code repository:\b"
		Indent
		"\Ihttp://hugo.gerynarsabode.org\i\n"
		Indent
		"\BThe joltcountry Hugo forum:\b"
		Indent
		"\Ihttp://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 ®
		(\Bhttp://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
		"\Ihttp://ifarchive.org/indexes/if-archiveXgamesXhugo.html\i"
		Indent(true)
		"\BOther sites of interest:\b"
		Indent
		"The Brass Lantern (\Ihttp://brasslantern.org/\i)"
		Indent
		"The People's Republic of Interactive Fiction
		(\Ihttp://pr-if.org/play/\i)"
		Indent
		"The IF Database (\Ihttp://ifdb.tads.org/\i)"
		Indent
		"IF Reviews (\Ihttp://www.ifreviews.org/\i)"
		Indent
		"The IF Archive (\Ihttp://ifarchive.org/\i)"

!		"\Ihttp://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