Skip to content

Instantly share code, notes, and snippets.

@mohiji
Created September 15, 2010 04:25
Show Gist options
  • Save mohiji/580235 to your computer and use it in GitHub Desktop.
Save mohiji/580235 to your computer and use it in GitHub Desktop.
Comparing my menu.c from 2007 with the one currently in Egoboo
#include "egoboo.h"
#include "Ui.h"
#include "Menu.h"
#include "Log.h"
// TEMPORARY!
#define NET_DONE_SENDING_FILES 10009
#define NET_NUM_FILES_TO_SEND 10010
//--------------------------------------------------------------------------------------------
// New menu code
//--------------------------------------------------------------------------------------------
enum MenuStates
{
MM_Begin,
MM_Entering,
MM_Running,
MM_Leaving,
MM_Finish,
};
static int selectedPlayer = 0;
static int selectedModule = 0;
/* Copyright text variables. Change these to change how the copyright text appears */
const char copyrightText[] = "Egoboo 2.x\nhttp://www.mohiji.org/projects/egoboo2x";
//const char copyrightText[] =
//"Welcome to Egoboo!\nhttp://home.no.net/egoboo\nhttp://egoboo.taxiwin.com\nVersion 2.3.6";
static int copyrightLeft = 0;
static int copyrightTop = 0;
/* Button labels. Defined here for consistency's sake, rather than leaving them as constants */
const char *mainMenuButtons[] = {
"Single Player",
"Multi-player",
"Options",
"Quit",
""
};
const char *singlePlayerButtons[] = {
"New Player",
"Load Saved Player",
"Back",
""
};
/* Button position for the "easy" menus, like the main one */
static int buttonLeft = 0;
static int buttonTop = 0;
static bool_t startNewPlayer = bfalse;
/* The font used for drawing text. It's smaller than the button font */
Font *menuFont = NULL;
// "Slidy" buttons used in some of the menus. They're shiny.
struct {
float lerp;
int top;
int left;
char **buttons;
}SlidyButtonState;
static void initSlidyButtons(float lerp, const char *buttons[])
{
SlidyButtonState.lerp = lerp;
SlidyButtonState.buttons = (char**)buttons;
}
static void updateSlidyButtons(float deltaTime)
{
SlidyButtonState.lerp += (deltaTime * 1.5f);
}
static void drawSlidyButtons()
{
int i;
for (i = 0; SlidyButtonState.buttons[i][0] != 0; i++)
{
int x = buttonLeft - (360 - i * 35) * SlidyButtonState.lerp;
int y = buttonTop + (i * 35);
ui_doButton(UI_Nothing, SlidyButtonState.buttons[i], x, y, 200, 30);
}
}
/** initMenus
* Loads resources for the menus, and figures out where things should
* be positioned. If we ever allow changing resolution on the fly, this
* function will have to be updated/called more than once.
*/
int initMenus()
{
int i;
menuFont = fnt_loadFont("basicdat/Negatori.ttf", 18);
if (!menuFont)
{
log_error("Could not load the menu font!\n");
return 0;
}
// Figure out where to draw the buttons
buttonLeft = 40;
buttonTop = displaySurface->h - 20;
for (i = 0; mainMenuButtons[i][0] != 0; i++)
{
buttonTop -= 35;
}
// Figure out where to draw the copyright text
copyrightLeft = 0;
copyrightLeft = 0;
fnt_getTextBoxSize(menuFont, copyrightText, 20, &copyrightLeft, &copyrightTop);
// Draw the copyright text to the right of the buttons
copyrightLeft = 280;
// And relative to the bottom of the screen
copyrightTop = displaySurface->h - copyrightTop - 20;
return 1;
}
int doMainMenu(float deltaTime)
{
static int menuState = MM_Begin;
static GLTexture background;
static float lerp;
static int menuChoice = 0;
int result = 0;
switch(menuState)
{
case MM_Begin:
// set up menu variables
GLTexture_Load(&background, "basicdat/menu/menu_advent.bmp");
menuChoice = 0;
menuState = MM_Entering;
initSlidyButtons(1.0f, mainMenuButtons);
// let this fall through into MM_Entering
case MM_Entering:
// do buttons sliding in animation, and background fading in
// background
glColor4f(1, 1, 1, 1 -SlidyButtonState.lerp);
ui_drawImage(0, &background, (displaySurface->w - background.imgWidth), 0, 0, 0);
// "Copyright" text
fnt_drawTextBox(menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20);
drawSlidyButtons();
updateSlidyButtons(-deltaTime);
// Let lerp wind down relative to the time elapsed
if (SlidyButtonState.lerp <= 0.0f)
{
menuState = MM_Running;
}
break;
case MM_Running:
// Do normal run
// Background
glColor4f(1, 1, 1, 1);
ui_drawImage(0, &background, (displaySurface->w - background.imgWidth), 0, 0, 0);
// "Copyright" text
fnt_drawTextBox(menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20);
// Buttons
if(ui_doButton(1, mainMenuButtons[0], buttonLeft, buttonTop, 200, 30) == 1)
{
// begin single player stuff
menuChoice = 1;
}
if(ui_doButton(2, mainMenuButtons[1], buttonLeft, buttonTop + 35, 200, 30) == 1)
{
// begin multi player stuff
menuChoice = 2;
}
if(ui_doButton(3, mainMenuButtons[2], buttonLeft, buttonTop + 35 * 2, 200, 30) == 1)
{
// go to options menu
menuChoice = 3;
}
if(ui_doButton(4, mainMenuButtons[3], buttonLeft, buttonTop + 35 * 3, 200, 30) == 1)
{
// quit game
menuChoice = 4;
}
if(menuChoice != 0)
{
menuState = MM_Leaving;
initSlidyButtons(0.0f, mainMenuButtons);
}
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
glColor4f(1, 1, 1, 1 - SlidyButtonState.lerp);
ui_drawImage(0, &background, (displaySurface->w - background.imgWidth), 0, 0, 0);
// "Copyright" text
fnt_drawTextBox(menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20);
// Buttons
drawSlidyButtons();
updateSlidyButtons(deltaTime);
if(SlidyButtonState.lerp >= 1.0f) {
menuState = MM_Finish;
}
break;
case MM_Finish:
// Free the background texture; don't need to hold onto it
GLTexture_Release(&background);
menuState = MM_Begin; // Make sure this all resets next time doMainMenu is called
// Set the next menu to load
result = menuChoice;
break;
};
return result;
}
int doSinglePlayerMenu(float deltaTime)
{
static int menuState = MM_Begin;
static GLTexture background;
static int menuChoice;
int result = 0;
switch(menuState)
{
case MM_Begin:
// Load resources for this menu
GLTexture_Load(&background, "basicdat/menu/menu_gnome.bmp");
menuChoice = 0;
menuState = MM_Entering;
initSlidyButtons(1.0f, singlePlayerButtons);
// Let this fall through
case MM_Entering:
glColor4f(1, 1, 1, 1 - SlidyButtonState.lerp);
// Draw the background image
ui_drawImage(0, &background, displaySurface->w - background.imgWidth, 0, 0, 0);
// "Copyright" text
fnt_drawTextBox(menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20);
drawSlidyButtons();
updateSlidyButtons(-deltaTime);
if (SlidyButtonState.lerp <= 0.0f)
menuState = MM_Running;
break;
case MM_Running:
// Draw the background image
ui_drawImage(0, &background, displaySurface->w - background.imgWidth, 0, 0, 0);
// "Copyright" text
fnt_drawTextBox(menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20);
// Buttons
if (ui_doButton(1, singlePlayerButtons[0], buttonLeft, buttonTop, 200, 30) == 1)
{
menuChoice = 1;
}
if (ui_doButton(2, singlePlayerButtons[1], buttonLeft, buttonTop + 35, 200, 30) == 1)
{
menuChoice = 2;
}
if (ui_doButton(3, singlePlayerButtons[2], buttonLeft, buttonTop + 35 * 2, 200, 30) == 1)
{
menuChoice = 3;
}
if(menuChoice != 0)
{
menuState = MM_Leaving;
initSlidyButtons(0.0f, singlePlayerButtons);
}
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
glColor4f(1, 1, 1, 1 - SlidyButtonState.lerp);
ui_drawImage(0, &background, displaySurface->w - background.imgWidth, 0, 0, 0);
// "Copyright" text
fnt_drawTextBox(menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20);
drawSlidyButtons();
updateSlidyButtons(deltaTime);
if(SlidyButtonState.lerp >= 1.0f)
{
menuState = MM_Finish;
}
break;
case MM_Finish:
// Release the background texture
GLTexture_Release(&background);
// Set the next menu to load
result = menuChoice;
// And make sure that if we come back to this menu, it resets
// properly
menuState = MM_Begin;
}
return result;
}
// TODO: I totally fudged the layout of this menu by adding an offset for when
// the game isn't in 640x480. Needs to be fixed.
int doChooseModule(float deltaTime)
{
static int menuState = MM_Begin;
static int startIndex;
static GLTexture background;
static int validModules[MAXMODULE];
static int numValidModules;
static int moduleMenuOffsetX;
static int moduleMenuOffsetY;
int result = 0;
int i, x, y;
char txtBuffer[128];
switch(menuState)
{
case MM_Begin:
// Load font & background
GLTexture_Load(&background, "basicdat/menu/menu_sleepy.bmp");
startIndex = 0;
selectedModule = -1;
// Find the module's that we want to allow loading for. If startNewPlayer
// is true, we want ones that don't allow imports (e.g. starter modules).
// Otherwise, we want modules that allow imports
memset(validModules, 0, sizeof(int) * MAXMODULE);
numValidModules = 0;
for (i = 0;i < globalnummodule; i++)
{
if (modimportamount[i] == 0)
{
if (startNewPlayer)
{
validModules[numValidModules] = i;
numValidModules++;
}
} else
{
if (!startNewPlayer)
{
validModules[numValidModules] = i;
numValidModules++;
}
}
}
// Figure out at what offset we want to draw the module menu.
moduleMenuOffsetX = (displaySurface->w - 640) / 2;
moduleMenuOffsetY = (displaySurface->h - 480) / 2;
menuState = MM_Entering;
// fall through...
case MM_Entering:
menuState = MM_Running;
// fall through for now...
case MM_Running:
// Draw the background
glColor4f(1, 1, 1, 1);
x = (displaySurface->w / 2) - (background.imgWidth / 2);
y = displaySurface->h - background.imgHeight;
ui_drawImage(0, &background, x, y, 0, 0);
// Fudged offset here.. DAMN! Doesn't work, as the mouse tracking gets skewed
// I guess I'll do it the uglier way
//glTranslatef(moduleMenuOffsetX, moduleMenuOffsetY, 0);
// Draw the arrows to pick modules
if(ui_doButton(1051, "<-", moduleMenuOffsetX + 20, moduleMenuOffsetY + 74, 30, 30))
{
startIndex--;
}
if(ui_doButton(1052, "->", moduleMenuOffsetX + 590, moduleMenuOffsetY + 74, 30, 30))
{
startIndex++;
if(startIndex + 3 >= numValidModules)
{
startIndex = numValidModules - 3;
}
}
// Clamp startIndex to 0
startIndex = (startIndex > 0) ? startIndex : 0;
// Draw buttons for the modules that can be selected
x = 93;
y = 20;
for(i = startIndex; i < (startIndex + 3) && i < numValidModules; i++)
{
if(ui_doImageButton(i, &TxTitleImage[validModules[i]],
moduleMenuOffsetX + x, moduleMenuOffsetY + y, 138, 138))
{
selectedModule = i;
}
x += 138 + 20; // Width of the button, and the spacing between buttons
}
// Draw an unused button as the backdrop for the text for now
ui_drawButton(0xFFFFFFFF, moduleMenuOffsetX + 21, moduleMenuOffsetY + 173, 291, 230);
// And draw the next & back buttons
if (ui_doButton(53, "Select Module",
moduleMenuOffsetX + 327, moduleMenuOffsetY + 173, 200, 30))
{
// go to the next menu with this module selected
selectedModule = validModules[selectedModule];
menuState = MM_Leaving;
}
if (ui_doButton(54, "Back", moduleMenuOffsetX + 327, moduleMenuOffsetY + 208, 200, 30))
{
// Signal doMenu to go back to the previous menu
selectedModule = -1;
menuState = MM_Leaving;
}
// Draw the text description of the selected module
if(selectedModule > -1)
{
y = 173 + 5;
x = 21 + 5;
glColor4f(1, 1, 1, 1);
fnt_drawText(menuFont, moduleMenuOffsetX + x, moduleMenuOffsetY + y,
modlongname[validModules[selectedModule]]);
y += 20;
snprintf(txtBuffer, 128, "Difficulty: %s", modrank[validModules[selectedModule]]);
fnt_drawText(menuFont, moduleMenuOffsetX + x, moduleMenuOffsetY + y, txtBuffer);
y += 20;
if(modmaxplayers[validModules[selectedModule]] > 1)
{
if(modminplayers[validModules[selectedModule]] == modmaxplayers[validModules[selectedModule]])
{
snprintf(txtBuffer, 128, "%d Players", modminplayers[validModules[selectedModule]]);
} else
{
snprintf(txtBuffer, 128, "%d - %d Players", modminplayers[validModules[selectedModule]], modmaxplayers[validModules[selectedModule]]);
}
} else
{
snprintf(txtBuffer, 128, "Starter Module");
}
fnt_drawText(menuFont, moduleMenuOffsetX + x, moduleMenuOffsetY + y, txtBuffer);
y += 20;
// And finally, the summary
snprintf(txtBuffer, 128, "modules/%s/gamedat/menu.txt", modloadname[validModules[selectedModule]]);
get_module_summary(txtBuffer);
for(i = 0;i < SUMMARYLINES;i++)
{
fnt_drawText(menuFont, moduleMenuOffsetX + x, moduleMenuOffsetY + y, modsummary[i]);
y += 20;
}
}
break;
case MM_Leaving:
menuState = MM_Finish;
// fall through for now
case MM_Finish:
GLTexture_Release(&background);
menuState = MM_Begin;
if(selectedModule == -1)
{
result = -1;
} else
{
// Save the name of the module that we've picked
strncpy(pickedmodule, modloadname[selectedModule], 64);
// If the module allows imports, return 1. Else, return 2
if(modimportamount[selectedModule] > 0)
{
importvalid = btrue;
importamount = modimportamount[selectedModule];
result = 1;
}
else
{
importvalid = bfalse;
result = 2;
}
exportvalid = modallowexport[selectedModule];
playeramount = modmaxplayers[selectedModule];
respawnvalid = bfalse;
respawnanytime = bfalse;
if(modrespawnvalid[selectedModule]) respawnvalid = btrue;
if(modrespawnvalid[selectedModule] == ANYTIME) respawnanytime = btrue;
rtscontrol = bfalse;
}
break;
}
return result;
}
int doChoosePlayer(float deltaTime)
{
static int menuState = MM_Begin;
static GLTexture background;
int result = 0;
int numVertical, numHorizontal;
int i, j, x, y;
int player;
char srcDir[64], destDir[64];
switch(menuState)
{
case MM_Begin:
selectedPlayer = 0;
GLTexture_Load(&background, "basicdat/menu/menu_sleepy.bmp");
// load information for all the players that could be imported
check_player_import("players");
menuState = MM_Entering;
// fall through
case MM_Entering:
menuState = MM_Running;
// fall through
case MM_Running:
// Figure out how many players we can show without scrolling
numVertical = 6;
numHorizontal = 2;
// Draw the player selection buttons
// I'm being tricky, and drawing two buttons right next to each other
// for each player: one with the icon, and another with the name. I'm
// given those buttons the same ID, so they'll act like the same button.
player = 0;
x = 20;
for(j = 0;j < numHorizontal && player < numloadplayer;j++)
{
y = 20;
for(i = 0;i < numVertical && player < numloadplayer;i++)
{
if(ui_doImageButtonWithText(player, &TxIcon[player], loadplayername[player], x, y, 175, 42))
{
selectedPlayer = player;
}
player++;
y += 47;
}
x += 180;
}
// Draw the background
x = (displaySurface->w / 2) - (background.imgWidth / 2);
y = displaySurface->h - background.imgHeight;
ui_drawImage(0, &background, x, y, 0, 0);
// Buttons for going ahead
if (ui_doButton(100, "Play!", 40, 350, 200, 30))
{
menuState = MM_Leaving;
}
if (ui_doButton(101, "Back", 40, 385, 200, 30))
{
selectedPlayer = -1;
menuState = MM_Leaving;
}
break;
case MM_Leaving:
menuState = MM_Finish;
// fall through
case MM_Finish:
GLTexture_Release(&background);
menuState = MM_Begin;
if(selectedPlayer == -1) result = -1;
else
{
// Build the import directory
// I'm just allowing 1 player for now...
empty_import_directory();
fs_createDirectory("import");
localcontrol[0] = INPUTKEY | INPUTMOUSE | INPUTJOYA;
localslot[0] = localmachine * 9;
// Copy the character to the import directory
sprintf(srcDir, "players/%s", loadplayerdir[selectedPlayer]);
sprintf(destDir, "import/temp%04d.obj", localslot[0]);
fs_copyDirectory(srcDir, destDir);
// Copy all of the character's items to the import directory
for(i = 0;i < 8;i++)
{
sprintf(srcDir, "players/%s/%d.obj", loadplayerdir[selectedPlayer], i);
sprintf(destDir, "import/temp%04d.obj", localslot[0] + i + 1);
fs_copyDirectory(srcDir, destDir);
}
numimport = 1;
result = 1;
}
break;
}
return result;
}
int doShowMenuResults(float deltaTime)
{
int x, y;
char text[128];
Font *font;
SDL_Surface *screen = SDL_GetVideoSurface();
font = ui_getFont();
ui_drawButton(0xFFFFFFFF, 30, 30, screen->w - 60, screen->h - 65);
x = 35;
y = 35;
glColor4f(1, 1, 1, 1);
snprintf(text, 128, "Module selected: %s", modloadname[selectedModule]);
fnt_drawText(font, x, y, text);
y += 35;
if(importvalid)
{
snprintf(text, 128, "Player selected: %s", loadplayername[selectedPlayer]);
} else
{
snprintf(text, 128, "Starting a new player.");
}
fnt_drawText(font, x, y, text);
return 1;
}
int doNotImplemented(float deltaTime)
{
int x, y;
int w, h;
char notImplementedMessage[] = "Not implemented yet! Check back soon!";
fnt_getTextSize(ui_getFont(), notImplementedMessage, &w, &h);
w += 50; // add some space on the sides
x = displaySurface->w / 2 - w / 2;
y = displaySurface->h / 2 - 17;
if(ui_doButton(1, notImplementedMessage, x, y, w, 30) == 1)
{
return 1;
}
return 0;
}
// All the different menus. yay!
enum
{
MainMenu,
SinglePlayer,
MultiPlayer,
ChooseModule,
ChoosePlayer,
TestResults,
Options,
VideoOptions,
AudioOptions,
InputOptions,
NewPlayer,
LoadPlayer,
HostGame,
JoinGame,
};
int doMenu(float deltaTime)
{
static int whichMenu = MainMenu;
static int lastMenu = MainMenu;
int result = 0;
switch(whichMenu)
{
case MainMenu:
result = doMainMenu(deltaTime);
if(result != 0)
{
lastMenu = MainMenu;
if(result == 1) whichMenu = SinglePlayer;
else if(result == 2) whichMenu = MultiPlayer;
else if(result == 3) whichMenu = Options;
else if(result == 4) return -1; // need to request a quit somehow
}
break;
case SinglePlayer:
result = doSinglePlayerMenu(deltaTime);
if(result != 0)
{
lastMenu = SinglePlayer;
if(result == 1)
{
whichMenu = ChooseModule;
startNewPlayer = btrue;
} else if(result == 2)
{
whichMenu = ChooseModule;
startNewPlayer = bfalse;
}
else if(result == 3) whichMenu = MainMenu;
else whichMenu = NewPlayer;
}
break;
case ChooseModule:
result = doChooseModule(deltaTime);
if(result == -1) whichMenu = lastMenu;
else if(result == 1) whichMenu = ChoosePlayer;
else if(result == 2) whichMenu = TestResults;
break;
case ChoosePlayer:
result = doChoosePlayer(deltaTime);
if(result == -1) whichMenu = ChooseModule;
else if(result == 1) whichMenu = TestResults;
break;
case TestResults:
result = doShowMenuResults(deltaTime);
if(result != 0)
{
whichMenu = MainMenu;
return 1;
}
break;
default:
result = doNotImplemented(deltaTime);
if(result != 0)
{
whichMenu = lastMenu;
}
}
return 0;
}
void menu_frameStep()
{
}
//********************************************************************************************
//*
//* This file is part of Egoboo.
//*
//* Egoboo is free software: you can redistribute it and/or modify it
//* under the terms of the GNU General Public License as published by
//* the Free Software Foundation, either version 3 of the License, or
//* (at your option) any later version.
//*
//* Egoboo is distributed in the hope that it will be useful, but
//* WITHOUT ANY WARRANTY; without even the implied warranty of
//* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//* General Public License for more details.
//*
//* You should have received a copy of the GNU General Public License
//* along with Egoboo. If not, see <http://www.gnu.org/licenses/>.
//*
//********************************************************************************************
/// @file menu.c
/// @brief Implements the main menu tree, using the code in Ui.*
/// @details
#include "menu.h"
#include "particle.inl"
#include "mad.h"
#include "char.inl"
#include "profile.inl"
#include "game.h"
#include "quest.h"
#include "controls_file.h"
#include "scancode_file.h"
#include "ui.h"
#include "log.h"
#include "link.h"
#include "game.h"
#include "texture.h"
#include "module_file.h"
// To allow changing settings
#include "sound.h"
#include "input.h"
#include "camera.h"
#include "graphic.h"
#include "egoboo_math.h"
#include "egoboo_vfs.h"
#include "egoboo_typedef.h"
#include "egoboo_fileutil.h"
#include "egoboo_setup.h"
#include "egoboo_strutil.h"
#include "egoboo.h"
#include "SDL_extensions.h"
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
/// The possible states of the menu state machine
enum e_menu_states
{
MM_Begin,
MM_Entering,
MM_Running,
MM_Leaving,
MM_Finish
};
#define MENU_STACK_COUNT 256
#define MAXWIDGET 100
#define MENU_MAX_GAMETIPS 100
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
// "Slidy" buttons used in some of the menus. They're shiny.
struct s_SlidyButtonState
{
char **buttons;
float lerp;
int top;
int left;
};
typedef struct s_SlidyButtonState mnu_SlidyButtonState_t;
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
/// the data to display a chosen player in the load player menu
struct s_ChoosePlayer_element
{
CAP_REF cap_ref; ///< the index of the cap_t
TX_REF tx_ref; ///< the index of the icon texture
chop_definition_t chop; ///< put this here so we can generate a name without loading an entire profile
};
typedef struct s_ChoosePlayer_element ChoosePlayer_element_t;
//--------------------------------------------------------------------------------------------
/// The data that menu.c uses to store the users' choice of players
struct s_ChoosePlayer_profiles
{
int count; ///< the profiles that have been loaded
ChoosePlayer_element_t pro_data[MAXIMPORTPERPLAYER + 1]; ///< the profile data
};
typedef struct s_ChoosePlayer_profiles ChoosePlayer_profiles_t;
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
/// the module data that the menu system needs
struct s_mnu_module
{
EGO_PROFILE_STUFF; ///< the "base class" of a profile obbject
mod_file_t base; ///< the data for the "base class" of the module
// extended data
TX_REF tex_index; ///< the index of the module's tile image
STRING vfs_path; ///< the virtual pathname of the module
STRING dest_path; ///< the path that module data can be written into
};
typedef struct s_mnu_module mnu_module_t;
#define VALID_MOD_RANGE( IMOD ) ( ((IMOD) >= 0) && ((IMOD) < MAX_MODULE) )
#define VALID_MOD( IMOD ) ( VALID_MOD_RANGE( IMOD ) && IMOD < mnu_ModList.count && mnu_ModList.lst[IMOD].loaded )
#define INVALID_MOD( IMOD ) ( !VALID_MOD_RANGE( IMOD ) || IMOD >= mnu_ModList.count || !mnu_ModList.lst[IMOD].loaded )
INSTANTIATE_STACK_STATIC( mnu_module_t, mnu_ModList, MAX_MODULE );
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
/// The data that menu.c uses to store the users' choice of players
struct s_GameTips
{
//These are loaded only once
Uint8 count; //< Number of global tips loaded
STRING hint[MENU_MAX_GAMETIPS]; //< The global hints/tips
//These are loaded for every module
Uint8 local_count; //< Number of module specific tips loaded
STRING local_hint[MENU_MAX_GAMETIPS]; //< Module specific hints and tips
};
typedef struct s_GameTips GameTips_t;
//--------------------------------------------------------------------------------------------
// declaration of "private" variables
//--------------------------------------------------------------------------------------------
static int mnu_stack_index = 0;
static which_menu_t mnu_stack[MENU_STACK_COUNT];
static which_menu_t mnu_whichMenu = emnu_Main;
static module_filter_t mnu_moduleFilter = FILTER_OFF;
static ui_Widget_t mnu_widgetList[MAXWIDGET];
static int selectedModule = -1;
/* Copyright text variables. Change these to change how the copyright text appears */
static const char * copyrightText = "Welcome to Egoboo!\nhttp://egoboo.sourceforge.net\nVersion " VERSION "\n";
static int copyrightLeft = 0;
static int copyrightTop = 0;
/* Options info text variables. Change these to change how the options text appears */
static const char * tipText = "Put a tip in this box";
static int tipTextLeft = 0;
static int tipTextTop = 0;
/* Button position for the "easy" menus, like the main one */
static int buttonLeft = 0;
static int buttonTop = 0;
static int selectedPlayer = 0; // Which player is currently selected to play
static menu_process_t _mproc;
static int mnu_selectedPlayerCount = 0;
static Uint32 mnu_selectedInput[MAX_PLAYER] = {0};
static int mnu_selectedPlayer[MAX_PLAYER] = {0};
static GameTips_t mnu_GameTip = { 0 };
static mnu_SlidyButtonState_t mnu_SlidyButtonState = { NULL };
//--------------------------------------------------------------------------------------------
// declaration of public variables
//--------------------------------------------------------------------------------------------
#define TITLE_TEXTURE_COUNT MAX_MODULE
#define INVALID_TITLE_TEXTURE TITLE_TEXTURE_COUNT
INSTANTIATE_STACK_STATIC( oglx_texture_t, TxTitleImage, TITLE_TEXTURE_COUNT ); // OpenGL title image surfaces
menu_process_t * MProc = &_mproc;
bool_t start_new_player = bfalse;
bool_t module_list_valid = bfalse;
/* The font used for drawing text. It's smaller than the button font */
Font *menuFont = NULL;
bool_t mnu_draw_background = btrue;
int loadplayer_count = 0;
LOAD_PLAYER_INFO loadplayer[MAXLOADPLAYER];
//--------------------------------------------------------------------------------------------
// "private" function prototypes
//--------------------------------------------------------------------------------------------
// Implementation of the mnu_stack
static bool_t mnu_stack_push( which_menu_t menu );
static which_menu_t mnu_stack_pop();
static which_menu_t mnu_stack_peek();
static void mnu_stack_clear();
// Implementation of the mnu_SlidyButton array
static void mnu_SlidyButton_init( float lerp, const char *button_text[] );
static void mnu_SlidyButton_update_all( float deltaTime );
static void mnu_SlidyButton_draw_all();
// implementation of the mnu_Selected* arrays
static bool_t mnu_Selected_check_loadplayer( int loadplayer_idx );
static bool_t mnu_Selected_add( int loadplayer_idx );
static bool_t mnu_Selected_remove( int loadplayer_idx );
static bool_t mnu_Selected_add_input( int loadplayer_idx, Uint32 input_bits );
static bool_t mnu_Selected_remove_input( int loadplayer_idx, Uint32 input_bits );
static int mnu_Selected_get_loadplayer( int loadplayer_idx );
// implementation of "private" TxTitleImage functions
static void TxTitleImage_clear_data();
static void TxTitleImage_release_one( const TX_REF by_reference index );
static void TxTitleImage_ctor();
static void TxTitleImage_release_all();
static void TxTitleImage_dtor();
static oglx_texture_t * TxTitleImage_get_ptr( const TX_REF by_reference itex );
// tipText functions
static void tipText_set_position( Font * font, const char * text, int spacing );
// copyrightText functions
static void copyrightText_set_position( Font * font, const char * text, int spacing );
// implementation of "private" ModList functions
static void mnu_ModList_release_images();
void mnu_ModList_release_all();
// "process" management
static int do_menu_proc_begin( menu_process_t * mproc );
static int do_menu_proc_running( menu_process_t * mproc );
static int do_menu_proc_leaving( menu_process_t * mproc );
// the hint system
static void mnu_GameTip_load_global_vfs();
static bool_t mnu_GameTip_load_local_vfs();
// "private" module utility
static void mnu_load_all_module_info();
// "private" asset function
static TX_REF mnu_get_icon_ref( const CAP_REF by_reference icap, const TX_REF by_reference default_ref );
// implementation of the autoformatting
static void autoformat_init_slidy_buttons();
static void autoformat_init_tip_text();
static void autoformat_init_copyright_text();
// misc other stuff
static void mnu_release_one_module( const MOD_REF by_reference imod );
static void mnu_load_all_module_images_vfs();
//--------------------------------------------------------------------------------------------
// implementation of the menu stack
//--------------------------------------------------------------------------------------------
bool_t mnu_stack_push( which_menu_t menu )
{
mnu_stack_index = CLIP( mnu_stack_index, 0, MENU_STACK_COUNT ) ;
if ( mnu_stack_index >= MENU_STACK_COUNT ) return bfalse;
mnu_stack[mnu_stack_index] = menu;
mnu_stack_index++;
return btrue;
}
//--------------------------------------------------------------------------------------------
which_menu_t mnu_stack_pop()
{
if ( mnu_stack_index < 0 )
{
mnu_stack_index = 0;
return emnu_Main;
}
if ( mnu_stack_index > MENU_STACK_COUNT )
{
mnu_stack_index = MENU_STACK_COUNT;
}
if ( mnu_stack_index == 0 ) return emnu_Main;
mnu_stack_index--;
return mnu_stack[mnu_stack_index];
}
//--------------------------------------------------------------------------------------------
which_menu_t mnu_stack_peek()
{
which_menu_t return_menu = emnu_Main;
if ( mnu_stack_index > 0 )
{
return_menu = mnu_stack[mnu_stack_index-1];
}
return return_menu;
}
//--------------------------------------------------------------------------------------------
void mnu_stack_clear()
{
mnu_stack_index = 0;
mnu_stack[0] = emnu_Main;
}
//--------------------------------------------------------------------------------------------
// The implementation of the menu process
//--------------------------------------------------------------------------------------------
int do_menu_proc_begin( menu_process_t * mproc )
{
// play some music
sound_play_song( MENU_SONG, 0, -1 );
// initialize all these structures
menu_system_begin(); // start the menu menu
// load all module info at menu initialization
// this will not change unless a new module is downloaded for a network menu?
mnu_load_all_module_info();
// initialize the process state
mproc->base.valid = btrue;
return 1;
}
//--------------------------------------------------------------------------------------------
int do_menu_proc_running( menu_process_t * mproc )
{
int menuResult;
if ( !process_validate( PROC_PBASE( mproc ) ) ) return -1;
mproc->was_active = mproc->base.valid;
if ( mproc->base.paused ) return 0;
// play the menu music
mnu_draw_background = !process_running( PROC_PBASE( GProc ) );
menuResult = game_do_menu( mproc );
switch ( menuResult )
{
case MENU_SELECT:
// go ahead and start the game
process_pause( PROC_PBASE( mproc ) );
break;
case MENU_QUIT:
// the user selected "quit"
process_kill( PROC_PBASE( mproc ) );
break;
}
if ( mnu_get_menu_depth() <= GProc->menu_depth )
{
GProc->menu_depth = -1;
GProc->escape_latch = bfalse;
// We have exited the menu and restarted the game
GProc->mod_paused = bfalse;
process_pause( PROC_PBASE( MProc ) );
}
return 0;
}
//--------------------------------------------------------------------------------------------
int do_menu_proc_leaving( menu_process_t * mproc )
{
if ( !process_validate( PROC_PBASE( mproc ) ) ) return -1;
// terminate the menu system
menu_system_end();
// finish the menu song
sound_finish_song( 500 );
return 1;
}
//--------------------------------------------------------------------------------------------
int do_menu_proc_run( menu_process_t * mproc, double frameDuration )
{
int result = 0, proc_result = 0;
if ( !process_validate( PROC_PBASE( mproc ) ) ) return -1;
mproc->base.dtime = frameDuration;
if ( mproc->base.paused ) return 0;
if ( mproc->base.killme )
{
mproc->base.state = proc_leaving;
}
switch ( mproc->base.state )
{
case proc_begin:
proc_result = do_menu_proc_begin( mproc );
if ( 1 == proc_result )
{
mproc->base.state = proc_entering;
}
break;
case proc_entering:
// proc_result = do_menu_proc_entering( mproc );
mproc->base.state = proc_running;
break;
case proc_running:
proc_result = do_menu_proc_running( mproc );
if ( 1 == proc_result )
{
mproc->base.state = proc_leaving;
}
break;
case proc_leaving:
proc_result = do_menu_proc_leaving( mproc );
if ( 1 == proc_result )
{
mproc->base.state = proc_finish;
mproc->base.killme = bfalse;
}
break;
case proc_finish:
process_terminate( PROC_PBASE( mproc ) );
break;
default:
case proc_invalid:
break;
}
return result;
}
//--------------------------------------------------------------------------------------------
menu_process_t * menu_process_init( menu_process_t * mproc )
{
if ( NULL == mproc ) return NULL;
memset( mproc, 0, sizeof( *mproc ) );
process_init( PROC_PBASE( mproc ) );
return mproc;
}
//--------------------------------------------------------------------------------------------
// Code for global initialization/deinitialization of the menu system
//--------------------------------------------------------------------------------------------
int menu_system_begin()
{
// initializes the menu system
//
// Loads resources for the menus, and figures out where things should
// be positioned. If we ever allow changing resolution on the fly, this
// function will have to be updated/called more than once.
autoformat_init( &gfx );
menuFont = ui_loadFont( vfs_resolveReadFilename( "mp_data/font.ttf" ), 18 );
if ( NULL == menuFont )
{
log_error( "Could not load the menu font! (\"mp_data/font.ttf\")\n" );
return 0;
}
// Figure out where to draw the copyright text
copyrightText_set_position( menuFont, copyrightText, 20 );
// Figure out where to draw the options text
tipText_set_position( menuFont, tipText, 20 );
// construct the TxTitleImage array
TxTitleImage_ctor();
// Load game hints
mnu_GameTip_load_global_vfs();
return 1;
}
//--------------------------------------------------------------------------------------------
void menu_system_end()
{
// initializes the menu system
//
// Loads resources for the menus, and figures out where things should
// be positioned. If we ever allow changing resolution on the fly, this
// function will have to be updated/called more than once.
if ( NULL != menuFont )
{
fnt_freeFont( menuFont );
menuFont = NULL;
}
// destruct the TxTitleImage array
TxTitleImage_dtor();
}
//--------------------------------------------------------------------------------------------
// Interface for starting and stopping menus
//--------------------------------------------------------------------------------------------
bool_t mnu_begin_menu( which_menu_t which )
{
if ( !mnu_stack_push( mnu_whichMenu ) ) return bfalse;
mnu_whichMenu = which;
return btrue;
}
//--------------------------------------------------------------------------------------------
void mnu_end_menu()
{
mnu_whichMenu = mnu_stack_pop();
}
//--------------------------------------------------------------------------------------------
int mnu_get_menu_depth()
{
return mnu_stack_index;
}
//--------------------------------------------------------------------------------------------
// Implementations of the various menus
//--------------------------------------------------------------------------------------------
int doMainMenu( float deltaTime )
{
static int menuState = MM_Begin;
static oglx_texture_t background;
static oglx_texture_t logo;
// static float lerp;
static int menuChoice = 0;
static SDL_Rect bg_rect, logo_rect;
/* Button labels. Defined here for consistency's sake, rather than leaving them as constants */
static const char *sz_buttons[] =
{
"New Game",
"Load Game",
"Options",
"Quit",
""
};
float fminw = 1, fminh = 1, fmin = 1;
int result = 0;
switch ( menuState )
{
case MM_Begin:
menuChoice = 0;
menuState = MM_Entering;
// load the menu image
ego_texture_load_vfs( &background, "mp_data/menu/menu_main", INVALID_KEY );
// load the logo image
ego_texture_load_vfs( &logo, "mp_data/menu/menu_logo", INVALID_KEY );
// calculate the centered position of the background
fminw = ( float ) MIN( GFX_WIDTH , background.imgW ) / ( float ) background.imgW;
fminh = ( float ) MIN( GFX_HEIGHT, background.imgH ) / ( float ) background.imgW;
fmin = MIN( fminw, fminh );
bg_rect.w = background.imgW * fmin;
bg_rect.h = background.imgH * fmin;
bg_rect.x = ( GFX_WIDTH - bg_rect.w ) * 0.5f;
bg_rect.y = ( GFX_HEIGHT - bg_rect.h ) * 0.5f;
// calculate the position of the logo
fmin = MIN( bg_rect.w * 0.5f / logo.imgW, bg_rect.h * 0.5f / logo.imgH );
logo_rect.x = bg_rect.x;
logo_rect.y = bg_rect.y;
logo_rect.w = logo.imgW * fmin;
logo_rect.h = logo.imgH * fmin;
mnu_SlidyButton_init( 1.0f, sz_buttons );
// let this fall through into MM_Entering
case MM_Entering:
// do buttons sliding in animation, and background fading in
// background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, bg_rect.x, bg_rect.y, bg_rect.w, bg_rect.h, NULL );
ui_drawImage( 0, &logo, logo_rect.x, logo_rect.y, logo_rect.w, logo_rect.h, NULL );
}
// "Copyright" text
ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( -deltaTime );
// Let lerp wind down relative to the time elapsed
if ( mnu_SlidyButtonState.lerp <= 0.0f )
{
menuState = MM_Running;
}
break;
case MM_Running:
// Do normal run
// Background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, bg_rect.x, bg_rect.y, bg_rect.w, bg_rect.h, NULL );
ui_drawImage( 0, &logo, logo_rect.x, logo_rect.y, logo_rect.w, logo_rect.h, NULL );
}
// "Copyright" text
ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
// Buttons
if ( BUTTON_UP == ui_doButton( 1, sz_buttons[0], NULL, buttonLeft, buttonTop, 200, 30 ) )
{
// begin single player stuff
menuChoice = 1;
}
if ( BUTTON_UP == ui_doButton( 2, sz_buttons[1], NULL, buttonLeft, buttonTop + 35, 200, 30 ) )
{
// begin multi player stuff
menuChoice = 2;
}
if ( BUTTON_UP == ui_doButton( 3, sz_buttons[2], NULL, buttonLeft, buttonTop + 35 * 2, 200, 30 ) )
{
// go to options menu
menuChoice = 3;
}
if ( SDLKEYDOWN( SDLK_ESCAPE ) || BUTTON_UP == ui_doButton( 4, sz_buttons[3], NULL, buttonLeft, buttonTop + 35 * 3, 200, 30 ) )
{
// quit game
menuChoice = 4;
}
if ( menuChoice != 0 )
{
menuState = MM_Leaving;
mnu_SlidyButton_init( 0.0f, sz_buttons );
}
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, bg_rect.x, bg_rect.y, bg_rect.w, bg_rect.h, NULL );
ui_drawImage( 0, &logo, logo_rect.x, logo_rect.y, logo_rect.w, logo_rect.h, NULL );
}
// "Copyright" text
ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
// Buttons
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( deltaTime );
if ( mnu_SlidyButtonState.lerp >= 1.0f )
{
menuState = MM_Finish;
}
break;
case MM_Finish:
// Free the background texture; don't need to hold onto it
oglx_texture_Release( &background );
menuState = MM_Begin; // Make sure this all resets next time
// reset the ui
ui_Reset();
// Set the next menu to load
result = menuChoice;
break;
};
return result;
}
//--------------------------------------------------------------------------------------------
int doSinglePlayerMenu( float deltaTime )
{
static int menuState = MM_Begin;
static oglx_texture_t background;
static int menuChoice;
static const char *sz_buttons[] =
{
"New Player",
"Load Saved Player",
"Back",
""
};
int result = 0;
switch ( menuState )
{
case MM_Begin:
// Load resources for this menu
ego_texture_load_vfs( &background, "mp_data/menu/menu_advent", TRANSCOLOR );
menuChoice = 0;
menuState = MM_Entering;
mnu_SlidyButton_init( 1.0f, sz_buttons );
// Let this fall through
case MM_Entering:
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
// Draw the background image
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, GFX_WIDTH - background.imgW, 0, 0, 0, NULL );
}
// "Copyright" text
ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( -deltaTime );
if ( mnu_SlidyButtonState.lerp <= 0.0f )
menuState = MM_Running;
break;
case MM_Running:
// Draw the background image
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, GFX_WIDTH - background.imgW, 0, 0, 0, NULL );
}
// "Copyright" text
ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
// Buttons
if ( BUTTON_UP == ui_doButton( 1, sz_buttons[0], NULL, buttonLeft, buttonTop, 200, 30 ) )
{
menuChoice = 1;
}
if ( BUTTON_UP == ui_doButton( 2, sz_buttons[1], NULL, buttonLeft, buttonTop + 35, 200, 30 ) )
{
menuChoice = 2;
}
if ( SDLKEYDOWN( SDLK_ESCAPE ) || BUTTON_UP == ui_doButton( 3, sz_buttons[2], NULL, buttonLeft, buttonTop + 35 * 2, 200, 30 ) )
{
menuChoice = 3; //back
}
if ( menuChoice != 0 )
{
menuState = MM_Leaving;
mnu_SlidyButton_init( 0.0f, sz_buttons );
}
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, GFX_WIDTH - background.imgW, 0, 0, 0, NULL);
}
// "Copyright" text
ui_drawTextBox( menuFont, copyrightText, copyrightLeft, copyrightTop, 0, 0, 20 );
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( deltaTime );
if ( mnu_SlidyButtonState.lerp >= 1.0f )
{
menuState = MM_Finish;
}
break;
case MM_Finish:
// Release the background texture
oglx_texture_Release( &background );
// reset the ui
ui_Reset();
// Set the next menu to load
result = menuChoice;
// And make sure that if we come back to this menu, it resets
// properly
menuState = MM_Begin;
}
return result;
}
//--------------------------------------------------------------------------------------------
static int cmp_mod_ref_mult = 1;
int cmp_mod_ref(const void * vref1, const void * vref2)
{
/// @details BB@> Sort MOD REF values based on the rank of the module that they point to.
/// Trap all stupid values.
MOD_REF * pref1 = (MOD_REF * )vref1;
MOD_REF * pref2 = (MOD_REF * )vref2;
int retval = 0;
if( NULL == pref1 && NULL == pref2 )
{
return 0;
}
else if( NULL == pref1 )
{
return 1;
}
else if ( NULL == pref2 )
{
return -1;
}
if( *pref1 > mnu_ModList.count && *pref2 > mnu_ModList.count )
{
return 0;
}
else if( *pref1 > mnu_ModList.count )
{
return 1;
}
else if ( *pref2 > mnu_ModList.count )
{
return -1;
}
// if they are beaten, float them to the end of the list
retval = (int)mnu_ModList.lst[*pref1].base.beaten - (int)mnu_ModList.lst[*pref2].base.beaten;
if( 0 == retval )
{
// I want to uot the "newest" == "hardest" modules at the front, but this should be opposite for
// beginner modules
retval = cmp_mod_ref_mult * strncmp(mnu_ModList.lst[*pref1].base.rank, mnu_ModList.lst[*pref2].base.rank, RANKSIZE );
}
if( 0 == retval )
{
retval = strncmp(mnu_ModList.lst[*pref1].base.longname, mnu_ModList.lst[*pref2].base.longname, sizeof(STRING) );
}
return retval;
}
//--------------------------------------------------------------------------------------------
int doChooseModule( float deltaTime )
{
/// @details Choose the module
static oglx_texture_t background;
static int menuState = MM_Begin;
static int startIndex;
static Uint8 keycooldown;
static char* filterText = "All Modules";
static int numValidModules;
static MOD_REF validModules[MAX_MODULE];
static int moduleMenuOffsetX;
static int moduleMenuOffsetY;
int result = 0;
int i, x, y;
MOD_REF imod;
switch ( menuState )
{
case MM_Begin:
if( !module_list_valid )
{
mnu_load_all_module_info();
}
// Reload all modules, something might be unlocked
mnu_load_all_module_images_vfs();
// Reset which module we are selecting
startIndex = 0;
selectedModule = -1;
// blank out the valid modules
numValidModules = 0;
for ( i = 0; i < MAX_MODULE; i++ )
{
memset( validModules + i, 0, sizeof( MOD_REF ) );
}
// Figure out at what offset we want to draw the module menu.
moduleMenuOffsetX = ( GFX_WIDTH - 640 ) / 2;
moduleMenuOffsetX = MAX(0,moduleMenuOffsetX);
moduleMenuOffsetY = ( GFX_HEIGHT - 480 ) / 2;
moduleMenuOffsetY = MAX(0,moduleMenuOffsetY);
menuState = MM_Entering;
// fall through...
case MM_Entering:
menuState = MM_Running;
if( !module_list_valid )
{
mnu_load_all_module_info();
mnu_load_all_module_images_vfs();
}
// Find the modules that we want to allow loading for. If start_new_player
// is true, we want ones that don't allow imports (e.g. starter modules).
// Otherwise, we want modules that allow imports
numValidModules = 0;
for ( imod = 0; imod < mnu_ModList.count; imod++ )
{
// if this module is not valid given the game options and the
// selected players, skip it
if ( !mnu_test_by_index( imod, 0, NULL ) ) continue;
if ( start_new_player && 0 == mnu_ModList.lst[imod].base.importamount )
{
// starter module
validModules[numValidModules] = REF_TO_INT( imod );
numValidModules++;
}
else
{
if ( FILTER_OFF != mnu_moduleFilter && mnu_ModList.lst[imod].base.moduletype != mnu_moduleFilter ) continue;
if ( mnu_selectedPlayerCount > mnu_ModList.lst[imod].base.importamount ) continue;
if ( mnu_selectedPlayerCount < mnu_ModList.lst[imod].base.minplayers ) continue;
if ( mnu_selectedPlayerCount > mnu_ModList.lst[imod].base.maxplayers ) continue;
// regular module
validModules[numValidModules] = REF_TO_INT( imod );
numValidModules++;
}
}
// sort the modules by difficulty. easiest to hardeest for starting a new character
// hardest to easiest for loading a module
cmp_mod_ref_mult = start_new_player ? 1 : -1;
qsort( validModules, numValidModules, sizeof(MOD_REF), cmp_mod_ref );
// load background depending on current filter
if( start_new_player )
{
ego_texture_load_vfs( &background, "mp_data/menu/menu_advent", TRANSCOLOR );
}
else switch( mnu_moduleFilter )
{
case FILTER_MAIN: ego_texture_load_vfs( &background, "mp_data/menu/menu_draco", TRANSCOLOR ); break;
case FILTER_SIDE: ego_texture_load_vfs( &background, "mp_data/menu/menu_sidequest", TRANSCOLOR ); break;
case FILTER_TOWN: ego_texture_load_vfs( &background, "mp_data/menu/menu_town", TRANSCOLOR ); break;
case FILTER_FUN: ego_texture_load_vfs( &background, "mp_data/menu/menu_funquest", TRANSCOLOR ); break;
default:
case FILTER_OFF: ego_texture_load_vfs( &background, "mp_data/menu/menu_allquest", TRANSCOLOR ); break;
}
// set the tip text
if ( 0 == numValidModules )
{
tipText_set_position( menuFont, "Sorry, there are no valid games!\n Please press the \"Back\" button.", 20 );
}
else if ( numValidModules <= 3 )
{
tipText_set_position( menuFont, "Press an icon to select a game.", 20 );
}
else
{
tipText_set_position( menuFont, "Press an icon to select a game.\nUse the mouse wheel or the \"<-\" and \"->\" buttons to scroll.", 20 );
}
// fall through for now...
case MM_Running:
{
GLXvector4f beat_tint = { 0.5f, 0.25f, 0.25f, 1.0f };
GLXvector4f normal_tint = { 1.0f, 1.0f, 1.0f, 1.0f };
if( !module_list_valid )
{
mnu_load_all_module_info();
mnu_load_all_module_images_vfs();
}
// Draw the background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
x = ( GFX_WIDTH / 2 ) - ( background.imgW / 2 );
y = GFX_HEIGHT - background.imgH;
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, x, y, 0, 0, NULL );
}
// use the mouse wheel to scan the modules
if ( cursor_wheel_event_pending() )
{
if ( cursor.z > 0 )
{
startIndex++;
}
else if ( cursor.z < 0 )
{
startIndex--;
}
cursor_finish_wheel_event();
}
//Allow arrow keys to scroll as well
if ( SDLKEYDOWN( SDLK_RIGHT ) )
{
if ( keycooldown == 0 )
{
startIndex++;
keycooldown = 5;
}
}
else if ( SDLKEYDOWN( SDLK_LEFT ) )
{
if ( keycooldown == 0 )
{
startIndex--;
keycooldown = 5;
}
}
else keycooldown = 0;
if ( keycooldown > 0 ) keycooldown--;
// Draw the arrows to pick modules
if ( numValidModules > 3 )
{
if ( BUTTON_UP == ui_doButton( 1051, "<-", NULL, moduleMenuOffsetX + 20, moduleMenuOffsetY + 74, 30, 30 ) )
{
startIndex--;
}
if ( BUTTON_UP == ui_doButton( 1052, "->", NULL, moduleMenuOffsetX + 590, moduleMenuOffsetY + 74, 30, 30 ) )
{
startIndex++;
}
}
// restrict the range to valid values
startIndex = CLIP( startIndex, 0, numValidModules - 3 );
// Draw buttons for the modules that can be selected
x = 93;
y = 20;
for ( i = startIndex; i < MIN(startIndex + 3, numValidModules); i++ )
{
// fix the menu images in case one or more of them are undefined
MOD_REF imod = validModules[i];
TX_REF tex_offset = mnu_ModList.lst[imod].tex_index;
oglx_texture_t * ptex = TxTitleImage_get_ptr( tex_offset );
GLfloat * img_tint = normal_tint;
if( mnu_ModList.lst[imod].base.beaten )
{
img_tint = beat_tint;
}
if ( ui_doImageButton( i, ptex, moduleMenuOffsetX + x, moduleMenuOffsetY + y, 138, 138, img_tint ) )
{
selectedModule = i;
}
//Draw a text over the image explaining what it means
if( mnu_ModList.lst[imod].base.beaten )
{
ui_drawTextBox( NULL, "BEATEN", moduleMenuOffsetX + x + 32, moduleMenuOffsetY + y + 64, 64, 30, 20 );
}
x += 138 + 20; // Width of the button, and the spacing between buttons
}
// Draw an empty button as the backdrop for the module text
ui_drawButton( UI_Nothing, moduleMenuOffsetX + 21, moduleMenuOffsetY + 173, 291, 250, NULL );
// Draw the text description of the selected module
if ( selectedModule > -1 && selectedModule < MAX_MODULE && validModules[selectedModule] >= 0 )
{
char buffer[1024] = EMPTY_CSTR;
const char * rank_string, * name_string;
char * carat = buffer, * carat_end = buffer + SDL_arraysize( buffer );
MOD_REF imodule = validModules[selectedModule];
mod_file_t * pmod = &(mnu_ModList.lst[imodule].base);
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
name_string = "Unnamed";
if( CSTR_END != pmod->longname[0] )
{
name_string = pmod->longname;
}
carat += snprintf( carat, carat_end - carat - 1, "%s\n", name_string );
rank_string = "Unranked";
if( CSTR_END != pmod->rank[0] )
{
rank_string = pmod->rank;
}
carat += snprintf( carat, carat_end - carat - 1, "Difficulty: %s\n", rank_string );
if ( pmod->maxplayers > 1 )
{
if ( pmod->minplayers == pmod->maxplayers )
{
carat += snprintf( carat, carat_end - carat - 1, "%d Players\n", pmod->minplayers );
}
else
{
carat += snprintf( carat, carat_end - carat - 1, "%d - %d Players\n", pmod->minplayers, pmod->maxplayers );
}
}
else
{
if ( 0 != pmod->importamount )
{
carat += snprintf( carat, carat_end - carat - 1, "Single Player\n" );
}
else
{
carat += snprintf( carat, carat_end - carat - 1, "Starter Module\n" );
}
}
carat += snprintf( carat, carat_end - carat - 1, " \n" );
for ( i = 0; i < SUMMARYLINES; i++ )
{
carat += snprintf( carat, carat_end - carat - 1, "%s\n", pmod->summary[i] );
}
// Draw a text box
ui_drawTextBox( menuFont, buffer, moduleMenuOffsetX + 21, moduleMenuOffsetY + 173, 291, 230, 20 );
}
// And draw the next & back buttons
if ( selectedModule > -1 )
{
if ( SDLKEYDOWN( SDLK_RETURN ) || BUTTON_UP == ui_doButton( 53, "Select Module", NULL, moduleMenuOffsetX + 327, moduleMenuOffsetY + 173, 200, 30 ) )
{
// go to the next menu with this module selected
selectedModule = REF_TO_INT( validModules[selectedModule] );
menuState = MM_Leaving;
}
}
if ( SDLKEYDOWN( SDLK_ESCAPE ) || BUTTON_UP == ui_doButton( 54, "Back", NULL, moduleMenuOffsetX + 327, moduleMenuOffsetY + 208, 200, 30 ) )
{
// Signal doMenu to go back to the previous menu
selectedModule = -1;
menuState = MM_Leaving;
}
//Do the module filter button
if ( !start_new_player )
{
bool_t click_button;
// unly display the filter name
ui_doButton( 55, filterText, NULL, moduleMenuOffsetX + 327, moduleMenuOffsetY + 390, 200, 30 );
// use the ">" button to change since we are already using arrows to indicate "spin control"-like widgets
click_button = (BUTTON_UP == ui_doButton( 56, ">", NULL, moduleMenuOffsetX + 532, moduleMenuOffsetY + 390, 30, 30 ) );
if( click_button )
{
//Reload the modules with the new filter
menuState = MM_Entering;
//Swap to the next filter
mnu_moduleFilter = CLIP(mnu_moduleFilter, FILTER_NORMAL_BEGIN, FILTER_NORMAL_END);
mnu_moduleFilter++;
if( mnu_moduleFilter > FILTER_NORMAL_END ) mnu_moduleFilter = FILTER_NORMAL_BEGIN;
switch( mnu_moduleFilter )
{
case FILTER_MAIN: filterText = "Main Quest"; break;
case FILTER_SIDE: filterText = "Sidequests"; break;
case FILTER_TOWN: filterText = "Towns and Cities"; break;
case FILTER_FUN: filterText = "Fun Modules"; break;
case FILTER_STARTER: filterText = "Starter Modules"; break;
default: case FILTER_OFF: filterText = "All Modules"; break;
}
}
}
// the tool-tip text
GL_DEBUG( glColor4f ) ( 1, 1, 1, 1 );
ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
}
break;
case MM_Leaving:
menuState = MM_Finish;
// fall through for now
case MM_Finish:
oglx_texture_Release( &background );
pickedmodule_index = -1;
pickedmodule_path[0] = CSTR_END;
pickedmodule_name[0] = CSTR_END;
pickedmodule_write_path[0] = CSTR_END;
menuState = MM_Begin;
if ( selectedModule == -1 )
{
result = -1;
}
else
{
// Save the name of the module that we've picked
pickedmodule_index = selectedModule;
strncpy( pickedmodule_path, mnu_ModList_get_vfs_path ( pickedmodule_index ), SDL_arraysize( pickedmodule_path ) );
strncpy( pickedmodule_name, mnu_ModList_get_name ( pickedmodule_index ), SDL_arraysize( pickedmodule_name ) );
strncpy( pickedmodule_write_path, mnu_ModList_get_dest_path( pickedmodule_index ), SDL_arraysize( pickedmodule_write_path ) );
if ( !game_choose_module( selectedModule, -1 ) )
{
log_warning( "Tried to select an invalid module. index == %d\n", selectedModule );
result = -1;
}
else
{
pickedmodule_ready = btrue;
result = ( PMod->importamount > 0 ) ? 1 : 2;
}
}
// reset the ui
ui_Reset();
break;
}
return result;
}
//--------------------------------------------------------------------------------------------
bool_t doChoosePlayer_load_profiles( int player, ChoosePlayer_profiles_t * pro_list )
{
int i;
CAP_REF ref_temp;
STRING szFilename;
ChoosePlayer_element_t * pdata;
// release all of the temporary profiles
release_all_profiles();
overrideslots = btrue;
if ( 0 == bookicon_count )
{
load_one_profile_vfs( "mp_data/globalobjects/book.obj", SPELLBOOK );
}
// release any data that we have accumulated
for ( i = 0; i < pro_list->count; i++ )
{
pdata = pro_list->pro_data + i;
TxTexture_free_one( pdata->tx_ref );
// initialize the data
pdata->cap_ref = MAX_CAP;
pdata->tx_ref = INVALID_TX_TEXTURE;
chop_definition_init( &( pdata->chop ) );
}
pro_list->count = 0;
if ( player < 0 || player >= MAXLOADPLAYER || player >= loadplayer_count ) return bfalse;
// grab the player data
ref_temp = load_one_character_profile_vfs( loadplayer[player].dir, 0, bfalse );
if ( !LOADED_CAP( ref_temp ) )
{
return bfalse;
}
// go to the next element in the list
pdata = pro_list->pro_data + pro_list->count;
pro_list->count++;
// set the index of this object
pdata->cap_ref = ref_temp;
// grab the inventory data
for ( i = 0; i < MAXIMPORTOBJECTS; i++ )
{
int slot = i + 1;
snprintf( szFilename, SDL_arraysize( szFilename ), "%s/%d.obj", loadplayer[player].dir, i );
// load the profile
ref_temp = load_one_character_profile_vfs( szFilename, slot, bfalse );
if ( LOADED_CAP( ref_temp ) )
{
cap_t * pcap = CapStack.lst + ref_temp;
// go to the next element in the list
pdata = pro_list->pro_data + pro_list->count;
pro_list->count++;
pdata->cap_ref = ref_temp;
// load the icon
snprintf( szFilename, SDL_arraysize( szFilename ), "%s/%d.obj/icon%d", loadplayer[player].dir, i, MAX( 0, pcap->skin_override ) );
pdata->tx_ref = TxTexture_load_one_vfs( szFilename, ( TX_REF )INVALID_TX_TEXTURE, INVALID_KEY );
// load the naming
snprintf( szFilename, SDL_arraysize( szFilename ), "%s/%d.obj/naming.txt", loadplayer[player].dir, i );
chop_load_vfs( &chop_mem, szFilename, &( pdata->chop ) );
}
}
return btrue;
}
//--------------------------------------------------------------------------------------------
bool_t doChoosePlayer_show_stats( int player, int mode, int x, int y, int width, int height )
{
int i, x1, y1;
static ChoosePlayer_profiles_t objects = { 0 };
if ( player < 0 ) mode = 1;
// handle the profile data
switch ( mode )
{
case 0: // load new player data
if ( !doChoosePlayer_load_profiles( player, &objects ) )
{
player = -1;
}
break;
case 1: // unload player data
player = -1;
objects.count = 0;
// release all of the temporary profiles
release_all_profiles();
break;
}
// do the actual display
x1 = x + 25;
y1 = y + 25;
if ( player >= 0 && objects.count > 0 )
{
CAP_REF icap = objects.pro_data[0].cap_ref;
if ( LOADED_CAP( icap ) )
{
cap_t * pcap = CapStack.lst + icap;
Uint8 skin = MAX( 0, pcap->skin_override );
ui_drawButton( UI_Nothing, x, y, width, height, NULL );
//Character level and class
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
// fix class name capitalization
pcap->classname[0] = toupper( pcap->classname[0] );
fnt_drawText( menuFont, NULL, x1, y1, "A level %d %s", pcap->level_override + 1, pcap->classname );
y1 += 20;
// Armor
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
fnt_drawText( menuFont, NULL, x1, y1, "Wearing %s %s", pcap->skinname[skin], HAS_SOME_BITS( pcap->skindressy, 1 << skin ) ? "(Light)" : "(Heavy)" );
y1 += 40;
// Life and mana (can be less than maximum if not in easy mode)
if ( cfg.difficulty >= GAME_NORMAL )
{
fnt_drawText( menuFont, NULL, x1, y1, "Life: %d/%d", MIN( FP8_TO_INT( pcap->life_spawn ), ( int )pcap->life_stat.val.from ), ( int )pcap->life_stat.val.from ); y1 += 20;
y1 = draw_one_bar( pcap->lifecolor, x1, y1, FP8_TO_INT( pcap->life_spawn ), ( int )pcap->life_stat.val.from );
if ( pcap->mana_stat.val.from > 0 )
{
fnt_drawText( menuFont, NULL, x1, y1, "Mana: %d/%d", MIN( FP8_TO_INT( pcap->mana_spawn ), ( int )pcap->mana_stat.val.from ), ( int )pcap->mana_stat.val.from ); y1 += 20;
y1 = draw_one_bar( pcap->manacolor, x1, y1, FP8_TO_INT( pcap->mana_spawn ), ( int )pcap->mana_stat.val.from );
}
}
else
{
fnt_drawText( menuFont, NULL, x1, y1, "Life: %d", ( int )pcap->life_stat.val.from ); y1 += 20;
y1 = draw_one_bar( pcap->lifecolor, x1, y1, ( int )pcap->life_stat.val.from, ( int )pcap->life_stat.val.from );
if ( pcap->mana_stat.val.from > 0 )
{
fnt_drawText( menuFont, NULL, x1, y1, "Mana: %d", ( int )pcap->mana_stat.val.from ); y1 += 20;
y1 = draw_one_bar( pcap->manacolor, x1, y1, ( int )pcap->mana_stat.val.from, ( int )pcap->mana_stat.val.from );
}
}
y1 += 20;
//SWID
fnt_drawText( menuFont, NULL, x1, y1, "Stats" ); y1 += 20;
fnt_drawText( menuFont, NULL, x1, y1, " Str: %s (%d)", describe_value( pcap->strength_stat.val.from, 60, NULL ), ( int )pcap->strength_stat.val.from ); y1 += 20;
fnt_drawText( menuFont, NULL, x1, y1, " Wis: %s (%d)", describe_value( pcap->wisdom_stat.val.from, 60, NULL ), ( int )pcap->wisdom_stat.val.from ); y1 += 20;
fnt_drawText( menuFont, NULL, x1, y1, " Int: %s (%d)", describe_value( pcap->intelligence_stat.val.from, 60, NULL ), ( int )pcap->intelligence_stat.val.from ); y1 += 20;
fnt_drawText( menuFont, NULL, x1, y1, " Dex: %s (%d)", describe_value( pcap->dexterity_stat.val.from, 60, NULL ), ( int )pcap->dexterity_stat.val.from ); y1 += 20;
y1 += 20;
if ( objects.count > 1 )
{
ChoosePlayer_element_t * pdata;
fnt_drawText( menuFont, NULL, x1, y1, "Inventory" ); y1 += 20;
for ( i = 1; i < objects.count; i++ )
{
pdata = objects.pro_data + i;
icap = pdata->cap_ref;
if ( LOADED_CAP( icap ) )
{
TX_REF icon_ref;
cap_t * pcap = CapStack.lst + icap;
STRING itemname;
if ( pcap->nameknown ) strncpy( itemname, chop_create( &chop_mem, &( pdata->chop ) ), SDL_arraysize( itemname ) );
else strncpy( itemname, pcap->classname, SDL_arraysize( itemname ) );
icon_ref = mnu_get_icon_ref( icap, pdata->tx_ref );
draw_one_icon( icon_ref, x1, y1, NOSPARKLE );
if ( icap == SLOT_LEFT + 1 )
{
fnt_drawText( menuFont, NULL, x1 + 32, y1 + 6, " Left: %s", itemname ); y1 += 32;
}
else if ( icap == SLOT_RIGHT + 1 )
{
fnt_drawText( menuFont, NULL, x1 + 32, y1 + 6, " Right: %s", itemname ); y1 += 32;
}
else
{
fnt_drawText( menuFont, NULL, x1 + 32, y1 + 6, " Item: %s", itemname ); y1 += 32;
}
}
}
}
}
}
return btrue;
}
//--------------------------------------------------------------------------------------------
int doChoosePlayer( float deltaTime )
{
static int menuState = MM_Begin;
static oglx_texture_t background;
int result = 0;
int i, j, x, y;
STRING srcDir, destDir;
static int startIndex = 0;
static int last_player = -1;
static bool_t new_player = bfalse;
const int x0 = 20, y0 = 20, icon_size = 42, text_width = 175, button_repeat = 47;
static int numVertical, numHorizontal;
static Uint32 BitsInput[4];
static bool_t device_on[4];
static const char * button_text[] = { "N/A", "Back", ""};
switch ( menuState )
{
case MM_Begin:
TxTexture_free_one(( TX_REF )TX_BARS );
mnu_selectedPlayerCount = 0;
mnu_selectedPlayer[0] = 0;
TxTexture_load_one_vfs( "mp_data/nullicon", ( TX_REF )ICON_NULL, INVALID_KEY );
TxTexture_load_one_vfs( "mp_data/keybicon", ( TX_REF )ICON_KEYB, INVALID_KEY );
BitsInput[0] = INPUT_BITS_KEYBOARD;
device_on[0] = keyb.on;
TxTexture_load_one_vfs( "mp_data/mousicon", ( TX_REF )ICON_MOUS, INVALID_KEY );
BitsInput[1] = INPUT_BITS_MOUSE;
device_on[1] = mous.on;
TxTexture_load_one_vfs( "mp_data/joyaicon", ( TX_REF )ICON_JOYA, INVALID_KEY );
BitsInput[2] = INPUT_BITS_JOYA;
device_on[2] = joy[0].on;
TxTexture_load_one_vfs( "mp_data/joybicon", ( TX_REF )ICON_JOYB, INVALID_KEY );
BitsInput[3] = INPUT_BITS_JOYB;
device_on[3] = joy[1].on;
ego_texture_load_vfs( &background, "mp_data/menu/menu_sleepy", TRANSCOLOR );
TxTexture_load_one_vfs( "mp_data/bars", ( TX_REF )TX_BARS, INVALID_KEY );
// load information for all the players that could be imported
mnu_player_check_import( "mp_players", btrue );
// reset button 0, or it will mess up the menu.
// must do it before mnu_SlidyButton_init()
button_text[0] = "N/A";
mnu_SlidyButton_init( 1.0f, button_text );
numVertical = ( buttonTop - y0 ) / button_repeat - 1;
numHorizontal = 1;
x = x0;
y = y0;
for ( i = 0; i < numVertical; i++ )
{
int m = i * 5;
ui_initWidget( mnu_widgetList + m, m, NULL, NULL, NULL, x, y, text_width, icon_size );
ui_widgetAddMask( mnu_widgetList + m, UI_BITS_CLICKED );
for ( j = 0, m++; j < 4; j++, m++ )
{
ui_initWidget( mnu_widgetList + m, m, menuFont, NULL, TxTexture_get_ptr(( TX_REF )( ICON_KEYB + j ) ), x + text_width + j*icon_size, y, icon_size, icon_size );
ui_widgetAddMask( mnu_widgetList + m, UI_BITS_CLICKED );
};
y += button_repeat;
};
if ( loadplayer_count < 10 )
{
tipText_set_position( menuFont, "Choose an input device to select your player(s)", 20 );
}
else
{
tipText_set_position( menuFont, "Choose an input device to select your player(s)\nUse the mouse wheel to scroll.", 20 );
}
menuState = MM_Entering;
// fall through
case MM_Entering:
/*GL_DEBUG(glColor4f)(1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( -deltaTime );
// Let lerp wind down relative to the time elapsed
if ( mnu_SlidyButtonState.lerp <= 0.0f )
{
menuState = MM_Running;
}*/
// Simply fall through
// menuState = MM_Running;
// break;
case MM_Running:
// Figure out how many players we can show without scrolling
if ( 0 == mnu_selectedPlayerCount )
{
button_text[0] = "";
}
else if ( 1 == mnu_selectedPlayerCount )
{
button_text[0] = "Select Player";
}
else
{
button_text[0] = "Select Players";
}
// Draw the background
x = ( GFX_WIDTH / 2 ) - ( background.imgW / 2 );
y = GFX_HEIGHT - background.imgH;
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, x, y, 0, 0, NULL );
}
// use the mouse wheel to scan the characters
if ( cursor_wheel_event_pending() )
{
if ( cursor.z > 0 )
{
if ( startIndex + numVertical < loadplayer_count )
{
startIndex++;
}
}
else if ( cursor.z < 0 )
{
if ( startIndex > 0 )
{
startIndex--;
}
}
cursor_finish_wheel_event();
}
// Draw the player selection buttons
x = x0;
y = y0;
for ( i = 0; i < numVertical; i++ )
{
int player;
int splayer;
int m = i * 5;
player = i + startIndex;
if ( player >= loadplayer_count ) continue;
splayer = mnu_Selected_get_loadplayer( player );
// do the character button
mnu_widgetList[m].img = TxTexture_get_ptr( loadplayer[player].tx_ref );
mnu_widgetList[m].text = loadplayer[player].name;
if ( INVALID_PLAYER != splayer )
{
SET_BIT( mnu_widgetList[m].state, UI_BITS_CLICKED);
}
else
{
UNSET_BIT( mnu_widgetList[m].state, UI_BITS_CLICKED);
}
if ( BUTTON_DOWN == ui_doWidget( mnu_widgetList + m ) )
{
if ( HAS_SOME_BITS( mnu_widgetList[m].state, UI_BITS_CLICKED ) && !mnu_Selected_check_loadplayer( player ) )
{
// button has become cursor_clicked
// mnu_Selected_add(player);
last_player = player;
new_player = btrue;
}
else if ( HAS_NO_BITS( mnu_widgetList[m].state, UI_BITS_CLICKED ) && mnu_Selected_check_loadplayer( player ) )
{
// button has become unclicked
if ( mnu_Selected_remove( player ) )
{
last_player = -1;
}
}
}
// do each of the input buttons
for ( j = 0, m++; j < 4; j++, m++ )
{
/// @note check for devices being turned on and off each time
/// technically we COULD recognize joysticks being inserted and removed while the
/// game is running but we don't. I will set this up to handle such future behavior
/// anyway :)
switch ( j )
{
case INPUT_DEVICE_KEYBOARD: device_on[j] = keyb.on; break;
case INPUT_DEVICE_MOUSE: device_on[j] = mous.on; break;
case INPUT_DEVICE_JOY_A: device_on[j] = joy[0].on; break;
case INPUT_DEVICE_JOY_B: device_on[j] = joy[1].on; break;
default: device_on[j] = bfalse;
}
// replace any not on device with a null icon
if ( !device_on[j] )
{
mnu_widgetList[m].img = TxTexture_get_ptr(( TX_REF )ICON_NULL );
// draw the widget, even though it will not do anything
// the menu would looks funny if odd columns missing
ui_doWidget( mnu_widgetList + m );
}
// make the button states reflect the chosen input devices
if ( INVALID_PLAYER == splayer || HAS_NO_BITS( mnu_selectedInput[ splayer ], BitsInput[j] ) )
{
UNSET_BIT( mnu_widgetList[m].state, UI_BITS_CLICKED );
}
else if ( HAS_SOME_BITS( mnu_selectedInput[splayer], BitsInput[j] ) )
{
SET_BIT( mnu_widgetList[m].state, UI_BITS_CLICKED );
}
if ( BUTTON_DOWN == ui_doWidget( mnu_widgetList + m ) )
{
if ( HAS_SOME_BITS( mnu_widgetList[m].state, UI_BITS_CLICKED ) )
{
// button has become cursor_clicked
if ( INVALID_PLAYER == splayer )
{
if ( mnu_Selected_add( player ) )
{
last_player = player;
new_player = btrue;
}
}
if ( mnu_Selected_add_input( player, BitsInput[j] ) )
{
last_player = player;
new_player = btrue;
}
}
else if ( INVALID_PLAYER != splayer && HAS_NO_BITS( mnu_widgetList[m].state, UI_BITS_CLICKED ) )
{
// button has become unclicked
if ( mnu_Selected_remove_input( player, BitsInput[j] ) )
{
last_player = -1;
}
}
}
}
}
// Buttons for going ahead
// Continue
if ( mnu_selectedPlayerCount != 0 )
{
if ( SDLKEYDOWN( SDLK_RETURN ) || BUTTON_UP == ui_doButton( 100, button_text[0], NULL, buttonLeft, buttonTop, 200, 30 ) )
{
menuState = MM_Leaving;
}
}
// Back
if ( SDLKEYDOWN( SDLK_ESCAPE ) || BUTTON_UP == ui_doButton( 101, button_text[1], NULL, buttonLeft, buttonTop + 35, 200, 30 ) )
{
mnu_selectedPlayerCount = 0;
menuState = MM_Leaving;
}
// show the stats
if ( -1 != last_player )
{
if ( new_player )
{
// load and display the new player data
new_player = bfalse;
doChoosePlayer_show_stats( last_player, 0, GFX_WIDTH - 400, 10, 350, GFX_HEIGHT - 60 );
}
else
{
// just display the new player data
doChoosePlayer_show_stats( last_player, 2, GFX_WIDTH - 400, 10, 350, GFX_HEIGHT - 60 );
}
}
else
{
doChoosePlayer_show_stats( last_player, 1, GFX_WIDTH - 100, 10, 100, GFX_HEIGHT - 60 );
}
// tool-tip text
ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
break;
case MM_Leaving:
/*
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
GL_DEBUG(glColor4f)(1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
// Buttons
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( deltaTime );
if ( mnu_SlidyButtonState.lerp >= 1.0f )
{
menuState = MM_Finish;
}
*/
// Simply fall through
// menuState = MM_Finish;
// break;
case MM_Finish:
// release all of the temporary profiles
doChoosePlayer_show_stats( -1, 1, 0, 0, 0, 0 );
oglx_texture_Release( &background );
TxTexture_free_one(( TX_REF )TX_BARS );
menuState = MM_Begin;
if ( 0 == mnu_selectedPlayerCount )
{
result = -1;
}
else
{
// Build the import directory
vfs_empty_import_directory();
if ( !vfs_mkdir( "import" ) )
{
log_warning( "game_update_imports() - Could not create the import folder. (%s)\n", vfs_getError() );
}
// set up the slots and the import stuff for the selected players
local_import_count = mnu_selectedPlayerCount;
for ( i = 0; i < local_import_count; i++ )
{
selectedPlayer = mnu_selectedPlayer[i];
local_import_control[i] = mnu_selectedInput[i];
local_import_slot[i] = i * MAXIMPORTPERPLAYER;
// Copy the character to the import directory
strncpy( srcDir, loadplayer[selectedPlayer].dir, SDL_arraysize( srcDir ) );
snprintf( destDir, SDL_arraysize( destDir ), "/import/temp%04d.obj", local_import_slot[i] );
vfs_copyDirectory( srcDir, destDir );
// Copy all of the character's items to the import directory
for ( j = 0; j < MAXIMPORTOBJECTS; j++ )
{
snprintf( srcDir, SDL_arraysize( srcDir ), "%s/%d.obj", loadplayer[selectedPlayer].dir, j );
// make sure the source directory exists
if ( vfs_isDirectory( srcDir ) )
{
snprintf( destDir, SDL_arraysize( destDir ), "/import/temp%04d.obj", local_import_slot[i] + j + 1 );
vfs_copyDirectory( srcDir, destDir );
}
}
}
result = 1;
}
// reset the ui
ui_Reset();
break;
}
return result;
}
//--------------------------------------------------------------------------------------------
int doOptions( float deltaTime )
{
static int menuState = MM_Begin;
static oglx_texture_t background;
static int menuChoice = 0;
static const char *sz_buttons[] =
{
"Game Options",
"Audio Options",
"Input Controls",
"Video Settings",
"Back",
""
};
int result = 0;
switch ( menuState )
{
case MM_Begin:
// set up menu variables
ego_texture_load_vfs( &background, "mp_data/menu/menu_gnome", TRANSCOLOR );
menuChoice = 0;
menuState = MM_Entering;
tipText_set_position( menuFont, "Change your audio, input and video\nsettings here.", 20 );
mnu_SlidyButton_init( 1.0f, sz_buttons );
// let this fall through into MM_Entering
case MM_Entering:
// do buttons sliding in animation, and background fading in
// background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
// Draw the background
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
}
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( -deltaTime );
// Let lerp wind down relative to the time elapsed
if ( mnu_SlidyButtonState.lerp <= 0.0f )
{
menuState = MM_Running;
}
break;
case MM_Running:
// Do normal run
// Background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
}
// "Options" text
ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
// Buttons
if ( BUTTON_UP == ui_doButton( 1, sz_buttons[0], NULL, buttonLeft, buttonTop, 200, 30 ) )
{
// game options
menuChoice = 5;
}
if ( BUTTON_UP == ui_doButton( 2, sz_buttons[1], NULL, buttonLeft, buttonTop + 35, 200, 30 ) )
{
// audio options
menuChoice = 1;
}
if ( BUTTON_UP == ui_doButton( 3, sz_buttons[2], NULL, buttonLeft, buttonTop + 35 * 2, 200, 30 ) )
{
// input options
menuChoice = 2;
}
if ( BUTTON_UP == ui_doButton( 4, sz_buttons[3], NULL, buttonLeft, buttonTop + 35 * 3, 200, 30 ) )
{
// video options
menuChoice = 3;
}
if ( SDLKEYDOWN( SDLK_ESCAPE ) || BUTTON_UP == ui_doButton( 5, sz_buttons[4], NULL, buttonLeft, buttonTop + 35 * 4, 200, 30 ) )
{
// back to main menu
menuChoice = 4;
}
if ( menuChoice != 0 )
{
menuState = MM_Leaving;
mnu_SlidyButton_init( 0.0f, sz_buttons );
}
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
}
// Buttons
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( deltaTime );
if ( mnu_SlidyButtonState.lerp >= 1.0f )
{
menuState = MM_Finish;
}
break;
case MM_Finish:
// Free the background texture; don't need to hold onto it
oglx_texture_Release( &background );
menuState = MM_Begin; // Make sure this all resets next time
// reset the ui
ui_Reset();
// Set the next menu to load
result = menuChoice;
break;
}
return result;
}
//--------------------------------------------------------------------------------------------
int doInputOptions( float deltaTime )
{
static int menuState = MM_Begin;
static int menuChoice = 0;
static int waitingforinput = -1;
static STRING inputOptionsButtons[CONTROL_COMMAND_COUNT + 2];
Sint8 result = 0;
static Sint32 player = 0;
Uint32 i;
Sint32 idevice, iicon;
device_controls_t * pdevice;
pdevice = NULL;
if ( player >= 0 && player < input_device_count )
{
pdevice = controls + player;
};
idevice = player;
if ( NULL == pdevice )
{
idevice = -1;
}
iicon = MIN( 4, idevice );
if ( idevice < 0 )
{
iicon = -1;
}
switch ( menuState )
{
case MM_Begin:
// set up menu variables
menuChoice = 0;
menuState = MM_Entering;
// let this fall through into MM_Entering
waitingforinput = -1;
for ( i = 0; i < CONTROL_COMMAND_COUNT; i++ )
{
inputOptionsButtons[i][0] = CSTR_END;
}
strncpy( inputOptionsButtons[i++], "Player 1", sizeof( STRING ) );
strncpy( inputOptionsButtons[i++], "Save Settings", sizeof( STRING ) );
tipText_set_position( menuFont, "Change input settings here.", 20 );
// Load the global icons (keyboard, mouse, etc.)
if ( !load_all_global_icons() ) log_warning( "Could not load all global icons!\n" );
case MM_Entering:
// do buttons sliding in animation, and background fading in
// background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
// Fall trough
menuState = MM_Running;
break;
case MM_Running:
// Do normal run
// Background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
ui_drawTextBox( menuFont, "ATK_LEFT HAND", buttonLeft, GFX_HEIGHT - 470, 0, 0, 20 );
// Are we waiting for input?
if ( SDLKEYDOWN( SDLK_ESCAPE ) ) waitingforinput = -1; // Someone pressed abort
// Grab the key/button input from the selected device
if ( waitingforinput != -1 )
{
if ( NULL == pdevice || idevice < 0 || idevice >= input_device_count )
{
waitingforinput = -1;
}
else
{
if ( waitingforinput >= pdevice->count )
{
// invalid input range for this device
waitingforinput = -1;
}
else
{
control_t * pcontrol;
int tag;
// make sure to update the input
input_read();
pcontrol = pdevice->control + waitingforinput;
if ( idevice >= INPUT_DEVICE_JOY )
{
int ijoy = idevice - INPUT_DEVICE_JOY;
if ( ijoy < MAXJOYSTICK )
{
for ( tag = 0; tag < scantag_count; tag++ )
{
if ( 0 != scantag[tag].value && ( Uint32 )scantag[tag].value == joy[ijoy].b )
{
pcontrol->tag = scantag[tag].value;
pcontrol->is_key = bfalse;
waitingforinput = -1;
}
}
for ( tag = 0; tag < scantag_count; tag++ )
{
if ( scantag[tag].value < SDLK_NUMLOCK && SDLKEYDOWN( scantag[tag].value ) )
{
pcontrol->tag = scantag[tag].value;
pcontrol->is_key = btrue;
waitingforinput = -1;
}
}
}
}
else
{
switch ( idevice )
{
case INPUT_DEVICE_KEYBOARD:
{
for ( tag = 0; tag < scantag_count; tag++ )
{
if ( scantag[tag].value < SDLK_NUMLOCK && SDLKEYDOWN( scantag[tag].value ) )
{
pcontrol->tag = scantag[tag].value;
pcontrol->is_key = btrue;
waitingforinput = -1;
}
}
}
break;
case INPUT_DEVICE_MOUSE:
{
for ( tag = 0; tag < scantag_count; tag++ )
{
if ( 0 != scantag[tag].value && ( Uint32 )scantag[tag].value == mous.b )
{
pcontrol->tag = scantag[tag].value;
pcontrol->is_key = bfalse;
waitingforinput = -1;
}
}
for ( tag = 0; tag < scantag_count; tag++ )
{
if ( scantag[tag].value < SDLK_NUMLOCK && SDLKEYDOWN( scantag[tag].value ) )
{
pcontrol->tag = scantag[tag].value;
pcontrol->is_key = btrue;
waitingforinput = -1;
}
}
}
break;
}
}
}
}
}
if ( NULL != pdevice && waitingforinput == -1 )
{
// update the control names
for ( i = CONTROL_BEGIN; i <= CONTROL_END && i < pdevice->count; i++ )
{
const char * tag = scantag_get_string( pdevice->device, pdevice->control[i].tag, pdevice->control[i].is_key );
strncpy( inputOptionsButtons[i], tag, sizeof( STRING ) );
}
for ( /* nothing */; i <= CONTROL_END ; i++ )
{
inputOptionsButtons[i][0] = CSTR_END;
}
}
// Left hand
if ( CSTR_END != inputOptionsButtons[CONTROL_LEFT_USE][0] )
{
ui_drawTextBox( menuFont, "Use:", buttonLeft, GFX_HEIGHT - 440, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 1, inputOptionsButtons[CONTROL_LEFT_USE], menuFont, buttonLeft + 100, GFX_HEIGHT - 440, 140, 30 ) )
{
waitingforinput = CONTROL_LEFT_USE;
strncpy( inputOptionsButtons[CONTROL_LEFT_USE], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_LEFT_GET][0] )
{
ui_drawTextBox( menuFont, "Get/Drop:", buttonLeft, GFX_HEIGHT - 410, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 2, inputOptionsButtons[CONTROL_LEFT_GET], menuFont, buttonLeft + 100, GFX_HEIGHT - 410, 140, 30 ) )
{
waitingforinput = CONTROL_LEFT_GET;
strncpy( inputOptionsButtons[CONTROL_LEFT_GET], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_LEFT_PACK][0] )
{
ui_drawTextBox( menuFont, "Inventory:", buttonLeft, GFX_HEIGHT - 380, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 3, inputOptionsButtons[CONTROL_LEFT_PACK], menuFont, buttonLeft + 100, GFX_HEIGHT - 380, 140, 30 ) )
{
waitingforinput = CONTROL_LEFT_PACK;
strncpy( inputOptionsButtons[CONTROL_LEFT_PACK], "...", sizeof( STRING ) );
}
}
// Right hand
ui_drawTextBox( menuFont, "ATK_RIGHT HAND", buttonLeft + 300, GFX_HEIGHT - 470, 0, 0, 20 );
if ( CSTR_END != inputOptionsButtons[CONTROL_RIGHT_USE][0] )
{
ui_drawTextBox( menuFont, "Use:", buttonLeft + 300, GFX_HEIGHT - 440, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 4, inputOptionsButtons[CONTROL_RIGHT_USE], menuFont, buttonLeft + 400, GFX_HEIGHT - 440, 140, 30 ) )
{
waitingforinput = CONTROL_RIGHT_USE;
strncpy( inputOptionsButtons[CONTROL_RIGHT_USE], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_RIGHT_GET][0] )
{
ui_drawTextBox( menuFont, "Get/Drop:", buttonLeft + 300, GFX_HEIGHT - 410, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 5, inputOptionsButtons[CONTROL_RIGHT_GET], menuFont, buttonLeft + 400, GFX_HEIGHT - 410, 140, 30 ) )
{
waitingforinput = CONTROL_RIGHT_GET;
strncpy( inputOptionsButtons[CONTROL_RIGHT_GET], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_RIGHT_PACK][0] )
{
ui_drawTextBox( menuFont, "Inventory:", buttonLeft + 300, GFX_HEIGHT - 380, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 6, inputOptionsButtons[CONTROL_RIGHT_PACK], menuFont, buttonLeft + 400, GFX_HEIGHT - 380, 140, 30 ) )
{
waitingforinput = CONTROL_RIGHT_PACK;
strncpy( inputOptionsButtons[CONTROL_RIGHT_PACK], "...", sizeof( STRING ) );
}
}
// Controls
ui_drawTextBox( menuFont, "CONTROLS", buttonLeft, GFX_HEIGHT - 320, 0, 0, 20 );
if ( CSTR_END != inputOptionsButtons[CONTROL_JUMP][0] )
{
ui_drawTextBox( menuFont, "Jump:", buttonLeft, GFX_HEIGHT - 290, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 7, inputOptionsButtons[CONTROL_JUMP], menuFont, buttonLeft + 100, GFX_HEIGHT - 290, 140, 30 ) )
{
waitingforinput = CONTROL_JUMP;
strncpy( inputOptionsButtons[CONTROL_JUMP], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_UP][0] )
{
ui_drawTextBox( menuFont, "Up:", buttonLeft, GFX_HEIGHT - 260, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 8, inputOptionsButtons[CONTROL_UP], menuFont, buttonLeft + 100, GFX_HEIGHT - 260, 140, 30 ) )
{
waitingforinput = CONTROL_UP;
strncpy( inputOptionsButtons[CONTROL_UP], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_DOWN][0] )
{
ui_drawTextBox( menuFont, "Down:", buttonLeft, GFX_HEIGHT - 230, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 9, inputOptionsButtons[CONTROL_DOWN], menuFont, buttonLeft + 100, GFX_HEIGHT - 230, 140, 30 ) )
{
waitingforinput = CONTROL_DOWN;
strncpy( inputOptionsButtons[CONTROL_DOWN], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_LEFT][0] )
{
ui_drawTextBox( menuFont, "Left:", buttonLeft, GFX_HEIGHT - 200, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 10, inputOptionsButtons[CONTROL_LEFT], menuFont, buttonLeft + 100, GFX_HEIGHT - 200, 140, 30 ) )
{
waitingforinput = CONTROL_LEFT;
strncpy( inputOptionsButtons[CONTROL_LEFT], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_RIGHT][0] )
{
ui_drawTextBox( menuFont, "Right:", buttonLeft, GFX_HEIGHT - 170, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 11, inputOptionsButtons[CONTROL_RIGHT], menuFont, buttonLeft + 100, GFX_HEIGHT - 170, 140, 30 ) )
{
waitingforinput = CONTROL_RIGHT;
strncpy( inputOptionsButtons[CONTROL_RIGHT], "...", sizeof( STRING ) );
}
}
// Controls
ui_drawTextBox( menuFont, "CAMERA CONTROL", buttonLeft + 300, GFX_HEIGHT - 320, 0, 0, 20 );
if ( CSTR_END != inputOptionsButtons[CONTROL_CAMERA_IN][0] )
{
ui_drawTextBox( menuFont, "Zoom In:", buttonLeft + 300, GFX_HEIGHT - 290, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 12, inputOptionsButtons[CONTROL_CAMERA_IN], menuFont, buttonLeft + 450, GFX_HEIGHT - 290, 140, 30 ) )
{
waitingforinput = CONTROL_CAMERA_IN;
strncpy( inputOptionsButtons[CONTROL_CAMERA_IN], "...", sizeof( STRING ) );
}
}
else
{
// single button camera control
ui_drawTextBox( menuFont, "Camera:", buttonLeft + 300, GFX_HEIGHT - 290, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 12, inputOptionsButtons[CONTROL_CAMERA], menuFont, buttonLeft + 450, GFX_HEIGHT - 290, 140, 30 ) )
{
waitingforinput = CONTROL_CAMERA;
strncpy( inputOptionsButtons[CONTROL_CAMERA], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_CAMERA_OUT][0] )
{
ui_drawTextBox( menuFont, "Zoom Out:", buttonLeft + 300, GFX_HEIGHT - 260, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 13, inputOptionsButtons[CONTROL_CAMERA_OUT], menuFont, buttonLeft + 450, GFX_HEIGHT - 260, 140, 30 ) )
{
waitingforinput = CONTROL_CAMERA_OUT;
strncpy( inputOptionsButtons[CONTROL_CAMERA_OUT], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_CAMERA_LEFT][0] )
{
ui_drawTextBox( menuFont, "Rotate Left:", buttonLeft + 300, GFX_HEIGHT - 230, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 14, inputOptionsButtons[CONTROL_CAMERA_LEFT], menuFont, buttonLeft + 450, GFX_HEIGHT - 230, 140, 30 ) )
{
waitingforinput = CONTROL_CAMERA_LEFT;
strncpy( inputOptionsButtons[CONTROL_CAMERA_LEFT], "...", sizeof( STRING ) );
}
}
if ( CSTR_END != inputOptionsButtons[CONTROL_CAMERA_RIGHT][0] )
{
ui_drawTextBox( menuFont, "Rotate Right:", buttonLeft + 300, GFX_HEIGHT - 200, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 15, inputOptionsButtons[CONTROL_CAMERA_RIGHT], menuFont, buttonLeft + 450, GFX_HEIGHT - 200, 140, 30 ) )
{
waitingforinput = CONTROL_CAMERA_RIGHT;
strncpy( inputOptionsButtons[CONTROL_CAMERA_RIGHT], "...", sizeof( STRING ) );
}
}
// The select player button
if ( iicon < 0 )
{
if ( BUTTON_UP == ui_doButton( 16, "Select Player...", NULL, buttonLeft + 300, GFX_HEIGHT - 90, 140, 50 ) )
{
player = 0;
}
}
else if ( BUTTON_UP == ui_doImageButtonWithText( 16, TxTexture_get_ptr(( TX_REF )( ICON_KEYB + iicon ) ), inputOptionsButtons[CONTROL_COMMAND_COUNT+0], menuFont, buttonLeft + 300, GFX_HEIGHT - 90, 140, 50 ) )
{
if ( input_device_count > 0 )
{
player++;
player %= input_device_count;
}
snprintf( inputOptionsButtons[CONTROL_COMMAND_COUNT+0], sizeof( STRING ), "Player %i", player + 1 );
}
// Save settings button
if ( BUTTON_UP == ui_doButton( 17, inputOptionsButtons[CONTROL_COMMAND_COUNT+1], menuFont, buttonLeft, GFX_HEIGHT - 60, 200, 30 ) )
{
// save settings and go back
player = 0;
input_settings_save_vfs( "controls.txt" );
menuState = MM_Leaving;
}
// tool-tip text
ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
// Fall trough
menuState = MM_Finish;
break;
case MM_Finish:
menuState = MM_Begin; // Make sure this all resets next time
// reset the ui
ui_Reset();
// Set the next menu to load
result = 1;
break;
}
return result;
}
//--------------------------------------------------------------------------------------------
int doGameOptions( float deltaTime )
{
/// @details Game options menu
static int menuState = MM_Begin;
static oglx_texture_t background;
static int menuChoice = 0;
static STRING Cdifficulty;
static STRING Cmaxmessage;
static const char *sz_buttons[] =
{
"N/A", // Difficulty
"N/A", // Max messages
"N/A", // Message duration
"N/A", // Autoturn camera
"N/A", // Show FPS
"N/A", // Feedback
"Save Settings",
""
};
char szDifficulty[4096] = EMPTY_CSTR;
int result = 0;
switch ( menuState )
{
case MM_Begin:
// set up menu variables
ego_texture_load_vfs( &background, "mp_data/menu/menu_fairy", TRANSCOLOR );
menuChoice = 0;
menuState = MM_Entering;
tipText_set_position( menuFont, "Change game settings here.", 20 );
mnu_SlidyButton_init( 1.0f, sz_buttons );
// let this fall through into MM_Entering
case MM_Entering:
// do buttons sliding in animation, and background fading in
// background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
// Draw the background
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH / 2 ) + ( background.imgW / 2 ), GFX_HEIGHT - background.imgH, 0, 0, NULL );
}
// Load the current settings
switch ( cfg.difficulty )
{
case GAME_HARD: snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Punishing" ); break;
case GAME_EASY: snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Forgiving" ); break;
default: cfg.difficulty = GAME_NORMAL; /* fall through */
case GAME_NORMAL: snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Challenging" ); break;
}
sz_buttons[0] = Cdifficulty;
maxmessage = CLIP( maxmessage, 4, MAX_MESSAGE );
if ( maxmessage == 0 )
{
snprintf( Cmaxmessage, SDL_arraysize( Cmaxmessage ), "None" ); // Set to default
}
else
{
snprintf( Cmaxmessage, SDL_arraysize( Cmaxmessage ), "%i", maxmessage );
}
sz_buttons[1] = Cmaxmessage;
// Message duration
if ( cfg.message_duration <= 100 )
{
sz_buttons[2] = "Short";
}
else if ( cfg.message_duration <= 150 )
{
sz_buttons[2] = "Normal";
}
else
{
sz_buttons[2] = "Long";
}
// Autoturn camera
if ( CAM_TURN_GOOD == cfg.autoturncamera ) sz_buttons[3] = "Fast";
else if ( CAM_TURN_AUTO == cfg.autoturncamera ) sz_buttons[3] = "On";
else
{
sz_buttons[3] = "Off";
cfg.autoturncamera = CAM_TURN_NONE;
}
// Show FPS
sz_buttons[4] = cfg.fps_allowed ? "On" : "Off";
//Billboard feedback
if ( !cfg.feedback ) sz_buttons[5] = "Disabled";
else
{
if ( cfg.feedback == FEEDBACK_TEXT ) sz_buttons[5] = "Enabled";
else sz_buttons[5] = "Debug";
}
// Fall trough
menuState = MM_Running;
//break;
case MM_Running:
// Do normal run
// Background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH / 2 ) - ( background.imgW / 2 ), GFX_HEIGHT - background.imgH, 0, 0, NULL );
}
ui_drawTextBox( menuFont, "Game Difficulty:", buttonLeft, 50, 0, 0, 20 );
// Buttons
if ( !PMod->active && BUTTON_UP == ui_doButton( 1, sz_buttons[0], menuFont, buttonLeft + 150, 50, 150, 30 ) )
{
// Increase difficulty
cfg.difficulty++;
switch ( cfg.difficulty )
{
case GAME_NORMAL: snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Challenging" ); break;
case GAME_HARD: snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Punishing" ); break;
default: case GAME_EASY:
{
snprintf( Cdifficulty, SDL_arraysize( Cdifficulty ), "Forgiving" );
cfg.difficulty = GAME_EASY;
break;
}
}
sz_buttons[0] = Cdifficulty;
}
// Now do difficulty description. Currently it's handled very bad, but it works.
switch ( cfg.difficulty )
{
case GAME_EASY:
strncpy( szDifficulty, "FORGIVING (Easy)\n - Players gain no bonus XP \n - 15%% XP loss upon death\n - Monsters take 25%% extra damage by players\n - Players take 25%% less damage by monsters\n - Halves the chance for Kursed items\n - Cannot unlock the final level in this mode\n - Life and Mana is refilled after quitting a module", SDL_arraysize( szDifficulty ) );
break;
case GAME_NORMAL:
strncpy( szDifficulty, "CHALLENGING (Normal)\n - Players gain 10%% bonus XP \n - 15%% XP loss upon death \n - 15%% money loss upon death", SDL_arraysize( szDifficulty ) );
break;
case GAME_HARD:
strncpy( szDifficulty, "PUNISHING (Hard)\n - Monsters award 20%% extra xp! \n - 15%% XP loss upon death\n - 15%% money loss upon death\n - No respawning\n - Channeling life can kill you\n - Players take 25%% more damage\n - Doubles the chance for Kursed items", SDL_arraysize( szDifficulty ) );
break;
}
str_add_linebreaks( szDifficulty, SDL_arraysize( szDifficulty ), 30 );
ui_drawTextBox( menuFont, szDifficulty, buttonLeft, 100, 0, 0, 20 );
// Text messages
ui_drawTextBox( menuFont, "Max Messages:", buttonLeft + 350, 50, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 2, sz_buttons[1], menuFont, buttonLeft + 515, 50, 75, 30 ) )
{
cfg.message_count_req++;
if ( cfg.message_count_req > MAX_MESSAGE ) cfg.message_count_req = 0;
if ( cfg.message_count_req < 4 && cfg.message_count_req != 0 ) cfg.message_count_req = 4;
if ( 0 == cfg.message_count_req )
{
snprintf( Cmaxmessage, SDL_arraysize( Cmaxmessage ), "None" );
}
else
{
snprintf( Cmaxmessage, SDL_arraysize( Cmaxmessage ), "%i", cfg.message_count_req ); // Convert integer to a char we can use
}
sz_buttons[1] = Cmaxmessage;
}
// Message time
ui_drawTextBox( menuFont, "Message Duration:", buttonLeft + 350, 100, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 3, sz_buttons[2], menuFont, buttonLeft + 515, 100, 100, 30 ) )
{
if ( cfg.message_duration <= 0 )
{
cfg.message_duration = 100;
}
else
{
cfg.message_duration += 50;
}
if ( cfg.message_duration >= 250 )
{
cfg.message_duration = 100;
}
if ( cfg.message_duration <= 100 )
{
sz_buttons[2] = "Short";
}
else if ( cfg.message_duration <= 150 )
{
sz_buttons[2] = "Normal";
}
else
{
sz_buttons[2] = "Long";
}
}
// Autoturn camera
ui_drawTextBox( menuFont, "Autoturn Camera:", buttonLeft + 350, 150, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 4, sz_buttons[3], menuFont, buttonLeft + 515, 150, 100, 30 ) )
{
if ( CAM_TURN_GOOD == cfg.autoturncamera )
{
sz_buttons[3] = "Off";
cfg.autoturncamera = CAM_TURN_NONE;
}
else if ( cfg.autoturncamera )
{
sz_buttons[3] = "Fast";
cfg.autoturncamera = CAM_TURN_GOOD;
}
else
{
sz_buttons[3] = "On";
cfg.autoturncamera = CAM_TURN_AUTO;
}
}
// Show the fps?
ui_drawTextBox( menuFont, "Display FPS:", buttonLeft + 350, 200, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 5, sz_buttons[4], menuFont, buttonLeft + 515, 200, 100, 30 ) )
{
cfg.fps_allowed = !cfg.fps_allowed;
if ( cfg.fps_allowed ) sz_buttons[4] = "On";
else sz_buttons[4] = "Off";
}
// Feedback
ui_drawTextBox( menuFont, "Floating Text:", buttonLeft + 350, 250, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 6, sz_buttons[5], menuFont, buttonLeft + 515, 250, 75, 30 ) )
{
if ( cfg.dev_mode )
{
cfg.feedback = ( FEEDBACK_TYPE )( cfg.feedback + 1 );
if ( cfg.feedback > FEEDBACK_NUMBER ) cfg.feedback = FEEDBACK_OFF;
}
else
{
if ( FEEDBACK_OFF == cfg.feedback )
{
cfg.feedback = FEEDBACK_TEXT;
}
else
{
cfg.feedback = FEEDBACK_OFF;
}
}
switch ( cfg.feedback )
{
case FEEDBACK_OFF: sz_buttons[5] = "Disabled"; break;
case FEEDBACK_TEXT: sz_buttons[5] = "Enabled"; break;
case FEEDBACK_NUMBER: sz_buttons[5] = "Debug"; break;
}
}
// Save settings
if ( BUTTON_UP == ui_doButton( 7, sz_buttons[6], menuFont, buttonLeft, GFX_HEIGHT - 60, 200, 30 ) )
{
// synchronoze the config values with the various game subsystems
setup_synch( &cfg );
// save the setup file
setup_upload( &cfg );
setup_write();
menuState = MM_Leaving;
}
// tool-tip text
ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH / 2 ) + ( background.imgW / 2 ), GFX_HEIGHT - background.imgH, 0, 0, NULL );
}
// Fall trough
menuState = MM_Finish;
break;
case MM_Finish:
// Free the background texture; don't need to hold onto it
oglx_texture_Release( &background );
menuState = MM_Begin; // Make sure this all resets next time
// reset the ui
ui_Reset();
// Set the next menu to load
result = 1;
break;
}
return result;
}
//--------------------------------------------------------------------------------------------
int doAudioOptions( float deltaTime )
{
/// @details Audio options menu
static int menuState = MM_Begin;
static oglx_texture_t background;
static int menuChoice = 0;
static STRING Cmaxsoundchannel;
static STRING Cbuffersize;
static STRING Csoundvolume;
static STRING Cmusicvolume;
static const char *sz_buttons[] =
{
"N/A", // Enable sound
"N/A", // Sound volume
"N/A", // Enable music
"N/A", // Music volume
"N/A", // Sound channels
"N/A", // Sound buffer
"N/A", // Sound quality
"N/A", // Play footsteps
"Save Settings",
""
};
int result = 0;
switch ( menuState )
{
case MM_Begin:
// set up menu variables
ego_texture_load_vfs( &background, "mp_data/menu/menu_sound", TRANSCOLOR );
menuChoice = 0;
menuState = MM_Entering;
tipText_set_position( menuFont, "Change audio settings here.", 20 );
mnu_SlidyButton_init( 1.0f, sz_buttons );
// let this fall through into MM_Entering
case MM_Entering:
// do buttons sliding in animation, and background fading in
// background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
// Draw the background
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
}
// Load the current settings
sz_buttons[0] = cfg.sound_allowed ? "On" : "Off";
snprintf( Csoundvolume, SDL_arraysize( Csoundvolume ), "%i", cfg.sound_volume );
sz_buttons[1] = Csoundvolume;
sz_buttons[2] = cfg.music_allowed ? "On" : "Off";
snprintf( Cmusicvolume, SDL_arraysize( Cmusicvolume ), "%i", cfg.music_volume );
sz_buttons[3] = Cmusicvolume;
snprintf( Cmaxsoundchannel, SDL_arraysize( Cmaxsoundchannel ), "%i", cfg.sound_channel_count );
sz_buttons[4] = Cmaxsoundchannel;
snprintf( Cbuffersize, SDL_arraysize( Cbuffersize ), "%i", cfg.sound_buffer_size );
sz_buttons[5] = Cbuffersize;
sz_buttons[6] = cfg.sound_highquality ? "Normal" : "High";
sz_buttons[7] = cfg.sound_footfall ? "Enabled" : "Disabled";
// Fall trough
menuState = MM_Running;
break;
case MM_Running:
// Do normal run
// Background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
}
ui_drawTextBox( menuFont, "Sound:", buttonLeft, GFX_HEIGHT - 270, 0, 0, 20 );
// Buttons
if ( BUTTON_UP == ui_doButton( 1, sz_buttons[0], menuFont, buttonLeft + 150, GFX_HEIGHT - 270, 100, 30 ) )
{
cfg.sound_allowed = !cfg.sound_allowed;
sz_buttons[0] = cfg.sound_allowed ? "On" : "Off";
}
ui_drawTextBox( menuFont, "Sound Volume:", buttonLeft, GFX_HEIGHT - 235, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 2, sz_buttons[1], menuFont, buttonLeft + 150, GFX_HEIGHT - 235, 100, 30 ) )
{
cfg.sound_volume += 5;
if ( cfg.sound_volume > 100 ) cfg.sound_volume = 0;
snprintf( Csoundvolume, SDL_arraysize( Csoundvolume ), "%i", cfg.sound_volume );
sz_buttons[1] = Csoundvolume;
}
ui_drawTextBox( menuFont, "Music:", buttonLeft, GFX_HEIGHT - 165, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 3, sz_buttons[2], menuFont, buttonLeft + 150, GFX_HEIGHT - 165, 100, 30 ) )
{
cfg.music_allowed = !cfg.music_allowed;
sz_buttons[2] = cfg.music_allowed ? "On" : "Off";
}
ui_drawTextBox( menuFont, "Music Volume:", buttonLeft, GFX_HEIGHT - 130, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 4, sz_buttons[3], menuFont, buttonLeft + 150, GFX_HEIGHT - 130, 100, 30 ) )
{
cfg.music_volume += 5;
if ( cfg.music_volume > 100 ) cfg.music_volume = 0;
snprintf( Cmusicvolume, SDL_arraysize( Cmusicvolume ), "%i", cfg.music_volume );
sz_buttons[3] = Cmusicvolume;
}
ui_drawTextBox( menuFont, "Sound Channels:", buttonLeft + 300, GFX_HEIGHT - 200, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 5, sz_buttons[4], menuFont, buttonLeft + 450, GFX_HEIGHT - 200, 100, 30 ) )
{
if ( cfg.sound_channel_count < 8 )
{
cfg.sound_channel_count = 8;
}
else
{
cfg.sound_channel_count <<= 1;
}
if ( cfg.sound_channel_count > 128 )
{
cfg.sound_channel_count = 8;
}
snprintf( Cmaxsoundchannel, SDL_arraysize( Cmaxsoundchannel ), "%i", cfg.sound_channel_count );
sz_buttons[4] = Cmaxsoundchannel;
}
ui_drawTextBox( menuFont, "Buffer Size:", buttonLeft + 300, GFX_HEIGHT - 165, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 6, sz_buttons[5], menuFont, buttonLeft + 450, GFX_HEIGHT - 165, 100, 30 ) )
{
if ( cfg.sound_buffer_size < 512 )
{
cfg.sound_buffer_size = 512;
}
else
{
cfg.sound_buffer_size <<= 1;
}
if ( cfg.sound_buffer_size > 8196 )
{
cfg.sound_buffer_size = 512;
}
snprintf( Cbuffersize, SDL_arraysize( Cbuffersize ), "%i", cfg.sound_buffer_size );
sz_buttons[5] = Cbuffersize;
}
ui_drawTextBox( menuFont, "Sound Quality:", buttonLeft + 300, GFX_HEIGHT - 130, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 7, sz_buttons[6], menuFont, buttonLeft + 450, GFX_HEIGHT - 130, 100, 30 ) )
{
cfg.sound_highquality = !cfg.sound_highquality;
sz_buttons[6] = cfg.sound_highquality ? "Normal" : "High";
}
//Footfall sounds
ui_drawTextBox( menuFont, "Footstep Sounds:", buttonLeft + 300, GFX_HEIGHT - 235, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 8, sz_buttons[7], menuFont, buttonLeft + 450, GFX_HEIGHT - 235, 100, 30 ) )
{
cfg.sound_footfall = !cfg.sound_footfall;
sz_buttons[7] = cfg.sound_footfall ? "Enabled" : "Disabled";
}
//Save settings
if ( BUTTON_UP == ui_doButton( 9, sz_buttons[8], menuFont, buttonLeft, GFX_HEIGHT - 60, 200, 30 ) )
{
// synchronoze the config values with the various game subsystems
setup_synch( &cfg );
// save the setup file
setup_upload( &cfg );
setup_write();
// Reload the sound system
sound_restart();
// Do we restart the music?
if ( cfg.music_allowed )
{
load_all_music_sounds_vfs();
fade_in_music( musictracksloaded[songplaying] );
}
menuState = MM_Leaving;
}
// tool-tip text
ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
}
// Fall trough
menuState = MM_Finish;
break;
case MM_Finish:
// Free the background texture; don't need to hold onto it
oglx_texture_Release( &background );
menuState = MM_Begin; // Make sure this all resets next time
// reset the ui
ui_Reset();
// Set the next menu to load
result = 1;
break;
}
return result;
}
//--------------------------------------------------------------------------------------------
bool_t doVideoOptions_coerce_aspect_ratio( int width, int height, float * pratio, STRING * psz_ratio )
{
/// @details BB@> coerce the aspect ratio of the screen to some standard size
float req_aspect_ratio;
if ( 0 == height || NULL == pratio || NULL == psz_ratio ) return bfalse;
req_aspect_ratio = ( float )width / ( float )height;
if ( req_aspect_ratio > 0.0 && req_aspect_ratio < 0.5f*(( 5.0f / 4.0f ) + ( 4.0f / 3.0f ) ) )
{
*pratio = 5.0f / 4.0f;
strncpy( *psz_ratio, "5:4", sizeof( *psz_ratio ) );
}
else if ( req_aspect_ratio >= 0.5f*(( 5.0f / 4.0f ) + ( 4.0f / 3.0f ) ) && req_aspect_ratio < 0.5f*(( 4.0f / 3.0f ) + ( 8.0f / 5.0f ) ) )
{
*pratio = 4.0f / 3.0f;
strncpy( *psz_ratio, "4:3", sizeof( *psz_ratio ) );
}
else if ( req_aspect_ratio >= 0.5f*(( 4.0f / 3.0f ) + ( 8.0f / 5.0f ) ) && req_aspect_ratio < 0.5f*(( 8.0f / 5.0f ) + ( 5.0f / 3.0f ) ) )
{
*pratio = 8.0f / 5.0f;
strncpy( *psz_ratio, "8:5", sizeof( *psz_ratio ) );
}
else if ( req_aspect_ratio >= 0.5f*(( 8.0f / 5.0f ) + ( 5.0f / 3.0f ) ) && req_aspect_ratio < 0.5f*(( 5.0f / 3.0f ) + ( 16.0f / 9.0f ) ) )
{
*pratio = 5.0f / 3.0f;
strncpy( *psz_ratio, "5:3", sizeof( *psz_ratio ) );
}
else
{
*pratio = 16.0f / 9.0f;
strncpy( *psz_ratio, "16:9", sizeof( *psz_ratio ) );
}
return btrue;
}
//--------------------------------------------------------------------------------------------
int doVideoOptions_fix_fullscreen_resolution( egoboo_config_t * pcfg, SDLX_screen_info_t * psdl_scr, STRING * psz_screen_size )
{
STRING sz_aspect_ratio = "unknown";
float req_screen_area = ( float )pcfg->scrx_req * ( float )pcfg->scry_req;
float min_diff = 0.0f;
SDL_Rect * found_rect = NULL, ** pprect = NULL;
float aspect_ratio;
doVideoOptions_coerce_aspect_ratio( pcfg->scrx_req, pcfg->scry_req, &aspect_ratio, &sz_aspect_ratio );
found_rect = NULL;
pprect = psdl_scr->video_mode_list;
while ( NULL != *pprect )
{
SDL_Rect * prect = *pprect;
float sdl_aspect_ratio;
float sdl_screen_area;
float diff, diff1, diff2;
sdl_aspect_ratio = ( float )prect->w / ( float )prect->h;
sdl_screen_area = prect->w * prect->h;
diff1 = log( sdl_aspect_ratio / aspect_ratio );
diff2 = log( sdl_screen_area / req_screen_area );
diff = 2.0f * ABS( diff1 ) + ABS( diff2 );
if ( NULL == found_rect || diff < min_diff )
{
found_rect = prect;
min_diff = diff;
if ( 0.0f == min_diff ) break;
}
pprect++;
}
if ( NULL != found_rect )
{
pcfg->scrx_req = found_rect->w;
pcfg->scry_req = found_rect->h;
}
else
{
// we cannot find an approximate screen size
switch ( pcfg->scrx_req )
{
// Normal resolutions
case 1024:
pcfg->scry_req = 768;
strncpy( sz_aspect_ratio, "4:3", sizeof( sz_aspect_ratio ) );
break;
case 640:
pcfg->scry_req = 480;
strncpy( sz_aspect_ratio, "4:3", sizeof( sz_aspect_ratio ) );
break;
case 800:
pcfg->scry_req = 600;
strncpy( sz_aspect_ratio, "4:3", sizeof( sz_aspect_ratio ) );
break;
// 1280 can be both widescreen and normal
case 1280:
if ( pcfg->scry_req > 800 )
{
pcfg->scry_req = 1024;
strncpy( sz_aspect_ratio, "5:4", sizeof( sz_aspect_ratio ) );
}
else
{
pcfg->scry_req = 800;
strncpy( sz_aspect_ratio, "8:5", sizeof( sz_aspect_ratio ) );
}
break;
// Widescreen resolutions
case 1440:
pcfg->scry_req = 900;
strncpy( sz_aspect_ratio, "8:5", sizeof( sz_aspect_ratio ) );
break;
case 1680:
pcfg->scry_req = 1050;
strncpy( sz_aspect_ratio, "8:5", sizeof( sz_aspect_ratio ) );
break;
case 1920:
pcfg->scry_req = 1200;
strncpy( sz_aspect_ratio, "8:5", sizeof( sz_aspect_ratio ) );
break;
// unknown
default:
doVideoOptions_coerce_aspect_ratio( pcfg->scrx_req, pcfg->scry_req, &aspect_ratio, &sz_aspect_ratio );
break;
}
}
snprintf( *psz_screen_size, sizeof( *psz_screen_size ), "%dx%d - %s", pcfg->scrx_req, pcfg->scry_req, sz_aspect_ratio );
return btrue;
}
//--------------------------------------------------------------------------------------------
int doVideoOptions( float deltaTime )
{
/// @details Video options menu
enum
{
but_antialiasing = 0, // Antialaising
but_unused , // Unused button
but_dither , // Fast & ugly
but_fullscreen , // Fullscreen
but_reflections , // Reflections
but_filtering , // Texture filtering
but_shadow , // Shadows
but_zbuffer , // Z bit
but_maxlights , // Fog
but_3dfx , // 3D effects
but_multiwater , // Multi water layer
but_widescreen , // Widescreen
but_screensize , // Screen resolution
but_save ,
but_maxparticles , // Max particles
but_end,
but_last
};
static int menuState = MM_Begin;
static oglx_texture_t background;
static int menuChoice = 0;
static STRING Cantialiasing;
static STRING Cmaxlights;
static STRING Cscrz;
static STRING Cmaxparticles;
static STRING Cmaxdyna;
static bool_t widescreen;
static float aspect_ratio;
static STRING sz_screen_size;
static const char *sz_buttons[but_last];
int cnt, result = 0;
switch ( menuState )
{
case MM_Begin:
// set up the button text
for ( cnt = 0; cnt <but_last; cnt++ ) sz_buttons[cnt] = "N/A";
sz_buttons[but_end] = "";
// set up menu variables
ego_texture_load_vfs( &background, "mp_data/menu/menu_video", TRANSCOLOR );
menuChoice = 0;
menuState = MM_Entering;
tipText_set_position( menuFont, "Change video settings here.", 20 );
mnu_SlidyButton_init( 1.0f, sz_buttons );
// let this fall through into MM_Entering
case MM_Entering:
// do buttons sliding in animation, and background fading in
// background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
// Draw the background
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
}
// Load all the current video settings
if ( cfg.multisamples == 0 ) strncpy( Cantialiasing , "Off", SDL_arraysize( Cantialiasing ) );
else snprintf( Cantialiasing, SDL_arraysize( Cantialiasing ), "X%i", cfg.multisamples );
sz_buttons[but_antialiasing] = Cantialiasing;
// Texture filtering
switch ( cfg.texturefilter_req )
{
case TX_UNFILTERED:
sz_buttons[but_filtering] = "Unfiltered";
break;
case TX_LINEAR:
sz_buttons[but_filtering] = "Linear";
break;
case TX_MIPMAP:
sz_buttons[but_filtering] = "Mipmap";
break;
case TX_BILINEAR:
sz_buttons[but_filtering] = "Bilinear";
break;
case TX_TRILINEAR_1:
sz_buttons[but_filtering] = "Trilinear 1";
break;
case TX_TRILINEAR_2:
sz_buttons[but_filtering] = "Trilinear 2";
break;
case TX_ANISOTROPIC:
sz_buttons[but_filtering] = "Ansiotropic";
break;
default: // Set to defaults
sz_buttons[but_filtering] = "Linear";
cfg.texturefilter_req = TX_LINEAR;
break;
}
sz_buttons[but_dither] = cfg.use_dither ? "Yes" : "No";
sz_buttons[but_fullscreen] = cfg.fullscreen_req ? "True" : "False";
if ( cfg.reflect_allowed )
{
sz_buttons[but_reflections] = "Low";
if ( cfg.reflect_prt )
{
sz_buttons[but_reflections] = "Medium";
if ( cfg.reflect_fade == 0 )
{
sz_buttons[but_reflections] = "High";
}
}
}
else
{
sz_buttons[but_reflections] = "Off";
}
if ( cfg.shadow_allowed )
{
sz_buttons[but_shadow] = "Normal";
if ( !cfg.shadow_sprite )
{
sz_buttons[but_shadow] = "Best";
}
}
else sz_buttons[but_shadow] = "Off";
#if defined(__unix__)
//Clip linux defaults to valid values so that the game doesn't crash on startup
if ( cfg.scrz_req == 32 ) cfg.scrz_req = 24;
if ( cfg.scrd_req == 32 ) cfg.scrd_req = 24;
#endif
if ( cfg.scrz_req != 32 && cfg.scrz_req != 16 && cfg.scrz_req != 24 )
{
cfg.scrz_req = 16; // Set to default
}
snprintf( Cscrz, SDL_arraysize( Cscrz ), "%i", cfg.scrz_req ); // Convert the integer to a char we can use
sz_buttons[but_zbuffer] = Cscrz;
snprintf( Cmaxlights, SDL_arraysize( Cmaxlights ), "%i", cfg.dyna_count_req );
sz_buttons[but_maxlights] = Cmaxlights;
if ( cfg.use_phong )
{
sz_buttons[but_3dfx] = "Okay";
if ( cfg.overlay_allowed && cfg.background_allowed )
{
sz_buttons[but_3dfx] = "Good";
if ( cfg.use_perspective )
{
sz_buttons[but_3dfx] = "Superb";
}
}
else // Set to defaults
{
cfg.use_perspective = bfalse;
cfg.background_allowed = bfalse;
cfg.overlay_allowed = bfalse;
sz_buttons[but_3dfx] = "Off";
}
}
else // Set to defaults
{
cfg.use_perspective = bfalse;
cfg.background_allowed = bfalse;
cfg.overlay_allowed = bfalse;
sz_buttons[but_3dfx] = "Off";
}
if ( cfg.twolayerwater_allowed ) sz_buttons[but_multiwater] = "On";
else sz_buttons[but_multiwater] = "Off";
snprintf( Cmaxparticles, SDL_arraysize( Cmaxparticles ), "%i", cfg.particle_count_req ); // Convert the integer to a char we can use
sz_buttons[but_maxparticles] = Cmaxparticles;
if ( cfg.fullscreen_req && NULL != sdl_scr.video_mode_list )
{
doVideoOptions_fix_fullscreen_resolution( &cfg, &sdl_scr, &sz_screen_size );
sz_buttons[but_screensize] = sz_screen_size;
aspect_ratio = ( float )cfg.scrx_req / ( float )cfg.scry_req;
widescreen = ( aspect_ratio > ( 4.0f / 3.0f ) );
}
else
{
snprintf( sz_screen_size, sizeof( sz_screen_size ), "%dx%d", cfg.scrx_req, cfg.scry_req );
sz_buttons[but_screensize] = sz_screen_size;
aspect_ratio = ( float )cfg.scrx_req / ( float )cfg.scry_req;
widescreen = ( aspect_ratio > ( 4.0f / 3.0f ) );
}
if ( widescreen ) sz_buttons[but_widescreen] = "X";
else sz_buttons[but_widescreen] = " ";
menuState = MM_Running;
break;
case MM_Running:
// Do normal run
// Background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
}
// Antialiasing Button
ui_drawTextBox( menuFont, "Antialiasing:", buttonLeft, GFX_HEIGHT - 215, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 1, sz_buttons[but_antialiasing], menuFont, buttonLeft + 150, GFX_HEIGHT - 215, 100, 30 ) )
{
// make the multi-sampling even
if ( cfg.multisamples < 0 )
{
cfg.multisamples = 0;
}
else
{
cfg.multisamples += 1;
}
// set some arbitrary limit
if ( cfg.multisamples > 4 ) cfg.multisamples = 0;
if ( cfg.multisamples == 0 ) strncpy( Cantialiasing , "Off", SDL_arraysize( Cantialiasing ) );
else snprintf( Cantialiasing, SDL_arraysize( Cantialiasing ), "X%i", cfg.multisamples );
sz_buttons[but_antialiasing] = Cantialiasing;
}
// Dithering
ui_drawTextBox( menuFont, "Dithering:", buttonLeft, GFX_HEIGHT - 145, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 3, sz_buttons[but_dither], menuFont, buttonLeft + 150, GFX_HEIGHT - 145, 100, 30 ) )
{
cfg.use_dither = !cfg.use_dither;
sz_buttons[but_dither] = cfg.use_dither ? "Yes" : "No";
}
// Fullscreen
ui_drawTextBox( menuFont, "Fullscreen:", buttonLeft, GFX_HEIGHT - 110, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 4, sz_buttons[but_fullscreen], menuFont, buttonLeft + 150, GFX_HEIGHT - 110, 100, 30 ) )
{
cfg.fullscreen_req = !cfg.fullscreen_req;
sz_buttons[but_fullscreen] = cfg.fullscreen_req ? "True" : "False";
}
// Reflection
ui_drawTextBox( menuFont, "Reflections:", buttonLeft, GFX_HEIGHT - 250, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 5, sz_buttons[but_reflections], menuFont, buttonLeft + 150, GFX_HEIGHT - 250, 100, 30 ) )
{
if ( cfg.reflect_allowed && cfg.reflect_fade == 0 && cfg.reflect_prt )
{
cfg.reflect_allowed = bfalse;
cfg.reflect_fade = 255;
cfg.reflect_prt = bfalse;
sz_buttons[but_reflections] = "Off";
}
else
{
if ( cfg.reflect_allowed && !cfg.reflect_prt )
{
sz_buttons[but_reflections] = "Medium";
cfg.reflect_fade = 255;
cfg.reflect_prt = btrue;
}
else
{
if ( cfg.reflect_allowed && cfg.reflect_fade == 255 && cfg.reflect_prt )
{
sz_buttons[but_reflections] = "High";
cfg.reflect_fade = 0;
}
else
{
cfg.reflect_allowed = btrue;
cfg.reflect_fade = 255;
sz_buttons[but_reflections] = "Low";
cfg.reflect_prt = bfalse;
}
}
}
}
// Texture Filtering
ui_drawTextBox( menuFont, "Texture Filtering:", buttonLeft, GFX_HEIGHT - 285, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 6, sz_buttons[but_filtering], menuFont, buttonLeft + 150, GFX_HEIGHT - 285, 130, 30 ) )
{
if ( cfg.texturefilter_req < TX_UNFILTERED )
{
cfg.texturefilter_req = TX_UNFILTERED;
}
else
{
cfg.texturefilter_req = ( TX_FILTERS )(( int )cfg.texturefilter_req + 1 );
}
if ( cfg.texturefilter_req > TX_ANISOTROPIC )
{
cfg.texturefilter_req = TX_UNFILTERED;
}
switch ( cfg.texturefilter_req )
{
case TX_UNFILTERED:
sz_buttons[but_filtering] = "Unfiltered";
break;
case TX_LINEAR:
sz_buttons[but_filtering] = "Linear";
break;
case TX_MIPMAP:
sz_buttons[but_filtering] = "Mipmap";
break;
case TX_BILINEAR:
sz_buttons[but_filtering] = "Bilinear";
break;
case TX_TRILINEAR_1:
sz_buttons[but_filtering] = "Trilinear 1";
break;
case TX_TRILINEAR_2:
sz_buttons[but_filtering] = "Trilinear 2";
break;
case TX_ANISOTROPIC:
sz_buttons[but_filtering] = "Anisotropic";
break;
default:
cfg.texturefilter_req = TX_UNFILTERED;
sz_buttons[but_filtering] = "Unfiltered";
break;
}
}
// Shadows
ui_drawTextBox( menuFont, "Shadows:", buttonLeft, GFX_HEIGHT - 320, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 7, sz_buttons[but_shadow], menuFont, buttonLeft + 150, GFX_HEIGHT - 320, 100, 30 ) )
{
if ( cfg.shadow_allowed && !cfg.shadow_sprite )
{
cfg.shadow_allowed = bfalse;
cfg.shadow_sprite = bfalse; // Just in case
sz_buttons[but_shadow] = "Off";
}
else
{
if ( cfg.shadow_allowed && cfg.shadow_sprite )
{
sz_buttons[but_shadow] = "Best";
cfg.shadow_sprite = bfalse;
}
else
{
cfg.shadow_allowed = btrue;
cfg.shadow_sprite = btrue;
sz_buttons[but_shadow] = "Normal";
}
}
}
// Z bit
ui_drawTextBox( menuFont, "Z Bit:", buttonLeft + 300, GFX_HEIGHT - 320, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 8, sz_buttons[but_zbuffer], menuFont, buttonLeft + 450, GFX_HEIGHT - 320, 100, 30 ) )
{
if ( cfg.scrz_req < 0 )
{
cfg.scrz_req = 8;
}
else
{
cfg.scrz_req += 8;
}
#if defined(__unix__)
if ( cfg.scrz_req > 24 ) cfg.scrz_req = 8; //Linux max is 24
#else
if ( cfg.scrz_req > 32 ) cfg.scrz_req = 8; //Others can have up to 32 bit!
#endif
snprintf( Cscrz, SDL_arraysize( Cscrz ), "%d", cfg.scrz_req );
sz_buttons[but_zbuffer] = Cscrz;
}
// Max dynamic lights
ui_drawTextBox( menuFont, "Max Lights:", buttonLeft + 300, GFX_HEIGHT - 285, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 9, sz_buttons[but_maxlights], menuFont, buttonLeft + 450, GFX_HEIGHT - 285, 100, 30 ) )
{
if ( cfg.dyna_count_req < 8 )
{
cfg.dyna_count_req = 8;
}
else
{
cfg.dyna_count_req += 8;
}
if ( cfg.dyna_count_req > TOTAL_MAX_DYNA )
{
cfg.dyna_count_req = 8;
}
snprintf( Cmaxdyna, SDL_arraysize( Cmaxdyna ), "%d", cfg.dyna_count_req );
sz_buttons[but_maxlights] = Cmaxdyna;
}
// Perspective correction, overlay, underlay and phong mapping
ui_drawTextBox( menuFont, "3D Effects:", buttonLeft + 300, GFX_HEIGHT - 250, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 10, sz_buttons[but_3dfx], menuFont, buttonLeft + 450, GFX_HEIGHT - 250, 100, 30 ) )
{
if ( cfg.use_phong && cfg.use_perspective && cfg.overlay_allowed && cfg.background_allowed )
{
cfg.use_phong = bfalse;
cfg.use_perspective = bfalse;
cfg.overlay_allowed = bfalse;
cfg.background_allowed = bfalse;
sz_buttons[but_3dfx] = "Off";
}
else
{
if ( !cfg.use_phong )
{
sz_buttons[but_3dfx] = "Okay";
cfg.use_phong = btrue;
}
else
{
if ( !cfg.use_perspective && cfg.overlay_allowed && cfg.background_allowed )
{
sz_buttons[but_3dfx] = "Superb";
cfg.use_perspective = btrue;
}
else
{
cfg.overlay_allowed = btrue;
cfg.background_allowed = btrue;
sz_buttons[but_3dfx] = "Good";
}
}
}
}
// Water Quality
ui_drawTextBox( menuFont, "Good Water:", buttonLeft + 300, GFX_HEIGHT - 215, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 11, sz_buttons[but_multiwater], menuFont, buttonLeft + 450, GFX_HEIGHT - 215, 100, 30 ) )
{
if ( cfg.twolayerwater_allowed )
{
sz_buttons[but_multiwater] = "Off";
cfg.twolayerwater_allowed = bfalse;
}
else
{
sz_buttons[but_multiwater] = "On";
cfg.twolayerwater_allowed = btrue;
}
}
// Max particles
ui_drawTextBox( menuFont, "Max Particles:", buttonLeft + 300, GFX_HEIGHT - 180, 0, 0, 20 );
if ( PMod->active )
{
snprintf( Cmaxparticles, SDL_arraysize( Cmaxparticles ), "%i (%i currently used)", maxparticles, maxparticles - prt_count_free() );
ui_drawTextBox( menuFont, Cmaxparticles, buttonLeft + 450, GFX_HEIGHT - 180, 0, 100, 30 );
}
else if ( BUTTON_UP == ui_doButton( 15, sz_buttons[but_maxparticles], menuFont, buttonLeft + 450, GFX_HEIGHT - 180, 100, 30 ) )
{
if ( cfg.particle_count_req < 256 )
{
cfg.particle_count_req = 256;
}
else
{
cfg.particle_count_req += 128;
}
if ( cfg.particle_count_req > TOTAL_MAX_PRT ) cfg.particle_count_req = 256;
snprintf( Cmaxparticles, SDL_arraysize( Cmaxparticles ), "%i", cfg.particle_count_req ); // Convert integer to a char we can use
sz_buttons[but_maxparticles] = Cmaxparticles;
}
// Widescreen
ui_drawTextBox( menuFont, "Widescreen:", buttonLeft + 300, GFX_HEIGHT - 70, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 12, sz_buttons[but_widescreen], menuFont, buttonLeft + 450, GFX_HEIGHT - 70, 25, 25 ) )
{
bool_t old_widescreen = widescreen;
// toggle widescreen
widescreen = !widescreen;
if ( old_widescreen )
{
// switch the display from widescreen to non-widescreen
sz_buttons[but_widescreen] = " ";
// Set to default non-widescreen resolution
cfg.scrx_req = 800;
cfg.scry_req = 600;
sz_buttons[but_screensize] = "800x600";
}
else
{
// switch the display from non-widescreen to widescreen
sz_buttons[but_widescreen] = "X";
// Set to "default" widescreen resolution
cfg.scrx_req = 960;
cfg.scry_req = 600;
sz_buttons[but_screensize] = "960x600";
}
}
// Screen Resolution
ui_drawTextBox( menuFont, "Resolution:", buttonLeft + 300, GFX_HEIGHT - 110, 0, 0, 20 );
if ( BUTTON_UP == ui_doButton( 13, sz_buttons[but_screensize], menuFont, buttonLeft + 450, GFX_HEIGHT - 110, 125, 30 ) )
{
float req_area;
cfg.scrx_req *= 1.1f;
cfg.scry_req *= 1.1f;
req_area = cfg.scrx_req * cfg.scry_req;
// use 1920x1200 as a kind of max resolution
if ( req_area > 1920 * 1200 )
{
// reset the screen size to the minimum
if ( widescreen )
{
// "default" widescreen
cfg.scrx_req = 960;
cfg.scry_req = 600;
}
else
{
// "default"
cfg.scrx_req = 800;
cfg.scry_req = 600;
}
}
if ( cfg.fullscreen_req && NULL != sdl_scr.video_mode_list )
{
// coerce the screen size to a valid fullscreen mode
doVideoOptions_fix_fullscreen_resolution( &cfg, &sdl_scr, &sz_screen_size );
}
else
{
// just accept whatever we are given
snprintf( sz_screen_size, sizeof( sz_screen_size ), "%dx%d", cfg.scrx_req, cfg.scry_req );
}
sz_buttons[but_screensize] = sz_screen_size;
aspect_ratio = ( float )cfg.scrx_req / ( float )cfg.scry_req;
// 1.539 is "half way" between normal aspect ratio (4/3) and anamorphic (16/9)
widescreen = ( aspect_ratio > ( 1.539f ) );
if ( widescreen ) sz_buttons[but_widescreen] = "X";
else sz_buttons[but_widescreen] = " ";
}
// Save settings button
if ( BUTTON_UP == ui_doButton( 14, "Save Settings", NULL, buttonLeft, GFX_HEIGHT - 60, 200, 30 ) )
{
menuChoice = 1;
// synchronoze the config values with the various game subsystems
setup_synch( &cfg );
// save the setup file
setup_upload( &cfg );
setup_write();
// Reload some of the graphics
load_graphics();
}
if ( menuChoice != 0 )
{
menuState = MM_Leaving;
mnu_SlidyButton_init( 0.0f, sz_buttons );
}
// tool-tip text
ui_drawTextBox( menuFont, tipText, tipTextLeft, tipTextTop, 0, 0, 20 );
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
if ( mnu_draw_background )
{
ui_drawImage( 0, &background, ( GFX_WIDTH - background.imgW ), 0, 0, 0, NULL );
}
// Fall trough
menuState = MM_Finish;
break;
case MM_Finish:
// Free the background texture; don't need to hold onto it
oglx_texture_Release( &background );
menuState = MM_Begin; // Make sure this all resets next time
// reset the ui
ui_Reset();
// Set the next menu to load
result = menuChoice;
break;
}
return result;
}
//--------------------------------------------------------------------------------------------
int doShowResults( float deltaTime )
{
static Font *font;
static int menuState = MM_Begin;
static int count;
static char* game_hint;
static char buffer[1024] = EMPTY_CSTR;
int menuResult = 0;
switch ( menuState )
{
case MM_Begin:
{
Uint8 i;
char * carat = buffer, * carat_end = buffer + SDL_arraysize( buffer );
font = ui_getFont();
count = 0;
menuState = MM_Entering;
// Prepeare the summary text
for ( i = 0; i < SUMMARYLINES; i++ )
{
carat += snprintf( carat, carat_end - carat - 1, "%s\n", mnu_ModList.lst[( MOD_REF )selectedModule].base.summary[i] );
}
// Randomize the next game hint, but only if not in hard mode
game_hint = CSTR_END;
if ( cfg.difficulty <= GAME_NORMAL )
{
// Should be okay to randomize the seed here, the random seed isnt standarized or
// used elsewhere before the module is loaded.
srand( time( NULL ) );
if ( mnu_GameTip_load_local_vfs() ) game_hint = mnu_GameTip.local_hint[rand() % mnu_GameTip.local_count];
else if ( mnu_GameTip.count > 0 ) game_hint = mnu_GameTip.hint[rand() % mnu_GameTip.count];
}
}
// pass through
case MM_Entering:
menuState = MM_Running;
// pass through
case MM_Running:
{
int text_h, text_w;
ui_drawButton( UI_Nothing, 30, 30, GFX_WIDTH - 60, GFX_HEIGHT - 65, NULL );
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
// the module name
ui_drawTextBox( font, mnu_ModList.lst[( MOD_REF )selectedModule].base.longname, 50, 80, 291, 230, 20 );
// Draw a text box
ui_drawTextBox( menuFont, buffer, 50, 120, 291, 230, 20 );
// Loading game... please wait
fnt_getTextSize( font, "Loading module...", &text_w, &text_h );
fnt_drawText( font, NULL, ( GFX_WIDTH / 2 ) - text_w / 2, GFX_HEIGHT - 200, "Loading module..." );
// Draw the game tip
if ( VALID_CSTR( game_hint ) )
{
fnt_getTextSize( menuFont, "GAME TIP", &text_w, &text_h );
fnt_drawText( menuFont, NULL, ( GFX_WIDTH / 2 ) - text_w / 2, GFX_HEIGHT - 150, "GAME TIP" );
fnt_getTextSize( menuFont, game_hint, &text_w, &text_h ); /// @todo ZF@> : this doesnt work as I intended, fnt_get_TextSize() does not take line breaks into account
ui_drawTextBox( menuFont, game_hint, ( GFX_WIDTH / 2 ) - text_w / 2, GFX_HEIGHT - 110, GFX_WIDTH + 150, GFX_HEIGHT, 20 );
}
// keep track of the iterations through this section for a timer
count++;
if ( count > UPDATE_SKIP )
{
menuState = MM_Leaving;
}
}
break;
case MM_Leaving:
menuState = MM_Finish;
// pass through
case MM_Finish:
menuResult = 1;
menuState = MM_Begin;
}
return menuResult;
}
//--------------------------------------------------------------------------------------------
int doNotImplemented( float deltaTime )
{
int x, y;
int w, h;
char notImplementedMessage[] = "Not implemented yet! Check back soon!";
fnt_getTextSize( ui_getFont(), notImplementedMessage, &w, &h );
w += 50; // add some space on the sides
x = GFX_WIDTH / 2 - w / 2;
y = GFX_HEIGHT / 2 - 17;
if ( BUTTON_UP == ui_doButton( 1, notImplementedMessage, NULL, x, y, w, 30 ) )
{
return 1;
}
return 0;
}
//--------------------------------------------------------------------------------------------
int doGamePaused( float deltaTime )
{
static int menuState = MM_Begin;
static int menuChoice = 0;
static const char * buttons[] =
{
"Quit Module",
"Restart Module",
"Return to Module",
"Options",
""
};
int result = 0, cnt;
switch ( menuState )
{
case MM_Begin:
// set up menu variables
menuChoice = 0;
menuState = MM_Entering;
if ( PMod->exportvalid && !local_allpladead ) buttons[0] = "Save and Exit";
else buttons[0] = "Quit Module";
mnu_SlidyButton_init( 1.0f, buttons );
case MM_Entering:
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( -deltaTime );
// Let lerp wind down relative to the time elapsed
if ( mnu_SlidyButtonState.lerp <= 0.0f )
{
menuState = MM_Running;
}
break;
case MM_Running:
// Do normal run
// Background
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
// Buttons
for ( cnt = 0; cnt < 4; cnt ++ )
{
if ( BUTTON_UP == ui_doButton( cnt + 1, buttons[cnt], NULL, buttonLeft, buttonTop + ( cnt * 35 ), 200, 30 ) )
{
// audio options
menuChoice = cnt + 1;
}
}
// Quick return to game
if ( SDLKEYDOWN( SDLK_ESCAPE ) ) menuChoice = 3;
if ( menuChoice != 0 )
{
menuState = MM_Leaving;
mnu_SlidyButton_init( 0.0f, buttons );
}
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
// Buttons
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( deltaTime );
if ( mnu_SlidyButtonState.lerp >= 1.0f )
{
menuState = MM_Finish;
}
break;
case MM_Finish:
// Free the background texture; don't need to hold onto it
menuState = MM_Begin; // Make sure this all resets next time
// reset the ui
ui_Reset();
// Set the next menu to load
result = menuChoice;
break;
}
return result;
}
//--------------------------------------------------------------------------------------------
int doShowEndgame( float deltaTime )
{
static int menuState = MM_Begin;
static int menuChoice = 0;
static int x, y, w, h;
static Font *font;
static const char * buttons[] =
{
"BLAH",
""
};
int cnt, retval;
retval = 0;
switch ( menuState )
{
case MM_Begin:
menuState = MM_Entering;
font = ui_getFont();
mnu_SlidyButton_init( 1.0f, buttons );
if ( PMod->exportvalid )
{
buttons[0] = "Save and Exit";
}
else
{
buttons[0] = "Exit Game";
}
x = 70;
y = 70;
w = GFX_WIDTH - 2 * x;
h = GFX_HEIGHT - 2 * y;
case MM_Entering:
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
ui_drawTextBox( NULL, endtext, x, y, w, h, 20 );
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( -deltaTime );
// Let lerp wind down relative to the time elapsed
if ( mnu_SlidyButtonState.lerp <= 0.0f )
{
menuState = MM_Running;
}
break;
case MM_Running:
GL_DEBUG( glColor4f )( 1, 1, 1, 1 );
// Buttons
for ( cnt = 0; cnt < 1; cnt ++ )
{
if ( BUTTON_UP == ui_doButton( cnt + 1, buttons[cnt], NULL, buttonLeft, buttonTop + ( cnt * 35 ), 200, 30 ) )
{
// audio options
menuChoice = cnt + 1;
menuState = MM_Leaving;
}
}
// escape also kills this menu
if ( SDLKEYDOWN( SDLK_ESCAPE ) )
{
menuChoice = 1;
menuState = MM_Leaving;
}
ui_drawTextBox( NULL, endtext, x, y, w, h, 20 );
break;
case MM_Leaving:
// Do buttons sliding out and background fading
// Do the same stuff as in MM_Entering, but backwards
GL_DEBUG( glColor4f )( 1, 1, 1, 1 - mnu_SlidyButtonState.lerp );
ui_drawTextBox( NULL, endtext, x, y, w, h, 20 );
// Buttons
mnu_SlidyButton_draw_all();
mnu_SlidyButton_update_all( deltaTime );
if ( mnu_SlidyButtonState.lerp >= 1.0f )
{
menuState = MM_Finish;
}
break;
case MM_Finish:
{
bool_t reloaded = bfalse;
// try to pop the last module off the module stack
reloaded = link_pop_module();
// try to go to the world map
// if( !reloaded )
// {
// reloaded = link_load_parent( mnu_ModList.lst[pickedmodule_index].base.parent_modname, mnu_ModList.lst[pickedmodule_index].base.parent_pos );
// }
// fix the menu that is returned when you break out of the game
if ( PMod->beat && start_new_player )
{
// we started with a new player and beat the module... yay!
// now we want to graduate to the ChoosePlayer menu to
// build our party
start_new_player = bfalse;
// if we beat a beginner module, we want to
// go to ChoosePlayer instead of ChooseModule.
if ( mnu_stack_peek() == emnu_ChooseModule )
{
mnu_stack_pop();
mnu_stack_push( emnu_ChoosePlayer );
}
}
// actually quit the module
if ( !reloaded )
{
game_finish_module();
pickedmodule_index = -1;
process_kill( PROC_PBASE( GProc ) );
}
menuState = MM_Begin;
// Set the next menu to load
retval = menuChoice;
}
}
return retval;
}
//--------------------------------------------------------------------------------------------
// place this last so that we do not have to prototype every menu function
int doMenu( float deltaTime )
{
/// @details the global function that controls the navigation between menus
int retval, result = 0;
if ( mnu_whichMenu == emnu_Main )
{
mnu_stack_clear();
};
retval = MENU_NOTHING;
switch ( mnu_whichMenu )
{
case emnu_Main:
result = doMainMenu( deltaTime );
if ( result != 0 )
{
if ( result == 1 ) { mnu_begin_menu( emnu_ChooseModule ); start_new_player = btrue; }
else if ( result == 2 ) { mnu_begin_menu( emnu_ChoosePlayer ); start_new_player = bfalse; }
else if ( result == 3 ) { mnu_begin_menu( emnu_Options ); }
else if ( result == 4 ) retval = MENU_QUIT; // need to request a quit somehow
}
break;
case emnu_SinglePlayer:
result = doSinglePlayerMenu( deltaTime );
if ( result != 0 )
{
if ( result == 1 )
{
mnu_begin_menu( emnu_ChooseModule );
start_new_player = btrue;
}
else if ( result == 2 )
{
mnu_begin_menu( emnu_ChoosePlayer );
start_new_player = bfalse;
}
else if ( result == 3 )
{
mnu_end_menu();
retval = MENU_END;
}
else
{
mnu_begin_menu( emnu_NewPlayer );
}
}
break;
case emnu_ChooseModule:
result = doChooseModule( deltaTime );
if ( result == -1 ) { mnu_end_menu(); retval = MENU_END; }
else if ( result == 1 ) mnu_begin_menu( emnu_ShowMenuResults ); // imports are not valid (starter module)
else if ( result == 2 ) mnu_begin_menu( emnu_ShowMenuResults ); // imports are valid
break;
case emnu_ChoosePlayer:
result = doChoosePlayer( deltaTime );
if ( result == -1 ) { mnu_end_menu(); retval = MENU_END; }
else if ( result == 1 ) mnu_begin_menu( emnu_ChooseModule );
break;
case emnu_Options:
result = doOptions( deltaTime );
if ( result != 0 )
{
if ( result == 1 ) mnu_begin_menu( emnu_AudioOptions );
else if ( result == 2 ) mnu_begin_menu( emnu_InputOptions );
else if ( result == 3 ) mnu_begin_menu( emnu_VideoOptions );
else if ( result == 4 ) { mnu_end_menu(); retval = MENU_END; }
else if ( result == 5 ) mnu_begin_menu( emnu_GameOptions );
}
break;
case emnu_GameOptions:
result = doGameOptions( deltaTime );
if ( result != 0 )
{
mnu_end_menu();
retval = MENU_END;
}
break;
case emnu_AudioOptions:
result = doAudioOptions( deltaTime );
if ( result != 0 )
{
mnu_end_menu();
retval = MENU_END;
}
break;
case emnu_VideoOptions:
result = doVideoOptions( deltaTime );
if ( result != 0 )
{
mnu_end_menu();
retval = MENU_END;
}
break;
case emnu_InputOptions:
result = doInputOptions( deltaTime );
if ( result != 0 )
{
mnu_end_menu();
retval = MENU_END;
}
break;
case emnu_ShowMenuResults:
result = doShowResults( deltaTime );
if ( result != 0 )
{
mnu_end_menu();
retval = MENU_SELECT;
}
break;
case emnu_GamePaused:
result = doGamePaused( deltaTime );
if ( result != 0 )
{
if ( result == 1 )
{
// "Quit Module"
bool_t reloaded = bfalse;
mnu_end_menu();
// try to pop the last module off the module stack
reloaded = link_pop_module();
// try to go to the world map
// if( !reloaded )
// {
// reloaded = link_load_parent( mnu_ModList.lst[pickedmodule_index].base.parent_modname, mnu_ModList.lst[pickedmodule_index].base.parent_pos );
// }
if ( !reloaded )
{
game_finish_module();
process_kill( PROC_PBASE( GProc ) );
}
result = MENU_QUIT;
}
else if ( result == 2 )
{
// "Restart Module"
mnu_end_menu();
game_begin_module( PMod->loadname, ( Uint32 )~0 );
retval = MENU_END;
}
else if ( result == 3 )
{
// "Return to Module"
mnu_end_menu();
retval = MENU_END;
}
else if ( result == 4 )
{
// "Options"
mnu_begin_menu( emnu_Options );
}
}
break;
case emnu_ShowEndgame:
result = doShowEndgame( deltaTime );
if ( result == 1 )
{
mnu_end_menu();
retval = MENU_END;
}
break;
case emnu_NotImplemented:
default:
result = doNotImplemented( deltaTime );
if ( result != 0 )
{
mnu_end_menu();
retval = MENU_END;
}
}
return retval;
}
//--------------------------------------------------------------------------------------------
// Auto formatting functions
//--------------------------------------------------------------------------------------------
void autoformat_init( gfx_config_t * pgfx )
{
autoformat_init_slidy_buttons();
autoformat_init_tip_text();
autoformat_init_copyright_text();
if ( NULL != pgfx )
{
ui_set_virtual_screen( pgfx->vw, pgfx->vh, GFX_WIDTH, GFX_HEIGHT );
}
}
//--------------------------------------------------------------------------------------------
void autoformat_init_slidy_buttons()
{
// Figure out where to draw the buttons
buttonLeft = 40;
buttonTop = GFX_HEIGHT - 20;
}
//--------------------------------------------------------------------------------------------
void autoformat_init_tip_text()
{
// set the text
tipText = NULL;
// Draw the options text to the right of the buttons
tipTextLeft = 280;
// And relative to the bottom of the screen
tipTextTop = GFX_HEIGHT;
}
//--------------------------------------------------------------------------------------------
void autoformat_init_copyright_text()
{
// set the text
copyrightText = "Welcome to Egoboo!\nhttp://egoboo.sourceforge.net\nVersion " VERSION "\n";
// Draw the copyright text to the right of the buttons
copyrightLeft = 280;
// And relative to the bottom of the screen
copyrightTop = GFX_HEIGHT;
}
//--------------------------------------------------------------------------------------------
// Implementation of tipText
//--------------------------------------------------------------------------------------------
void tipText_set_position( Font * font, const char * text, int spacing )
{
int w, h;
autoformat_init_tip_text();
if ( NULL == text ) return;
fnt_getTextBoxSize( font, text, spacing, &w, &h );
// set the text
tipText = text;
// Draw the options text to the right of the buttons
tipTextLeft = 280;
// And relative to the bottom of the screen
tipTextTop = GFX_HEIGHT - h - spacing;
}
//--------------------------------------------------------------------------------------------
// Implementation of copyrightText
//--------------------------------------------------------------------------------------------
void copyrightText_set_position( Font * font, const char * text, int spacing )
{
int w, h;
autoformat_init_copyright_text();
if ( NULL == text ) return;
copyrightLeft = 0;
copyrightLeft = 0;
// Figure out where to draw the copyright text
fnt_getTextBoxSize( font, text, 20, &w, &h );
// set the text
copyrightText = text;
// Draw the copyright text to the right of the buttons
copyrightLeft = 280;
// And relative to the bottom of the screen
copyrightTop = GFX_HEIGHT - h - spacing;
}
//--------------------------------------------------------------------------------------------
// Asset management
//--------------------------------------------------------------------------------------------
void mnu_load_all_module_images_vfs()
{
/// @details ZZ@> This function loads the title image for each module. Modules without a
/// title are marked as invalid
STRING loadname;
MOD_REF imod;
vfs_FILE* filesave;
// release all allocated data from the mnu_ModList and empty the list
mnu_ModList_release_images();
// Log a directory list
filesave = vfs_openWrite( "/debug/modules.txt" );
if ( NULL != filesave )
{
vfs_printf( filesave, "This file logs all of the modules found\n" );
vfs_printf( filesave, "** Denotes an invalid module\n" );
vfs_printf( filesave, "## Denotes an unlockable module\n\n" );
}
// load all the title images for modules that we are going to display
for ( imod = 0; imod < mnu_ModList.count; imod++ )
{
if ( !mnu_ModList.lst[imod].loaded )
{
vfs_printf( filesave, "**. %s\n", mnu_ModList.lst[imod].vfs_path );
}
else if ( mnu_test_by_index( imod, 0, NULL ) )
{
// @note just because we can't load the title image DOES NOT mean that we ignore the module
snprintf( loadname, SDL_arraysize( loadname ), "%s/gamedat/title", mnu_ModList.lst[imod].vfs_path );
mnu_ModList.lst[imod].tex_index = TxTitleImage_load_one_vfs( loadname );
vfs_printf( filesave, "%02d. %s\n", REF_TO_INT( imod ), mnu_ModList.lst[imod].vfs_path );
}
else
{
vfs_printf( filesave, "##. %s\n", mnu_ModList.lst[imod].vfs_path );
}
}
if ( NULL != filesave )
{
vfs_close( filesave );
}
}
//--------------------------------------------------------------------------------------------
TX_REF mnu_get_icon_ref( const CAP_REF by_reference icap, const TX_REF by_reference default_ref )
{
/// @details BB@> This function gets the proper icon for a an object profile.
//
// In the character preview section of the menu system, we do not load
// entire profiles, just the character definition file ("data.txt")
// and one icon. Sometimes, though the item is actually a spell effect which means
// that we need to display the book icon.
TX_REF icon_ref = ( TX_REF )ICON_NULL;
bool_t is_spell_fx, is_book, draw_book;
cap_t * pitem_cap;
if ( !LOADED_CAP( icap ) ) return icon_ref;
pitem_cap = CapStack.lst + icap;
// what do we need to draw?
is_spell_fx = (NO_SKIN_OVERRIDE != pitem_cap->spelleffect_type);
is_book = ( SPELLBOOK == icap );
draw_book = ( is_book || is_spell_fx ) && ( bookicon_count > 0 );
if ( !draw_book )
{
icon_ref = default_ref;
}
else if ( draw_book )
{
int iskin = 0;
if ( pitem_cap->spelleffect_type != 0 )
{
iskin = pitem_cap->spelleffect_type;
}
else if ( pitem_cap->skin_override != 0 )
{
iskin = pitem_cap->skin_override;
}
iskin = CLIP( iskin, 0, bookicon_count );
icon_ref = bookicon_ref[ iskin ];
}
return icon_ref;
}
//--------------------------------------------------------------------------------------------
// module utilities
//--------------------------------------------------------------------------------------------
int mnu_get_mod_number( const char *szModName )
{
/// @details ZZ@> This function returns -1 if the module does not exist locally, the module
/// index otherwise
MOD_REF modnum;
int retval = -1;
for ( modnum = 0; modnum < mnu_ModList.count; modnum++ )
{
if ( 0 == strcmp( mnu_ModList.lst[modnum].vfs_path, szModName ) )
{
retval = REF_TO_INT( modnum );
break;
}
}
return retval;
}
//--------------------------------------------------------------------------------------------
bool_t mnu_test_by_index( const MOD_REF by_reference modnumber, size_t buffer_len, char * buffer )
{
int cnt;
mnu_module_t * pmod;
bool_t allowed;
if ( INVALID_MOD( modnumber ) ) return bfalse;
pmod = mnu_ModList.lst + modnumber;
// First check if we are in developers mode or that the right module has been beaten before
allowed = bfalse;
if ( cfg.dev_mode || module_has_idsz_vfs( pmod->base.reference, pmod->base.quest_idsz, buffer_len, buffer ) )
{
allowed = btrue;
}
else
{
// If that did not work, then check all selected players directories
for ( cnt = 0; cnt < mnu_selectedPlayerCount; cnt++ )
{
if ( pmod->base.quest_level <= quest_check_vfs( loadplayer[mnu_selectedPlayer[cnt]].dir, pmod->base.quest_idsz ) )
{
allowed = btrue;
break;
}
}
}
return allowed;
}
//--------------------------------------------------------------------------------------------
bool_t mnu_test_by_name( const char *szModName )
{
/// @details ZZ@> This function tests to see if a module can be entered by
/// the players
bool_t retval;
// find the module by name
int modnumber = mnu_get_mod_number( szModName );
retval = bfalse;
if ( modnumber >= 0 )
{
retval = mnu_test_by_index( ( MOD_REF )modnumber, 0, NULL );
}
return retval;
}
//--------------------------------------------------------------------------------------------
void mnu_module_init( mnu_module_t * pmod )
{
if ( NULL == pmod ) return;
// clear the module
memset( pmod, 0, sizeof( *pmod ) );
pmod->tex_index = INVALID_TITLE_TEXTURE;
}
//--------------------------------------------------------------------------------------------
void mnu_load_all_module_info()
{
vfs_search_context_t * ctxt;
const char *vfs_ModPath;
STRING loadname;
// reset the module list
mnu_ModList_release_all();
// Search for all .mod directories and load the module info
ctxt = vfs_findFirst( "mp_modules", "mod", VFS_SEARCH_DIR );
vfs_ModPath = vfs_search_context_get_current( ctxt );
while ( NULL != ctxt && VALID_CSTR( vfs_ModPath ) && mnu_ModList.count < MAX_MODULE )
{
mnu_module_t * pmod = mnu_ModList.lst + ( MOD_REF )mnu_ModList.count;
// clear the module
mnu_module_init( pmod );
// save the filename
snprintf( loadname, SDL_arraysize( loadname ), "%s/gamedat/menu.txt", vfs_ModPath );
if ( NULL != module_load_info_vfs( loadname, &( pmod->base ) ) )
{
mnu_ModList.count++;
// mark the module data as loaded
pmod->loaded = btrue;
// save the module path
strncpy( pmod->vfs_path, vfs_ModPath, SDL_arraysize( pmod->vfs_path ) );
// Save the user data directory version of the module path.
// @note This is kinda a cheat since we know that the virtual paths all begin with "mp_" at the moment.
// If that changes, this line must be changed as well.
snprintf( pmod->dest_path, SDL_arraysize( pmod->dest_path ), "/%s", vfs_ModPath + 3 );
// same problem as above
strncpy( pmod->name, vfs_ModPath + 11, SDL_arraysize(pmod->name) );
};
ctxt = vfs_findNext( &ctxt );
vfs_ModPath = vfs_search_context_get_current( ctxt );
}
vfs_findClose( &ctxt );
module_list_valid = btrue;
}
//--------------------------------------------------------------------------------------------
void mnu_release_one_module( const MOD_REF by_reference imod )
{
mnu_module_t * pmod;
if ( !VALID_MOD( imod ) ) return;
pmod = mnu_ModList.lst + imod;
TxTitleImage_release_one( pmod->tex_index );
pmod->tex_index = INVALID_TITLE_TEXTURE;
}
//--------------------------------------------------------------------------------------------
// Implementation of the ModList struct
//--------------------------------------------------------------------------------------------
mod_file_t * mnu_ModList_get_base( int imod )
{
if ( imod < 0 || imod >= MAX_MODULE ) return NULL;
return &( mnu_ModList.lst[( MOD_REF )imod].base );
}
//--------------------------------------------------------------------------------------------
const char * mnu_ModList_get_vfs_path( int imod )
{
if ( imod < 0 || imod >= MAX_MODULE ) return NULL;
return mnu_ModList.lst[( MOD_REF )imod].vfs_path;
}
//--------------------------------------------------------------------------------------------
const char * mnu_ModList_get_dest_path( int imod )
{
if ( imod < 0 || imod >= MAX_MODULE ) return NULL;
return mnu_ModList.lst[( MOD_REF )imod].dest_path;
}
//--------------------------------------------------------------------------------------------
const char * mnu_ModList_get_name( int imod )
{
if ( imod < 0 || imod >= MAX_MODULE ) return NULL;
return mnu_ModList.lst[( MOD_REF )imod].name;
}
//--------------------------------------------------------------------------------------------
void mnu_ModList_release_all()
{
MOD_REF cnt;
for ( cnt = 0; cnt < MAX_MODULE; cnt++ )
{
// release any allocated data
if ( cnt < mnu_ModList.count )
{
mnu_release_one_module( cnt );
}
memset( mnu_ModList.lst + cnt, 0, sizeof( mnu_module_t ) );
}
mnu_ModList.count = 0;
}
//--------------------------------------------------------------------------------------------
void mnu_ModList_release_images()
{
MOD_REF cnt;
int tnc;
tnc = -1;
for ( cnt = 0; cnt < mnu_ModList.count; cnt++ )
{
if ( !mnu_ModList.lst[cnt].loaded ) continue;
tnc = REF_TO_INT( cnt );
TxTitleImage_release_one( mnu_ModList.lst[cnt].tex_index );
mnu_ModList.lst[cnt].tex_index = INVALID_TITLE_TEXTURE;
}
TxTitleImage.count = 0;
// make sure that mnu_ModList.count is the right size, in case some modules were unloaded?
mnu_ModList.count = tnc + 1;
}
//--------------------------------------------------------------------------------------------
// Functions for implementing the TxTitleImage array of textures
//--------------------------------------------------------------------------------------------
void TxTitleImage_clear_data()
{
TxTitleImage.count = 0;
}
//--------------------------------------------------------------------------------------------
void TxTitleImage_ctor()
{
/// @details ZZ@> This function clears out all of the textures
TX_REF cnt;
for ( cnt = 0; cnt < MAX_MODULE; cnt++ )
{
oglx_texture_ctor( TxTitleImage.lst + cnt );
}
TxTitleImage_clear_data();
}
//--------------------------------------------------------------------------------------------
void TxTitleImage_release_one( const TX_REF by_reference index )
{
if ( index < 0 || index >= MAX_MODULE ) return;
oglx_texture_Release( TxTitleImage.lst + index );
}
//--------------------------------------------------------------------------------------------
void TxTitleImage_release_all()
{
/// @details ZZ@> This function releases all of the textures
TX_REF cnt;
for ( cnt = 0; cnt < MAX_MODULE; cnt++ )
{
TxTitleImage_release_one( cnt );
}
TxTitleImage_clear_data();
}
//--------------------------------------------------------------------------------------------
void TxTitleImage_dtor()
{
/// @details ZZ@> This function clears out all of the textures
TX_REF cnt;
for ( cnt = 0; cnt < MAX_MODULE; cnt++ )
{
oglx_texture_dtor( TxTitleImage.lst + cnt );
}
TxTitleImage_clear_data();
}
//--------------------------------------------------------------------------------------------
TX_REF TxTitleImage_load_one_vfs( const char *szLoadName )
{
/// @details ZZ@> This function loads a title in the specified image slot, forcing it into
/// system memory. Returns btrue if it worked
TX_REF itex;
if ( INVALID_CSTR( szLoadName ) ) return ( TX_REF )INVALID_TITLE_TEXTURE;
if ( TxTitleImage.count >= TITLE_TEXTURE_COUNT ) return ( TX_REF )INVALID_TITLE_TEXTURE;
itex = ( TX_REF )TxTitleImage.count;
if ( INVALID_TX_ID != ego_texture_load_vfs( TxTitleImage.lst + itex, szLoadName, INVALID_KEY ) )
{
TxTitleImage.count++;
}
else
{
itex = ( TX_REF )INVALID_TITLE_TEXTURE;
}
return itex;
}
//--------------------------------------------------------------------------------------------
oglx_texture_t * TxTitleImage_get_ptr( const TX_REF by_reference itex )
{
if ( itex >= TxTitleImage.count || itex >= MAX_MODULE ) return NULL;
return TxTitleImage.lst + itex;
}
//--------------------------------------------------------------------------------------------
void TxTitleImage_reload_all()
{
/// @details ZZ@> This function re-loads all the current textures back into
/// OpenGL texture memory using the cached SDL surfaces
TX_REF cnt;
for ( cnt = 0; cnt < TX_TEXTURE_COUNT; cnt++ )
{
oglx_texture_t * ptex = TxTitleImage.lst + cnt;
if ( ptex->valid )
{
oglx_texture_Convert( ptex, ptex->surface, INVALID_KEY );
}
}
}
//--------------------------------------------------------------------------------------------
// Implementation of the mnu_GameTip system
//--------------------------------------------------------------------------------------------
void mnu_GameTip_load_global_vfs()
{
/// ZF@> This function loads all of the game hints and tips
STRING buffer;
vfs_FILE *fileread;
Uint8 cnt;
// reset the count
mnu_GameTip.count = 0;
// Open the file with all the tips
fileread = vfs_openRead( "mp_data/gametips.txt" );
if ( NULL == fileread )
{
log_warning( "Could not load the game tips and hints. (\"mp_data/gametips.txt\")\n" );
return;
}
// Load the data
for ( cnt = 0; cnt < MENU_MAX_GAMETIPS && !vfs_eof( fileread ); cnt++ )
{
if ( goto_colon( NULL, fileread, btrue ) )
{
//Read the line
fget_string( fileread, buffer, SDL_arraysize( buffer ) );
strcpy( mnu_GameTip.hint[cnt], buffer );
//Make it look nice
str_decode( mnu_GameTip.hint[cnt], SDL_arraysize( mnu_GameTip.hint[cnt] ), mnu_GameTip.hint[cnt] );
//str_add_linebreaks( mnu_GameTip.hint[cnt], SDL_arraysize( mnu_GameTip.hint[cnt] ), 50 );
//Keep track of how many we have total
mnu_GameTip.count++;
}
}
vfs_close( fileread );
}
//--------------------------------------------------------------------------------------------
bool_t mnu_GameTip_load_local_vfs()
{
/// ZF@> This function loads all module specific hints and tips. If this fails, the game will
// default to the global hints and tips instead
STRING buffer;
vfs_FILE *fileread;
Uint8 cnt;
// reset the count
mnu_GameTip.local_count = 0;
// Open all the tips
fileread = vfs_openRead( "mp_data/gametips.txt" );
if ( NULL == fileread ) return bfalse;
// Load the data
for ( cnt = 0; cnt < MENU_MAX_GAMETIPS && !vfs_eof( fileread ); cnt++ )
{
if ( goto_colon( NULL, fileread, btrue ) )
{
//Read the line
fget_string( fileread, buffer, SDL_arraysize( buffer ) );
strcpy( mnu_GameTip.local_hint[cnt], buffer );
//Make it look nice
str_decode( mnu_GameTip.local_hint[cnt], SDL_arraysize( mnu_GameTip.local_hint[cnt] ), mnu_GameTip.local_hint[cnt] );
//str_add_linebreaks( mnu_GameTip.local_hint[cnt], SDL_arraysize( mnu_GameTip.local_hint[cnt] ), 50 );
//Keep track of how many we have total
mnu_GameTip.local_count++;
}
}
vfs_close( fileread );
return mnu_GameTip.local_count > 0;
}
//--------------------------------------------------------------------------------------------
// Implementation of the mnu_SlidyButton array
//--------------------------------------------------------------------------------------------
void mnu_SlidyButton_init( float lerp, const char *button_text[] )
{
int i;
autoformat_init_slidy_buttons();
// Figure out where to draw the buttons
for ( i = 0; button_text[i][0] != 0; i++ )
{
buttonTop -= 35;
}
mnu_SlidyButtonState.lerp = lerp;
mnu_SlidyButtonState.buttons = ( char** )button_text;
}
//--------------------------------------------------------------------------------------------
void mnu_SlidyButton_update_all( float deltaTime )
{
mnu_SlidyButtonState.lerp += ( deltaTime * 1.5f );
}
//--------------------------------------------------------------------------------------------
void mnu_SlidyButton_draw_all()
{
int i;
for ( i = 0; mnu_SlidyButtonState.buttons[i][0] != 0; i++ )
{
int x = buttonLeft - ( 360 - i * 35 ) * mnu_SlidyButtonState.lerp;
int y = buttonTop + ( i * 35 );
ui_doButton( UI_Nothing, mnu_SlidyButtonState.buttons[i], NULL, x, y, 200, 30 );
}
}
//--------------------------------------------------------------------------------------------
// implementation of the mnu_Selected* arrays
//--------------------------------------------------------------------------------------------
bool_t mnu_Selected_check_loadplayer( int loadplayer_idx )
{
int i;
if ( loadplayer_idx > loadplayer_count ) return bfalse;
for ( i = 0; i < MAX_PLAYER && i < mnu_selectedPlayerCount; i++ )
{
if ( mnu_selectedPlayer[i] == loadplayer_idx ) return btrue;
}
return bfalse;
}
//--------------------------------------------------------------------------------------------
int mnu_Selected_get_loadplayer( int loadplayer_idx )
{
int cnt, selected_index;
if ( loadplayer_idx > loadplayer_count ) return INVALID_PLAYER;
selected_index = INVALID_PLAYER;
for ( cnt = 0; cnt < MAX_PLAYER && cnt < mnu_selectedPlayerCount; cnt++ )
{
if ( mnu_selectedPlayer[ cnt ] == loadplayer_idx )
{
selected_index = cnt;
break;
}
}
return selected_index;
}
//--------------------------------------------------------------------------------------------
bool_t mnu_Selected_add( int loadplayer_idx )
{
if ( loadplayer_idx > loadplayer_count || mnu_selectedPlayerCount >= MAX_PLAYER ) return bfalse;
if ( mnu_Selected_check_loadplayer( loadplayer_idx ) ) return bfalse;
mnu_selectedPlayer[mnu_selectedPlayerCount] = loadplayer_idx;
mnu_selectedInput[mnu_selectedPlayerCount] = INPUT_BITS_NONE;
mnu_selectedPlayerCount++;
return btrue;
}
//--------------------------------------------------------------------------------------------
bool_t mnu_Selected_remove( int loadplayer_idx )
{
int i;
bool_t found = bfalse;
if ( loadplayer_idx > loadplayer_count || mnu_selectedPlayerCount <= 0 ) return bfalse;
if ( mnu_selectedPlayerCount == 1 )
{
if ( mnu_selectedPlayer[0] == loadplayer_idx )
{
mnu_selectedPlayerCount = 0;
};
}
else
{
for ( i = 0; i < MAX_PLAYER && i < mnu_selectedPlayerCount; i++ )
{
if ( mnu_selectedPlayer[i] == loadplayer_idx )
{
found = btrue;
break;
}
}
if ( found )
{
i++;
for ( /* nothing */; i < MAX_PLAYER && i < mnu_selectedPlayerCount; i++ )
{
mnu_selectedPlayer[i-1] = mnu_selectedPlayer[i];
mnu_selectedInput[i-1] = mnu_selectedInput[i];
}
mnu_selectedPlayerCount--;
}
};
return found;
}
//--------------------------------------------------------------------------------------------
bool_t mnu_Selected_add_input( int loadplayer_idx, BIT_FIELD input_bits )
{
int i;
bool_t done, retval = bfalse;
int selected_index = -1;
for ( i = 0; i < mnu_selectedPlayerCount; i++ )
{
if ( mnu_selectedPlayer[i] == loadplayer_idx )
{
selected_index = i;
break;
}
}
if ( -1 == selected_index )
{
mnu_Selected_add( loadplayer_idx );
}
if ( selected_index >= 0 && selected_index < mnu_selectedPlayerCount )
{
for ( i = 0; i < mnu_selectedPlayerCount; i++ )
{
if ( i == selected_index )
{
// add in the selected bits for the selected loadplayer_idx
SET_BIT( mnu_selectedInput[i], input_bits);
retval = btrue;
}
else
{
// remove the selectd bits from all other players
UNSET_BIT( mnu_selectedInput[i], input_bits);
}
}
}
// Do the tricky part of removing all players with invalid inputs from the list
// It is tricky because removing a loadplayer_idx changes the value of the loop control
// value mnu_selectedPlayerCount within the loop.
done = bfalse;
while ( !done )
{
// assume the best
done = btrue;
for ( i = 0; i < mnu_selectedPlayerCount; i++ )
{
if ( INPUT_BITS_NONE == mnu_selectedInput[i] )
{
// we found one
done = bfalse;
mnu_Selected_remove( mnu_selectedPlayer[i] );
}
}
}
return retval;
}
//--------------------------------------------------------------------------------------------
bool_t mnu_Selected_remove_input( int loadplayer_idx, Uint32 input_bits )
{
int i;
bool_t retval = bfalse;
for ( i = 0; i < MAX_PLAYER && i < mnu_selectedPlayerCount; i++ )
{
if ( mnu_selectedPlayer[i] == loadplayer_idx )
{
UNSET_BIT( mnu_selectedInput[i], input_bits );
// This part is not so tricky as in mnu_Selected_add_input.
// Even though we are modding the loop control variable, it is never
// tested in the loop because we are using the break command to
// break out of the loop immediately
if ( INPUT_BITS_NONE == mnu_selectedInput[i] )
{
mnu_Selected_remove( loadplayer_idx );
}
retval = btrue;
break;
}
}
return retval;
}
//--------------------------------------------------------------------------------------------
// Implementation of the loadplayer array
//--------------------------------------------------------------------------------------------
void loadplayer_init()
{
// restart from nothing
loadplayer_count = 0;
release_all_profile_textures();
chop_data_init( &chop_mem );
}
//--------------------------------------------------------------------------------------------
bool_t loadplayer_import_one( const char * foundfile )
{
STRING filename;
LOAD_PLAYER_INFO * pinfo;
int skin = 0;
if ( !VALID_CSTR( foundfile ) || !vfs_exists( foundfile ) ) return bfalse;
if ( loadplayer_count >= MAXLOADPLAYER ) return bfalse;
pinfo = loadplayer + loadplayer_count;
snprintf( pinfo->dir, SDL_arraysize( pinfo->dir ), "%s", str_convert_slash_net(( char* )foundfile, strlen( foundfile ) ) );
snprintf( filename, SDL_arraysize( filename ), "%s/skin.txt", foundfile );
skin = read_skin_vfs( filename );
//snprintf( filename, SDL_arraysize(filename), "%s" SLASH_STR "tris.md2", foundfile );
//md2_load_one( vfs_resolveReadFilename(filename), &(MadStack.lst[loadplayer_count].md2_data) );
snprintf( filename, SDL_arraysize( filename ), "%s/icon%d", foundfile, skin );
pinfo->tx_ref = TxTexture_load_one_vfs( filename, ( TX_REF )INVALID_TX_TEXTURE, INVALID_KEY );
// load the chop data
snprintf( filename, SDL_arraysize( filename ), "%s/naming.txt", foundfile );
chop_load_vfs( &chop_mem, filename, &( pinfo->chop ) );
// generate the name from the chop
snprintf( pinfo->name, SDL_arraysize( pinfo->name ), "%s", chop_create( &chop_mem, &( pinfo->chop ) ) );
loadplayer_count++;
return btrue;
}
//--------------------------------------------------------------------------------------------
// Player utilities
//--------------------------------------------------------------------------------------------
void mnu_player_check_import( const char *dirname, bool_t initialize )
{
/// @details ZZ@> This function figures out which players may be imported, and loads basic
/// data for each
vfs_search_context_t * ctxt;
const char *foundfile;
if ( initialize )
{
loadplayer_init();
};
// Search for all objects
ctxt = vfs_findFirst( dirname, "obj", VFS_SEARCH_DIR );
foundfile = vfs_search_context_get_current( ctxt );
while ( NULL != ctxt && VALID_CSTR( foundfile ) && loadplayer_count < MAXLOADPLAYER )
{
loadplayer_import_one( foundfile );
ctxt = vfs_findNext( &ctxt );
foundfile = vfs_search_context_get_current( ctxt );
}
vfs_findClose( &ctxt );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment