Extract mainmenu
This commit is contained in:
parent
1570f860e8
commit
3e8227a62b
|
@ -140,6 +140,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||||
"src/loadsave.h"
|
"src/loadsave.h"
|
||||||
"src/main.cc"
|
"src/main.cc"
|
||||||
"src/main.h"
|
"src/main.h"
|
||||||
|
"src/mainmenu.cc"
|
||||||
|
"src/mainmenu.h"
|
||||||
"src/map_defs.h"
|
"src/map_defs.h"
|
||||||
"src/map.cc"
|
"src/map.cc"
|
||||||
"src/map.h"
|
"src/map.h"
|
||||||
|
|
397
src/main.cc
397
src/main.cc
|
@ -1,6 +1,5 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -21,6 +20,7 @@
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "kb.h"
|
#include "kb.h"
|
||||||
#include "loadsave.h"
|
#include "loadsave.h"
|
||||||
|
#include "mainmenu.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "mouse.h"
|
#include "mouse.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
@ -35,7 +35,6 @@
|
||||||
#include "sfall_config.h"
|
#include "sfall_config.h"
|
||||||
#include "svga.h"
|
#include "svga.h"
|
||||||
#include "text_font.h"
|
#include "text_font.h"
|
||||||
#include "version.h"
|
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "window_manager.h"
|
#include "window_manager.h"
|
||||||
#include "window_manager_private.h"
|
#include "window_manager_private.h"
|
||||||
|
@ -44,35 +43,9 @@
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
#define MAIN_MENU_WINDOW_WIDTH 640
|
|
||||||
#define MAIN_MENU_WINDOW_HEIGHT 480
|
|
||||||
|
|
||||||
#define DEATH_WINDOW_WIDTH 640
|
#define DEATH_WINDOW_WIDTH 640
|
||||||
#define DEATH_WINDOW_HEIGHT 480
|
#define DEATH_WINDOW_HEIGHT 480
|
||||||
|
|
||||||
typedef enum MainMenuButton {
|
|
||||||
MAIN_MENU_BUTTON_INTRO,
|
|
||||||
MAIN_MENU_BUTTON_NEW_GAME,
|
|
||||||
MAIN_MENU_BUTTON_LOAD_GAME,
|
|
||||||
MAIN_MENU_BUTTON_OPTIONS,
|
|
||||||
MAIN_MENU_BUTTON_CREDITS,
|
|
||||||
MAIN_MENU_BUTTON_EXIT,
|
|
||||||
MAIN_MENU_BUTTON_COUNT,
|
|
||||||
} MainMenuButton;
|
|
||||||
|
|
||||||
typedef enum MainMenuOption {
|
|
||||||
MAIN_MENU_INTRO,
|
|
||||||
MAIN_MENU_NEW_GAME,
|
|
||||||
MAIN_MENU_LOAD_GAME,
|
|
||||||
MAIN_MENU_SCREENSAVER,
|
|
||||||
MAIN_MENU_TIMEOUT,
|
|
||||||
MAIN_MENU_CREDITS,
|
|
||||||
MAIN_MENU_QUOTES,
|
|
||||||
MAIN_MENU_EXIT,
|
|
||||||
MAIN_MENU_SELFRUN,
|
|
||||||
MAIN_MENU_OPTIONS,
|
|
||||||
} MainMenuOption;
|
|
||||||
|
|
||||||
static bool falloutInit(int argc, char** argv);
|
static bool falloutInit(int argc, char** argv);
|
||||||
static int main_reset_system();
|
static int main_reset_system();
|
||||||
static void main_exit_system();
|
static void main_exit_system();
|
||||||
|
@ -87,14 +60,6 @@ static void showDeath();
|
||||||
static void _main_death_voiceover_callback();
|
static void _main_death_voiceover_callback();
|
||||||
static int _mainDeathGrabTextFile(const char* fileName, char* dest);
|
static int _mainDeathGrabTextFile(const char* fileName, char* dest);
|
||||||
static int _mainDeathWordWrap(char* text, int width, short* beginnings, short* count);
|
static int _mainDeathWordWrap(char* text, int width, short* beginnings, short* count);
|
||||||
static int mainMenuWindowInit();
|
|
||||||
static void mainMenuWindowFree();
|
|
||||||
static void mainMenuWindowHide(bool animate);
|
|
||||||
static void mainMenuWindowUnhide(bool animate);
|
|
||||||
static int _main_menu_is_enabled();
|
|
||||||
static int mainMenuWindowHandleEvents();
|
|
||||||
static int main_menu_fatal_error();
|
|
||||||
static void main_menu_play_sound(const char* fileName);
|
|
||||||
|
|
||||||
// 0x5194C8
|
// 0x5194C8
|
||||||
static char _mainMap[] = "artemple.map";
|
static char _mainMap[] = "artemple.map";
|
||||||
|
@ -124,54 +89,9 @@ static bool _main_show_death_scene = false;
|
||||||
// 0x5194EC
|
// 0x5194EC
|
||||||
static bool gMainMenuScreensaverCycle = false;
|
static bool gMainMenuScreensaverCycle = false;
|
||||||
|
|
||||||
// 0x5194F0
|
|
||||||
static int gMainMenuWindow = -1;
|
|
||||||
|
|
||||||
// 0x5194F4
|
|
||||||
static unsigned char* gMainMenuWindowBuffer = NULL;
|
|
||||||
|
|
||||||
// 0x519504
|
|
||||||
static bool _in_main_menu = false;
|
|
||||||
|
|
||||||
// 0x519508
|
|
||||||
static bool gMainMenuWindowInitialized = false;
|
|
||||||
|
|
||||||
// 0x51950C
|
|
||||||
static unsigned int gMainMenuScreensaverDelay = 120000;
|
|
||||||
|
|
||||||
// 0x519510
|
|
||||||
static const int gMainMenuButtonKeyBindings[MAIN_MENU_BUTTON_COUNT] = {
|
|
||||||
KEY_LOWERCASE_I, // intro
|
|
||||||
KEY_LOWERCASE_N, // new game
|
|
||||||
KEY_LOWERCASE_L, // load game
|
|
||||||
KEY_LOWERCASE_O, // options
|
|
||||||
KEY_LOWERCASE_C, // credits
|
|
||||||
KEY_LOWERCASE_E, // exit
|
|
||||||
};
|
|
||||||
|
|
||||||
// 0x519528
|
|
||||||
static const int _return_values[MAIN_MENU_BUTTON_COUNT] = {
|
|
||||||
MAIN_MENU_INTRO,
|
|
||||||
MAIN_MENU_NEW_GAME,
|
|
||||||
MAIN_MENU_LOAD_GAME,
|
|
||||||
MAIN_MENU_OPTIONS,
|
|
||||||
MAIN_MENU_CREDITS,
|
|
||||||
MAIN_MENU_EXIT,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 0x614838
|
// 0x614838
|
||||||
static bool _main_death_voiceover_done;
|
static bool _main_death_voiceover_done;
|
||||||
|
|
||||||
// 0x614840
|
|
||||||
static int gMainMenuButtons[MAIN_MENU_BUTTON_COUNT];
|
|
||||||
|
|
||||||
// 0x614858
|
|
||||||
static bool gMainMenuWindowHidden;
|
|
||||||
|
|
||||||
static FrmImage _mainMenuBackgroundFrmImage;
|
|
||||||
static FrmImage _mainMenuButtonNormalFrmImage;
|
|
||||||
static FrmImage _mainMenuButtonPressedFrmImage;
|
|
||||||
|
|
||||||
// 0x48099C
|
// 0x48099C
|
||||||
int falloutMain(int argc, char** argv)
|
int falloutMain(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
@ -790,319 +710,4 @@ static int _mainDeathWordWrap(char* text, int width, short* beginnings, short* c
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x481650
|
|
||||||
static int mainMenuWindowInit()
|
|
||||||
{
|
|
||||||
int fid;
|
|
||||||
MessageListItem msg;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
if (gMainMenuWindowInitialized) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
colorPaletteLoad("color.pal");
|
|
||||||
|
|
||||||
int mainMenuWindowX = (screenGetWidth() - MAIN_MENU_WINDOW_WIDTH) / 2;
|
|
||||||
int mainMenuWindowY = (screenGetHeight() - MAIN_MENU_WINDOW_HEIGHT) / 2;
|
|
||||||
gMainMenuWindow = windowCreate(mainMenuWindowX,
|
|
||||||
mainMenuWindowY,
|
|
||||||
MAIN_MENU_WINDOW_WIDTH,
|
|
||||||
MAIN_MENU_WINDOW_HEIGHT,
|
|
||||||
0,
|
|
||||||
WINDOW_HIDDEN | WINDOW_MOVE_ON_TOP);
|
|
||||||
if (gMainMenuWindow == -1) {
|
|
||||||
// NOTE: Uninline.
|
|
||||||
return main_menu_fatal_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
gMainMenuWindowBuffer = windowGetBuffer(gMainMenuWindow);
|
|
||||||
|
|
||||||
// mainmenu.frm
|
|
||||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 140, 0, 0, 0);
|
|
||||||
if (!_mainMenuBackgroundFrmImage.lock(backgroundFid)) {
|
|
||||||
// NOTE: Uninline.
|
|
||||||
return main_menu_fatal_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
blitBufferToBuffer(_mainMenuBackgroundFrmImage.getData(), 640, 480, 640, gMainMenuWindowBuffer, 640);
|
|
||||||
_mainMenuBackgroundFrmImage.unlock();
|
|
||||||
|
|
||||||
int oldFont = fontGetCurrent();
|
|
||||||
fontSetCurrent(100);
|
|
||||||
|
|
||||||
// SFALL: Allow to change font color/flags of copyright/version text
|
|
||||||
// It's the last byte ('3C' by default) that picks the colour used. The first byte supplies additional flags for this option
|
|
||||||
// 0x010000 - change the color for version string only
|
|
||||||
// 0x020000 - underline text (only for the version string)
|
|
||||||
// 0x040000 - monospace font (only for the version string)
|
|
||||||
int fontSettings = _colorTable[21091], fontSettingsSFall = 0;
|
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_FONT_COLOR_KEY, &fontSettingsSFall);
|
|
||||||
if (fontSettingsSFall && !(fontSettingsSFall & 0x010000))
|
|
||||||
fontSettings = fontSettingsSFall & 0xFF;
|
|
||||||
|
|
||||||
// SFALL: Allow to move copyright text
|
|
||||||
int offsetX = 0, offsetY = 0;
|
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_X_KEY, &offsetX);
|
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_Y_KEY, &offsetY);
|
|
||||||
|
|
||||||
// Copyright.
|
|
||||||
msg.num = 20;
|
|
||||||
if (messageListGetItem(&gMiscMessageList, &msg)) {
|
|
||||||
windowDrawText(gMainMenuWindow, msg.text, 0, offsetX + 15, offsetY + 460, fontSettings | 0x06000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SFALL: Make sure font settings are applied when using 0x010000 flag
|
|
||||||
if (fontSettingsSFall)
|
|
||||||
fontSettings = fontSettingsSFall;
|
|
||||||
|
|
||||||
// TODO: Allow to move version text
|
|
||||||
// Version.
|
|
||||||
char version[VERSION_MAX];
|
|
||||||
versionGetVersion(version, sizeof(version));
|
|
||||||
len = fontGetStringWidth(version);
|
|
||||||
windowDrawText(gMainMenuWindow, version, 0, 615 - len, 460, fontSettings | 0x06000000);
|
|
||||||
|
|
||||||
// menuup.frm
|
|
||||||
fid = buildFid(OBJ_TYPE_INTERFACE, 299, 0, 0, 0);
|
|
||||||
if (!_mainMenuButtonNormalFrmImage.lock(fid)) {
|
|
||||||
// NOTE: Uninline.
|
|
||||||
return main_menu_fatal_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
// menudown.frm
|
|
||||||
fid = buildFid(OBJ_TYPE_INTERFACE, 300, 0, 0, 0);
|
|
||||||
if (!_mainMenuButtonPressedFrmImage.lock(fid)) {
|
|
||||||
// NOTE: Uninline.
|
|
||||||
return main_menu_fatal_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
|
||||||
gMainMenuButtons[index] = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SFALL: Allow to move menu buttons
|
|
||||||
offsetX = offsetY = 0;
|
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_OFFSET_X_KEY, &offsetX);
|
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_OFFSET_Y_KEY, &offsetY);
|
|
||||||
|
|
||||||
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
|
||||||
gMainMenuButtons[index] = buttonCreate(gMainMenuWindow,
|
|
||||||
offsetX + 30,
|
|
||||||
offsetY + 19 + index * 42 - index,
|
|
||||||
26,
|
|
||||||
26,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
1111,
|
|
||||||
gMainMenuButtonKeyBindings[index],
|
|
||||||
_mainMenuButtonNormalFrmImage.getData(),
|
|
||||||
_mainMenuButtonPressedFrmImage.getData(),
|
|
||||||
0,
|
|
||||||
BUTTON_FLAG_TRANSPARENT);
|
|
||||||
if (gMainMenuButtons[index] == -1) {
|
|
||||||
// NOTE: Uninline.
|
|
||||||
return main_menu_fatal_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonSetMask(gMainMenuButtons[index], _mainMenuButtonNormalFrmImage.getData());
|
|
||||||
}
|
|
||||||
|
|
||||||
fontSetCurrent(104);
|
|
||||||
|
|
||||||
// SFALL: Allow to change font color of buttons
|
|
||||||
fontSettings = _colorTable[21091];
|
|
||||||
fontSettingsSFall = 0;
|
|
||||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY, &fontSettingsSFall);
|
|
||||||
if (fontSettingsSFall)
|
|
||||||
fontSettings = fontSettingsSFall & 0xFF;
|
|
||||||
|
|
||||||
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
|
||||||
msg.num = 9 + index;
|
|
||||||
if (messageListGetItem(&gMiscMessageList, &msg)) {
|
|
||||||
len = fontGetStringWidth(msg.text);
|
|
||||||
fontDrawText(gMainMenuWindowBuffer + offsetX + 640 * (offsetY + 42 * index - index + 20) + 126 - (len / 2), msg.text, 640 - (126 - (len / 2)) - 1, 640, fontSettings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fontSetCurrent(oldFont);
|
|
||||||
|
|
||||||
gMainMenuWindowInitialized = true;
|
|
||||||
gMainMenuWindowHidden = true;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x481968
|
|
||||||
static void mainMenuWindowFree()
|
|
||||||
{
|
|
||||||
if (!gMainMenuWindowInitialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
|
||||||
// FIXME: Why it tries to free only invalid buttons?
|
|
||||||
if (gMainMenuButtons[index] == -1) {
|
|
||||||
buttonDestroy(gMainMenuButtons[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_mainMenuButtonPressedFrmImage.unlock();
|
|
||||||
_mainMenuButtonNormalFrmImage.unlock();
|
|
||||||
|
|
||||||
if (gMainMenuWindow != -1) {
|
|
||||||
windowDestroy(gMainMenuWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
gMainMenuWindowInitialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x481A00
|
|
||||||
static void mainMenuWindowHide(bool animate)
|
|
||||||
{
|
|
||||||
if (!gMainMenuWindowInitialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gMainMenuWindowHidden) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
soundContinueAll();
|
|
||||||
|
|
||||||
if (animate) {
|
|
||||||
paletteFadeTo(gPaletteBlack);
|
|
||||||
soundContinueAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
windowHide(gMainMenuWindow);
|
|
||||||
|
|
||||||
gMainMenuWindowHidden = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x481A48
|
|
||||||
static void mainMenuWindowUnhide(bool animate)
|
|
||||||
{
|
|
||||||
if (!gMainMenuWindowInitialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gMainMenuWindowHidden) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
windowShow(gMainMenuWindow);
|
|
||||||
|
|
||||||
if (animate) {
|
|
||||||
colorPaletteLoad("color.pal");
|
|
||||||
paletteFadeTo(_cmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
gMainMenuWindowHidden = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x481AA8
|
|
||||||
static int _main_menu_is_enabled()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x481AEC
|
|
||||||
static int mainMenuWindowHandleEvents()
|
|
||||||
{
|
|
||||||
_in_main_menu = true;
|
|
||||||
|
|
||||||
bool oldCursorIsHidden = cursorIsHidden();
|
|
||||||
if (oldCursorIsHidden) {
|
|
||||||
mouseShowCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int tick = getTicks();
|
|
||||||
|
|
||||||
int rc = -1;
|
|
||||||
while (rc == -1) {
|
|
||||||
sharedFpsLimiter.mark();
|
|
||||||
|
|
||||||
int keyCode = inputGetInput();
|
|
||||||
|
|
||||||
for (int buttonIndex = 0; buttonIndex < MAIN_MENU_BUTTON_COUNT; buttonIndex++) {
|
|
||||||
if (keyCode == gMainMenuButtonKeyBindings[buttonIndex] || keyCode == toupper(gMainMenuButtonKeyBindings[buttonIndex])) {
|
|
||||||
// NOTE: Uninline.
|
|
||||||
main_menu_play_sound("nmselec1");
|
|
||||||
|
|
||||||
rc = _return_values[buttonIndex];
|
|
||||||
|
|
||||||
if (buttonIndex == MAIN_MENU_BUTTON_CREDITS && (gPressedPhysicalKeys[SDL_SCANCODE_RSHIFT] != KEY_STATE_UP || gPressedPhysicalKeys[SDL_SCANCODE_LSHIFT] != KEY_STATE_UP)) {
|
|
||||||
rc = MAIN_MENU_QUOTES;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == -1) {
|
|
||||||
if (keyCode == KEY_CTRL_R) {
|
|
||||||
rc = MAIN_MENU_SELFRUN;
|
|
||||||
continue;
|
|
||||||
} else if (keyCode == KEY_PLUS || keyCode == KEY_EQUAL) {
|
|
||||||
brightnessIncrease();
|
|
||||||
} else if (keyCode == KEY_MINUS || keyCode == KEY_UNDERSCORE) {
|
|
||||||
brightnessDecrease();
|
|
||||||
} else if (keyCode == KEY_UPPERCASE_D || keyCode == KEY_LOWERCASE_D) {
|
|
||||||
rc = MAIN_MENU_SCREENSAVER;
|
|
||||||
continue;
|
|
||||||
} else if (keyCode == 1111) {
|
|
||||||
if (!(mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_REPEAT)) {
|
|
||||||
// NOTE: Uninline.
|
|
||||||
main_menu_play_sound("nmselec0");
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit == 3) {
|
|
||||||
rc = MAIN_MENU_EXIT;
|
|
||||||
|
|
||||||
// NOTE: Uninline.
|
|
||||||
main_menu_play_sound("nmselec1");
|
|
||||||
break;
|
|
||||||
} else if (_game_user_wants_to_quit == 2) {
|
|
||||||
_game_user_wants_to_quit = 0;
|
|
||||||
} else {
|
|
||||||
if (getTicksSince(tick) >= gMainMenuScreensaverDelay) {
|
|
||||||
rc = MAIN_MENU_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderPresent();
|
|
||||||
sharedFpsLimiter.throttle();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldCursorIsHidden) {
|
|
||||||
mouseHideCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
_in_main_menu = false;
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Inlined.
|
|
||||||
//
|
|
||||||
// 0x481C88
|
|
||||||
static int main_menu_fatal_error()
|
|
||||||
{
|
|
||||||
mainMenuWindowFree();
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Inlined.
|
|
||||||
//
|
|
||||||
// 0x481C94
|
|
||||||
static void main_menu_play_sound(const char* fileName)
|
|
||||||
{
|
|
||||||
soundPlayFile(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
|
@ -0,0 +1,399 @@
|
||||||
|
#include "mainmenu.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "art.h"
|
||||||
|
#include "color.h"
|
||||||
|
#include "draw.h"
|
||||||
|
#include "game.h"
|
||||||
|
#include "game_sound.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "kb.h"
|
||||||
|
#include "mouse.h"
|
||||||
|
#include "palette.h"
|
||||||
|
#include "preferences.h"
|
||||||
|
#include "sfall_config.h"
|
||||||
|
#include "svga.h"
|
||||||
|
#include "text_font.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "window_manager.h"
|
||||||
|
|
||||||
|
namespace fallout {
|
||||||
|
|
||||||
|
#define MAIN_MENU_WINDOW_WIDTH 640
|
||||||
|
#define MAIN_MENU_WINDOW_HEIGHT 480
|
||||||
|
|
||||||
|
typedef enum MainMenuButton {
|
||||||
|
MAIN_MENU_BUTTON_INTRO,
|
||||||
|
MAIN_MENU_BUTTON_NEW_GAME,
|
||||||
|
MAIN_MENU_BUTTON_LOAD_GAME,
|
||||||
|
MAIN_MENU_BUTTON_OPTIONS,
|
||||||
|
MAIN_MENU_BUTTON_CREDITS,
|
||||||
|
MAIN_MENU_BUTTON_EXIT,
|
||||||
|
MAIN_MENU_BUTTON_COUNT,
|
||||||
|
} MainMenuButton;
|
||||||
|
|
||||||
|
static int main_menu_fatal_error();
|
||||||
|
static void main_menu_play_sound(const char* fileName);
|
||||||
|
|
||||||
|
// 0x5194F0
|
||||||
|
static int gMainMenuWindow = -1;
|
||||||
|
|
||||||
|
// 0x5194F4
|
||||||
|
static unsigned char* gMainMenuWindowBuffer = NULL;
|
||||||
|
|
||||||
|
// 0x519504
|
||||||
|
static bool _in_main_menu = false;
|
||||||
|
|
||||||
|
// 0x519508
|
||||||
|
static bool gMainMenuWindowInitialized = false;
|
||||||
|
|
||||||
|
// 0x51950C
|
||||||
|
static unsigned int gMainMenuScreensaverDelay = 120000;
|
||||||
|
|
||||||
|
// 0x519510
|
||||||
|
static const int gMainMenuButtonKeyBindings[MAIN_MENU_BUTTON_COUNT] = {
|
||||||
|
KEY_LOWERCASE_I, // intro
|
||||||
|
KEY_LOWERCASE_N, // new game
|
||||||
|
KEY_LOWERCASE_L, // load game
|
||||||
|
KEY_LOWERCASE_O, // options
|
||||||
|
KEY_LOWERCASE_C, // credits
|
||||||
|
KEY_LOWERCASE_E, // exit
|
||||||
|
};
|
||||||
|
|
||||||
|
// 0x519528
|
||||||
|
static const int _return_values[MAIN_MENU_BUTTON_COUNT] = {
|
||||||
|
MAIN_MENU_INTRO,
|
||||||
|
MAIN_MENU_NEW_GAME,
|
||||||
|
MAIN_MENU_LOAD_GAME,
|
||||||
|
MAIN_MENU_OPTIONS,
|
||||||
|
MAIN_MENU_CREDITS,
|
||||||
|
MAIN_MENU_EXIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 0x614840
|
||||||
|
static int gMainMenuButtons[MAIN_MENU_BUTTON_COUNT];
|
||||||
|
|
||||||
|
// 0x614858
|
||||||
|
static bool gMainMenuWindowHidden;
|
||||||
|
|
||||||
|
static FrmImage _mainMenuBackgroundFrmImage;
|
||||||
|
static FrmImage _mainMenuButtonNormalFrmImage;
|
||||||
|
static FrmImage _mainMenuButtonPressedFrmImage;
|
||||||
|
|
||||||
|
// 0x481650
|
||||||
|
int mainMenuWindowInit()
|
||||||
|
{
|
||||||
|
int fid;
|
||||||
|
MessageListItem msg;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (gMainMenuWindowInitialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
colorPaletteLoad("color.pal");
|
||||||
|
|
||||||
|
int mainMenuWindowX = (screenGetWidth() - MAIN_MENU_WINDOW_WIDTH) / 2;
|
||||||
|
int mainMenuWindowY = (screenGetHeight() - MAIN_MENU_WINDOW_HEIGHT) / 2;
|
||||||
|
gMainMenuWindow = windowCreate(mainMenuWindowX,
|
||||||
|
mainMenuWindowY,
|
||||||
|
MAIN_MENU_WINDOW_WIDTH,
|
||||||
|
MAIN_MENU_WINDOW_HEIGHT,
|
||||||
|
0,
|
||||||
|
WINDOW_HIDDEN | WINDOW_MOVE_ON_TOP);
|
||||||
|
if (gMainMenuWindow == -1) {
|
||||||
|
// NOTE: Uninline.
|
||||||
|
return main_menu_fatal_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
gMainMenuWindowBuffer = windowGetBuffer(gMainMenuWindow);
|
||||||
|
|
||||||
|
// mainmenu.frm
|
||||||
|
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 140, 0, 0, 0);
|
||||||
|
if (!_mainMenuBackgroundFrmImage.lock(backgroundFid)) {
|
||||||
|
// NOTE: Uninline.
|
||||||
|
return main_menu_fatal_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
blitBufferToBuffer(_mainMenuBackgroundFrmImage.getData(), 640, 480, 640, gMainMenuWindowBuffer, 640);
|
||||||
|
_mainMenuBackgroundFrmImage.unlock();
|
||||||
|
|
||||||
|
int oldFont = fontGetCurrent();
|
||||||
|
fontSetCurrent(100);
|
||||||
|
|
||||||
|
// SFALL: Allow to change font color/flags of copyright/version text
|
||||||
|
// It's the last byte ('3C' by default) that picks the colour used. The first byte supplies additional flags for this option
|
||||||
|
// 0x010000 - change the color for version string only
|
||||||
|
// 0x020000 - underline text (only for the version string)
|
||||||
|
// 0x040000 - monospace font (only for the version string)
|
||||||
|
int fontSettings = _colorTable[21091], fontSettingsSFall = 0;
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_FONT_COLOR_KEY, &fontSettingsSFall);
|
||||||
|
if (fontSettingsSFall && !(fontSettingsSFall & 0x010000))
|
||||||
|
fontSettings = fontSettingsSFall & 0xFF;
|
||||||
|
|
||||||
|
// SFALL: Allow to move copyright text
|
||||||
|
int offsetX = 0, offsetY = 0;
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_X_KEY, &offsetX);
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_Y_KEY, &offsetY);
|
||||||
|
|
||||||
|
// Copyright.
|
||||||
|
msg.num = 20;
|
||||||
|
if (messageListGetItem(&gMiscMessageList, &msg)) {
|
||||||
|
windowDrawText(gMainMenuWindow, msg.text, 0, offsetX + 15, offsetY + 460, fontSettings | 0x06000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SFALL: Make sure font settings are applied when using 0x010000 flag
|
||||||
|
if (fontSettingsSFall)
|
||||||
|
fontSettings = fontSettingsSFall;
|
||||||
|
|
||||||
|
// TODO: Allow to move version text
|
||||||
|
// Version.
|
||||||
|
char version[VERSION_MAX];
|
||||||
|
versionGetVersion(version, sizeof(version));
|
||||||
|
len = fontGetStringWidth(version);
|
||||||
|
windowDrawText(gMainMenuWindow, version, 0, 615 - len, 460, fontSettings | 0x06000000);
|
||||||
|
|
||||||
|
// menuup.frm
|
||||||
|
fid = buildFid(OBJ_TYPE_INTERFACE, 299, 0, 0, 0);
|
||||||
|
if (!_mainMenuButtonNormalFrmImage.lock(fid)) {
|
||||||
|
// NOTE: Uninline.
|
||||||
|
return main_menu_fatal_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
// menudown.frm
|
||||||
|
fid = buildFid(OBJ_TYPE_INTERFACE, 300, 0, 0, 0);
|
||||||
|
if (!_mainMenuButtonPressedFrmImage.lock(fid)) {
|
||||||
|
// NOTE: Uninline.
|
||||||
|
return main_menu_fatal_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
||||||
|
gMainMenuButtons[index] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SFALL: Allow to move menu buttons
|
||||||
|
offsetX = offsetY = 0;
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_OFFSET_X_KEY, &offsetX);
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_OFFSET_Y_KEY, &offsetY);
|
||||||
|
|
||||||
|
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
||||||
|
gMainMenuButtons[index] = buttonCreate(gMainMenuWindow,
|
||||||
|
offsetX + 30,
|
||||||
|
offsetY + 19 + index * 42 - index,
|
||||||
|
26,
|
||||||
|
26,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
1111,
|
||||||
|
gMainMenuButtonKeyBindings[index],
|
||||||
|
_mainMenuButtonNormalFrmImage.getData(),
|
||||||
|
_mainMenuButtonPressedFrmImage.getData(),
|
||||||
|
0,
|
||||||
|
BUTTON_FLAG_TRANSPARENT);
|
||||||
|
if (gMainMenuButtons[index] == -1) {
|
||||||
|
// NOTE: Uninline.
|
||||||
|
return main_menu_fatal_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonSetMask(gMainMenuButtons[index], _mainMenuButtonNormalFrmImage.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
fontSetCurrent(104);
|
||||||
|
|
||||||
|
// SFALL: Allow to change font color of buttons
|
||||||
|
fontSettings = _colorTable[21091];
|
||||||
|
fontSettingsSFall = 0;
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY, &fontSettingsSFall);
|
||||||
|
if (fontSettingsSFall)
|
||||||
|
fontSettings = fontSettingsSFall & 0xFF;
|
||||||
|
|
||||||
|
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
||||||
|
msg.num = 9 + index;
|
||||||
|
if (messageListGetItem(&gMiscMessageList, &msg)) {
|
||||||
|
len = fontGetStringWidth(msg.text);
|
||||||
|
fontDrawText(gMainMenuWindowBuffer + offsetX + 640 * (offsetY + 42 * index - index + 20) + 126 - (len / 2), msg.text, 640 - (126 - (len / 2)) - 1, 640, fontSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fontSetCurrent(oldFont);
|
||||||
|
|
||||||
|
gMainMenuWindowInitialized = true;
|
||||||
|
gMainMenuWindowHidden = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x481968
|
||||||
|
void mainMenuWindowFree()
|
||||||
|
{
|
||||||
|
if (!gMainMenuWindowInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
||||||
|
// FIXME: Why it tries to free only invalid buttons?
|
||||||
|
if (gMainMenuButtons[index] == -1) {
|
||||||
|
buttonDestroy(gMainMenuButtons[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_mainMenuButtonPressedFrmImage.unlock();
|
||||||
|
_mainMenuButtonNormalFrmImage.unlock();
|
||||||
|
|
||||||
|
if (gMainMenuWindow != -1) {
|
||||||
|
windowDestroy(gMainMenuWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
gMainMenuWindowInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x481A00
|
||||||
|
void mainMenuWindowHide(bool animate)
|
||||||
|
{
|
||||||
|
if (!gMainMenuWindowInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gMainMenuWindowHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
soundContinueAll();
|
||||||
|
|
||||||
|
if (animate) {
|
||||||
|
paletteFadeTo(gPaletteBlack);
|
||||||
|
soundContinueAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
windowHide(gMainMenuWindow);
|
||||||
|
|
||||||
|
gMainMenuWindowHidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x481A48
|
||||||
|
void mainMenuWindowUnhide(bool animate)
|
||||||
|
{
|
||||||
|
if (!gMainMenuWindowInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gMainMenuWindowHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
windowShow(gMainMenuWindow);
|
||||||
|
|
||||||
|
if (animate) {
|
||||||
|
colorPaletteLoad("color.pal");
|
||||||
|
paletteFadeTo(_cmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
gMainMenuWindowHidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x481AA8
|
||||||
|
int _main_menu_is_enabled()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x481AEC
|
||||||
|
int mainMenuWindowHandleEvents()
|
||||||
|
{
|
||||||
|
_in_main_menu = true;
|
||||||
|
|
||||||
|
bool oldCursorIsHidden = cursorIsHidden();
|
||||||
|
if (oldCursorIsHidden) {
|
||||||
|
mouseShowCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int tick = getTicks();
|
||||||
|
|
||||||
|
int rc = -1;
|
||||||
|
while (rc == -1) {
|
||||||
|
sharedFpsLimiter.mark();
|
||||||
|
|
||||||
|
int keyCode = inputGetInput();
|
||||||
|
|
||||||
|
for (int buttonIndex = 0; buttonIndex < MAIN_MENU_BUTTON_COUNT; buttonIndex++) {
|
||||||
|
if (keyCode == gMainMenuButtonKeyBindings[buttonIndex] || keyCode == toupper(gMainMenuButtonKeyBindings[buttonIndex])) {
|
||||||
|
// NOTE: Uninline.
|
||||||
|
main_menu_play_sound("nmselec1");
|
||||||
|
|
||||||
|
rc = _return_values[buttonIndex];
|
||||||
|
|
||||||
|
if (buttonIndex == MAIN_MENU_BUTTON_CREDITS && (gPressedPhysicalKeys[SDL_SCANCODE_RSHIFT] != KEY_STATE_UP || gPressedPhysicalKeys[SDL_SCANCODE_LSHIFT] != KEY_STATE_UP)) {
|
||||||
|
rc = MAIN_MENU_QUOTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == -1) {
|
||||||
|
if (keyCode == KEY_CTRL_R) {
|
||||||
|
rc = MAIN_MENU_SELFRUN;
|
||||||
|
continue;
|
||||||
|
} else if (keyCode == KEY_PLUS || keyCode == KEY_EQUAL) {
|
||||||
|
brightnessIncrease();
|
||||||
|
} else if (keyCode == KEY_MINUS || keyCode == KEY_UNDERSCORE) {
|
||||||
|
brightnessDecrease();
|
||||||
|
} else if (keyCode == KEY_UPPERCASE_D || keyCode == KEY_LOWERCASE_D) {
|
||||||
|
rc = MAIN_MENU_SCREENSAVER;
|
||||||
|
continue;
|
||||||
|
} else if (keyCode == 1111) {
|
||||||
|
if (!(mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_REPEAT)) {
|
||||||
|
// NOTE: Uninline.
|
||||||
|
main_menu_play_sound("nmselec0");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit == 3) {
|
||||||
|
rc = MAIN_MENU_EXIT;
|
||||||
|
|
||||||
|
// NOTE: Uninline.
|
||||||
|
main_menu_play_sound("nmselec1");
|
||||||
|
break;
|
||||||
|
} else if (_game_user_wants_to_quit == 2) {
|
||||||
|
_game_user_wants_to_quit = 0;
|
||||||
|
} else {
|
||||||
|
if (getTicksSince(tick) >= gMainMenuScreensaverDelay) {
|
||||||
|
rc = MAIN_MENU_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPresent();
|
||||||
|
sharedFpsLimiter.throttle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldCursorIsHidden) {
|
||||||
|
mouseHideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
_in_main_menu = false;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Inlined.
|
||||||
|
//
|
||||||
|
// 0x481C88
|
||||||
|
static int main_menu_fatal_error()
|
||||||
|
{
|
||||||
|
mainMenuWindowFree();
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Inlined.
|
||||||
|
//
|
||||||
|
// 0x481C94
|
||||||
|
static void main_menu_play_sound(const char* fileName)
|
||||||
|
{
|
||||||
|
soundPlayFile(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fallout
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef FALLOUT_MAINMENU_H_
|
||||||
|
#define FALLOUT_MAINMENU_H_
|
||||||
|
|
||||||
|
namespace fallout {
|
||||||
|
|
||||||
|
typedef enum MainMenuOption {
|
||||||
|
MAIN_MENU_INTRO,
|
||||||
|
MAIN_MENU_NEW_GAME,
|
||||||
|
MAIN_MENU_LOAD_GAME,
|
||||||
|
MAIN_MENU_SCREENSAVER,
|
||||||
|
MAIN_MENU_TIMEOUT,
|
||||||
|
MAIN_MENU_CREDITS,
|
||||||
|
MAIN_MENU_QUOTES,
|
||||||
|
MAIN_MENU_EXIT,
|
||||||
|
MAIN_MENU_SELFRUN,
|
||||||
|
MAIN_MENU_OPTIONS,
|
||||||
|
} MainMenuOption;
|
||||||
|
|
||||||
|
int mainMenuWindowInit();
|
||||||
|
void mainMenuWindowFree();
|
||||||
|
void mainMenuWindowHide(bool animate);
|
||||||
|
void mainMenuWindowUnhide(bool animate);
|
||||||
|
int _main_menu_is_enabled();
|
||||||
|
int mainMenuWindowHandleEvents();
|
||||||
|
|
||||||
|
} // namespace fallout
|
||||||
|
|
||||||
|
#endif /* FALLOUT_MAINMENU_H_ */
|
Loading…
Reference in New Issue