/*
 *  This is a copy of the SCRIPTS lump for the menu level.
 *  For easier reading.
 *
 */

#include "zcommon.acs"

// Global variables
global int 51:returningToMenu; // When 1, player is returning to the menu from a map
global int 52:option_music; // The "varied music" option
global int 53:option_inv; // The "keep inventory" option

global int 54:recentPlayResults[]; // Stores the kills, secrets, etc. of the last map played
global int 55:playResults[]; // Which maps are beaten: 0 if not, 1 for beaten before
global int 56:killsResults[]; // Stores how many kills on each map
global int 57:killsMaxResults[]; // Stores the max kills of each map
global int 58:itemsResults[]; // items
global int 59:itemsMaxResults[]; // max items
global int 60:secretsResults[]; // bleh
global int 61:secretsMaxResults[]; // blah
global int 62:timeResults[];  // Stores the time, in tics, played on each map
global int 63:timeParResults[]; // Stores the par time, in seconds 

// CONSTANTS FOR THE recentPlayResults ARRAY.
//   This is what is stored at each index
#define R_LEVELNUM		0
#define R_KILLS			1
#define R_KILLS_MAX		2
#define R_ITEMS			3
#define R_ITEMS_MAX		4
#define R_SECRETS		5
#define R_SECRETS_MAX	6
#define R_TIME			7
#define R_TIME_PAR		8

// CONSTANTS FOR THE wad information
#define NUMBER_OF_WADS 20
#define NUMBER_OF_WAD_FIELDS 4
#define WAD_LUMPNAME 0
#define WAD_TITLE 1
#define WAD_AUTHOR 2
#define WAD_IMAGELUMP 3 
// This is the data for each wad entry in the wad list
int wadList[NUMBER_OF_WADS][NUMBER_OF_WAD_FIELDS]
	= {	{ "ATTACK", "Attack", "Tim Willits", "ATTKSCRN" },
		{ "BLACKTWR", "Black Tower", "Sverre Andre Kvernmo AKA Cranium", "BLTWSCRN" },
		{ "BLOODSEA", "Bloodsea Keep", "Sverre Andre Kvernmo AKA Cranium", "BDSESCRN" },
		{ "CANYON", "Canyon", "Tim Willits", "CANYSCRN" },
		{ "CATWALK", "The Catwalk", "Christen David Klie", "CATWSCRN" },
		{ "COMBINE", "The Combine", "Christen David Klie", "COMBSCRN" },
		{ "FISTULA", "The Fistula", "Christen David Klie", "FISTSCRN" },
		{ "GARRISON", "The Garrison", "Christen David Klie", "GARRSCRN" },
		{ "GERYON", "Geryon: 6th Canto of INFERNO", "John W. Anderson AKA Dr. Sleep", "GERYSCRN" },
		{ "MANOR", "Titan Manor", "Jim Flynn", "MANRSCRN" },
		{ "MEPHISTO", "Mephisto's Maosoleum", "Sverre Andre Kvernmo AKA Cranium", "MEPHSCRN" },
		{ "MINOS", "Minos' Judgement: 4th Canto of INFERNO", "John W. Anderson AKA Dr. Sleep", "MINOSCRN" },
		{ "NESSUS", "Nessus: 5th Canto of INFERNO", "John W. Anderson AKA Dr. Sleep", "NESSSCRN" },
		{ "PARADOX", "Paradox", "Tom Mustaine", "PARASCRN"},
		{ "SUBSPACE" , "SUBSPACE", "Christen David Klie", "SUBSSCRN" },
		{ "SUBTERRA" , "SUBTERRA", "Christen David Klie", "SUBTSCRN" },
		{ "TEETH", "The Express Elevator to Hell", "Sverre Andre Kvernmo AKA Cranium", "TETHSCRN"},
		{ "TTRAP", "Trapped on Titan", "Jim Flynn", "TTRPSCRN"},
		{ "VESPERAS", "Vesperas: 7th Canto of INFERNO", "John W. Anderson AKA Dr. Sleep", "VESPSCRN" },
		{ "VIRGIL", "Virgil's Lead: 3rd Canto of INFERNO", "John W. Anderson AKA Dr. Sleep", "VIRGSCRN" }
	 };
int selectedIndex = 0; // Currently selected menu index

// CONSTANTS FOR THE menu tabs
#define NUMBER_OF_TABS 3
#define TAB_WADDETAILS 0
#define TAB_PLAYRESULTS 1
#define TAB_OPTIONS 2
#define LAST_HUDMSG_ID 74
int currentTab = TAB_WADDETAILS; // The currently highlighted tab

// CONSTANTS FOR THE options menu
#define NUMBER_OF_OPTIONS 3
#define OPT_DIFFICULTY 0
#define OPT_MUSIC 1
#define OPT_INVENTORY 2
int currentOpt = OPT_DIFFICULTY; // The currently selected option
int currentSkill; // Records the current skill level
bool musicOpt; // The state of the MENU music option (as opposed to the global setting)
bool invOpt; // The state of the MENU inventory option (yadda yadda)


//
//  FOR THE PURPOSES OF THIS WAD SERVING AS A BASIC GETPLAYERINPUT EXAMPLE, I'M
//  GOING TO TRY TO KEEP THE GETPLAYERINPUT FUNCTIONALITY SEPERATE FROM THE
//  MASTER LEVELS RELATED THINGS (E.G. RECORDING PLAY RESULTS, ETC.).
//  
//  SO, IF YOU ARE ONLY INTERESTED IN THE GETPLAYERINPUT MENU FUNCTIONALITY, THEN
//  SCRIPT 2 IS THE ONLY THING YOU NEED CONCERN YOURSELF WITH.
//

//
// GetPlayerInput Menu Script
//   This script is the player input loop.  It's ENTER so it runs for all players,
//   but aborts shortly after player setup for all players EXCEPT player 1, who
//   will control the menu.
script 2 ENTER
{
	// Freeze the player
	SetPlayerProperty(0,ON,PROP_TOTALLYFROZEN);
	
	// Draw the menu background
	SetHudSize(150,480,1);
	SetFont("WIDEBACK"); // Widescreen background covers
	HudMessage(s:"A"; HUDMSG_PLAIN, 1001, CR_UNTRANSLATED, 0.2, 0.1, 0);
	HudMessage(s:"A"; HUDMSG_PLAIN, 1002, CR_UNTRANSLATED, 150.1, 0.1, 0);
	SetHudSize(640,480,1);
	SetFont("MENUBACK");
	HudMessage(s:"A"; HUDMSG_PLAIN, 1000, CR_UNTRANSLATED, 0.1, 0.1, 0);
  

	// If you're not the first player, then you're done here.
	if( PlayerNumber() != 0 )
	{
		terminate;
	}

	// Draw all the dynamic menu elements.  The wad list, the contents of the currently
	// viewed tab, etc.
	SetFont("FIXEDSYS");
	drawSelections();

	delay(1); // Give a brief moment before reading player input

	int butIn; // This is the currently read player input
	int butOld; // This is the old player input
	bool held = FALSE; // Records if the player is holding a DIRECTION key down
	int waitTime = 0; // Generic variable used to count how many tics we wait after a press
					  
	delay(12); // Don't take input for a little bit just to prevent
            // accidental selection with USE on map load
                      
	// This is the main menu loop, and it runs FOREVER.  Basically, it is a loop
	// which checks the player's input every tic to see what keys the player has
	// hit/released, and determines if it should take any action based on this.
	//
	// All the actions are handled in outside functions to keep the menu loop
	// from being too cluttered.
	while( TRUE )
	{
		// With this menu, the important keys are
		//  LEFT, RIGHT, UP, DOWN, and USE.
		//  GetPlayerInput checks what player commands are being input, not what
		//    what physical buttons are being held.  So, we must instead pick the
		//    player inputs that will be associated with each "key".
		//  LEFT  = Strafe left OR turn left
		//  RIGHT = Strafe right OR turn right
		//  UP    = Move forward
		//  DOWN  = Move backwards
		//  USE   = Attack 1 (primary fire) OR use
		//
		//  LEFT, RIGHT, UP, and DOWN will control the player's menu selection and
		//    USE will be the action button.  This makes for a nice, simplistic
		//    menu model:
		//		1) Get player input
		//		2) Check LEFT RIGHT UP DOWN and if needed move the player's cursor
		//      3) Check USE and if needed perform an action based on selection
		//
		//  Checking the direction is the most difficult part of this, especially
		//    if you want to support something like holding direction == fast
		//    scrolling.  But that's exactly what I do here.
		//
		//  This implementation doesn't have complex handling of multiple inputs
		//    (e.g. holding left and up at the same time) but it is robust enough
		//    that it shouldn't break.  Getting complex handling in wouldn't be
		//    too difficult though: give the inputs each a priority and the take
		//    the highest priority action in the case of input conflicts.
		//
		//  Here we go.
		
		// Get the player's input
		butIn = GetPlayerInput(0,INPUT_BUTTONS);
		butOld = GetPlayerInput(0,INPUT_OLDBUTTONS);
		
		
		//==
		// This entire section manages recording if direction buttons are being held
		// and engaging FAST SCROLLING behavior if the same button is held down for
		// long enough.
		//==
		
		// If no DIRECTION key is being held...
		if( !held )
		{
			// Check for a DIRECTION key press.
			if((butIn & BT_FORWARD) ||
			   (butIn & BT_BACK) ||
			   (butIn & (BT_LEFT | BT_MOVELEFT)) ||
			   (butIn & (BT_RIGHT | BT_MOVERIGHT)) )
			{
				// Because HELD was FALSE and DIRECTION press was positive, it
				// means the player has JUST pressed a direction
				held = TRUE; // Remember that the player has a key down
				waitTime = 14; // Wait 14 tics until we start fast scrolling
			}
		}
		else  // DIRECTION key WAS being held...
		{
			// Check for a DIRECTION button release by seeing if the player's OLD
			// input DOES NOT MATCH their NEW input
			if(((butIn & BT_FORWARD) != (butOld & BT_FORWARD)) ||
			   ((butIn & BT_BACK) != (butOld & BT_BACK)) ||
			   ((butIn & (BT_LEFT | BT_MOVELEFT)) != (butOld & (BT_LEFT | BT_MOVELEFT))) ||
			   ((butIn & (BT_RIGHT | BT_MOVERIGHT)) != (butOld & (BT_RIGHT | BT_MOVERIGHT))) )
			{
			    // Because HELD was TRUE and there was a mismatch between the DIRECTION
			    // key state last tic to this tic, the player has JUST released a
			    // a direction
			 	held = FALSE; // The player is no longer holding down the same direction key
			 	waitTime = 0; // Reset the wait time to 0
			}
			
			// Button is being held, check if we still have waiting time left
			if( waitTime != 0 )
			{
				// Still waiting, decrement the waiting time and restart the loop
				waitTime--; 
				delay(1);
				continue; // Jump back to the top of the loop
			}
			else if (held)
			{ // waitTime is 0 and the button is still being held...
				waitTime = 3; // ENGAGE FAST SCROLL - wait 3 tics between selection changes
			}
		}
		
		
		//==
		// This section performs actions based on the buttons being pressed.
		//==
		
		// UP
		if( butIn & BT_FORWARD )
		{
			if( currentTab != TAB_OPTIONS )
			{
				// Outside of the options tab, hitting UP will move the currently
				// selected wad index up by 1.
				if( selectedIndex > 0 )
				{
					selectedIndex--;
				}
				else
				{
					// Hit the top, loop around to the bottom
					selectedIndex = NUMBER_OF_WADS - 1;
				}
			}
			else
			{
				// Inside the options tab, hitting UP will move the currently
				// selected option index up by 1
				if( currentOpt > 0 )
				{
					currentOpt--;
				}
				else
				{
					// Hit the top, loop around to the bottom
					currentOpt = NUMBER_OF_OPTIONS - 1;
				}
			}
			
			// Update the menu screen because something has changed
			drawSelections();
		}
		
		// DOWN
		if( butIn & BT_BACK )
		{
			if( currentTab != TAB_OPTIONS )
			{
				// Outside of the options tab, hitting DOWN will move the currently
				// selected wad index down by 1.
				if( selectedIndex < NUMBER_OF_WADS-1 )
				{
					selectedIndex++;
				}
				else
				{
					// Hit the bottom, loop around to the top
					selectedIndex = 0;
				}
			}
			else
			{
				// Inside the options tab, hitting DOWN will move the currently
				// selected option index down by 1
				if( currentOpt < NUMBER_OF_OPTIONS-1 )
				{
					currentOpt++;
				}
				else
				{
					// Hit the bottom, loop around to the top
					currentOpt = 0;
				}
			}
			
			// Update the menu screen because something has changed
			drawSelections();
		}
		
		// USE
		if( butIn & (BT_ATTACK | BT_USE) )
		{
			// The effect of USE is going to depend on the player's selection.
			//   OPTIONS TAB
			//     Toggle the selected option
			//   ANYWHERE ELSE
			//     Change level to the currently selected wad
			if( currentTab != TAB_OPTIONS )
			{
				SetPlayerProperty(1,OFF,PROP_TOTALLYFROZEN);
				int clFlags = CHANGELEVEL_NOINTERMISSION;
				if( !option_inv )
				{
					clFlags = clFlags | CHANGELEVEL_RESETINVENTORY | CHANGELEVEL_RESETHEALTH;
				}
                
				ChangeLevel(wadList[selectedIndex], 0, clFlags, currentSkill);
			}
			else
			{
				// Toggle the selected option
				switch( currentOpt )
				{
					case OPT_DIFFICULTY:
						// Difficulty toggles by going up one every time it
						// is "used".  When it hits the top, it cycles around
						// to the bottom
						if( currentSkill == SKILL_VERY_HARD )
						{
							currentSkill = SKILL_VERY_EASY;
						}
						else
						{
							currentSkill++;
						}
						break;
					case OPT_MUSIC:
						musicOpt = !musicOpt; // This is the local menu option
						option_music = musicOpt; // Save it to the global variable
						break;
					case OPT_INVENTORY:
						invOpt = !invOpt; // This is the local menu option
						option_inv = invOpt; // Save it to the global variable
						break;
				}
				
				// Something has changed so update the menu screen
				drawSelections();
				
				// After the player has pressed USE, force a 4 tic delay before
				// we do anymore input checks.  This avoids effects like the player
				// taps USE but the input loop cycles twice and thinks the player
				// has hit it twice.
				//
				// If you need more complex handling, you will have to record when
				// the player presses and releases the USE key, like done above
				// with the DIRECTION keys.
				delay(4);
			}
		}
		
		// LEFT
		if( butIn & (BT_LEFT | BT_MOVELEFT) )
		{
			// LEFT will always cycle the tab left by 1
			if( currentTab > 0 )
			{
				currentTab--;
			}
			else
			{
				// Hit the left edge, loop around to the right
				currentTab = NUMBER_OF_TABS - 1;
			}
			
			// Update the menu screen because something has changed
			drawSelections();
		}
		
		// RIGHT
		if( butIn & (BT_RIGHT | BT_MOVERIGHT) )
		{
			// RIGHT will always cycle the tab right by 1
			if( currentTab < NUMBER_OF_TABS-1 )
			{
				currentTab++;
			}
			else
			{
				// Hit the right edge, loop around to the left
				currentTab = 0;
			}
			
			// Update the menu screen because something has changed
			drawSelections();
		}
		
		// Delay required to prevent runaway script and give everything a chance
		// to draw, not to mention to give an opportunity for the player's input
		// to update.
		delay(1);
	}
}


//
//  FROM THIS POINT ON, GETPLAYERINPUT IS NO LONGER USED.  THE REST OF THE
//  SCRIPTS ARE FOR THE SPECIFICALLY HANDLING OF DRAWING THE MENU, ETC.
//


// OPEN setup script.
//   Setup some menu variables and if the players have just returned from
//   playing a map, display their play results to them.
script 1 OPEN
{
	currentSkill = GameSkill();
	
	// When returning to the menu from a level playthrough, record our play results
	if( returningToMenu )
	{
		// Go to play results tab and make sure the last played map is selected
		selectedIndex = recentPlayResults[R_LEVELNUM] - 1;
		currentTab = TAB_PLAYRESULTS;
		
		// Calculate percentage scores.  If there were 0 maximum it counts as
		// 100% instead of... divide by zero error%.
		int killPer = 100;
		int itemPer = 100;
		int secrPer = 100;
		if( recentPlayResults[R_KILLS_MAX] > 0 )
		{
			killPer = 100 * recentPlayResults[R_KILLS] / recentPlayResults[R_KILLS_MAX];
		}
		if( recentPlayResults[R_ITEMS_MAX] > 0 )
		{
			itemPer = 100 * recentPlayResults[R_ITEMS] / recentPlayResults[R_ITEMS_MAX];
		}
		if( recentPlayResults[R_SECRETS_MAX] > 0 )
		{
			secrPer = 100 * recentPlayResults[R_SECRETS] / recentPlayResults[R_SECRETS_MAX];
		}	
		
		// Calculate the level and par time as hours, minutes, seconds
		int timeInSec = recentPlayResults[R_TIME] / 35;
		int timeH = timeInSec / 3600;
		int timeM = (timeInSec / 60) - (60 * timeH);
		int timeS = timeInSec - (3600 * timeH) - (60 * timeM);
		int temp = recentPlayResults[R_TIME_PAR];
		int ptimeH = temp / 3600;
		int ptimeM = (temp / 60) - (60 * ptimeH);
		int ptimeS = temp - (3600 * ptimeH) - (60 * ptimeM);
		
		// Print out the results from this playthrough (the normal Play Results
		// tab drawing will take care of drawing the Best results)
		SetHudSize(640,480,1);
		SetFont("FIXEDSYS");
	
		// General layout
		HudMessageBold(s:"Kills  :      /           %\n",
				   s:"Items  :      /           %\n",
				   s:"Secrets:      /           %\n",
				   s:"Time   :               Par:";
			HUDMSG_PLAIN, 63, CR_WHITE, 205.1, 170.1, 0);
			
		// Numerical player results
		HudMessageBold(d:recentPlayResults[R_KILLS];
			HUDMSG_PLAIN, 64, CR_WHITE, 309.2, 170.1, 0);
		HudMessageBold(d:recentPlayResults[R_ITEMS];
			HUDMSG_PLAIN, 65, CR_WHITE, 309.2, 185.1, 0);
		HudMessageBold(d:recentPlayResults[R_SECRETS];
			HUDMSG_PLAIN, 66, CR_WHITE, 309.2, 200.1, 0);
			
		// Numerical level maximums
		HudMessageBold(d:recentPlayResults[R_KILLS_MAX];
			HUDMSG_PLAIN, 67, CR_WHITE, 365.2, 170.1, 0);
		HudMessageBold(d:recentPlayResults[R_ITEMS_MAX];
			HUDMSG_PLAIN, 68, CR_WHITE, 365.2, 185.1, 0);
		HudMessageBold(d:recentPlayResults[R_SECRETS_MAX];
			HUDMSG_PLAIN, 69, CR_WHITE, 365.2, 200.1, 0);

		// Percentages
		HudMessageBold(d:killPer;
			HUDMSG_PLAIN, 70, CR_WHITE, 413.2, 170.1, 0);
		HudMessageBold(d:itemPer;
			HUDMSG_PLAIN, 71, CR_WHITE, 413.2, 185.1, 0);
		HudMessageBold(d:secrPer;
			HUDMSG_PLAIN, 72, CR_WHITE, 413.2, 200.1, 0);
			
		// Time and Par
		HudMessageBold(d:timeH, s:"h:", d:timeM, s:"m:", d:timeS, s:"s";
			HUDMSG_PLAIN, 73, CR_WHITE, 365.2, 215.1, 0);
		HudMessageBold(d:ptimeH, s:"h:", d:ptimeM, s:"m:", d:ptimeS, s:"s";
			HUDMSG_PLAIN, 74, CR_WHITE, 517.2, 215.1, 0);
		
		// Obligitory delay to let the rest of the drawing occur, including
		// displaying the old BEST result
		delay(1);
		
		// Store these play results if they are better than
		// the best previous playthrough or if this is the first playthrough.
		// We aren't counting time, only percentages.
		// So a playthrough's "score" is just the sum of the percentages.
		bool save = TRUE;
		if( playResults[selectedIndex] != 0 )
		{
			int oldKill = 100;
			int oldItem = 100;
			int oldSecr = 100;
			if( killsMaxResults[selectedIndex] > 0 )
			{
				oldKill = 100 * killsResults[selectedIndex] / killsMaxResults[selectedIndex];
			}
			if( itemsMaxResults[selectedIndex] > 0 )
			{
				oldItem = 100 * itemsResults[selectedIndex] / itemsMaxResults[selectedIndex];
			}
			if( secretsMaxResults[selectedIndex] > 0 )
			{
				oldSecr = 100 * secretsResults[selectedIndex] / secretsMaxResults[selectedIndex];
			}
			
			// Did you do worse?
			if( killPer + itemPer + secrPer   <   oldKill + oldItem + oldSecr )
			{
				save = FALSE;
				
				// YOU FAIL IT!
				HudMessageBold(s:"Better luck next time!";
					HUDMSG_PLAIN, 54, CR_WHITE, 173.1, 260.1, 0);
			}
		}
		else
		{
			// Record that we have beaten this map
			playResults[selectedIndex] = 1;
			
			// Draw the beaten marker (necessary because we are past the delay()
			// statement, so main drawing is already done
			HudMessageBold(s:"*"; HUDMSG_PLAIN, 0, CR_GREEN, 21.1, 35.1 + ((15*selectedIndex)<<16), 0);
		}
		
		if (save)
		{
			killsResults[selectedIndex] = recentPlayResults[R_KILLS];
			killsMaxResults[selectedIndex] = recentPlayResults[R_KILLS_MAX];
			itemsResults[selectedIndex] = recentPlayResults[R_ITEMS];
			itemsMaxResults[selectedIndex] = recentPlayResults[R_ITEMS_MAX];
			secretsResults[selectedIndex] = recentPlayResults[R_SECRETS];
			secretsMaxResults[selectedIndex] = recentPlayResults[R_SECRETS_MAX];
			timeResults[selectedIndex] = recentPlayResults[R_TIME];
			timeParResults[selectedIndex] = recentPlayResults[R_TIME_PAR];
			HudMessageBold(s:"New record!  Nice work!";
				HUDMSG_PLAIN, 54, CR_WHITE, 173.1, 260.1, 0);
		}
		
		// End play results
		returningToMenu = 0;
	}
	else
	{
		// This is the FIRST time loading the level menu, e.g. just starting
		// a new game.  Set the DEFAULT OPTIONS.
		option_music = TRUE;
		option_inv = FALSE;
	}
	
	// Set options on map load
	musicOpt = option_music;
	invOpt = option_inv;
}


//
//  THESE NAMED FUNCTIONS ARE USED AT VARIOUS POINTS TO DO THE DRAWING OF THE MENU.
//  THE MAIN FUNCTION IS drawSelections, WHICH WILL BASICALLY DRAW THE ENTIRE MENU
//  FOREGROUND, INCLUDING TABS.
//

// Draw everything
function int drawSelections(void)
{
	// Draw the wad selection list on the left
	int y = 35.1;
	for( int i = 0; i < NUMBER_OF_WADS; i++ )
	{
		HudMessageBold(s:wadList[i][WAD_LUMPNAME], s:".WAD";
			HUDMSG_PLAIN, i+1, CR_WHITE, 127.2, y, 0);
		if( playResults[i] == 1 )
		{
			HudMessageBold(s:"*"; HUDMSG_PLAIN, 0, CR_GREEN, 21.1, y, 0);
		}
		if( i == selectedIndex )
		{
			SetFont("SELETION");
			HudMessageBold(s:"A";
				HUDMSG_PLAIN, 999, CR_UNTRANSLATED, 31.1, y+2.0, 0);
			SetFont("FIXEDSYS");
		}
		y += 15.0;	
	}
	
	// Draw the tab headers
	HudMessageBold(s:"WAD DETAILS"; HUDMSG_PLAIN, 100,
		getTabNameColor(TAB_WADDETAILS), 141.1, 21.1, 0);
	HudMessageBold(s:"PLAY RESULTS"; HUDMSG_PLAIN, 101,
		getTabNameColor(TAB_PLAYRESULTS), 239.1, 21.1, 0);
	HudMessageBold(s:"OPTIONS"; HUDMSG_PLAIN, 102,
		getTabNameColor(TAB_OPTIONS), 345.1, 21.1, 0);

	// Draw the difficulty indicator
	switch( currentSkill )
	{
	case SKILL_VERY_EASY:
		HudMessageBold(s:"ITYTD"; HUDMSG_PLAIN, 200, CR_DARKGREEN,
			586.1, 454.1, 0);
		break;
	case SKILL_EASY:
		HudMessageBold(s:"HNTR"; HUDMSG_PLAIN, 200, CR_BLUE,
			586.1, 454.1, 0);
		break;
	case SKILL_NORMAL:
		HudMessageBold(s:"HMP"; HUDMSG_PLAIN, 200, CR_YELLOW,
			586.1, 454.1, 0);
		break;
	case SKILL_HARD:
		HudMessageBold(s:"UV"; HUDMSG_PLAIN, 200, CR_ORANGE,
			586.1, 454.1, 0);
		break;
	case SKILL_VERY_HARD:
		HudMessageBold(s:"NM"; HUDMSG_PLAIN, 200, CR_RED,
			586.1, 454.1, 0);
		break;
	default:
		// This should NEVER happen
		HudMessageBold(s:"???"; HUDMSG_PLAIN, 200, CR_BROWN,
			586.1, 454.1, 0);
		break;
	}
	
	// Draw the current tab details.
	// In order to avoid bloating this function, these details will be
	// exported to other functions.
	if( currentTab == TAB_WADDETAILS )
	{
		drawWadDetails();
	}
	else if ( currentTab == TAB_PLAYRESULTS )
	{
		drawWadPlayResults();
	}
	else
	{ // TAB_OPTIONS
		drawOptions();
	}
	
	return 0;
}

// Checks the given tab (by index) and returns the color that tab name should
// be drawn in.
// Used by drawSelections().
function int getTabNameColor(int tab)
{
	if( tab == currentTab )
	{
		return CR_WHITE;
	}
	
	return CR_BLACK;
}


// Draws the contents of the drawWadDetails tab, based upon the currently
// selected wad (selectedIndex)
function int drawWadDetails(void)
{
	HudMessageBold(s:"File  : ", s:wadList[selectedIndex][WAD_LUMPNAME], s:".WAD\n",
			       s:"Title : ", s:wadList[selectedIndex][WAD_TITLE], s:"\n",
			       s:"Author: ", s:wadList[selectedIndex][WAD_AUTHOR];
		HUDMSG_PLAIN, 50, CR_WHITE, 141.1, 35.1, 0);
	SetHudSize(1280,960,1);
	SetFont(wadList[selectedIndex][WAD_IMAGELUMP]);
	HudMessageBold(s:"A";
		HUDMSG_PLAIN, 51, CR_UNTRANSLATED, 900.1, 625.1, 0);
	SetFont("SCRNBACK");
	HudMessageBold(s:"A";
		HUDMSG_PLAIN, 53, CR_UNTRANSLATED, 896.1, 621.1, 0);
	SetFont("FixedSys");
	SetHudSize(640,480,1);
	
	switch( selectedIndex )
	{
		case 1: // Black Tower
			HudMessageBold(
					   s:"You were once the biggest and baddest Cyber-demon to rule\n",
					   s:"Hell.  Betrayed by your council, \"The Cabal\", you find\n",
					   s:"yourself victim to the utmost humilation: morphed into a\n",
					   s:"human!  Of course you're out for revenge on \"The Cabal\".\n\n",
					   s:"You're nearing the end of your journey.  Chagrin, the ruler\n",
					   s:"of the Black Tower, was the closest thing you had to a\n",
					   s:"friend as a demon. \"Oil runs thicker than blood\" the two of\n",
					   s:"you used to say.  Well, now your buddy rules the hordes of\n",
					   s:"Hell previously under your command and has left you for\n",
					   s:"dead.  The task is simple: ascend the Black Tower and slay\n",
					   s:"Chagrin.  Then there is problem of getting back out...";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case 2: // Bloodsea
			HudMessageBold(
					   s:"You were once the biggest and baddest Cyber-demon to rule\n",
					   s:"Hell.  Betrayed by your council, \"The Cabal\", you find\n",
					   s:"yourself victim to the utmost humilation: morphed into a\n",
					   s:"human!  Of course you're out for revenge on \"The Cabal\".\n\n",
					   s:"\"Bloodsea Keep\" is the home of your past advisor,\n",
					   s:"Veavitdpoh.  After being dumped into the \"Sea of Blood\"\n",
					   s:"following your humiliating transformation into a human, you\n",
					   s:"swim until you come to the keep pier.  All who enter\n",
					   s:"\"Bloodsea Keep\" fall victim to your former advisor's\n",
					   s:"favorite pastime: torture.";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case 8: // Geryon
			HudMessageBold(
					   s:"GERYON is the 6th Canto in Dr. Sleep's INFERNO series.\n\n",
					   s:"This level is a little more spread out than previous\n",
					   s:"efforts, but it provides for a nice and leisurely jaunt\n",
					   s:"through Hell.";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case 9: // Titan Manor
			HudMessageBold(
					   s:"A strange and enigmatic building on a moon of Saturn\n",
					   s:"contains the latest in alien weapons technology.  If you\n",
					   s:"can survive the guards and solve the puzzles, the\n",
					   s:"Federation will leapfrog in technology.  It's all up to\n",
					   s:"you.\n\nOh, and watch those windows!";
			HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case 10: // Mephisto
			HudMessageBold(
					   s:"You were once the biggest and baddest Cyber-demon to rule\n",
					   s:"Hell.  Betrayed by your council, \"The Cabal\", you find\n",
					   s:"yourself victim to the utmost humilation: morphed into a\n",
					   s:"human!  Of course you're out for revenge on \"The Cabal\".\n\n",
					   s:"You have reached the grave of an old friend and mentor:\n",
					   s:"Mephisto.  In the past there was an incident with an\n",
					   s:"earthling marine that lost him a lot of credit in Hell.\n",
					   s:"So, you had him kicked off the throne.  His immortal soul\n",
					   s:"was kept as a member of \"The Cabal\" though, and so he was\n",
					   s:"in on your betrayal.  Time to enter his tomb and lay the\n",
					   s:"old man down to rest for good.";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case 11: // Minos
			HudMessageBold(
					   s:"MINOS'S JUDGEMENT is the 4th Canto in Dr. Sleep's INFERNO\n",
					   s:"series.\n\n",
					   s:"In your search for Beatrice, your guide, Virgil (the\n",
					   s:"beatnik space-poet) has just successfully lead you through\n",
					   s:"the First Circle of Hades -- only to bring you to the court\n",
					   s:"of Minos, the Judge of Hell.  \"Well,\" you say, \"this is\n",
					   s:"another fine mess you've gotten us into.  Now what?\"\n",
					   s:"Virgil, with his usual loquacity, replies, \"Heh heh.\"";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case 12: // Nessus
			HudMessageBold(
					   s:"NESSUS is the 5th Canto in Dr. Sleep's INFERNO series.\n\n",
					   s:"Minos decided to grant you leniency and not kill you until\n",
					   s:"next week.  In the meantime, you and Virgil come to a\n",
					   s:"precipice overlooking the river Phlegethon.  You grab\n",
					   s:"Virgil and climb down some boulders to  the foot of the\n",
					   s:"cliff where Chiron, the chief Centaur, offers to have\n",
					   s:"Nessus carry you across the river on his shoulders.  \"Why,\n",
					   s:"that's mighty white of ya,\" says Virgil.  \"No problem,\n",
					   s:"sailor,\" says Nessus.  \"Hop on.\"";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case  13: // Paradox
			HudMessageBold(
					   s:"Extreme planning went into the play flow on this level.\n",
					   s:"The archeticture is designed around a large castle with\n",
					   s:"guard towers that hold each access key.  The level is\n",
					   s:"extremtly non-linear to allow for the player to choose a\n",
					   s:"varied path each time.  Ammo and health is placed in key\n",
					   s:"positions, not enough to be wasteful, but more than enough\n",
					   s:"to finish the level from a pistol start.";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case 16: // TEETH
			HudMessageBold(
					   s:"You were once the biggest and baddest Cyber-demon to rule\n",
					   s:"Hell.  Betrayed by your council, \"The Cabal\", you find\n",
					   s:"yourself victim to the utmost humilation: morphed into a\n",
					   s:"human!  Of course you're out for revenge on \"The Cabal\".\n\n",
					   s:"When the \"Express Elevator to Hell\" starts descending \"The\n",
					   s:"Cabal\" has begun to realize you might be a threat to them,\n",
					   s:"human or not.  Half way down the shaft that should have\n",
					   s:"taken you to the deepest pits	of Hell, the lift first slows\n",
					   s:"down before it jerks to a halt.  It's an ambush! Survive\n",
					   s:"the initial onslaught and find a gateway out of the now\n",
					   s:"sealed elevator.  Tough,	but that's the way you like it.";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case 17: // Trapped
			HudMessageBold(
					   s:"Every step you take may be your last.  If it looks too\n",
					   s:"easy, it probably isn't.  Good luck - you'll need it.";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case 18: // Vesperas
			HudMessageBold(
					   s:"VESPERAS is the 7th Canto in Dr. Sleep's INFERNO series.\n\n",
					   s:"\"Vesperas\" (or \"vespers\"): an evening ceremony.  \"Now it's\n",
					   s:"dark.\"";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		case 19: // Virgil
			HudMessageBold(
					   s:"VIRGIL'S LEAD is the 3th Canto in Dr. Sleep's INFERNO\n",
					   s:"series.\n\n",
					   s:"In your search for Beatrice, you lost your guide Virgil\n",
					   s:"(the beatnik space-poet) while crossing Acheron. But you've\n",
					   s:"caught up with him again, and he's agreed to lead you\n",
					   s:"through the current way-station.  \"You can get a lot\n",
					   s:"further with a kind word and a gun then you can with a kind\n",
					   s:"word,\" you tell Virgil.  \"You belong to the NRA, don't\n",
					   s:"you?\" Virgil asks.  \"No, I'm just a pessimistic pacifist.\"";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
		default:
			// Every other map that came with the Master Levels wasn't given any kind
			// of detailed description, so we'll fall back to that for all the other maps.
			HudMessageBold(s:"No extra details given.";
				HUDMSG_PLAIN, 52, CR_WHITE, 141.1, 95.1, 0);
			break;
	}
	
	// Clean up unused HudMessages
	hmCleanUp(54);
		
	return 0;
}


// Draws the contents of the Play Results tab.  This WON'T draw the recent
// play results when coming back from a map (that is done in the OPEN script).
function int drawWadPlayResults(void)
{
	HudMessageBold(s:wadList[selectedIndex][WAD_LUMPNAME], s:".WAD  :  ",
			       s:wadList[selectedIndex][WAD_TITLE], s:"\n\n",
			       s:"    Best Play Results:";
		HUDMSG_PLAIN, 50, CR_WHITE, 141.1, 35.1, 0);
	
	// If this map has been beaten (and therefore must have play results)...
	if( playResults[selectedIndex] == 1 )
	{
		// Calculate percentage scores.  If there were 0 maximum it counts as
		// 100% instead of... divide by zero error%.
		int killPer = 100;
		int itemPer = 100;
		int secrPer = 100;
		if( killsMaxResults[selectedIndex] > 0 )
		{
			killPer = 100 * killsResults[selectedIndex] / killsMaxResults[selectedIndex];
		}
		if( itemsMaxResults[selectedIndex] > 0 )
		{
			itemPer = 100 * itemsResults[selectedIndex] / itemsMaxResults[selectedIndex];
		}
		if( secretsMaxResults[selectedIndex] > 0 )
		{
			secrPer = 100 * secretsResults[selectedIndex] / secretsMaxResults[selectedIndex];
		}
		
		// Calculate the level and par time as hours, minutes, seconds
		int timeInSec = timeResults[selectedIndex] / 35;
		int timeH = timeInSec / 3600;
		int timeM = (timeInSec / 60) - (60 * timeH);
		int timeS = timeInSec - (3600 * timeH) - (60 * timeM);
		int temp = timeParResults[selectedIndex];
		int ptimeH = temp / 3600;
		int ptimeM = (temp / 60) - (60 * ptimeH);
		int ptimeS = temp - (3600 * ptimeH) - (60 * ptimeM);


		// General layout
		HudMessageBold(s:"Kills  :      /           %\n",
				       s:"Items  :      /           %\n",
				       s:"Secrets:      /           %\n",
				       s:"Time   :               Par:";
			HUDMSG_PLAIN, 51, CR_WHITE, 205.1, 80.1, 0);
			
		// Numerical player results
		HudMessageBold(d:killsResults[selectedIndex];
			HUDMSG_PLAIN, 52, CR_WHITE, 309.2, 80.1, 0);
		HudMessageBold(d:itemsResults[selectedIndex];
			HUDMSG_PLAIN, 53, CR_WHITE, 309.2, 95.1, 0);
		HudMessageBold(d:secretsResults[selectedIndex];
			HUDMSG_PLAIN, 54, CR_WHITE, 309.2, 110.1, 0);
			
		// Numerical level maximums
		HudMessageBold(d:killsMaxResults[selectedIndex];
			HUDMSG_PLAIN, 55, CR_WHITE, 365.2, 80.1, 0);
		HudMessageBold(d:itemsMaxResults[selectedIndex];
			HUDMSG_PLAIN, 56, CR_WHITE, 365.2, 95.1, 0);
		HudMessageBold(d:secretsMaxResults[selectedIndex];
			HUDMSG_PLAIN, 57, CR_WHITE, 365.2, 110.1, 0);
			
		// Percentages
		HudMessageBold(d:killPer;
			HUDMSG_PLAIN, 58, CR_WHITE, 413.2, 80.1, 0);
		HudMessageBold(d:itemPer;
			HUDMSG_PLAIN, 59, CR_WHITE, 413.2, 95.1, 0);
		HudMessageBold(d:secrPer;
			HUDMSG_PLAIN, 60, CR_WHITE, 413.2, 110.1, 0);
			
		// Time and Par
		HudMessageBold(d:timeH, s:"h:", d:timeM, s:"m:", d:timeS, s:"s";
			HUDMSG_PLAIN, 61, CR_WHITE, 365.2, 125.1, 0);
		HudMessageBold(d:ptimeH, s:"h:", d:ptimeM, s:"m:", d:ptimeS, s:"s";
			HUDMSG_PLAIN, 62, CR_WHITE, 517.2, 125.1, 0);
			
		// If the player has 300% total, display "Rock, rock on!"
		// ....... nah.......
	}
	else
	{
		// Players have not beaten this map yet
		HudMessageBold(s:"NO RESULTS TO DISPLAY";
		   HUDMSG_PLAIN, 51, CR_WHITE, 205.1, 80.1, 0);
		
		// Only clean up HudMessages if we aren't just coming back from a level
		if( !returningToMenu )
		{
			hmCleanUp(52);
		}
	}
	
	// If you haven't just come back from a level, clean up the extraneous hudmessages.
	if( !returningToMenu )
	{
		hmCleanup(63);	
	}
	
	return 0;
}


// Draws the contents of the options tab
function int drawOptions(void)
{
	// Draw the static text and the little *'s that show the current value of
	// each option
	HudMessageBold(
			   s:"-- DIFFICULTY --\n",
			   s:"    [ ] I'm too young to die\n",
			   s:"    [ ] Hey, not too rough\n",
			   s:"    [ ] Hurt me plenty\n",
			   s:"    [ ] Ultra-violence\n",
			   s:"    [ ] NIGHTMARE!\n";
		HUDMSG_PLAIN, 50, CR_WHITE, 165.1, 35.1, 0);
	HudMessageBold(s:"*";
		HUDMSG_PLAIN, 51, CR_RED, 205.1, 50.1 + ((currentSkill*15)<<16), 0);
	HudMessageBold(s:"-- VARIED MUSIC --\n",
			       s:"    [ ] On    [ ] Off";
		HUDMSG_PLAIN, 52, CR_WHITE, 165.1, 140.1, 0);
	HudMessageBold(s:"*";
		HUDMSG_PLAIN, 53, CR_RED, 285.1 - ((musicOpt*80)<<16), 155.1, 0);
	HudMessageBold(s:"-- KEEP INVENTORY --\n",
			       s:"    [ ] On    [ ] Off";
		HUDMSG_PLAIN, 54, CR_WHITE, 165.1, 185.1, 0);
	HudMessageBold(s:"*";
		HUDMSG_PLAIN, 55, CR_RED, 285.1 - ((invOpt*80)<<16), 200.1, 0);
		
	// Draw selected option arrow
	int yOff = 35.1;
	if( currentOpt == OPT_MUSIC ) { yOff = 140.1; }
	if( currentOpt == OPT_INVENTORY ) { yOff = 185.1; }
	
	HudMessage(s:"->";
			HUDMSG_PLAIN, 56, CR_GREEN, 141.1, yOff, 0);

	// Clean up any unused HudMessages
	hmCleanUp(57);

	return 0;
}


// Cleans up unused HudMessages, starting at the given on and going to the maximum
// foreground HudMessage.  This is useful when drawing tabs.  If the player changes
// tabs it will make sure the screen is clear of details from tab to tab.
function int hmCleanUp(int startId)
{
	for( int i = startId; i <= LAST_HUDMSG_ID; i++ )
	{
		HudMessageBold(s:"";
			HUDMSG_PLAIN, i, CR_WHITE, 0.0, 0.0, 0);
	}
	
	return 0;
}
