2022-05-19 01:51:26 -07:00
|
|
|
#include "main.h"
|
|
|
|
|
2022-09-15 02:38:23 -07:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2022-06-18 07:56:37 -07:00
|
|
|
#include "art.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "autorun.h"
|
|
|
|
#include "character_selector.h"
|
|
|
|
#include "color.h"
|
|
|
|
#include "credits.h"
|
|
|
|
#include "cycle.h"
|
|
|
|
#include "db.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "draw.h"
|
|
|
|
#include "endgame.h"
|
2022-06-18 07:56:37 -07:00
|
|
|
#include "fps_limiter.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "game.h"
|
|
|
|
#include "game_mouse.h"
|
|
|
|
#include "game_movie.h"
|
|
|
|
#include "game_sound.h"
|
2022-10-04 23:23:27 -07:00
|
|
|
#include "input.h"
|
2022-10-03 06:42:34 -07:00
|
|
|
#include "kb.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "loadsave.h"
|
|
|
|
#include "map.h"
|
2022-10-03 02:41:33 -07:00
|
|
|
#include "mouse.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "object.h"
|
|
|
|
#include "options.h"
|
|
|
|
#include "palette.h"
|
2022-05-28 02:34:49 -07:00
|
|
|
#include "platform_compat.h"
|
2022-07-29 06:04:05 -07:00
|
|
|
#include "proto.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "random.h"
|
|
|
|
#include "scripts.h"
|
|
|
|
#include "selfrun.h"
|
2022-10-06 06:32:46 -07:00
|
|
|
#include "settings.h"
|
2022-07-29 06:04:05 -07:00
|
|
|
#include "sfall_config.h"
|
2022-10-05 00:35:05 -07:00
|
|
|
#include "svga.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "text_font.h"
|
|
|
|
#include "version.h"
|
2022-07-29 06:04:05 -07:00
|
|
|
#include "window.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "window_manager.h"
|
2022-07-29 06:04:05 -07:00
|
|
|
#include "window_manager_private.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "word_wrap.h"
|
2022-09-14 23:00:11 -07:00
|
|
|
#include "worldmap.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-09-23 05:43:44 -07:00
|
|
|
namespace fallout {
|
|
|
|
|
2022-05-21 10:35:18 -07:00
|
|
|
#define MAIN_MENU_WINDOW_WIDTH 640
|
|
|
|
#define MAIN_MENU_WINDOW_HEIGHT 480
|
|
|
|
|
2022-05-21 10:42:14 -07:00
|
|
|
#define DEATH_WINDOW_WIDTH 640
|
|
|
|
#define DEATH_WINDOW_HEIGHT 480
|
|
|
|
|
2022-06-18 07:56:37 -07:00
|
|
|
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,
|
2022-07-29 06:04:05 -07:00
|
|
|
MAIN_MENU_SCREENSAVER,
|
2022-06-18 07:56:37 -07:00
|
|
|
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);
|
2022-09-01 08:41:37 -07:00
|
|
|
static int main_reset_system();
|
|
|
|
static void main_exit_system();
|
2022-06-18 07:56:37 -07:00
|
|
|
static int _main_load_new(char* fname);
|
2022-09-01 08:41:37 -07:00
|
|
|
static int main_loadgame_new();
|
|
|
|
static void main_unload_new();
|
2022-06-18 07:56:37 -07:00
|
|
|
static void mainLoop(FpsLimiter& fpsLimiter);
|
|
|
|
static void _main_selfrun_exit();
|
2022-07-29 06:04:05 -07:00
|
|
|
static void _main_selfrun_record();
|
|
|
|
static void _main_selfrun_play();
|
2022-06-18 07:56:37 -07:00
|
|
|
static void showDeath();
|
|
|
|
static void _main_death_voiceover_callback();
|
|
|
|
static int _mainDeathGrabTextFile(const char* fileName, char* dest);
|
|
|
|
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(FpsLimiter& fpsLimiter);
|
2022-09-01 08:41:37 -07:00
|
|
|
static int main_menu_fatal_error();
|
|
|
|
static void main_menu_play_sound(const char* fileName);
|
2022-06-18 07:56:37 -07:00
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x5194C8
|
2022-06-18 07:56:37 -07:00
|
|
|
static char _mainMap[] = "artemple.map";
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x5194D8
|
2022-06-18 07:56:37 -07:00
|
|
|
static int _main_game_paused = 0;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x5194DC
|
2022-06-18 07:56:37 -07:00
|
|
|
static char** _main_selfrun_list = NULL;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x5194E0
|
2022-06-18 07:56:37 -07:00
|
|
|
static int _main_selfrun_count = 0;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x5194E4
|
2022-06-18 07:56:37 -07:00
|
|
|
static int _main_selfrun_index = 0;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x5194E8
|
2022-06-18 07:56:37 -07:00
|
|
|
static bool _main_show_death_scene = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
// A switch to pick selfrun vs. intro video for screensaver:
|
|
|
|
// - `false` - will play next selfrun recording
|
|
|
|
// - `true` - will play intro video
|
|
|
|
//
|
|
|
|
// This value will alternate on every attempt, even if there are no selfrun
|
|
|
|
// recordings.
|
|
|
|
//
|
|
|
|
// 0x5194EC
|
|
|
|
static bool gMainMenuScreensaverCycle = false;
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x5194F0
|
2022-06-18 07:56:37 -07:00
|
|
|
static int gMainMenuWindow = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x5194F4
|
2022-06-18 07:56:37 -07:00
|
|
|
static unsigned char* gMainMenuWindowBuffer = NULL;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x519504
|
2022-06-18 07:56:37 -07:00
|
|
|
static bool _in_main_menu = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x519508
|
2022-06-18 07:56:37 -07:00
|
|
|
static bool gMainMenuWindowInitialized = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51950C
|
2022-06-18 07:56:37 -07:00
|
|
|
static unsigned int gMainMenuScreensaverDelay = 120000;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x519510
|
2022-06-18 07:56:37 -07:00
|
|
|
static const int gMainMenuButtonKeyBindings[MAIN_MENU_BUTTON_COUNT] = {
|
2022-05-19 01:51:26 -07:00
|
|
|
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
|
2022-06-18 07:56:37 -07:00
|
|
|
static const int _return_values[MAIN_MENU_BUTTON_COUNT] = {
|
2022-05-19 01:51:26 -07:00
|
|
|
MAIN_MENU_INTRO,
|
|
|
|
MAIN_MENU_NEW_GAME,
|
|
|
|
MAIN_MENU_LOAD_GAME,
|
|
|
|
MAIN_MENU_OPTIONS,
|
|
|
|
MAIN_MENU_CREDITS,
|
|
|
|
MAIN_MENU_EXIT,
|
|
|
|
};
|
|
|
|
|
|
|
|
// 0x614838
|
2022-06-18 07:56:37 -07:00
|
|
|
static bool _main_death_voiceover_done;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x614840
|
2022-06-18 07:56:37 -07:00
|
|
|
static int gMainMenuButtons[MAIN_MENU_BUTTON_COUNT];
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x614858
|
2022-06-18 07:56:37 -07:00
|
|
|
static bool gMainMenuWindowHidden;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-09-26 00:36:54 -07:00
|
|
|
static FrmImage _mainMenuBackgroundFrmImage;
|
|
|
|
static FrmImage _mainMenuButtonNormalFrmImage;
|
|
|
|
static FrmImage _mainMenuButtonPressedFrmImage;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x48099C
|
|
|
|
int falloutMain(int argc, char** argv)
|
|
|
|
{
|
|
|
|
if (!autorunMutexCreate()) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!falloutInit(argc, argv)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-04 03:22:40 -07:00
|
|
|
// SFALL: Allow to skip intro movies
|
|
|
|
int skipOpeningMovies;
|
|
|
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_SKIP_OPENING_MOVIES_KEY, &skipOpeningMovies);
|
2022-07-29 06:04:05 -07:00
|
|
|
if (skipOpeningMovies < 1) {
|
2022-06-04 03:22:40 -07:00
|
|
|
gameMoviePlay(MOVIE_IPLOGO, GAME_MOVIE_FADE_IN);
|
|
|
|
gameMoviePlay(MOVIE_INTRO, 0);
|
|
|
|
gameMoviePlay(MOVIE_CREDITS, 0);
|
|
|
|
}
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-05-23 01:13:28 -07:00
|
|
|
FpsLimiter fpsLimiter;
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
if (mainMenuWindowInit() == 0) {
|
|
|
|
bool done = false;
|
|
|
|
while (!done) {
|
|
|
|
keyboardReset();
|
|
|
|
_gsound_background_play_level_music("07desert", 11);
|
|
|
|
mainMenuWindowUnhide(1);
|
|
|
|
|
|
|
|
mouseShowCursor();
|
2022-05-23 01:13:28 -07:00
|
|
|
int mainMenuRc = mainMenuWindowHandleEvents(fpsLimiter);
|
2022-05-19 01:51:26 -07:00
|
|
|
mouseHideCursor();
|
|
|
|
|
|
|
|
switch (mainMenuRc) {
|
|
|
|
case MAIN_MENU_INTRO:
|
|
|
|
mainMenuWindowHide(true);
|
|
|
|
gameMoviePlay(MOVIE_INTRO, GAME_MOVIE_PAUSE_MUSIC);
|
|
|
|
gameMoviePlay(MOVIE_CREDITS, 0);
|
|
|
|
break;
|
|
|
|
case MAIN_MENU_NEW_GAME:
|
|
|
|
mainMenuWindowHide(true);
|
|
|
|
mainMenuWindowFree();
|
|
|
|
if (characterSelectorOpen() == 2) {
|
|
|
|
gameMoviePlay(MOVIE_ELDER, GAME_MOVIE_STOP_MUSIC);
|
|
|
|
randomSeedPrerandom(-1);
|
2022-05-25 14:16:20 -07:00
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
// SFALL: Override starting map.
|
2022-05-25 14:16:20 -07:00
|
|
|
char* mapName = NULL;
|
|
|
|
if (configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_STARTING_MAP_KEY, &mapName)) {
|
|
|
|
if (*mapName == '\0') {
|
|
|
|
mapName = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-31 20:48:26 -07:00
|
|
|
char* mapNameCopy = compat_strdup(mapName != NULL ? mapName : _mainMap);
|
2022-05-25 14:16:20 -07:00
|
|
|
_main_load_new(mapNameCopy);
|
|
|
|
free(mapNameCopy);
|
|
|
|
|
2022-05-23 01:13:28 -07:00
|
|
|
mainLoop(fpsLimiter);
|
2022-05-19 01:51:26 -07:00
|
|
|
paletteFadeTo(gPaletteWhite);
|
2022-09-01 08:41:37 -07:00
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_unload_new();
|
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_reset_system();
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
if (_main_show_death_scene != 0) {
|
|
|
|
showDeath();
|
|
|
|
_main_show_death_scene = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mainMenuWindowInit();
|
|
|
|
|
|
|
|
break;
|
|
|
|
case MAIN_MENU_LOAD_GAME:
|
|
|
|
if (1) {
|
2022-05-21 11:06:13 -07:00
|
|
|
int win = windowCreate(0, 0, screenGetWidth(), screenGetHeight(), _colorTable[0], WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
|
2022-05-19 01:51:26 -07:00
|
|
|
mainMenuWindowHide(true);
|
|
|
|
mainMenuWindowFree();
|
2022-09-01 08:41:37 -07:00
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_loadgame_new();
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
colorPaletteLoad("color.pal");
|
|
|
|
paletteFadeTo(_cmap);
|
|
|
|
int loadGameRc = lsgLoadGame(LOAD_SAVE_MODE_FROM_MAIN_MENU);
|
|
|
|
if (loadGameRc == -1) {
|
|
|
|
debugPrint("\n ** Error running LoadGame()! **\n");
|
|
|
|
} else if (loadGameRc != 0) {
|
|
|
|
windowDestroy(win);
|
|
|
|
win = -1;
|
2022-05-23 01:13:28 -07:00
|
|
|
mainLoop(fpsLimiter);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
paletteFadeTo(gPaletteWhite);
|
|
|
|
if (win != -1) {
|
|
|
|
windowDestroy(win);
|
|
|
|
}
|
2022-09-01 08:41:37 -07:00
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_unload_new();
|
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_reset_system();
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
if (_main_show_death_scene != 0) {
|
|
|
|
showDeath();
|
|
|
|
_main_show_death_scene = 0;
|
|
|
|
}
|
|
|
|
mainMenuWindowInit();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MAIN_MENU_TIMEOUT:
|
|
|
|
debugPrint("Main menu timed-out\n");
|
|
|
|
// FALLTHROUGH
|
2022-07-29 06:04:05 -07:00
|
|
|
case MAIN_MENU_SCREENSAVER:
|
|
|
|
_main_selfrun_play();
|
2022-05-19 01:51:26 -07:00
|
|
|
break;
|
|
|
|
case MAIN_MENU_OPTIONS:
|
|
|
|
mainMenuWindowHide(false);
|
|
|
|
mouseShowCursor();
|
|
|
|
showOptionsWithInitialKeyCode(112);
|
|
|
|
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
|
|
|
mouseShowCursor();
|
|
|
|
mainMenuWindowUnhide(0);
|
|
|
|
break;
|
|
|
|
case MAIN_MENU_CREDITS:
|
|
|
|
mainMenuWindowHide(true);
|
|
|
|
creditsOpen("credits.txt", -1, false);
|
|
|
|
break;
|
|
|
|
case MAIN_MENU_QUOTES:
|
|
|
|
// NOTE: There is a strange cmp at 0x480C50. Both operands are
|
|
|
|
// zero, set before the loop and do not modify afterwards. For
|
|
|
|
// clarity this condition is omitted.
|
|
|
|
mainMenuWindowHide(true);
|
|
|
|
creditsOpen("quotes.txt", -1, true);
|
|
|
|
break;
|
|
|
|
case MAIN_MENU_EXIT:
|
|
|
|
case -1:
|
|
|
|
done = true;
|
|
|
|
mainMenuWindowHide(true);
|
|
|
|
mainMenuWindowFree();
|
|
|
|
backgroundSoundDelete();
|
|
|
|
break;
|
|
|
|
case MAIN_MENU_SELFRUN:
|
2022-07-29 06:04:05 -07:00
|
|
|
_main_selfrun_record();
|
2022-05-19 01:51:26 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
main_exit_system();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
autorunMutexClose();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x480CC0
|
2022-06-18 07:56:37 -07:00
|
|
|
static bool falloutInit(int argc, char** argv)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (gameInitWithOptions("FALLOUT II", false, 0, 0, argc, argv) == -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_main_selfrun_list != NULL) {
|
|
|
|
_main_selfrun_exit();
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
if (selfrunInitFileList(&_main_selfrun_list, &_main_selfrun_count) == 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
_main_selfrun_index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Inlined.
|
|
|
|
//
|
|
|
|
// 0x480D0C
|
|
|
|
static int main_reset_system()
|
|
|
|
{
|
|
|
|
gameReset();
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: Inlined.
|
|
|
|
//
|
|
|
|
// 0x480D18
|
|
|
|
static void main_exit_system()
|
|
|
|
{
|
|
|
|
backgroundSoundDelete();
|
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
_main_selfrun_exit();
|
|
|
|
|
|
|
|
gameExit();
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x480D4C
|
2022-06-18 07:56:37 -07:00
|
|
|
static int _main_load_new(char* mapFileName)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
_game_user_wants_to_quit = 0;
|
|
|
|
_main_show_death_scene = 0;
|
2022-06-08 10:38:46 -07:00
|
|
|
gDude->flags &= ~OBJECT_FLAT;
|
2022-05-19 01:51:26 -07:00
|
|
|
objectShow(gDude, NULL);
|
|
|
|
mouseHideCursor();
|
|
|
|
|
2022-05-21 11:06:13 -07:00
|
|
|
int win = windowCreate(0, 0, screenGetWidth(), screenGetHeight(), _colorTable[0], WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
|
2022-05-19 01:51:26 -07:00
|
|
|
windowRefresh(win);
|
|
|
|
|
|
|
|
colorPaletteLoad("color.pal");
|
|
|
|
paletteFadeTo(_cmap);
|
|
|
|
_map_init();
|
|
|
|
gameMouseSetCursor(MOUSE_CURSOR_NONE);
|
|
|
|
mouseShowCursor();
|
|
|
|
mapLoadByName(mapFileName);
|
2022-09-15 01:42:02 -07:00
|
|
|
wmMapMusicStart();
|
2022-05-19 01:51:26 -07:00
|
|
|
paletteFadeTo(gPaletteWhite);
|
|
|
|
windowDestroy(win);
|
|
|
|
colorPaletteLoad("color.pal");
|
|
|
|
paletteFadeTo(_cmap);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Inlined.
|
|
|
|
//
|
|
|
|
// 0x480DF8
|
|
|
|
static int main_loadgame_new()
|
|
|
|
{
|
|
|
|
_game_user_wants_to_quit = 0;
|
|
|
|
_main_show_death_scene = 0;
|
|
|
|
|
|
|
|
gDude->flags &= ~OBJECT_FLAT;
|
|
|
|
|
|
|
|
objectShow(gDude, NULL);
|
|
|
|
mouseHideCursor();
|
|
|
|
|
|
|
|
_map_init();
|
|
|
|
|
|
|
|
gameMouseSetCursor(MOUSE_CURSOR_NONE);
|
|
|
|
mouseShowCursor();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x480E34
|
|
|
|
static void main_unload_new()
|
|
|
|
{
|
|
|
|
objectHide(gDude, NULL);
|
|
|
|
_map_exit();
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x480E48
|
2022-06-18 07:56:37 -07:00
|
|
|
static void mainLoop(FpsLimiter& fpsLimiter)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
bool cursorWasHidden = cursorIsHidden();
|
|
|
|
if (cursorWasHidden) {
|
|
|
|
mouseShowCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
_main_game_paused = 0;
|
|
|
|
|
|
|
|
scriptsEnable();
|
|
|
|
|
|
|
|
while (_game_user_wants_to_quit == 0) {
|
2022-05-23 01:13:28 -07:00
|
|
|
fpsLimiter.mark();
|
|
|
|
|
2022-10-05 00:11:47 -07:00
|
|
|
int keyCode = inputGetInput();
|
2022-05-19 01:51:26 -07:00
|
|
|
gameHandleKey(keyCode, false);
|
|
|
|
|
|
|
|
scriptsHandleRequests();
|
|
|
|
|
|
|
|
mapHandleTransition();
|
|
|
|
|
|
|
|
if (_main_game_paused != 0) {
|
|
|
|
_main_game_paused = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((gDude->data.critter.combat.results & (DAM_DEAD | DAM_KNOCKED_OUT)) != 0) {
|
|
|
|
endgameSetupDeathEnding(ENDGAME_DEATH_ENDING_REASON_DEATH);
|
|
|
|
_main_show_death_scene = 1;
|
|
|
|
_game_user_wants_to_quit = 2;
|
|
|
|
}
|
2022-05-23 01:13:28 -07:00
|
|
|
|
|
|
|
fpsLimiter.throttle();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
scriptsDisable();
|
|
|
|
|
|
|
|
if (cursorWasHidden) {
|
|
|
|
mouseHideCursor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x480F38
|
2022-06-18 07:56:37 -07:00
|
|
|
static void _main_selfrun_exit()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (_main_selfrun_list != NULL) {
|
2022-07-29 06:04:05 -07:00
|
|
|
selfrunFreeFileList(&_main_selfrun_list);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
_main_selfrun_count = 0;
|
|
|
|
_main_selfrun_index = 0;
|
|
|
|
_main_selfrun_list = NULL;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
// 0x480F64
|
|
|
|
static void _main_selfrun_record()
|
|
|
|
{
|
|
|
|
SelfrunData selfrunData;
|
|
|
|
bool ready = false;
|
|
|
|
|
|
|
|
char** fileList;
|
|
|
|
int fileListLength = fileNameListInit("maps\\*.map", &fileList, 0, 0);
|
|
|
|
if (fileListLength != 0) {
|
|
|
|
int selectedFileIndex = _win_list_select("Select Map", fileList, fileListLength, 0, 80, 80, 0x10000 | 0x100 | 4);
|
|
|
|
if (selectedFileIndex != -1) {
|
|
|
|
// NOTE: It's size is likely 13 chars (on par with SelfrunData
|
|
|
|
// fields), but due to the padding it takes 16 chars on stack.
|
|
|
|
char recordingName[SELFRUN_RECORDING_FILE_NAME_LENGTH];
|
|
|
|
recordingName[0] = '\0';
|
|
|
|
if (_win_get_str(recordingName, sizeof(recordingName) - 2, "Enter name for recording (8 characters max, no extension):", 100, 100) == 0) {
|
|
|
|
memset(&selfrunData, 0, sizeof(selfrunData));
|
|
|
|
if (selfrunPrepareRecording(recordingName, fileList[selectedFileIndex], &selfrunData) == 0) {
|
|
|
|
ready = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fileNameListFree(&fileList, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ready) {
|
|
|
|
mainMenuWindowHide(true);
|
|
|
|
mainMenuWindowFree();
|
|
|
|
backgroundSoundDelete();
|
|
|
|
randomSeedPrerandom(0xBEEFFEED);
|
2022-09-01 08:41:37 -07:00
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_reset_system();
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
_proto_dude_init("premade\\combat.gcd");
|
|
|
|
_main_load_new(selfrunData.mapFileName);
|
|
|
|
selfrunRecordingLoop(&selfrunData);
|
|
|
|
paletteFadeTo(gPaletteWhite);
|
2022-09-01 08:41:37 -07:00
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_unload_new();
|
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_reset_system();
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
mainMenuWindowInit();
|
|
|
|
|
|
|
|
if (_main_selfrun_list != NULL) {
|
|
|
|
_main_selfrun_exit();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selfrunInitFileList(&_main_selfrun_list, &_main_selfrun_count) == 0) {
|
|
|
|
_main_selfrun_index = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x48109C
|
|
|
|
static void _main_selfrun_play()
|
|
|
|
{
|
|
|
|
if (!gMainMenuScreensaverCycle && _main_selfrun_count > 0) {
|
|
|
|
SelfrunData selfrunData;
|
|
|
|
if (selfrunPreparePlayback(_main_selfrun_list[_main_selfrun_index], &selfrunData) == 0) {
|
|
|
|
mainMenuWindowHide(true);
|
|
|
|
mainMenuWindowFree();
|
|
|
|
backgroundSoundDelete();
|
|
|
|
randomSeedPrerandom(0xBEEFFEED);
|
2022-09-01 08:41:37 -07:00
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_reset_system();
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
_proto_dude_init("premade\\combat.gcd");
|
|
|
|
_main_load_new(selfrunData.mapFileName);
|
|
|
|
selfrunPlaybackLoop(&selfrunData);
|
|
|
|
paletteFadeTo(gPaletteWhite);
|
2022-09-01 08:41:37 -07:00
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_unload_new();
|
|
|
|
|
|
|
|
// NOTE: Uninline.
|
|
|
|
main_reset_system();
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
mainMenuWindowInit();
|
|
|
|
}
|
|
|
|
|
|
|
|
_main_selfrun_index++;
|
|
|
|
if (_main_selfrun_index >= _main_selfrun_count) {
|
|
|
|
_main_selfrun_index = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
mainMenuWindowHide(true);
|
|
|
|
gameMoviePlay(MOVIE_INTRO, GAME_MOVIE_PAUSE_MUSIC);
|
|
|
|
}
|
|
|
|
|
|
|
|
gMainMenuScreensaverCycle = !gMainMenuScreensaverCycle;
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x48118C
|
2022-06-18 07:56:37 -07:00
|
|
|
static void showDeath()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
artCacheFlush();
|
|
|
|
colorCycleDisable();
|
|
|
|
gameMouseSetCursor(MOUSE_CURSOR_NONE);
|
|
|
|
|
|
|
|
bool oldCursorIsHidden = cursorIsHidden();
|
|
|
|
if (oldCursorIsHidden) {
|
|
|
|
mouseShowCursor();
|
|
|
|
}
|
|
|
|
|
2022-05-21 10:42:14 -07:00
|
|
|
int deathWindowX = (screenGetWidth() - DEATH_WINDOW_WIDTH) / 2;
|
|
|
|
int deathWindowY = (screenGetHeight() - DEATH_WINDOW_HEIGHT) / 2;
|
|
|
|
int win = windowCreate(deathWindowX,
|
|
|
|
deathWindowY,
|
|
|
|
DEATH_WINDOW_WIDTH,
|
|
|
|
DEATH_WINDOW_HEIGHT,
|
|
|
|
0,
|
|
|
|
WINDOW_FLAG_0x04);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (win != -1) {
|
|
|
|
do {
|
|
|
|
unsigned char* windowBuffer = windowGetBuffer(win);
|
|
|
|
if (windowBuffer == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// DEATH.FRM
|
2022-09-26 00:36:54 -07:00
|
|
|
FrmImage backgroundFrmImage;
|
2022-07-29 06:04:05 -07:00
|
|
|
int fid = buildFid(OBJ_TYPE_INTERFACE, 309, 0, 0, 0);
|
2022-09-26 00:36:54 -07:00
|
|
|
if (!backgroundFrmImage.lock(fid)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (mouseGetEvent() != 0) {
|
2022-10-05 00:11:47 -07:00
|
|
|
inputGetInput();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
keyboardReset();
|
|
|
|
inputEventQueueReset();
|
|
|
|
|
2022-09-26 00:36:54 -07:00
|
|
|
blitBufferToBuffer(backgroundFrmImage.getData(), 640, 480, 640, windowBuffer, 640);
|
|
|
|
backgroundFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
const char* deathFileName = endgameDeathEndingGetFileName();
|
|
|
|
|
2022-10-06 06:32:46 -07:00
|
|
|
if (settings.preferences.subtitles) {
|
2022-05-19 01:51:26 -07:00
|
|
|
char text[512];
|
|
|
|
if (_mainDeathGrabTextFile(deathFileName, text) == 0) {
|
|
|
|
debugPrint("\n((ShowDeath)): %s\n", text);
|
|
|
|
|
|
|
|
short beginnings[WORD_WRAP_MAX_COUNT];
|
|
|
|
short count;
|
|
|
|
if (_mainDeathWordWrap(text, 560, beginnings, &count) == 0) {
|
|
|
|
unsigned char* p = windowBuffer + 640 * (480 - fontGetLineHeight() * count - 8);
|
|
|
|
bufferFill(p - 602, 564, fontGetLineHeight() * count + 2, 640, 0);
|
|
|
|
p += 40;
|
|
|
|
for (int index = 0; index < count; index++) {
|
|
|
|
fontDrawText(p, text + beginnings[index], 560, 640, _colorTable[32767]);
|
|
|
|
p += 640 * fontGetLineHeight();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
windowRefresh(win);
|
|
|
|
|
|
|
|
colorPaletteLoad("art\\intrface\\death.pal");
|
|
|
|
paletteFadeTo(_cmap);
|
|
|
|
|
|
|
|
_main_death_voiceover_done = false;
|
|
|
|
speechSetEndCallback(_main_death_voiceover_callback);
|
|
|
|
|
|
|
|
unsigned int delay;
|
|
|
|
if (speechLoad(deathFileName, 10, 14, 15) == -1) {
|
|
|
|
delay = 3000;
|
|
|
|
} else {
|
|
|
|
delay = UINT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
_gsound_speech_play_preloaded();
|
|
|
|
|
2022-05-20 01:02:31 -07:00
|
|
|
// SFALL: Fix the playback of the speech sound file for the death
|
|
|
|
// screen.
|
2022-10-05 00:11:47 -07:00
|
|
|
inputBlockForTocks(100);
|
2022-05-20 01:02:31 -07:00
|
|
|
|
2022-10-05 00:11:47 -07:00
|
|
|
unsigned int time = getTicks();
|
2022-05-19 01:51:26 -07:00
|
|
|
int keyCode;
|
|
|
|
do {
|
2022-10-05 00:11:47 -07:00
|
|
|
keyCode = inputGetInput();
|
2022-05-19 01:51:26 -07:00
|
|
|
} while (keyCode == -1 && !_main_death_voiceover_done && getTicksSince(time) < delay);
|
|
|
|
|
|
|
|
speechSetEndCallback(NULL);
|
|
|
|
|
|
|
|
speechDelete();
|
|
|
|
|
|
|
|
while (mouseGetEvent() != 0) {
|
2022-10-05 00:11:47 -07:00
|
|
|
inputGetInput();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (keyCode == -1) {
|
2022-10-05 00:11:47 -07:00
|
|
|
inputPauseForTocks(500);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
paletteFadeTo(gPaletteBlack);
|
|
|
|
colorPaletteLoad("color.pal");
|
|
|
|
} while (0);
|
|
|
|
windowDestroy(win);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldCursorIsHidden) {
|
|
|
|
mouseHideCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
|
|
|
|
|
|
|
colorCycleEnable();
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4814A8
|
2022-06-18 07:56:37 -07:00
|
|
|
static void _main_death_voiceover_callback()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
_main_death_voiceover_done = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read endgame subtitle.
|
|
|
|
//
|
|
|
|
// 0x4814B4
|
2022-06-18 07:56:37 -07:00
|
|
|
static int _mainDeathGrabTextFile(const char* fileName, char* dest)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
const char* p = strrchr(fileName, '\\');
|
|
|
|
if (p == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-05-28 02:34:49 -07:00
|
|
|
char path[COMPAT_MAX_PATH];
|
2022-10-06 06:32:46 -07:00
|
|
|
sprintf(path, "text\\%s\\cuts\\%s%s", settings.system.language.c_str(), p + 1, ".TXT");
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
File* stream = fileOpen(path, "rt");
|
|
|
|
if (stream == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
int c = fileReadChar(stream);
|
|
|
|
if (c == -1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '\n') {
|
|
|
|
c = ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
*dest++ = (c & 0xFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
fileClose(stream);
|
|
|
|
|
|
|
|
*dest = '\0';
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x481598
|
2022-06-18 07:56:37 -07:00
|
|
|
static int _mainDeathWordWrap(char* text, int width, short* beginnings, short* count)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
while (true) {
|
2022-07-29 06:04:05 -07:00
|
|
|
char* sep = strchr(text, ':');
|
|
|
|
if (sep == NULL) {
|
2022-05-19 01:51:26 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
if (sep - 1 < text) {
|
2022-05-19 01:51:26 -07:00
|
|
|
break;
|
|
|
|
}
|
2022-07-29 06:04:05 -07:00
|
|
|
sep[0] = ' ';
|
|
|
|
sep[-1] = ' ';
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (wordWrap(text, width, beginnings, count) == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Probably wrong.
|
|
|
|
*count -= 1;
|
|
|
|
|
|
|
|
for (int index = 1; index < *count; index++) {
|
|
|
|
char* p = text + beginnings[index];
|
|
|
|
while (p >= text && *p != ' ') {
|
|
|
|
p--;
|
|
|
|
beginnings[index]--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p != NULL) {
|
|
|
|
*p = '\0';
|
|
|
|
beginnings[index]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x481650
|
2022-06-18 07:56:37 -07:00
|
|
|
static int mainMenuWindowInit()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
int fid;
|
|
|
|
MessageListItem msg;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (gMainMenuWindowInitialized) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
colorPaletteLoad("color.pal");
|
|
|
|
|
2022-05-21 10:35:18 -07:00
|
|
|
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_FLAG_0x04);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gMainMenuWindow == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return main_menu_fatal_error();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gMainMenuWindowBuffer = windowGetBuffer(gMainMenuWindow);
|
|
|
|
|
|
|
|
// mainmenu.frm
|
2022-07-29 06:04:05 -07:00
|
|
|
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 140, 0, 0, 0);
|
2022-09-26 00:36:54 -07:00
|
|
|
if (!_mainMenuBackgroundFrmImage.lock(backgroundFid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return main_menu_fatal_error();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-26 00:36:54 -07:00
|
|
|
blitBufferToBuffer(_mainMenuBackgroundFrmImage.getData(), 640, 480, 640, gMainMenuWindowBuffer, 640);
|
|
|
|
_mainMenuBackgroundFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
int oldFont = fontGetCurrent();
|
|
|
|
fontSetCurrent(100);
|
|
|
|
|
2022-06-07 14:20:55 -07:00
|
|
|
// 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
|
2022-06-09 23:36:47 -07:00
|
|
|
// 0x010000 - change the color for version string only
|
|
|
|
// 0x020000 - underline text (only for the version string)
|
|
|
|
// 0x040000 - monospace font (only for the version string)
|
2022-06-07 14:20:55 -07:00
|
|
|
int fontSettings = _colorTable[21091], fontSettingsSFall = 0;
|
2022-06-09 23:36:47 -07:00
|
|
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_FONT_COLOR_KEY, &fontSettingsSFall);
|
2022-06-07 14:20:55 -07:00
|
|
|
if (fontSettingsSFall && !(fontSettingsSFall & 0x010000))
|
2022-07-29 06:04:05 -07:00
|
|
|
fontSettings = fontSettingsSFall & 0xFF;
|
2022-06-07 14:20:55 -07:00
|
|
|
|
2022-06-18 01:06:00 -07:00
|
|
|
// 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);
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// Copyright.
|
|
|
|
msg.num = 20;
|
|
|
|
if (messageListGetItem(&gMiscMessageList, &msg)) {
|
2022-06-18 01:06:00 -07:00
|
|
|
windowDrawText(gMainMenuWindow, msg.text, 0, offsetX + 15, offsetY + 460, fontSettings | 0x06000000);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-06-09 23:36:47 -07:00
|
|
|
// SFALL: Make sure font settings are applied when using 0x010000 flag
|
2022-06-07 14:20:55 -07:00
|
|
|
if (fontSettingsSFall)
|
|
|
|
fontSettings = fontSettingsSFall;
|
|
|
|
|
2022-06-18 01:06:00 -07:00
|
|
|
// TODO: Allow to move version text
|
2022-05-19 01:51:26 -07:00
|
|
|
// Version.
|
|
|
|
char version[VERSION_MAX];
|
|
|
|
versionGetVersion(version);
|
|
|
|
len = fontGetStringWidth(version);
|
2022-06-07 14:20:55 -07:00
|
|
|
windowDrawText(gMainMenuWindow, version, 0, 615 - len, 460, fontSettings | 0x06000000);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// menuup.frm
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 299, 0, 0, 0);
|
2022-09-26 00:36:54 -07:00
|
|
|
if (!_mainMenuButtonNormalFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return main_menu_fatal_error();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// menudown.frm
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 300, 0, 0, 0);
|
2022-09-26 00:36:54 -07:00
|
|
|
if (!_mainMenuButtonPressedFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return main_menu_fatal_error();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
|
|
|
gMainMenuButtons[index] = -1;
|
|
|
|
}
|
|
|
|
|
2022-06-18 01:06:00 -07:00
|
|
|
// 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);
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
2022-09-26 00:36:54 -07:00
|
|
|
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);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gMainMenuButtons[index] == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return main_menu_fatal_error();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-26 00:36:54 -07:00
|
|
|
buttonSetMask(gMainMenuButtons[index], _mainMenuButtonNormalFrmImage.getData());
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fontSetCurrent(104);
|
|
|
|
|
2022-06-07 14:20:55 -07:00
|
|
|
// SFALL: Allow to change font color of buttons
|
|
|
|
fontSettings = _colorTable[21091];
|
|
|
|
fontSettingsSFall = 0;
|
2022-06-09 23:36:47 -07:00
|
|
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY, &fontSettingsSFall);
|
2022-06-07 14:20:55 -07:00
|
|
|
if (fontSettingsSFall)
|
|
|
|
fontSettings = fontSettingsSFall & 0xFF;
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
|
|
|
|
msg.num = 9 + index;
|
|
|
|
if (messageListGetItem(&gMiscMessageList, &msg)) {
|
|
|
|
len = fontGetStringWidth(msg.text);
|
2022-06-18 01:06:00 -07:00
|
|
|
fontDrawText(gMainMenuWindowBuffer + offsetX + 640 * (offsetY + 42 * index - index + 20) + 126 - (len / 2), msg.text, 640 - (126 - (len / 2)) - 1, 640, fontSettings);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fontSetCurrent(oldFont);
|
|
|
|
|
|
|
|
gMainMenuWindowInitialized = true;
|
|
|
|
gMainMenuWindowHidden = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x481968
|
2022-06-18 07:56:37 -07:00
|
|
|
static void mainMenuWindowFree()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
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]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-26 00:36:54 -07:00
|
|
|
_mainMenuButtonPressedFrmImage.unlock();
|
|
|
|
_mainMenuButtonNormalFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gMainMenuWindow != -1) {
|
|
|
|
windowDestroy(gMainMenuWindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
gMainMenuWindowInitialized = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x481A00
|
2022-06-18 07:56:37 -07:00
|
|
|
static void mainMenuWindowHide(bool animate)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (!gMainMenuWindowInitialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gMainMenuWindowHidden) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
soundContinueAll();
|
|
|
|
|
|
|
|
if (animate) {
|
|
|
|
paletteFadeTo(gPaletteBlack);
|
|
|
|
soundContinueAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
windowHide(gMainMenuWindow);
|
|
|
|
|
|
|
|
gMainMenuWindowHidden = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x481A48
|
2022-06-18 07:56:37 -07:00
|
|
|
static void mainMenuWindowUnhide(bool animate)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (!gMainMenuWindowInitialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gMainMenuWindowHidden) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowUnhide(gMainMenuWindow);
|
|
|
|
|
|
|
|
if (animate) {
|
|
|
|
colorPaletteLoad("color.pal");
|
|
|
|
paletteFadeTo(_cmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
gMainMenuWindowHidden = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x481AA8
|
2022-06-18 07:56:37 -07:00
|
|
|
static int _main_menu_is_enabled()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x481AEC
|
2022-06-18 07:56:37 -07:00
|
|
|
static int mainMenuWindowHandleEvents(FpsLimiter& fpsLimiter)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
_in_main_menu = true;
|
|
|
|
|
|
|
|
bool oldCursorIsHidden = cursorIsHidden();
|
|
|
|
if (oldCursorIsHidden) {
|
|
|
|
mouseShowCursor();
|
|
|
|
}
|
|
|
|
|
2022-10-05 00:11:47 -07:00
|
|
|
unsigned int tick = getTicks();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
int rc = -1;
|
|
|
|
while (rc == -1) {
|
2022-05-23 01:13:28 -07:00
|
|
|
fpsLimiter.mark();
|
|
|
|
|
2022-10-05 00:11:47 -07:00
|
|
|
int keyCode = inputGetInput();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
for (int buttonIndex = 0; buttonIndex < MAIN_MENU_BUTTON_COUNT; buttonIndex++) {
|
|
|
|
if (keyCode == gMainMenuButtonKeyBindings[buttonIndex] || keyCode == toupper(gMainMenuButtonKeyBindings[buttonIndex])) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
main_menu_play_sound("nmselec1");
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
rc = _return_values[buttonIndex];
|
|
|
|
|
2022-05-23 01:44:49 -07:00
|
|
|
if (buttonIndex == MAIN_MENU_BUTTON_CREDITS && (gPressedPhysicalKeys[SDL_SCANCODE_RSHIFT] != KEY_STATE_UP || gPressedPhysicalKeys[SDL_SCANCODE_LSHIFT] != KEY_STATE_UP)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
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) {
|
2022-07-29 06:04:05 -07:00
|
|
|
rc = MAIN_MENU_SCREENSAVER;
|
2022-05-19 01:51:26 -07:00
|
|
|
continue;
|
|
|
|
} else if (keyCode == 1111) {
|
|
|
|
if (!(mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_REPEAT)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
main_menu_play_sound("nmselec0");
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit == 3) {
|
|
|
|
rc = MAIN_MENU_EXIT;
|
2022-10-03 02:41:33 -07:00
|
|
|
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
main_menu_play_sound("nmselec1");
|
2022-05-19 01:51:26 -07:00
|
|
|
break;
|
|
|
|
} else if (_game_user_wants_to_quit == 2) {
|
|
|
|
_game_user_wants_to_quit = 0;
|
|
|
|
} else {
|
|
|
|
if (getTicksSince(tick) >= gMainMenuScreensaverDelay) {
|
|
|
|
rc = MAIN_MENU_TIMEOUT;
|
|
|
|
}
|
|
|
|
}
|
2022-05-23 01:13:28 -07:00
|
|
|
|
|
|
|
fpsLimiter.throttle();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (oldCursorIsHidden) {
|
|
|
|
mouseHideCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
_in_main_menu = false;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2022-09-01 08:41:37 -07:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
2022-09-23 05:43:44 -07:00
|
|
|
|
|
|
|
} // namespace fallout
|