diff --git a/src/m_menu.c b/src/m_menu.c deleted file mode 100644 index 16cef2eb9..000000000 --- a/src/m_menu.c +++ /dev/null @@ -1,11208 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1993-1996 by id Software, Inc. -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 2011-2016 by Matthew "Inuyasha" Walsh. -// Copyright (C) 1999-2018 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file m_menu.c -/// \brief XMOD's extremely revamped menu system. - -#ifdef __GNUC__ -#include -#endif - -#include "m_menu.h" - -#include "doomdef.h" -#include "d_main.h" -#include "d_netcmd.h" -#include "console.h" -#include "r_local.h" -#include "hu_stuff.h" -#include "g_game.h" -#include "g_input.h" -#include "m_argv.h" - -// Data. -#include "sounds.h" -#include "s_sound.h" -#include "i_system.h" - -// Addfile -#include "filesrch.h" - -#include "v_video.h" -#include "i_video.h" -#include "keys.h" -#include "z_zone.h" -#include "w_wad.h" -#include "p_local.h" -#include "p_setup.h" -#include "f_finale.h" - -#ifdef HWRENDER -#include "hardware/hw_main.h" -#endif - -#include "d_net.h" -#include "mserv.h" -#include "m_misc.h" -#include "m_anigif.h" -#include "byteptr.h" -#include "st_stuff.h" -#include "i_sound.h" -#include "k_kart.h" // SRB2kart -#include "k_pwrlv.h" -#include "d_player.h" // KITEM_ constants -#include "k_color.h" -#include "k_grandprix.h" - -#include "i_joy.h" // for joystick menu controls - -// Condition Sets -#include "m_cond.h" - -// And just some randomness for the exits. -#include "m_random.h" - -#if defined(HAVE_SDL) -#include "SDL.h" -#if SDL_VERSION_ATLEAST(2,0,0) -#include "sdl/sdlmain.h" // JOYSTICK_HOTPLUG -#endif -#endif - -#ifdef PC_DOS -#include // for snprintf -int snprintf(char *str, size_t n, const char *fmt, ...); -//int vsnprintf(char *str, size_t n, const char *fmt, va_list ap); -#endif - -#define SKULLXOFF -32 -#define LINEHEIGHT 16 -#define STRINGHEIGHT 8 -#define FONTBHEIGHT 20 -#define SMALLLINEHEIGHT 8 -#define SLIDER_RANGE 10 -#define SLIDER_WIDTH (8*SLIDER_RANGE+6) -#define SERVERS_PER_PAGE 11 - -#if defined (NONET) || defined (TESTERS) -#define NOMENUHOST -#endif - -typedef enum -{ - QUITMSG = 0, - QUITMSG1, - QUITMSG2, - QUITMSG3, - QUITMSG4, - QUITMSG5, - QUITMSG6, - QUITMSG7, - - QUIT2MSG, - QUIT2MSG1, - QUIT2MSG2, - QUIT2MSG3, - QUIT2MSG4, - QUIT2MSG5, - QUIT2MSG6, - - QUIT3MSG, - QUIT3MSG1, - QUIT3MSG2, - QUIT3MSG3, - QUIT3MSG4, - QUIT3MSG5, - QUIT3MSG6, - NUM_QUITMESSAGES -} text_enum; - -const char *quitmsg[NUM_QUITMESSAGES]; - -// Stuff for customizing the player select screen Tails 09-22-2003 -description_t description[MAXSKINS]; - -//static char *char_notes = NULL; -//static fixed_t char_scroll = 0; - -boolean menuactive = false; -boolean fromlevelselect = false; - -typedef enum -{ - LLM_CREATESERVER, - LLM_LEVELSELECT, - LLM_TIMEATTACK, - LLM_BREAKTHECAPSULES -} levellist_mode_t; - -levellist_mode_t levellistmode = LLM_CREATESERVER; -UINT8 maplistoption = 0; - -static char joystickInfo[8][29]; -#ifndef NONET -static UINT32 serverlistpage; -#endif - -//static saveinfo_t savegameinfo[MAXSAVEGAMES]; // Extra info about the save games. - -INT16 startmap; // Mario, NiGHTS, or just a plain old normal game? - -static INT16 itemOn = 1; // menu item skull is on, Hack by Tails 09-18-2002 -static INT16 skullAnimCounter = 10; // skull animation counter - -static UINT8 setupcontrolplayer; -static INT32 (*setupcontrols)[2]; // pointer to the gamecontrols of the player being edited - -// shhh... what am I doing... nooooo! -static INT32 vidm_testingmode = 0; -static INT32 vidm_previousmode; -static INT32 vidm_selected = 0; -static INT32 vidm_nummodes; -static INT32 vidm_column_size; - -// -// PROTOTYPES -// - -static void M_StopMessage(INT32 choice); - -#ifndef NONET -static void M_HandleServerPage(INT32 choice); -static void M_RoomMenu(INT32 choice); -#endif - -// Prototyping is fun, innit? -// ========================================================================== -// NEEDED FUNCTION PROTOTYPES GO HERE -// ========================================================================== - -// the haxor message menu -menu_t MessageDef; - -menu_t SPauseDef; - -#define lsheadingheight 16 - -// Sky Room -//static void M_CustomLevelSelect(INT32 choice); -//static void M_CustomWarp(INT32 choice); -FUNCNORETURN static ATTRNORETURN void M_UltimateCheat(INT32 choice); -//static void M_LoadGameLevelSelect(INT32 choice); -static void M_GetAllEmeralds(INT32 choice); -static void M_DestroyRobots(INT32 choice); -//static void M_LevelSelectWarp(INT32 choice); -static void M_Credits(INT32 choice); -static void M_PandorasBox(INT32 choice); -static void M_EmblemHints(INT32 choice); -static char *M_GetConditionString(condition_t cond); -menu_t SR_MainDef, SR_UnlockChecklistDef; - -// Misc. Main Menu -static void M_SinglePlayerMenu(INT32 choice); -static void M_Options(INT32 choice); -static void M_Manual(INT32 choice); -static void M_SelectableClearMenus(INT32 choice); -static void M_Retry(INT32 choice); -static void M_EndGame(INT32 choice); -static void M_MapChange(INT32 choice); -static void M_ChangeLevel(INT32 choice); -static void M_ConfirmSpectate(INT32 choice); -static void M_ConfirmEnterGame(INT32 choice); -static void M_ConfirmTeamScramble(INT32 choice); -static void M_ConfirmTeamChange(INT32 choice); -static void M_ConfirmSpectateChange(INT32 choice); -//static void M_SecretsMenu(INT32 choice); -//static void M_SetupChoosePlayer(INT32 choice); -static void M_QuitSRB2(INT32 choice); -menu_t SP_MainDef, MP_MainDef, OP_MainDef; -menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef, MISC_ChangeSpectateDef; - -// Single Player -static void M_GrandPrixTemp(INT32 choice); -static void M_StartGrandPrix(INT32 choice); -static void M_TimeAttack(INT32 choice); -static boolean M_QuitTimeAttackMenu(void); -static void M_BreakTheCapsules(INT32 choice); -static void M_Statistics(INT32 choice); -static void M_HandleStaffReplay(INT32 choice); -static void M_ReplayTimeAttack(INT32 choice); -static void M_ChooseTimeAttack(INT32 choice); -//static void M_ChooseNightsAttack(INT32 choice); -static void M_ModeAttackEndGame(INT32 choice); -static void M_SetGuestReplay(INT32 choice); -//static void M_ChoosePlayer(INT32 choice); -menu_t SP_LevelStatsDef; -static menu_t SP_GrandPrixTempDef; -static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; -//static menu_t SP_NightsAttackDef, SP_NightsReplayDef, SP_NightsGuestReplayDef, SP_NightsGhostDef; - -// Multiplayer -#ifndef NONET -#ifndef TESTERS -static void M_StartServerMenu(INT32 choice); -#endif -static void M_ConnectMenu(INT32 choice); -static void M_ConnectMenuModChecks(INT32 choice); -static void M_Refresh(INT32 choice); -static void M_Connect(INT32 choice); -static void M_ChooseRoom(INT32 choice); -#endif -#ifndef TESTERS -static void M_StartOfflineServerMenu(INT32 choice); -#endif -static void M_StartServer(INT32 choice); -static void M_SetupMultiPlayer(INT32 choice); -static void M_SetupMultiPlayer2(INT32 choice); -static void M_SetupMultiPlayer3(INT32 choice); -static void M_SetupMultiPlayer4(INT32 choice); -static void M_SetupMultiHandler(INT32 choice); - -// Options -// Split into multiple parts due to size -// Controls -menu_t OP_ControlsDef, OP_AllControlsDef; -menu_t OP_MouseOptionsDef, OP_Mouse2OptionsDef; -menu_t OP_Joystick1Def, OP_Joystick2Def, OP_Joystick3Def, OP_Joystick4Def; -static void M_VideoModeMenu(INT32 choice); -static void M_Setup1PControlsMenu(INT32 choice); -static void M_Setup2PControlsMenu(INT32 choice); -static void M_Setup3PControlsMenu(INT32 choice); -static void M_Setup4PControlsMenu(INT32 choice); - -static void M_Setup1PJoystickMenu(INT32 choice); -static void M_Setup2PJoystickMenu(INT32 choice); -static void M_Setup3PJoystickMenu(INT32 choice); -static void M_Setup4PJoystickMenu(INT32 choice); - -static void M_AssignJoystick(INT32 choice); -static void M_ChangeControl(INT32 choice); -static void M_ResetControls(INT32 choice); - -// Video & Sound -menu_t OP_VideoOptionsDef, OP_VideoModeDef; -#ifdef HWRENDER -menu_t OP_OpenGLOptionsDef, OP_OpenGLColorDef; -#endif -menu_t OP_SoundOptionsDef; -//static void M_RestartAudio(void); - -//Misc -menu_t OP_DataOptionsDef, OP_ScreenshotOptionsDef, OP_EraseDataDef; -menu_t OP_HUDOptionsDef, OP_ChatOptionsDef; -menu_t OP_GameOptionsDef, OP_ServerOptionsDef; -#ifndef NONET -menu_t OP_AdvServerOptionsDef; -#endif -//menu_t OP_NetgameOptionsDef, OP_GametypeOptionsDef; -menu_t OP_MonitorToggleDef; -static void M_ScreenshotOptions(INT32 choice); -static void M_EraseData(INT32 choice); - -static void M_Addons(INT32 choice); -static void M_AddonsOptions(INT32 choice); -static patch_t *addonsp[NUM_EXT+5]; - -#define numaddonsshown 4 - -// Replay hut -menu_t MISC_ReplayHutDef; -menu_t MISC_ReplayOptionsDef; -static void M_HandleReplayHutList(INT32 choice); -static void M_DrawReplayHut(void); -static void M_DrawReplayStartMenu(void); -static boolean M_QuitReplayHut(void); -static void M_HutStartReplay(INT32 choice); - -static void M_DrawPlaybackMenu(void); -static void M_PlaybackRewind(INT32 choice); -static void M_PlaybackPause(INT32 choice); -static void M_PlaybackFastForward(INT32 choice); -static void M_PlaybackAdvance(INT32 choice); -static void M_PlaybackSetViews(INT32 choice); -static void M_PlaybackAdjustView(INT32 choice); -static void M_PlaybackToggleFreecam(INT32 choice); -static void M_PlaybackQuit(INT32 choice); - -static UINT8 playback_enterheld = 0; // horrid hack to prevent holding the button from being extremely fucked - -// Drawing functions -static void M_DrawGenericMenu(void); -static void M_DrawGenericBackgroundMenu(void); -static void M_DrawCenteredMenu(void); -static void M_DrawAddons(void); -static void M_DrawSkyRoom(void); -static void M_DrawChecklist(void); -static void M_DrawEmblemHints(void); -static void M_DrawPauseMenu(void); -static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade); -static void M_DrawServerMenu(void); -static void M_DrawImageDef(void); -//static void M_DrawLoad(void); -static void M_DrawLevelStats(void); -static void M_DrawTimeAttackMenu(void); -//static void M_DrawNightsAttackMenu(void); -//static void M_DrawSetupChoosePlayerMenu(void); -static void M_DrawControl(void); -static void M_DrawVideoMenu(void); -static void M_DrawHUDOptions(void); -static void M_DrawVideoMode(void); -static void M_DrawMonitorToggles(void); -#ifdef HWRENDER -static void M_OGL_DrawColorMenu(void); -#endif -static void M_DrawMPMainMenu(void); -#ifndef NONET -static void M_DrawConnectMenu(void); -static void M_DrawRoomMenu(void); -#endif -static void M_DrawJoystick(void); -static void M_DrawSetupMultiPlayerMenu(void); - -// Handling functions -#ifndef NONET -static boolean M_CancelConnect(void); -#endif -static boolean M_ExitPandorasBox(void); -static boolean M_QuitMultiPlayerMenu(void); -static void M_HandleAddons(INT32 choice); -static void M_HandleSoundTest(INT32 choice); -static void M_HandleImageDef(INT32 choice); -//static void M_HandleLoadSave(INT32 choice); -static void M_HandleLevelStats(INT32 choice); -#ifndef NONET -static void M_HandleConnectIP(INT32 choice); -#endif -static void M_HandleSetupMultiPlayer(INT32 choice); -static void M_HandleVideoMode(INT32 choice); -static void M_HandleMonitorToggles(INT32 choice); - -// Consvar onchange functions -static void Nextmap_OnChange(void); -static void Newgametype_OnChange(void); -static void Dummymenuplayer_OnChange(void); -//static void Dummymares_OnChange(void); -static void Dummystaff_OnChange(void); - -// ========================================================================== -// CONSOLE VARIABLES AND THEIR POSSIBLE VALUES GO HERE. -// ========================================================================== - -consvar_t cv_showfocuslost = {"showfocuslost", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL }; - -static CV_PossibleValue_t map_cons_t[] = { - {0,"MIN"}, - {NUMMAPS, "MAX"}, - {0, NULL} -}; -consvar_t cv_nextmap = {"nextmap", "1", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL}; - -static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}}; -consvar_t cv_chooseskin = {"chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL}; - -// This gametype list is integral for many different reasons. -// When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h! -CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1]; - -consvar_t cv_newgametype = {"newgametype", "Race", CV_HIDEN|CV_CALL, gametype_cons_t, Newgametype_OnChange, 0, NULL, NULL, 0, 0, NULL}; - -static CV_PossibleValue_t serversort_cons_t[] = { - {0,"Ping"}, - {1,"Modified State"}, - {2,"Most Players"}, - {3,"Least Players"}, - {4,"Max Player Slots"}, - {5,"Gametype"}, - {0,NULL} -}; -consvar_t cv_serversort = {"serversort", "Ping", CV_CALL, serversort_cons_t, M_SortServerList, 0, NULL, NULL, 0, 0, NULL}; - -// autorecord demos for time attack -static consvar_t cv_autorecord = {"autorecord", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; - -CV_PossibleValue_t ghost_cons_t[] = {{0, "Hide"}, {1, "Show Character"}, {2, "Show All"}, {0, NULL}}; -CV_PossibleValue_t ghost2_cons_t[] = {{0, "Hide"}, {1, "Show"}, {0, NULL}}; - -consvar_t cv_ghost_besttime = {"ghost_besttime", "Show All", CV_SAVE, ghost_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_ghost_bestlap = {"ghost_bestlap", "Show All", CV_SAVE, ghost_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_ghost_last = {"ghost_last", "Show All", CV_SAVE, ghost_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_ghost_guest = {"ghost_guest", "Show", CV_SAVE, ghost2_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_ghost_staff = {"ghost_staff", "Show", CV_SAVE, ghost2_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; - -//Console variables used solely in the menu system. -//todo: add a way to use non-console variables in the menu -// or make these consvars legitimate like color or skin. -static void Splitplayers_OnChange(void); -CV_PossibleValue_t splitplayers_cons_t[] = {{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}, {0, NULL}}; -consvar_t cv_splitplayers = {"splitplayers", "One", CV_CALL, splitplayers_cons_t, Splitplayers_OnChange, 0, NULL, NULL, 0, 0, NULL}; - -static CV_PossibleValue_t dummymenuplayer_cons_t[] = {{0, "NOPE"}, {1, "P1"}, {2, "P2"}, {3, "P3"}, {4, "P4"}, {0, NULL}}; -static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; -static CV_PossibleValue_t dummyspectate_cons_t[] = {{0, "Spectator"}, {1, "Playing"}, {0, NULL}}; -static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}}; -static CV_PossibleValue_t ringlimit_cons_t[] = {{0, "MIN"}, {9999, "MAX"}, {0, NULL}}; -static CV_PossibleValue_t liveslimit_cons_t[] = {{0, "MIN"}, {99, "MAX"}, {0, NULL}}; -/*static CV_PossibleValue_t dummymares_cons_t[] = { - {-1, "END"}, {0,"Overall"}, {1,"Mare 1"}, {2,"Mare 2"}, {3,"Mare 3"}, {4,"Mare 4"}, {5,"Mare 5"}, {6,"Mare 6"}, {7,"Mare 7"}, {8,"Mare 8"}, {0,NULL} -};*/ -static CV_PossibleValue_t dummystaff_cons_t[] = {{0, "MIN"}, {100, "MAX"}, {0, NULL}}; - -static consvar_t cv_dummymenuplayer = {"dummymenuplayer", "P1", CV_HIDEN|CV_CALL, dummymenuplayer_cons_t, Dummymenuplayer_OnChange, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_dummyteam = {"dummyteam", "Spectator", CV_HIDEN, dummyteam_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_dummyspectate = {"dummyspectate", "Spectator", CV_HIDEN, dummyspectate_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_dummyscramble = {"dummyscramble", "Random", CV_HIDEN, dummyscramble_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_dummyrings = {"dummyrings", "0", CV_HIDEN, ringlimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_dummylives = {"dummylives", "0", CV_HIDEN, liveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_dummycontinues = {"dummycontinues", "0", CV_HIDEN, liveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -//static consvar_t cv_dummymares = {"dummymares", "Overall", CV_HIDEN|CV_CALL, dummymares_cons_t, Dummymares_OnChange, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_dummystaff = {"dummystaff", "0", CV_HIDEN|CV_CALL, dummystaff_cons_t, Dummystaff_OnChange, 0, NULL, NULL, 0, 0, NULL}; - -static CV_PossibleValue_t dummygpdifficulty_cons_t[] = {{0, "Easy"}, {1, "Normal"}, {2, "Hard"}, {3, "Master"}, {0, NULL}}; -static CV_PossibleValue_t dummygpcup_cons_t[50] = {{1, "TEMP"}}; // A REALLY BIG NUMBER, SINCE THIS IS TEMP UNTIL NEW MENUS - -static consvar_t cv_dummygpdifficulty = {"dummygpdifficulty", "Normal", CV_HIDEN, dummygpdifficulty_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_dummygpencore = {"dummygpencore", "Off", CV_HIDEN, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_dummygpcup = {"dummygpcup", "TEMP", CV_HIDEN, dummygpcup_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; - -// ========================================================================== -// ORGANIZATION START. -// ========================================================================== -// Note: Never should we be jumping from one category of menu options to another -// without first going to the Main Menu. -// Note: Ignore the above if you're working with the Pause menu. -// Note: (Prefix)_MainMenu should be the target of all Main Menu options that -// point to submenus. - -// --------- -// Main Menu -// --------- -static menuitem_t MainMenu[] = -{ - {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_MainDef, 76}, -#ifdef TESTERS - {IT_GRAYEDOUT, NULL, "1 Player", NULL, 84}, -#else - {IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, -#endif - {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92}, - {IT_CALL |IT_STRING, NULL, "Options", M_Options, 100}, - /* I don't think is useful at all... */ - {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108}, - {IT_CALL |IT_STRING, NULL, "Quit Game", M_QuitSRB2, 116}, -}; - -typedef enum -{ - secrets = 0, - singleplr, - multiplr, - options, - addons, - quitdoom -} main_e; - -static menuitem_t MISC_AddonsMenu[] = -{ - {IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleAddons, 0}, // dummy menuitem for the control func -}; - -static menuitem_t MISC_ReplayHutMenu[] = -{ - {IT_KEYHANDLER|IT_NOTHING, NULL, "", M_HandleReplayHutList, 0}, // Dummy menuitem for the replay list - {IT_NOTHING, NULL, "", NULL, 0}, // Dummy for handling wrapping to the top of the menu.. -}; - -static menuitem_t MISC_ReplayStartMenu[] = -{ - {IT_CALL |IT_STRING, NULL, "Load Addons and Watch", M_HutStartReplay, 0}, - {IT_CALL |IT_STRING, NULL, "Watch Without Addons", M_HutStartReplay, 10}, - {IT_CALL |IT_STRING, NULL, "Watch Replay", M_HutStartReplay, 10}, - {IT_SUBMENU |IT_STRING, NULL, "Back", &MISC_ReplayHutDef, 30}, -}; - -static menuitem_t MISC_ReplayOptionsMenu[] = -{ - {IT_CVAR|IT_STRING, NULL, "Record Replays", &cv_recordmultiplayerdemos, 0}, - {IT_CVAR|IT_STRING, NULL, "Sync Check Interval", &cv_netdemosyncquality, 10}, -}; - -static tic_t playback_last_menu_interaction_leveltime = 0; -static menuitem_t PlaybackMenu[] = -{ - {IT_CALL | IT_STRING, "M_PHIDE", "Hide Menu (Esc)", M_SelectableClearMenus, 0}, - - {IT_CALL | IT_STRING, "M_PREW", "Rewind ([)", M_PlaybackRewind, 20}, - {IT_CALL | IT_STRING, "M_PPAUSE", "Pause (\\)", M_PlaybackPause, 36}, - {IT_CALL | IT_STRING, "M_PFFWD", "Fast-Forward (])", M_PlaybackFastForward, 52}, - {IT_CALL | IT_STRING, "M_PSTEPB", "Backup Frame ([)", M_PlaybackRewind, 20}, - {IT_CALL | IT_STRING, "M_PRESUM", "Resume", M_PlaybackPause, 36}, - {IT_CALL | IT_STRING, "M_PFADV", "Advance Frame (])", M_PlaybackAdvance, 52}, - - {IT_ARROWS | IT_STRING, "M_PVIEWS", "View Count (- and =)", M_PlaybackSetViews, 72}, - {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint (1)", M_PlaybackAdjustView, 88}, - {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 2 (2)", M_PlaybackAdjustView, 104}, - {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 3 (3)", M_PlaybackAdjustView, 120}, - {IT_ARROWS | IT_STRING, "M_PNVIEW", "Viewpoint 4 (4)", M_PlaybackAdjustView, 136}, - - {IT_CALL | IT_STRING, "M_PVIEWS", "Toggle Free Camera (')", M_PlaybackToggleFreecam, 156}, - {IT_CALL | IT_STRING, "M_PEXIT", "Stop Playback", M_PlaybackQuit, 172}, -}; -typedef enum -{ - playback_hide, - playback_rewind, - playback_pause, - playback_fastforward, - playback_backframe, - playback_resume, - playback_advanceframe, - playback_viewcount, - playback_view1, - playback_view2, - playback_view3, - playback_view4, - playback_freecamera, - //playback_moreoptions, - playback_quit -} playback_e; - -// --------------------------------- -// Pause Menu Mode Attacking Edition -// --------------------------------- -static menuitem_t MAPauseMenu[] = -{ - {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,48}, - {IT_CALL | IT_STRING, NULL, "Retry", M_ModeAttackRetry, 56}, - {IT_CALL | IT_STRING, NULL, "Abort", M_ModeAttackEndGame, 64}, -}; - -typedef enum -{ - mapause_continue, - mapause_retry, - mapause_abort -} mapause_e; - -// --------------------- -// Pause Menu MP Edition -// --------------------- -static menuitem_t MPauseMenu[] = -{ - {IT_STRING | IT_CALL, NULL, "Addons...", M_Addons, 8}, - {IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16}, - {IT_STRING | IT_CALL, NULL, "Switch Map..." , M_MapChange, 24}, - - {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus, 40}, - {IT_CALL | IT_STRING, NULL, "P1 Setup...", M_SetupMultiPlayer, 48}, // splitscreen - {IT_CALL | IT_STRING, NULL, "P2 Setup...", M_SetupMultiPlayer2, 56}, // splitscreen - {IT_CALL | IT_STRING, NULL, "P3 Setup...", M_SetupMultiPlayer3, 64}, // splitscreen - {IT_CALL | IT_STRING, NULL, "P4 Setup...", M_SetupMultiPlayer4, 72}, // splitscreen - - {IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 48}, // alone - {IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 48}, // alone - {IT_STRING | IT_CALL, NULL, "Cancel Join", M_ConfirmSpectate, 48}, // alone - {IT_STRING | IT_SUBMENU, NULL, "Switch Team...", &MISC_ChangeTeamDef, 48}, - {IT_STRING | IT_SUBMENU, NULL, "Enter/Spectate...", &MISC_ChangeSpectateDef,48}, - {IT_CALL | IT_STRING, NULL, "Player Setup...", M_SetupMultiPlayer, 56}, // alone - {IT_CALL | IT_STRING, NULL, "Options", M_Options, 64}, - - {IT_CALL | IT_STRING, NULL, "Return to Title", M_EndGame, 80}, - {IT_CALL | IT_STRING, NULL, "Quit Game", M_QuitSRB2, 88}, -}; - -typedef enum -{ - mpause_addons = 0, - mpause_scramble, - mpause_switchmap, - - mpause_continue, - mpause_psetupsplit, - mpause_psetupsplit2, - mpause_psetupsplit3, - mpause_psetupsplit4, - - mpause_spectate, - mpause_entergame, - mpause_canceljoin, - mpause_switchteam, - mpause_switchspectate, - mpause_psetup, - mpause_options, - - mpause_title, - mpause_quit -} mpause_e; - -// --------------------- -// Pause Menu SP Edition -// --------------------- -static menuitem_t SPauseMenu[] = -{ - // Pandora's Box will be shifted up if both options are available - {IT_CALL | IT_STRING, NULL, "Pandora's Box...", M_PandorasBox, 16}, - {IT_CALL | IT_STRING, NULL, "Medal Hints...", M_EmblemHints, 24}, - //{IT_CALL | IT_STRING, NULL, "Level Select...", M_LoadGameLevelSelect, 32}, - - {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,48}, - {IT_CALL | IT_STRING, NULL, "Retry", M_Retry, 56}, - {IT_CALL | IT_STRING, NULL, "Options", M_Options, 64}, - - {IT_CALL | IT_STRING, NULL, "Return to Title", M_EndGame, 80}, - {IT_CALL | IT_STRING, NULL, "Quit Game", M_QuitSRB2, 88}, -}; - -typedef enum -{ - spause_pandora = 0, - spause_hints, - //spause_levelselect, - - spause_continue, - spause_retry, - spause_options, - spause_title, - spause_quit -} spause_e; - -// ----------------- -// Misc menu options -// ----------------- -// Prefix: MISC_ -static menuitem_t MISC_ScrambleTeamMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Scramble Method", &cv_dummyscramble, 30}, - {IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmTeamScramble, 90}, -}; - -static menuitem_t MISC_ChangeTeamMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Player", &cv_dummymenuplayer, 30}, - {IT_STRING|IT_CVAR, NULL, "Team", &cv_dummyteam, 40}, - {IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmTeamChange, 90}, -}; - -static menuitem_t MISC_ChangeSpectateMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Player", &cv_dummymenuplayer, 30}, - {IT_STRING|IT_CVAR, NULL, "Status", &cv_dummyspectate, 40}, - {IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmSpectateChange, 90}, -}; - -static menuitem_t MISC_ChangeLevelMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, - {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, - {IT_WHITESTRING|IT_CALL, NULL, "Change Level", M_ChangeLevel, 130}, -}; - -static menuitem_t MISC_HelpMenu[] = -{ - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL00", M_HandleImageDef, 0}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL01", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL02", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL03", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL04", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL05", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL06", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL07", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL08", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL09", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL10", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL11", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL12", M_HandleImageDef, 1}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "MANUAL99", M_HandleImageDef, 0}, -}; - -// -------------------------------- -// Sky Room and all of its submenus -// -------------------------------- -// Prefix: SR_ - -// Pause Menu Pandora's Box Options -static menuitem_t SR_PandorasBox[] = -{ - {IT_STRING | IT_CVAR, NULL, "Rings", &cv_dummyrings, 20}, - {IT_STRING | IT_CVAR, NULL, "Lives", &cv_dummylives, 30}, - {IT_STRING | IT_CVAR, NULL, "Continues", &cv_dummycontinues, 40}, - - {IT_STRING | IT_CVAR, NULL, "Gravity", &cv_gravity, 60}, - {IT_STRING | IT_CVAR, NULL, "Throw Rings", &cv_ringslinger, 70}, - - {IT_STRING | IT_CALL, NULL, "Get All Emeralds", M_GetAllEmeralds, 90}, - {IT_STRING | IT_CALL, NULL, "Destroy All Robots", M_DestroyRobots, 100}, - - {IT_STRING | IT_CALL, NULL, "Ultimate Cheat", M_UltimateCheat, 130}, -}; - -// Sky Room Custom Unlocks -static menuitem_t SR_MainMenu[] = -{ -#ifndef TESTERS - {IT_STRING|IT_SUBMENU, NULL, "Unlockables", &SR_UnlockChecklistDef, 100}, -#endif - {IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 108}, - {IT_CALL|IT_STRING, NULL, "Replay Hut", M_ReplayHut, 116}, - {IT_DISABLED, NULL, "", NULL, 0}, // Custom1 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom2 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom3 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom4 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom5 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom6 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom7 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom8 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom9 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom10 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom11 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom12 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom13 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom14 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom15 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom16 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom17 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom18 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom19 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom20 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom21 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom22 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom23 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom24 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom25 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom26 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom27 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom28 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom29 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom30 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom31 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom32 - -}; - -/*static menuitem_t SR_LevelSelectMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, - {IT_WHITESTRING|IT_CALL, NULL, "Start", M_LevelSelectWarp, 130}, -};*/ - -static menuitem_t SR_UnlockChecklistMenu[] = -{ - {IT_SUBMENU | IT_STRING, NULL, "NEXT", &MainDef, 192}, -}; - -static menuitem_t SR_EmblemHintMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Medal Radar", &cv_itemfinder, 10}, - {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SPauseDef, 20} -}; - -// -------------------------------- -// 1 Player and all of its submenus -// -------------------------------- -// Prefix: SP_ - -// Single Player Main -static menuitem_t SP_MainMenu[] = -{ - {IT_STRING|IT_CALL, NULL, "Grand Prix", M_GrandPrixTemp, 92}, - {IT_SECRET, NULL, "Time Attack", M_TimeAttack, 100}, - {IT_SECRET, NULL, "Break the Capsules", M_BreakTheCapsules, 108}, -}; - -enum -{ - spgrandprix, - sptimeattack, - spbreakthecapsules -}; - -// Single Player Load Game -static menuitem_t SP_GrandPrixPlaceholderMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Character", &cv_chooseskin, 10}, - {IT_STRING|IT_CVAR, NULL, "Color", &cv_playercolor, 20}, - - {IT_STRING|IT_CVAR, NULL, "Difficulty", &cv_dummygpdifficulty, 40}, - {IT_STRING|IT_CVAR, NULL, "Encore Mode", &cv_dummygpencore, 50}, - - {IT_STRING|IT_CVAR, NULL, "Cup", &cv_dummygpcup, 70}, - {IT_STRING|IT_CALL, NULL, "Start", M_StartGrandPrix, 80}, -}; - -// Single Player Time Attack -static menuitem_t SP_TimeAttackMenu[] = -{ - {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Name", &cv_playername, 0}, - {IT_STRING|IT_CVAR, NULL, "Character", &cv_chooseskin, 13}, - {IT_STRING|IT_CVAR, NULL, "Color", &cv_playercolor, 26}, - {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, - - {IT_DISABLED, NULL, "Guest...", &SP_GuestReplayDef, 98}, - {IT_DISABLED, NULL, "Replay...", &SP_ReplayDef, 108}, - {IT_WHITESTRING|IT_SUBMENU, NULL, "Ghosts...", &SP_GhostDef, 118}, - {IT_WHITESTRING|IT_CALL|IT_CALL_NOTMODIFIED, NULL, "Start", M_ChooseTimeAttack, 130}, -}; - -enum -{ - taname, - taplayer, - tacolor, - talevel, - - taguest, - tareplay, - taghost, - tastart -}; - -static menuitem_t SP_ReplayMenu[] = -{ - {IT_WHITESTRING|IT_CALL, NULL, "Replay Best Time", M_ReplayTimeAttack, 90}, - {IT_WHITESTRING|IT_CALL, NULL, "Replay Best Lap", M_ReplayTimeAttack, 98}, - - {IT_WHITESTRING|IT_CALL, NULL, "Replay Last", M_ReplayTimeAttack, 106}, - {IT_WHITESTRING|IT_CALL, NULL, "Replay Guest", M_ReplayTimeAttack, 114}, - {IT_WHITESTRING|IT_KEYHANDLER, NULL, "Replay Staff",M_HandleStaffReplay,122}, - - {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_TimeAttackDef, 130} -}; - -/*static menuitem_t SP_NightsReplayMenu[] = -{ - {IT_WHITESTRING|IT_CALL, NULL, "Replay Best Score", M_ReplayTimeAttack, 0}, - {IT_WHITESTRING|IT_CALL, NULL, "Replay Best Time", M_ReplayTimeAttack,16}, - - {IT_WHITESTRING|IT_CALL, NULL, "Replay Last", M_ReplayTimeAttack,21}, - {IT_WHITESTRING|IT_CALL, NULL, "Replay Guest", M_ReplayTimeAttack,29}, - {IT_WHITESTRING|IT_KEYHANDLER, NULL, "Replay Staff",M_HandleStaffReplay,37}, - - {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_NightsAttackDef, 50} -};*/ - -static menuitem_t SP_GuestReplayMenu[] = -{ - {IT_WHITESTRING|IT_CALL, NULL, "Save Best Time as Guest", M_SetGuestReplay, 94}, - {IT_WHITESTRING|IT_CALL, NULL, "Save Best Lap as Guest", M_SetGuestReplay,102}, - {IT_WHITESTRING|IT_CALL, NULL, "Save Last as Guest", M_SetGuestReplay,110}, - - {IT_WHITESTRING|IT_CALL, NULL, "Delete Guest Replay", M_SetGuestReplay,120}, - - {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_TimeAttackDef, 130} -}; - -/*static menuitem_t SP_NightsGuestReplayMenu[] = -{ - {IT_WHITESTRING|IT_CALL, NULL, "Save Best Score as Guest", M_SetGuestReplay, 8}, - {IT_WHITESTRING|IT_CALL, NULL, "Save Best Time as Guest", M_SetGuestReplay,16}, - {IT_WHITESTRING|IT_CALL, NULL, "Save Last as Guest", M_SetGuestReplay,24}, - - {IT_WHITESTRING|IT_CALL, NULL, "Delete Guest Replay", M_SetGuestReplay,37}, - - {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_NightsAttackDef, 50} -};*/ - -static menuitem_t SP_GhostMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Best Time", &cv_ghost_besttime, 88}, - {IT_STRING|IT_CVAR, NULL, "Best Lap", &cv_ghost_bestlap, 96}, - {IT_STRING|IT_CVAR, NULL, "Last", &cv_ghost_last, 104}, - {IT_DISABLED, NULL, "Guest", &cv_ghost_guest, 112}, - {IT_DISABLED, NULL, "Staff Attack",&cv_ghost_staff, 120}, - - {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_TimeAttackDef, 130} -}; - -/*static menuitem_t SP_NightsGhostMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Best Score", &cv_ghost_bestscore, 0}, - {IT_STRING|IT_CVAR, NULL, "Best Time", &cv_ghost_besttime, 8}, - {IT_STRING|IT_CVAR, NULL, "Last", &cv_ghost_last, 16}, - - {IT_STRING|IT_CVAR, NULL, "Guest", &cv_ghost_guest, 29}, - {IT_STRING|IT_CVAR, NULL, "Staff Attack",&cv_ghost_staff, 37}, - - {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_NightsAttackDef, 50} -};*/ - -// Single Player Nights Attack -/*static menuitem_t SP_NightsAttackMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 44}, - {IT_STRING|IT_CVAR, NULL, "Show Records For", &cv_dummymares, 54}, - - {IT_DISABLED, NULL, "Guest Option...", &SP_NightsGuestReplayDef, 108}, - {IT_DISABLED, NULL, "Replay...", &SP_NightsReplayDef, 118}, - {IT_DISABLED, NULL, "Ghosts...", &SP_NightsGhostDef, 128}, - {IT_WHITESTRING|IT_CALL|IT_CALL_NOTMODIFIED, NULL, "Start", M_ChooseNightsAttack, 138}, -};*/ - -enum -{ - nalevel, - narecords, - - naguest, - nareplay, - naghost, - nastart -}; - -// Statistics -static menuitem_t SP_LevelStatsMenu[] = -{ - {IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleLevelStats, '\0'}, // dummy menuitem for the control func -}; - -// A rare case. -// External files modify this menu, so we can't call it static. -// And I'm too lazy to go through and rename it everywhere. ARRGH! -#define M_ChoosePlayer NULL -menuitem_t PlayerMenu[MAXSKINS]; - -// ----------------------------------- -// Multiplayer and all of its submenus -// ----------------------------------- -// Prefix: MP_ - -static menuitem_t MP_MainMenu[] = -{ - {IT_HEADER, NULL, "Players", NULL, 0}, - {IT_STRING|IT_CVAR, NULL, "Number of local players", &cv_splitplayers, 10}, - - {IT_STRING|IT_KEYHANDLER,NULL, "Player setup...", M_SetupMultiHandler,18}, - - {IT_HEADER, NULL, "Host a game", NULL, 100-24}, -#ifndef NOMENUHOST - {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 110-24}, -#else - {IT_GRAYEDOUT, NULL, "Internet/LAN...", NULL, 110-24}, -#endif -#ifdef TESTERS - {IT_GRAYEDOUT, NULL, "Offline...", NULL, 118-24}, -#else - {IT_STRING|IT_CALL, NULL, "Offline...", M_StartOfflineServerMenu, 118-24}, -#endif - - {IT_HEADER, NULL, "Join a game", NULL, 132-24}, -#ifndef NONET - {IT_STRING|IT_CALL, NULL, "Internet server browser...",M_ConnectMenuModChecks, 142-24}, - {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 150-24}, -#else - {IT_GRAYEDOUT, NULL, "Internet server browser...",NULL, 142-24}, - {IT_GRAYEDOUT, NULL, "Specify IPv4 address:", NULL, 150-24}, -#endif - //{IT_HEADER, NULL, "Player setup", NULL, 80}, - //{IT_STRING|IT_CALL, NULL, "Name, character, color...", M_SetupMultiPlayer, 90}, -}; - -#ifndef NONET - -static menuitem_t MP_ServerMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 10}, - {IT_STRING|IT_CALL, NULL, "Room...", M_RoomMenu, 20}, - {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Server Name", &cv_servername, 30}, - - {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, - {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, - - {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, -}; - -#endif - -// Separated offline and normal servers. -static menuitem_t MP_OfflineServerMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, - {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, - - {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, -}; - -static menuitem_t MP_PlayerSetupMenu[] = -{ - {IT_KEYHANDLER | IT_STRING, NULL, "Name", M_HandleSetupMultiPlayer, 0}, - {IT_KEYHANDLER | IT_STRING, NULL, "Character", M_HandleSetupMultiPlayer, 16}, // Tails 01-18-2001 - {IT_KEYHANDLER | IT_STRING, NULL, "Color", M_HandleSetupMultiPlayer, 152}, -}; - -#ifndef NONET -static menuitem_t MP_ConnectMenu[] = -{ - {IT_STRING | IT_CALL, NULL, "Room...", M_RoomMenu, 4}, - {IT_STRING | IT_CVAR, NULL, "Sort By", &cv_serversort, 12}, - {IT_STRING | IT_KEYHANDLER, NULL, "Page", M_HandleServerPage, 20}, - {IT_STRING | IT_CALL, NULL, "Refresh", M_Refresh, 28}, - - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 48-4}, - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 60-4}, - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 72-4}, - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 84-4}, - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 96-4}, - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 108-4}, - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 120-4}, - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 132-4}, - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 144-4}, - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 156-4}, - {IT_STRING | IT_SPACE, NULL, "", M_Connect, 168-4}, -}; - -enum -{ - mp_connect_room, - mp_connect_sort, - mp_connect_page, - mp_connect_refresh, - FIRSTSERVERLINE -}; - -static menuitem_t MP_RoomMenu[] = -{ - {IT_STRING | IT_CALL, NULL, "", M_ChooseRoom, 9}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 18}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 27}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 36}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 45}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 54}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 63}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 72}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 81}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 90}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 99}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 108}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 117}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 126}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 135}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 144}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 153}, - {IT_DISABLED, NULL, "", M_ChooseRoom, 162}, -}; -#endif - -// ------------------------------------ -// Options and most (?) of its submenus -// ------------------------------------ -// Prefix: OP_ -static menuitem_t OP_MainMenu[] = -{ - {IT_SUBMENU|IT_STRING, NULL, "Control Setup...", &OP_ControlsDef, 10}, - - {IT_SUBMENU|IT_STRING, NULL, "Video Options...", &OP_VideoOptionsDef, 30}, - {IT_SUBMENU|IT_STRING, NULL, "Sound Options...", &OP_SoundOptionsDef, 40}, - - {IT_SUBMENU|IT_STRING, NULL, "HUD Options...", &OP_HUDOptionsDef, 60}, - {IT_SUBMENU|IT_STRING, NULL, "Gameplay Options...", &OP_GameOptionsDef, 70}, - {IT_SUBMENU|IT_STRING, NULL, "Server Options...", &OP_ServerOptionsDef, 80}, - - {IT_SUBMENU|IT_STRING, NULL, "Data Options...", &OP_DataOptionsDef, 100}, - - {IT_CALL|IT_STRING, NULL, "Tricks & Secrets (F1)", M_Manual, 120}, - {IT_CALL|IT_STRING, NULL, "Play Credits", M_Credits, 130}, -}; - -static menuitem_t OP_ControlsMenu[] = -{ - {IT_CALL | IT_STRING, NULL, "Player 1 Controls...", M_Setup1PControlsMenu, 10}, - {IT_CALL | IT_STRING, NULL, "Player 2 Controls...", M_Setup2PControlsMenu, 20}, - - {IT_CALL | IT_STRING, NULL, "Player 3 Controls...", &M_Setup3PControlsMenu, 30}, - {IT_CALL | IT_STRING, NULL, "Player 4 Controls...", &M_Setup4PControlsMenu, 40}, - - {IT_STRING | IT_CVAR, NULL, "Controls per key", &cv_controlperkey, 60}, -}; - -static menuitem_t OP_AllControlsMenu[] = -{ - {IT_SUBMENU|IT_STRING, NULL, "Gamepad Options...", &OP_Joystick1Def, 0}, - {IT_CALL|IT_STRING, NULL, "Reset to defaults", M_ResetControls, 8}, - //{IT_SPACE, NULL, NULL, NULL, 0}, - {IT_HEADER, NULL, "Gameplay Controls", NULL, 0}, - {IT_SPACE, NULL, NULL, NULL, 0}, - {IT_CONTROL, NULL, "Accelerate", M_ChangeControl, gc_accelerate }, - {IT_CONTROL, NULL, "Turn Left", M_ChangeControl, gc_turnleft }, - {IT_CONTROL, NULL, "Turn Right", M_ChangeControl, gc_turnright }, - {IT_CONTROL, NULL, "Drift", M_ChangeControl, gc_drift }, - {IT_CONTROL, NULL, "Brake", M_ChangeControl, gc_brake }, - {IT_CONTROL, NULL, "Use/Throw Item", M_ChangeControl, gc_fire }, - {IT_CONTROL, NULL, "Aim Forward", M_ChangeControl, gc_aimforward }, - {IT_CONTROL, NULL, "Aim Backward", M_ChangeControl, gc_aimbackward}, - {IT_CONTROL, NULL, "Look Backward", M_ChangeControl, gc_lookback }, - {IT_HEADER, NULL, "Miscelleanous Controls", NULL, 0}, - {IT_SPACE, NULL, NULL, NULL, 0}, - {IT_CONTROL, NULL, "Chat", M_ChangeControl, gc_talkkey }, - //{IT_CONTROL, NULL, "Team Chat", M_ChangeControl, gc_teamkey }, - {IT_CONTROL, NULL, "Show Rankings", M_ChangeControl, gc_scores }, - {IT_CONTROL, NULL, "Change Viewpoint", M_ChangeControl, gc_viewpoint }, - {IT_CONTROL, NULL, "Reset Camera", M_ChangeControl, gc_camreset }, - {IT_CONTROL, NULL, "Toggle First-Person", M_ChangeControl, gc_camtoggle }, - {IT_CONTROL, NULL, "Pause", M_ChangeControl, gc_pause }, - {IT_CONTROL, NULL, "Screenshot", M_ChangeControl, gc_screenshot }, - {IT_CONTROL, NULL, "Toggle GIF Recording", M_ChangeControl, gc_recordgif }, - {IT_CONTROL, NULL, "Open/Close Menu (ESC)", M_ChangeControl, gc_systemmenu }, - {IT_CONTROL, NULL, "Developer Console", M_ChangeControl, gc_console }, - {IT_HEADER, NULL, "Spectator Controls", NULL, 0}, - {IT_SPACE, NULL, NULL, NULL, 0}, - {IT_CONTROL, NULL, "Become Spectator", M_ChangeControl, gc_spectate }, - {IT_CONTROL, NULL, "Look Up", M_ChangeControl, gc_lookup }, - {IT_CONTROL, NULL, "Look Down", M_ChangeControl, gc_lookdown }, - {IT_CONTROL, NULL, "Center View", M_ChangeControl, gc_centerview }, - {IT_HEADER, NULL, "Custom Lua Actions", NULL, 0}, - {IT_SPACE, NULL, NULL, NULL, 0}, - {IT_CONTROL, NULL, "Custom Action 1", M_ChangeControl, gc_custom1 }, - {IT_CONTROL, NULL, "Custom Action 2", M_ChangeControl, gc_custom2 }, - {IT_CONTROL, NULL, "Custom Action 3", M_ChangeControl, gc_custom3 }, -}; - -static menuitem_t OP_Joystick1Menu[] = -{ - {IT_STRING | IT_CALL, NULL, "Select Gamepad..." , M_Setup1PJoystickMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis , 30}, - {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis , 40}, - {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis , 50}, - {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis , 60}, - {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis , 70}, - {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis , 80}, - {IT_STRING | IT_CVAR, NULL, "Look Up/Down" , &cv_lookaxis , 90}, -}; - -static menuitem_t OP_Joystick2Menu[] = -{ - {IT_STRING | IT_CALL, NULL, "Select Gamepad..." , M_Setup2PJoystickMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis2 , 30}, - {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis2 , 40}, - {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis2 , 50}, - {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis2 , 60}, - {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis2 , 70}, - {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis2 , 80}, - {IT_STRING | IT_CVAR, NULL, "Look Up/Down" , &cv_lookaxis2 , 90}, -}; - -static menuitem_t OP_Joystick3Menu[] = -{ - {IT_STRING | IT_CALL, NULL, "Select Gamepad..." , M_Setup3PJoystickMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis3 , 30}, - {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis3 , 40}, - {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis3 , 50}, - {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis3 , 60}, - {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis3 , 70}, - {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis3 , 80}, - {IT_STRING | IT_CVAR, NULL, "Look Up/Down" , &cv_lookaxis3 , 90}, -}; - -static menuitem_t OP_Joystick4Menu[] = -{ - {IT_STRING | IT_CALL, NULL, "Select Gamepad..." , M_Setup4PJoystickMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis4 , 30}, - {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis4 , 40}, - {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis4 , 50}, - {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis4 , 60}, - {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis4 , 70}, - {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis4 , 80}, - {IT_STRING | IT_CVAR, NULL, "Look Up/Down" , &cv_lookaxis4 , 90}, -}; - -static menuitem_t OP_JoystickSetMenu[] = -{ - {IT_CALL | IT_NOTHING, "None", NULL, M_AssignJoystick, LINEHEIGHT+5}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, (LINEHEIGHT*2)+5}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, (LINEHEIGHT*3)+5}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, (LINEHEIGHT*4)+5}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, (LINEHEIGHT*5)+5}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, (LINEHEIGHT*6)+5}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, (LINEHEIGHT*7)+5}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, (LINEHEIGHT*8)+5}, -}; - -/*static menuitem_t OP_MouseOptionsMenu[] = -{ - {IT_STRING | IT_CVAR, NULL, "Use Mouse", &cv_usemouse, 10}, - - - {IT_STRING | IT_CVAR, NULL, "First-Person MouseLook", &cv_alwaysfreelook, 30}, - {IT_STRING | IT_CVAR, NULL, "Third-Person MouseLook", &cv_chasefreelook, 40}, - {IT_STRING | IT_CVAR, NULL, "Mouse Move", &cv_mousemove, 50}, - {IT_STRING | IT_CVAR, NULL, "Invert Mouse", &cv_invertmouse, 60}, - {IT_STRING | IT_CVAR | IT_CV_SLIDER, - NULL, "Mouse X Speed", &cv_mousesens, 70}, - {IT_STRING | IT_CVAR | IT_CV_SLIDER, - NULL, "Mouse Y Speed", &cv_mouseysens, 80}, -}; - -static menuitem_t OP_Mouse2OptionsMenu[] = -{ - {IT_STRING | IT_CVAR, NULL, "Use Mouse 2", &cv_usemouse2, 10}, - {IT_STRING | IT_CVAR, NULL, "Second Mouse Serial Port", - &cv_mouse2port, 20}, - {IT_STRING | IT_CVAR, NULL, "First-Person MouseLook", &cv_alwaysfreelook2, 30}, - {IT_STRING | IT_CVAR, NULL, "Third-Person MouseLook", &cv_chasefreelook2, 40}, - {IT_STRING | IT_CVAR, NULL, "Mouse Move", &cv_mousemove2, 50}, - {IT_STRING | IT_CVAR, NULL, "Invert Mouse", &cv_invertmouse2, 60}, - {IT_STRING | IT_CVAR | IT_CV_SLIDER, - NULL, "Mouse X Speed", &cv_mousesens2, 70}, - {IT_STRING | IT_CVAR | IT_CV_SLIDER, - NULL, "Mouse Y Speed", &cv_mouseysens2, 80}, -};*/ - -static menuitem_t OP_VideoOptionsMenu[] = -{ - {IT_STRING | IT_CALL, NULL, "Set Resolution...", M_VideoModeMenu, 10}, -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) - {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 20}, -#endif - {IT_STRING | IT_CVAR | IT_CV_SLIDER, - NULL, "Gamma", &cv_globalgamma, 30}, - - {IT_STRING | IT_CVAR, NULL, "Draw Distance", &cv_drawdist, 45}, - //{IT_STRING | IT_CVAR, NULL, "NiGHTS Draw Dist", &cv_drawdist_nights, 55}, - {IT_STRING | IT_CVAR, NULL, "Weather Draw Distance",&cv_drawdist_precip, 55}, - //{IT_STRING | IT_CVAR, NULL, "Weather Density", &cv_precipdensity, 65}, - {IT_STRING | IT_CVAR, NULL, "Skyboxes", &cv_skybox, 65}, - {IT_STRING | IT_CVAR, NULL, "Field of View", &cv_fov, 75}, - - {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 90}, - {IT_STRING | IT_CVAR, NULL, "Vertical Sync", &cv_vidwait, 100}, - -#ifdef HWRENDER - {IT_SUBMENU|IT_STRING, NULL, "OpenGL Options...", &OP_OpenGLOptionsDef, 120}, -#endif -}; - -enum -{ - op_video_res = 0, -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) - op_video_fullscreen, -#endif - op_video_gamma, - op_video_dd, - op_video_wdd, - //op_video_wd, - op_video_skybox, - op_video_fov, - op_video_fps, - op_video_vsync, -#ifdef HWRENDER - op_video_ogl, -#endif -}; - -static menuitem_t OP_VideoModeMenu[] = -{ - {IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleVideoMode, '\0'}, // dummy menuitem for the control func -}; - -#ifdef HWRENDER -static menuitem_t OP_OpenGLOptionsMenu[] = -{ - {IT_STRING | IT_CVAR, NULL, "3D Models", &cv_grmdls, 10}, - {IT_STRING | IT_CVAR, NULL, "Fallback Player 3D Model", &cv_grfallbackplayermodel, 20}, - {IT_STRING|IT_CVAR, NULL, "Shaders", &cv_grshaders, 30}, - - {IT_STRING|IT_CVAR, NULL, "Texture Quality", &cv_scr_depth, 50}, - {IT_STRING|IT_CVAR, NULL, "Texture Filter", &cv_grfiltermode, 60}, - {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_granisotropicmode, 70}, - - {IT_STRING|IT_CVAR, NULL, "Wall Contrast Style", &cv_grfakecontrast, 90}, - {IT_STRING|IT_CVAR, NULL, "Sprite Billboarding", &cv_grspritebillboarding, 100}, - {IT_STRING|IT_CVAR, NULL, "Software Perspective", &cv_grshearing, 110}, - - {IT_SUBMENU|IT_STRING, NULL, "Gamma...", &OP_OpenGLColorDef, 130}, -}; - -static menuitem_t OP_OpenGLColorMenu[] = -{ - {IT_STRING|IT_CVAR|IT_CV_SLIDER, NULL, "Red", &cv_grgammared, 10}, - {IT_STRING|IT_CVAR|IT_CV_SLIDER, NULL, "Green", &cv_grgammagreen, 20}, - {IT_STRING|IT_CVAR|IT_CV_SLIDER, NULL, "Blue", &cv_grgammablue, 30}, -}; -#endif - -static menuitem_t OP_SoundOptionsMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "SFX", &cv_gamesounds, 10}, - {IT_STRING|IT_CVAR|IT_CV_SLIDER, - NULL, "SFX Volume", &cv_soundvolume, 18}, - - {IT_STRING|IT_CVAR, NULL, "Music", &cv_gamedigimusic, 30}, - {IT_STRING|IT_CVAR|IT_CV_SLIDER, - NULL, "Music Volume", &cv_digmusicvolume, 38}, - -/* -- :nonnathisshit: - {IT_STRING|IT_CVAR, NULL, "MIDI", &cv_gamemidimusic, 50}, - {IT_STRING|IT_CVAR|IT_CV_SLIDER, - NULL, "MIDI Volume", &cv_midimusicvolume, 58}, -#ifdef PC_DOS - {IT_STRING|IT_CVAR|IT_CV_SLIDER, - NULL, "CD Volume", &cd_volume, 40}, -#endif*/ - - //{IT_STRING|IT_CALL, NULL, "Restart Audio System", M_RestartAudio, 50}, - - {IT_STRING|IT_CVAR, NULL, "Reverse L/R Channels", &stereoreverse, 50}, - {IT_STRING|IT_CVAR, NULL, "Surround Sound", &surround, 60}, - - {IT_STRING|IT_CVAR, NULL, "Chat Notifications", &cv_chatnotifications, 75}, - {IT_STRING|IT_CVAR, NULL, "Character voices", &cv_kartvoices, 85}, - {IT_STRING|IT_CVAR, NULL, "Powerup Warning", &cv_kartinvinsfx, 95}, - - {IT_KEYHANDLER|IT_STRING, NULL, "Sound Test", M_HandleSoundTest, 110}, - - {IT_STRING|IT_CVAR, NULL, "Play Music While Unfocused", &cv_playmusicifunfocused, 125}, - {IT_STRING|IT_CVAR, NULL, "Play SFX While Unfocused", &cv_playsoundifunfocused, 135}, -}; - -static menuitem_t OP_DataOptionsMenu[] = -{ - {IT_STRING | IT_CALL, NULL, "Screenshot Options...", M_ScreenshotOptions, 10}, - {IT_STRING | IT_CALL, NULL, "Addon Options...", M_AddonsOptions, 20}, - {IT_STRING | IT_SUBMENU, NULL, "Replay Options...", &MISC_ReplayOptionsDef, 30}, - - {IT_STRING | IT_SUBMENU, NULL, "Erase Data...", &OP_EraseDataDef, 50}, -}; - -static menuitem_t OP_ScreenshotOptionsMenu[] = -{ - {IT_STRING|IT_CVAR, NULL, "Storage Location", &cv_screenshot_option, 10}, - {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_screenshot_folder, 20}, - - {IT_HEADER, NULL, "Screenshots (F8)", NULL, 50}, - {IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memory, 60}, - {IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_level, 70}, - {IT_STRING|IT_CVAR, NULL, "Strategy", &cv_zlib_strategy, 80}, - {IT_STRING|IT_CVAR, NULL, "Window Size", &cv_zlib_window_bits, 90}, - - {IT_HEADER, NULL, "Movie Mode (F9)", NULL, 105}, - {IT_STRING|IT_CVAR, NULL, "Capture Mode", &cv_moviemode, 115}, - - {IT_STRING|IT_CVAR, NULL, "Region Optimizing", &cv_gif_optimize, 125}, - {IT_STRING|IT_CVAR, NULL, "Downscaling", &cv_gif_downscale, 135}, - - {IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memorya, 125}, - {IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_levela, 135}, - {IT_STRING|IT_CVAR, NULL, "Strategy", &cv_zlib_strategya, 145}, - {IT_STRING|IT_CVAR, NULL, "Window Size", &cv_zlib_window_bitsa, 155}, -}; - -enum -{ - op_screenshot_folder = 1, - op_screenshot_capture = 8, - op_screenshot_gif_start = 9, - op_screenshot_gif_end = 10, - op_screenshot_apng_start = 11, - op_screenshot_apng_end = 14, -}; - -static menuitem_t OP_EraseDataMenu[] = -{ - {IT_STRING | IT_CALL, NULL, "Erase Record Data", M_EraseData, 10}, - {IT_STRING | IT_CALL, NULL, "Erase Unlockable Data", M_EraseData, 20}, - - {IT_STRING | IT_CALL, NULL, "\x85" "Erase ALL Data", M_EraseData, 40}, -}; - -static menuitem_t OP_AddonsOptionsMenu[] = -{ - {IT_HEADER, NULL, "Menu", NULL, 0}, - {IT_STRING|IT_CVAR, NULL, "Location", &cv_addons_option, 10}, - {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_addons_folder, 20}, - {IT_STRING|IT_CVAR, NULL, "Identify addons via", &cv_addons_md5, 48}, - {IT_STRING|IT_CVAR, NULL, "Show unsupported file types", &cv_addons_showall, 58}, - - {IT_HEADER, NULL, "Search", NULL, 76}, - {IT_STRING|IT_CVAR, NULL, "Matching", &cv_addons_search_type, 86}, - {IT_STRING|IT_CVAR, NULL, "Case-sensitive", &cv_addons_search_case, 96}, -}; - -enum -{ - op_addons_folder = 2, -}; - -static menuitem_t OP_HUDOptionsMenu[] = -{ - {IT_STRING | IT_CVAR, NULL, "Show HUD (F3)", &cv_showhud, 10}, - {IT_STRING | IT_CVAR | IT_CV_SLIDER, - NULL, "HUD Visibility", &cv_translucenthud, 20}, - - {IT_STRING | IT_SUBMENU, NULL, "Online HUD options...",&OP_ChatOptionsDef, 35}, - {IT_STRING | IT_CVAR, NULL, "Background Glass", &cons_backcolor, 45}, - - {IT_STRING | IT_CVAR | IT_CV_SLIDER, - NULL, "Minimap Visibility", &cv_kartminimap, 60}, - {IT_STRING | IT_CVAR, NULL, "Speedometer Display", &cv_kartspeedometer, 70}, - {IT_STRING | IT_CVAR, NULL, "Show \"CHECK\"", &cv_kartcheck, 80}, - - {IT_STRING | IT_CVAR, NULL, "Menu Highlights", &cons_menuhighlight, 95}, - // highlight info - (GOOD HIGHLIGHT, WARNING HIGHLIGHT) - 105 (see M_DrawHUDOptions) - - {IT_STRING | IT_CVAR, NULL, "Console Text Size", &cv_constextsize, 120}, - - {IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 135}, -}; - -// Ok it's still called chatoptions but we'll put ping display in here to be clean -static menuitem_t OP_ChatOptionsMenu[] = -{ - // will ANYONE who doesn't know how to use the console want to touch this one? - {IT_STRING | IT_CVAR, NULL, "Chat Mode", &cv_consolechat, 10}, // nonetheless... - - {IT_STRING | IT_CVAR | IT_CV_SLIDER, - NULL, "Chat Box Width", &cv_chatwidth, 25}, - {IT_STRING | IT_CVAR | IT_CV_SLIDER, - NULL, "Chat Box Height", &cv_chatheight, 35}, - - {IT_STRING | IT_CVAR, NULL, "Chat Background Tint", &cv_chatbacktint, 50}, - {IT_STRING | IT_CVAR, NULL, "Message Fadeout Time", &cv_chattime, 60}, - {IT_STRING | IT_CVAR, NULL, "Spam Protection", &cv_chatspamprotection, 70}, - - {IT_STRING | IT_CVAR, NULL, "Local ping display", &cv_showping, 90}, // shows ping next to framerate if we want to. -}; - -static menuitem_t OP_GameOptionsMenu[] = -{ - {IT_STRING | IT_SUBMENU, NULL, "Random Item Toggles...", &OP_MonitorToggleDef, 10}, - - {IT_STRING | IT_CVAR, NULL, "Game Speed", &cv_kartspeed, 30}, - {IT_STRING | IT_CVAR, NULL, "Frantic Items", &cv_kartfrantic, 40}, - {IT_SECRET, NULL, "Encore Mode", &cv_kartencore, 50}, - - {IT_STRING | IT_CVAR, NULL, "Number of Laps", &cv_basenumlaps, 70}, - {IT_STRING | IT_CVAR, NULL, "Exit Countdown Timer", &cv_countdowntime, 80}, - - {IT_STRING | IT_CVAR, NULL, "Time Limit", &cv_timelimit, 100}, - {IT_STRING | IT_CVAR, NULL, "Starting Bumpers", &cv_kartbumpers, 110}, - {IT_STRING | IT_CVAR, NULL, "Karma Comeback", &cv_kartcomeback, 120}, - - {IT_STRING | IT_CVAR, NULL, "Track Power Levels", &cv_kartusepwrlv, 140}, -}; - -static menuitem_t OP_ServerOptionsMenu[] = -{ -#ifndef NONET - {IT_STRING | IT_CVAR | IT_CV_STRING, - NULL, "Server Name", &cv_servername, 10}, -#endif - - {IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 40}, - {IT_STRING | IT_CVAR, NULL, "Map Progression", &cv_advancemap, 50}, - {IT_STRING | IT_CVAR, NULL, "Voting Timer", &cv_votetime, 60}, - {IT_STRING | IT_CVAR, NULL, "Voting Rule Changes", &cv_kartvoterulechanges, 70}, - -#ifndef NONET - {IT_STRING | IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 90}, - {IT_STRING | IT_CVAR, NULL, "Allow Players to Join", &cv_allownewplayer, 100}, - {IT_STRING | IT_CVAR, NULL, "Allow Addon Downloading", &cv_downloading, 110}, - {IT_STRING | IT_CVAR, NULL, "Pause Permission", &cv_pause, 120}, - {IT_STRING | IT_CVAR, NULL, "Mute All Chat", &cv_mute, 130}, - - {IT_SUBMENU|IT_STRING, NULL, "Advanced Options...", &OP_AdvServerOptionsDef,150}, -#endif -}; - -#ifndef NONET -static menuitem_t OP_AdvServerOptionsMenu[] = -{ - {IT_STRING | IT_CVAR | IT_CV_STRING, - NULL, "Server Browser Address", &cv_masterserver, 10}, - - {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 40}, - {IT_STRING | IT_CVAR, NULL, "Ping limit (ms)", &cv_maxping, 50}, - {IT_STRING | IT_CVAR, NULL, "Ping timeout (s)", &cv_pingtimeout, 60}, - {IT_STRING | IT_CVAR, NULL, "Connection timeout (tics)", &cv_nettimeout, 70}, - {IT_STRING | IT_CVAR, NULL, "Join timeout (tics)", &cv_jointimeout, 80}, - - {IT_STRING | IT_CVAR, NULL, "Max. file transfer send (KB)", &cv_maxsend, 100}, - {IT_STRING | IT_CVAR, NULL, "File transfer packet rate", &cv_downloadspeed, 110}, - - {IT_STRING | IT_CVAR, NULL, "Log join addresses", &cv_showjoinaddress, 130}, - {IT_STRING | IT_CVAR, NULL, "Log resyncs", &cv_blamecfail, 140}, - {IT_STRING | IT_CVAR, NULL, "Log file transfers", &cv_noticedownload, 150}, -}; -#endif - -/*static menuitem_t OP_NetgameOptionsMenu[] = -{ - {IT_STRING | IT_CVAR, NULL, "Time Limit", &cv_timelimit, 10}, - {IT_STRING | IT_CVAR, NULL, "Point Limit", &cv_pointlimit, 18}, - - {IT_STRING | IT_CVAR, NULL, "Frantic Items", &cv_kartfrantic, 34}, - - {IT_STRING | IT_CVAR, NULL, "Item Respawn", &cv_itemrespawn, 50}, - {IT_STRING | IT_CVAR, NULL, "Item Respawn Delay", &cv_itemrespawntime, 58}, - - {IT_STRING | IT_CVAR, NULL, "Player Respawn Delay", &cv_respawntime, 74}, - - {IT_STRING | IT_CVAR, NULL, "Force Skin #", &cv_forceskin, 90}, - {IT_STRING | IT_CVAR, NULL, "Restrict Skin Changes", &cv_restrictskinchange, 98}, - - //{IT_STRING | IT_CVAR, NULL, "Autobalance Teams", &cv_autobalance, 114}, - //{IT_STRING | IT_CVAR, NULL, "Scramble Teams on Map Change", &cv_scrambleonchange, 122}, -};*/ - -/*static menuitem_t OP_GametypeOptionsMenu[] = -{ - {IT_HEADER, NULL, "RACE", NULL, 2}, - {IT_STRING | IT_CVAR, NULL, "Game Speed", &cv_kartspeed, 10}, - {IT_STRING | IT_CVAR, NULL, "Encore Mode", &cv_kartencore, 18}, - {IT_STRING | IT_CVAR, NULL, "Number of Laps", &cv_numlaps, 26}, - {IT_STRING | IT_CVAR, NULL, "Use Map Lap Counts", &cv_usemapnumlaps, 34}, - - {IT_HEADER, NULL, "BATTLE", NULL, 50}, - {IT_STRING | IT_CVAR, NULL, "Starting Bumpers", &cv_kartbumpers, 58}, - {IT_STRING | IT_CVAR, NULL, "Karma Comeback", &cv_kartcomeback, 66}, -};*/ - -//#define ITEMTOGGLEBOTTOMRIGHT - -static menuitem_t OP_MonitorToggleMenu[] = -{ - // Mostly handled by the drawing function. - // Instead of using this for dumb monitors, lets use the new item bools we have :V - {IT_KEYHANDLER | IT_NOTHING, NULL, "Sneakers", M_HandleMonitorToggles, KITEM_SNEAKER}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Sneakers x3", M_HandleMonitorToggles, KRITEM_TRIPLESNEAKER}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Rocket Sneakers", M_HandleMonitorToggles, KITEM_ROCKETSNEAKER}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Toggle All", M_HandleMonitorToggles, 0}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Bananas", M_HandleMonitorToggles, KITEM_BANANA}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Bananas x3", M_HandleMonitorToggles, KRITEM_TRIPLEBANANA}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Bananas x10", M_HandleMonitorToggles, KRITEM_TENFOLDBANANA}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Eggman Monitors", M_HandleMonitorToggles, KITEM_EGGMAN}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinauts", M_HandleMonitorToggles, KITEM_ORBINAUT}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinauts x3", M_HandleMonitorToggles, KRITEM_TRIPLEORBINAUT}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinauts x4", M_HandleMonitorToggles, KRITEM_QUADORBINAUT}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Mines", M_HandleMonitorToggles, KITEM_MINE}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Jawz", M_HandleMonitorToggles, KITEM_JAWZ}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Jawz x2", M_HandleMonitorToggles, KRITEM_DUALJAWZ}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Ballhogs", M_HandleMonitorToggles, KITEM_BALLHOG}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Self-Propelled Bombs", M_HandleMonitorToggles, KITEM_SPB}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Invinciblity", M_HandleMonitorToggles, KITEM_INVINCIBILITY}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Grow", M_HandleMonitorToggles, KITEM_GROW}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Shrink", M_HandleMonitorToggles, KITEM_SHRINK}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Thunder Shields", M_HandleMonitorToggles, KITEM_THUNDERSHIELD}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Hyudoros", M_HandleMonitorToggles, KITEM_HYUDORO}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Pogo Springs", M_HandleMonitorToggles, KITEM_POGOSPRING}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Super Rings", M_HandleMonitorToggles, KITEM_SUPERRING}, - {IT_KEYHANDLER | IT_NOTHING, NULL, "Kitchen Sinks", M_HandleMonitorToggles, KITEM_KITCHENSINK}, -#ifdef ITEMTOGGLEBOTTOMRIGHT - {IT_KEYHANDLER | IT_NOTHING, NULL, "---", M_HandleMonitorToggles, 255}, -#endif -}; - -// ========================================================================== -// ALL MENU DEFINITIONS GO HERE -// ========================================================================== - -// Main Menu and related -menu_t MainDef = CENTERMENUSTYLE(NULL, MainMenu, NULL, 72); - -menu_t MISC_AddonsDef = -{ - NULL, - sizeof (MISC_AddonsMenu)/sizeof (menuitem_t), - &OP_DataOptionsDef, - MISC_AddonsMenu, - M_DrawAddons, - 50, 28, - 0, - NULL -}; - -menu_t MISC_ReplayHutDef = -{ - NULL, - sizeof (MISC_ReplayHutMenu)/sizeof (menuitem_t), - NULL, - MISC_ReplayHutMenu, - M_DrawReplayHut, - 30, 80, - 0, - M_QuitReplayHut -}; - -menu_t MISC_ReplayOptionsDef = -{ - "M_REPOPT", - sizeof (MISC_ReplayOptionsMenu)/sizeof (menuitem_t), - &OP_DataOptionsDef, - MISC_ReplayOptionsMenu, - M_DrawGenericMenu, - 27, 40, - 0, - NULL -}; - -menu_t MISC_ReplayStartDef = -{ - NULL, - sizeof (MISC_ReplayStartMenu)/sizeof (menuitem_t), - &MISC_ReplayHutDef, - MISC_ReplayStartMenu, - M_DrawReplayStartMenu, - 30, 90, - 0, - NULL -}; - -menu_t PlaybackMenuDef = { - NULL, - sizeof (PlaybackMenu)/sizeof (menuitem_t), - NULL, - PlaybackMenu, - M_DrawPlaybackMenu, - //BASEVIDWIDTH/2 - 94, 2, - BASEVIDWIDTH/2 - 88, 2, - 0, - NULL -}; - -menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); -menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); -menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); - -// Misc Main Menu -menu_t MISC_ScrambleTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ScrambleTeamMenu, &MPauseDef, 27, 40); -menu_t MISC_ChangeTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ChangeTeamMenu, &MPauseDef, 27, 40); -menu_t MISC_ChangeSpectateDef = DEFAULTMENUSTYLE(NULL, MISC_ChangeSpectateMenu, &MPauseDef, 27, 40); -menu_t MISC_ChangeLevelDef = MAPICONMENUSTYLE(NULL, MISC_ChangeLevelMenu, &MPauseDef); -menu_t MISC_HelpDef = IMAGEDEF(MISC_HelpMenu); - -// -// M_GetGametypeColor -// -// Pretty and consistent ^u^ -// See also G_GetGametypeColor. -// - -static INT32 highlightflags, recommendedflags, warningflags; - -inline static void M_GetGametypeColor(void) -{ - INT16 gt; - - warningflags = V_REDMAP; - recommendedflags = V_GREENMAP; - - if (cons_menuhighlight.value) - { - highlightflags = cons_menuhighlight.value; - if (highlightflags == V_REDMAP) - { - warningflags = V_ORANGEMAP; - return; - } - if (highlightflags == V_GREENMAP) - { - recommendedflags = V_SKYMAP; - return; - } - return; - } - - warningflags = V_REDMAP; - recommendedflags = V_GREENMAP; - - if (modeattacking // == ATTACKING_RECORD - || gamestate == GS_TIMEATTACK) - { - highlightflags = V_ORANGEMAP; - return; - } - - if (currentMenu->drawroutine == M_DrawServerMenu) - gt = cv_newgametype.value; - else if (!Playing()) - { - highlightflags = V_YELLOWMAP; - return; - } - else - gt = gametype; - - if (gt == GT_MATCH) - { - highlightflags = V_REDMAP; - warningflags = V_ORANGEMAP; - return; - } - if (gt == GT_RACE) - { - highlightflags = V_SKYMAP; - return; - } - - highlightflags = V_YELLOWMAP; // FALLBACK -} - -// excuse me but I'm extremely lazy: -INT32 HU_GetHighlightColor(void) -{ - M_GetGametypeColor(); // update flag colour reguardless of the menu being opened or not. - return highlightflags; -} - -// Sky Room -menu_t SR_PandoraDef = -{ - "M_PANDRA", - sizeof (SR_PandorasBox)/sizeof (menuitem_t), - &SPauseDef, - SR_PandorasBox, - M_DrawGenericMenu, - 60, 40, - 0, - M_ExitPandorasBox -}; -menu_t SR_MainDef = CENTERMENUSTYLE(NULL, SR_MainMenu, &MainDef, 72); - -//menu_t SR_LevelSelectDef = MAPICONMENUSTYLE(NULL, SR_LevelSelectMenu, &SR_MainDef); - -menu_t SR_UnlockChecklistDef = -{ - NULL, - 1, - &SR_MainDef, - SR_UnlockChecklistMenu, - M_DrawChecklist, - 280, 185, - 0, - NULL -}; -menu_t SR_EmblemHintDef = -{ - NULL, - sizeof (SR_EmblemHintMenu)/sizeof (menuitem_t), - &SPauseDef, - SR_EmblemHintMenu, - M_DrawEmblemHints, - 60, 150, - 0, - NULL -}; - -// Single Player -menu_t SP_MainDef = CENTERMENUSTYLE(NULL, SP_MainMenu, &MainDef, 72); -/*menu_t SP_LoadDef = -{ - "M_PICKG", - 1, - &SP_MainDef, - SP_LoadGameMenu, - M_DrawLoad, - 68, 46, - 0, - NULL -}; -menu_t SP_LevelSelectDef = MAPICONMENUSTYLE(NULL, SP_LevelSelectMenu, &SP_LoadDef);*/ - -menu_t SP_LevelStatsDef = -{ - "M_STATS", - 1, - &SR_MainDef, - SP_LevelStatsMenu, - M_DrawLevelStats, - 280, 185, - 0, - NULL -}; - -static menu_t SP_GrandPrixTempDef = DEFAULTMENUSTYLE(NULL, SP_GrandPrixPlaceholderMenu, &MainDef, 60, 30); - -static menu_t SP_TimeAttackDef = -{ - "M_ATTACK", - sizeof (SP_TimeAttackMenu)/sizeof (menuitem_t), - &MainDef, // Doesn't matter. - SP_TimeAttackMenu, - M_DrawTimeAttackMenu, - 34, 40, - 0, - M_QuitTimeAttackMenu -}; -static menu_t SP_ReplayDef = -{ - "M_ATTACK", - sizeof(SP_ReplayMenu)/sizeof(menuitem_t), - &SP_TimeAttackDef, - SP_ReplayMenu, - M_DrawTimeAttackMenu, - 34, 40, - 0, - NULL -}; -static menu_t SP_GuestReplayDef = -{ - "M_ATTACK", - sizeof(SP_GuestReplayMenu)/sizeof(menuitem_t), - &SP_TimeAttackDef, - SP_GuestReplayMenu, - M_DrawTimeAttackMenu, - 34, 40, - 0, - NULL -}; -static menu_t SP_GhostDef = -{ - "M_ATTACK", - sizeof(SP_GhostMenu)/sizeof(menuitem_t), - &SP_TimeAttackDef, - SP_GhostMenu, - M_DrawTimeAttackMenu, - 34, 40, - 0, - NULL -}; - -/*menu_t SP_PlayerDef = -{ - "M_PICKP", - sizeof (PlayerMenu)/sizeof (menuitem_t),//player_end, - &SP_MainDef, - PlayerMenu, - M_DrawSetupChoosePlayerMenu, - 24, 32, - 0, - NULL -};*/ - -// Multiplayer -menu_t MP_MainDef = -{ - "M_MULTI", - sizeof (MP_MainMenu)/sizeof (menuitem_t), - &MainDef, - MP_MainMenu, - M_DrawMPMainMenu, - 42, 30, - 0, -#ifndef NONET - M_CancelConnect -#else - NULL -#endif -}; - -menu_t MP_OfflineServerDef = MAPICONMENUSTYLE("M_MULTI", MP_OfflineServerMenu, &MP_MainDef); - -#ifndef NONET -menu_t MP_ServerDef = MAPICONMENUSTYLE("M_MULTI", MP_ServerMenu, &MP_MainDef); - -menu_t MP_ConnectDef = -{ - "M_MULTI", - sizeof (MP_ConnectMenu)/sizeof (menuitem_t), - &MP_MainDef, - MP_ConnectMenu, - M_DrawConnectMenu, - 27,24, - 0, - M_CancelConnect -}; -menu_t MP_RoomDef = -{ - "M_MULTI", - sizeof (MP_RoomMenu)/sizeof (menuitem_t), - &MP_ConnectDef, - MP_RoomMenu, - M_DrawRoomMenu, - 27, 32, - 0, - NULL -}; -#endif -menu_t MP_PlayerSetupDef = -{ - NULL, //"M_SPLAYR" - sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t), - &MP_MainDef, - MP_PlayerSetupMenu, - M_DrawSetupMultiPlayerMenu, - 36, 14, - 0, - M_QuitMultiPlayerMenu -}; - -// Options -menu_t OP_MainDef = -{ - "M_OPTTTL", - sizeof (OP_MainMenu)/sizeof (menuitem_t), - &MainDef, - OP_MainMenu, - M_DrawGenericMenu, - 60, 30, - 0, - NULL -}; - -menu_t OP_ControlsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_ControlsMenu, &OP_MainDef, 60, 30); -menu_t OP_AllControlsDef = CONTROLMENUSTYLE(OP_AllControlsMenu, &OP_ControlsDef); -menu_t OP_Joystick1Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick1Menu, &OP_AllControlsDef, 60, 30); -menu_t OP_Joystick2Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick2Menu, &OP_AllControlsDef, 60, 30); -menu_t OP_Joystick3Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick3Menu, &OP_AllControlsDef, 60, 30); -menu_t OP_Joystick4Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick4Menu, &OP_AllControlsDef, 60, 30); -menu_t OP_JoystickSetDef = -{ - "M_CONTRO", - sizeof (OP_JoystickSetMenu)/sizeof (menuitem_t), - &OP_Joystick1Def, - OP_JoystickSetMenu, - M_DrawJoystick, - 50, 40, - 0, - NULL -}; - -menu_t OP_VideoOptionsDef = -{ - "M_VIDEO", - sizeof(OP_VideoOptionsMenu)/sizeof(menuitem_t), - &OP_MainDef, - OP_VideoOptionsMenu, - M_DrawVideoMenu, - 30, 30, - 0, - NULL -}; - -menu_t OP_VideoModeDef = -{ - "M_VIDEO", - 1, - &OP_VideoOptionsDef, - OP_VideoModeMenu, - M_DrawVideoMode, - 48, 26, - 0, - NULL -}; - -menu_t OP_SoundOptionsDef = -{ - "M_SOUND", - sizeof (OP_SoundOptionsMenu)/sizeof (menuitem_t), - &OP_MainDef, - OP_SoundOptionsMenu, - M_DrawSkyRoom, - 30, 30, - 0, - NULL -}; - -menu_t OP_HUDOptionsDef = -{ - "M_HUD", - sizeof (OP_HUDOptionsMenu)/sizeof (menuitem_t), - &OP_MainDef, - OP_HUDOptionsMenu, - M_DrawHUDOptions, - 30, 30, - 0, - NULL -}; - -menu_t OP_ChatOptionsDef = DEFAULTMENUSTYLE("M_HUD", OP_ChatOptionsMenu, &OP_HUDOptionsDef, 30, 30); - -menu_t OP_GameOptionsDef = DEFAULTMENUSTYLE("M_GAME", OP_GameOptionsMenu, &OP_MainDef, 30, 30); -menu_t OP_ServerOptionsDef = DEFAULTMENUSTYLE("M_SERVER", OP_ServerOptionsMenu, &OP_MainDef, 24, 30); -#ifndef NONET -menu_t OP_AdvServerOptionsDef = DEFAULTMENUSTYLE("M_SERVER", OP_AdvServerOptionsMenu, &OP_ServerOptionsDef, 24, 30); -#endif - -//menu_t OP_NetgameOptionsDef = DEFAULTMENUSTYLE("M_SERVER", OP_NetgameOptionsMenu, &OP_ServerOptionsDef, 30, 30); -//menu_t OP_GametypeOptionsDef = DEFAULTMENUSTYLE("M_SERVER", OP_GametypeOptionsMenu, &OP_ServerOptionsDef, 30, 30); -//menu_t OP_ChatOptionsDef = DEFAULTMENUSTYLE("M_GAME", OP_ChatOptionsMenu, &OP_GameOptionsDef, 30, 30); -menu_t OP_MonitorToggleDef = -{ - "M_GAME", - sizeof (OP_MonitorToggleMenu)/sizeof (menuitem_t), - &OP_GameOptionsDef, - OP_MonitorToggleMenu, - M_DrawMonitorToggles, - 47, 30, - 0, - NULL -}; - -#ifdef HWRENDER -menu_t OP_OpenGLOptionsDef = DEFAULTMENUSTYLE("M_VIDEO", OP_OpenGLOptionsMenu, &OP_VideoOptionsDef, 30, 30); -menu_t OP_OpenGLColorDef = -{ - "M_VIDEO", - sizeof (OP_OpenGLColorMenu)/sizeof (menuitem_t), - &OP_OpenGLOptionsDef, - OP_OpenGLColorMenu, - M_OGL_DrawColorMenu, - 60, 40, - 0, - NULL -}; -#endif -menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); -menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_SCSHOT", OP_ScreenshotOptionsMenu, &OP_DataOptionsDef, 30, 30); -menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30); -menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 30, 30); - -// ========================================================================== -// CVAR ONCHANGE EVENTS GO HERE -// ========================================================================== -// (there's only a couple anyway) - -// Prototypes -static INT32 M_FindFirstMap(INT32 gtype); -static INT32 M_GetFirstLevelInList(void); - -// Nextmap. Used for Time Attack. -static void Nextmap_OnChange(void) -{ - char *leveltitle; - UINT8 active; - - // Update the string in the consvar. - Z_Free(cv_nextmap.zstring); - leveltitle = G_BuildMapTitle(cv_nextmap.value); - cv_nextmap.string = cv_nextmap.zstring = leveltitle ? leveltitle : Z_StrDup(G_BuildMapName(cv_nextmap.value)); - - if (currentMenu == &SP_TimeAttackDef) - { - // see also p_setup.c's P_LoadRecordGhosts - const size_t glen = strlen(srb2home)+1+strlen("media")+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; - char *gpath = malloc(glen); - INT32 i; - - if (!gpath) - return; - - sprintf(gpath,"%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); - - CV_StealthSetValue(&cv_dummystaff, 0); - - active = 0; - SP_TimeAttackMenu[taguest].status = IT_DISABLED; - SP_TimeAttackMenu[tareplay].status = IT_DISABLED; - //SP_TimeAttackMenu[taghost].status = IT_DISABLED; - - // Check if file exists, if not, disable REPLAY option - for (i = 0; i < 4; i++) - { - SP_ReplayMenu[i].status = IT_DISABLED; - SP_GuestReplayMenu[i].status = IT_DISABLED; - } - SP_ReplayMenu[4].status = IT_DISABLED; - - SP_GhostMenu[3].status = IT_DISABLED; - SP_GhostMenu[4].status = IT_DISABLED; - - if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, cv_chooseskin.string))) { - SP_ReplayMenu[0].status = IT_WHITESTRING|IT_CALL; - SP_GuestReplayMenu[0].status = IT_WHITESTRING|IT_CALL; - active |= 3; - } - - if (levellistmode != LLM_BREAKTHECAPSULES) { - if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, cv_chooseskin.string))) { - SP_ReplayMenu[1].status = IT_WHITESTRING|IT_CALL; - SP_GuestReplayMenu[1].status = IT_WHITESTRING|IT_CALL; - active |= 3; - } - } - - if (FIL_FileExists(va("%s-%s-last.lmp", gpath, cv_chooseskin.string))) { - SP_ReplayMenu[2].status = IT_WHITESTRING|IT_CALL; - SP_GuestReplayMenu[2].status = IT_WHITESTRING|IT_CALL; - active |= 3; - } - - if (FIL_FileExists(va("%s-guest.lmp", gpath))) - { - SP_ReplayMenu[3].status = IT_WHITESTRING|IT_CALL; - SP_GuestReplayMenu[3].status = IT_WHITESTRING|IT_CALL; - SP_GhostMenu[3].status = IT_STRING|IT_CVAR; - active |= 3; - } - - CV_SetValue(&cv_dummystaff, 1); - if (cv_dummystaff.value) - { - SP_ReplayMenu[4].status = IT_WHITESTRING|IT_KEYHANDLER; - SP_GhostMenu[4].status = IT_STRING|IT_CVAR; - CV_StealthSetValue(&cv_dummystaff, 1); - active |= 1; - } - - if (active) { - if (active & 1) - SP_TimeAttackMenu[tareplay].status = IT_WHITESTRING|IT_SUBMENU; - if (active & 2) - SP_TimeAttackMenu[taguest].status = IT_WHITESTRING|IT_SUBMENU; - } - else if (itemOn == tareplay) // Reset lastOn so replay isn't still selected when not available. - { - currentMenu->lastOn = itemOn; - itemOn = tastart; - } - - if (mapheaderinfo[cv_nextmap.value-1] && mapheaderinfo[cv_nextmap.value-1]->forcecharacter[0] != '\0') - CV_Set(&cv_chooseskin, mapheaderinfo[cv_nextmap.value-1]->forcecharacter); - - free(gpath); - } -} - -static void Dummymenuplayer_OnChange(void) -{ - if (cv_dummymenuplayer.value < 1) - CV_StealthSetValue(&cv_dummymenuplayer, splitscreen+1); - else if (cv_dummymenuplayer.value > splitscreen+1) - CV_StealthSetValue(&cv_dummymenuplayer, 1); -} - -/*static void Dummymares_OnChange(void) -{ - if (!nightsrecords[cv_nextmap.value-1]) - { - CV_StealthSetValue(&cv_dummymares, 0); - return; - } - else - { - UINT8 mares = nightsrecords[cv_nextmap.value-1]->nummares; - - if (cv_dummymares.value < 0) - CV_StealthSetValue(&cv_dummymares, mares); - else if (cv_dummymares.value > mares) - CV_StealthSetValue(&cv_dummymares, 0); - } -}*/ - -char dummystaffname[22]; - -static void Dummystaff_OnChange(void) -{ - lumpnum_t l; - - dummystaffname[0] = '\0'; - - if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) == LUMPERROR) - { - CV_StealthSetValue(&cv_dummystaff, 0); - return; - } - else - { - char *temp = dummystaffname; - UINT8 numstaff = 1; - while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),numstaff+1))) != LUMPERROR) - numstaff++; - - if (cv_dummystaff.value < 1) - CV_StealthSetValue(&cv_dummystaff, numstaff); - else if (cv_dummystaff.value > numstaff) - CV_StealthSetValue(&cv_dummystaff, 1); - - if ((l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value), cv_dummystaff.value))) == LUMPERROR) - return; // shouldn't happen but might as well check... - - G_UpdateStaffGhostName(l); - - while (*temp) - temp++; - - sprintf(temp, " - %d", cv_dummystaff.value); - } -} - -// Newgametype. Used for gametype changes. -static void Newgametype_OnChange(void) -{ - if (cv_nextmap.value && menuactive) - { - if (!mapheaderinfo[cv_nextmap.value-1]) - P_AllocMapHeader((INT16)(cv_nextmap.value-1)); - - if ((cv_newgametype.value == GT_RACE && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_RACE)) || // SRB2kart - //(cv_newgametype.value == GT_COMPETITION && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_COMPETITION)) || - //(cv_newgametype.value == GT_RACE && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_RACE)) || - ((cv_newgametype.value == GT_MATCH || cv_newgametype.value == GT_TEAMMATCH) && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_MATCH))) // || - //((cv_newgametype.value == GT_TAG || cv_newgametype.value == GT_HIDEANDSEEK) && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_TAG)) || - //(cv_newgametype.value == GT_CTF && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_CTF))) - { - INT32 value = 0; - - switch (cv_newgametype.value) - { - case GT_COOP: - value = TOL_RACE; // SRB2kart - break; - case GT_COMPETITION: - value = TOL_COMPETITION; - break; - case GT_RACE: - value = TOL_RACE; - break; - case GT_MATCH: - case GT_TEAMMATCH: - value = TOL_MATCH; - break; - case GT_TAG: - case GT_HIDEANDSEEK: - value = TOL_TAG; - break; - case GT_CTF: - value = TOL_CTF; - break; - } - - CV_SetValue(&cv_nextmap, M_FindFirstMap(value)); - //CV_AddValue(&cv_nextmap, -1); - //CV_AddValue(&cv_nextmap, 1); - } - } -} - -void Screenshot_option_Onchange(void) -{ - OP_ScreenshotOptionsMenu[op_screenshot_folder].status = - (cv_screenshot_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED); -} - -void Moviemode_mode_Onchange(void) -{ - INT32 i, cstart, cend; - for (i = op_screenshot_gif_start; i <= op_screenshot_apng_end; ++i) - OP_ScreenshotOptionsMenu[i].status = IT_DISABLED; - - switch (cv_moviemode.value) - { - case MM_GIF: - cstart = op_screenshot_gif_start; - cend = op_screenshot_gif_end; - break; - case MM_APNG: - cstart = op_screenshot_apng_start; - cend = op_screenshot_apng_end; - break; - default: - return; - } - for (i = cstart; i <= cend; ++i) - OP_ScreenshotOptionsMenu[i].status = IT_STRING|IT_CVAR; -} - -void Addons_option_Onchange(void) -{ - OP_AddonsOptionsMenu[op_addons_folder].status = - (cv_addons_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED); -} - -// ========================================================================== -// END ORGANIZATION STUFF. -// ========================================================================== - -// current menudef -menu_t *currentMenu = &MainDef; - -// ========================================================================= -// BASIC MENU HANDLING -// ========================================================================= - -static void M_ChangeCvar(INT32 choice) -{ - consvar_t *cv = (consvar_t *)currentMenu->menuitems[itemOn].itemaction; - - if (choice == -1) - { - if (cv == &cv_playercolor) - { - SINT8 skinno = R_SkinAvailable(cv_chooseskin.string); - if (skinno != -1) - CV_SetValue(cv,skins[skinno].prefcolor); - return; - } - CV_Set(cv,cv->defaultvalue); - return; - } - - choice = (choice<<1) - 1; - - if (((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_SLIDER) - ||((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_INVISSLIDER) - ||((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_NOMOD)) - { - CV_SetValue(cv,cv->value+choice); - } - else if (cv->flags & CV_FLOAT) - { - char s[20]; - sprintf(s,"%f",FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f)); - CV_Set(cv,s); - } - else - { -#ifndef NONET - if (cv == &cv_nettimeout || cv == &cv_jointimeout) - choice *= (TICRATE/7); - else if (cv == &cv_maxsend) - choice *= 512; - else if (cv == &cv_maxping) - choice *= 50; -#endif - CV_AddValue(cv,choice); - } -} - -static boolean M_ChangeStringCvar(INT32 choice) -{ - consvar_t *cv = (consvar_t *)currentMenu->menuitems[itemOn].itemaction; - char buf[MAXSTRINGLENGTH]; - size_t len; - - if (shiftdown && choice >= 32 && choice <= 127) - choice = shiftxform[choice]; - - switch (choice) - { - case KEY_BACKSPACE: - len = strlen(cv->string); - if (len > 0) - { - S_StartSound(NULL,sfx_menu1); // Tails - M_Memcpy(buf, cv->string, len); - buf[len-1] = 0; - CV_Set(cv, buf); - } - return true; - case KEY_DEL: - if (cv->string[0]) - { - S_StartSound(NULL,sfx_menu1); // Tails - CV_Set(cv, ""); - } - return true; - default: - if (choice >= 32 && choice <= 127) - { - len = strlen(cv->string); - if (len < MAXSTRINGLENGTH - 1) - { - S_StartSound(NULL,sfx_menu1); // Tails - M_Memcpy(buf, cv->string, len); - buf[len++] = (char)choice; - buf[len] = 0; - CV_Set(cv, buf); - } - return true; - } - break; - } - return false; -} - -static void M_NextOpt(void) -{ - INT16 oldItemOn = itemOn; // prevent infinite loop - - do - { - if (itemOn + 1 > currentMenu->numitems - 1) - itemOn = 0; - else - itemOn++; - } while (oldItemOn != itemOn && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_SPACE); -} - -static void M_PrevOpt(void) -{ - INT16 oldItemOn = itemOn; // prevent infinite loop - - do - { - if (!itemOn) - itemOn = currentMenu->numitems - 1; - else - itemOn--; - } while (oldItemOn != itemOn && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_SPACE); -} - -// lock out further input in a tic when important buttons are pressed -// (in other words -- stop bullshit happening by mashing buttons in fades) -static boolean noFurtherInput = false; - -static void Command_Manual_f(void) -{ - if (modeattacking) - return; - M_StartControlPanel(); - M_Manual(INT32_MAX); - itemOn = 0; -} - -// -// M_Responder -// -boolean M_Responder(event_t *ev) -{ - INT32 ch = -1; -// INT32 i; - static tic_t joywait = 0, mousewait = 0; - static INT32 pjoyx = 0, pjoyy = 0; - static INT32 pmousex = 0, pmousey = 0; - static INT32 lastx = 0, lasty = 0; - void (*routine)(INT32 choice); // for some casting problem - - if (dedicated || (demo.playback && demo.title) - || gamestate == GS_INTRO || gamestate == GS_CUTSCENE || gamestate == GS_GAMEEND - || gamestate == GS_CREDITS || gamestate == GS_EVALUATION) - return false; - - if (noFurtherInput) - { - // Ignore input after enter/escape/other buttons - // (but still allow shift keyup so caps doesn't get stuck) - return false; - } - else if (ev->type == ev_keydown) - { - ch = ev->data1; - - // added 5-2-98 remap virtual keys (mouse & joystick buttons) - switch (ch) - { - case KEY_MOUSE1: - //case KEY_JOY1: - //case KEY_JOY1 + 2: - ch = KEY_ENTER; - break; - /*case KEY_JOY1 + 3: // Brake can function as 'n' for message boxes now. - ch = 'n'; - break;*/ - case KEY_MOUSE1 + 1: - //case KEY_JOY1 + 1: - ch = KEY_BACKSPACE; - break; - case KEY_HAT1: - ch = KEY_UPARROW; - break; - case KEY_HAT1 + 1: - ch = KEY_DOWNARROW; - break; - case KEY_HAT1 + 2: - ch = KEY_LEFTARROW; - break; - case KEY_HAT1 + 3: - ch = KEY_RIGHTARROW; - break; - } - } - else if (menuactive) - { - if (ev->type == ev_joystick && ev->data1 == 0 && joywait < I_GetTime()) - { - const INT32 jdeadzone = ((JOYAXISRANGE-1) * cv_deadzone.value) >> FRACBITS; - if (ev->data3 != INT32_MAX) - { - if (Joystick.bGamepadStyle || abs(ev->data3) > jdeadzone) - { - if (ev->data3 < 0 && pjoyy >= 0) - { - ch = KEY_UPARROW; - joywait = I_GetTime() + NEWTICRATE/7; - } - else if (ev->data3 > 0 && pjoyy <= 0) - { - ch = KEY_DOWNARROW; - joywait = I_GetTime() + NEWTICRATE/7; - } - pjoyy = ev->data3; - } - else - pjoyy = 0; - } - - if (ev->data2 != INT32_MAX) - { - if (Joystick.bGamepadStyle || abs(ev->data2) > jdeadzone) - { - if (ev->data2 < 0 && pjoyx >= 0) - { - ch = KEY_LEFTARROW; - joywait = I_GetTime() + NEWTICRATE/17; - } - else if (ev->data2 > 0 && pjoyx <= 0) - { - ch = KEY_RIGHTARROW; - joywait = I_GetTime() + NEWTICRATE/17; - } - pjoyx = ev->data2; - } - else - pjoyx = 0; - } - } - else if (ev->type == ev_mouse && mousewait < I_GetTime()) - { - pmousey += ev->data3; - if (pmousey < lasty-30) - { - ch = KEY_DOWNARROW; - mousewait = I_GetTime() + NEWTICRATE/7; - pmousey = lasty -= 30; - } - else if (pmousey > lasty + 30) - { - ch = KEY_UPARROW; - mousewait = I_GetTime() + NEWTICRATE/7; - pmousey = lasty += 30; - } - - pmousex += ev->data2; - if (pmousex < lastx - 30) - { - ch = KEY_LEFTARROW; - mousewait = I_GetTime() + NEWTICRATE/7; - pmousex = lastx -= 30; - } - else if (pmousex > lastx+30) - { - ch = KEY_RIGHTARROW; - mousewait = I_GetTime() + NEWTICRATE/7; - pmousex = lastx += 30; - } - } - } - - if (ch == -1) - return false; - else if (ch == gamecontrol[gc_systemmenu][0] || ch == gamecontrol[gc_systemmenu][1]) // allow remappable ESC key - ch = KEY_ESCAPE; - else if ((ch == gamecontrol[gc_accelerate][0] || ch == gamecontrol[gc_accelerate][1]) && ch >= KEY_MOUSE1) - ch = KEY_ENTER; - - // F-Keys - if (!menuactive) - { - noFurtherInput = true; - - switch (ch) - { - case KEY_F1: // Help key - Command_Manual_f(); - return true; - - case KEY_F2: // Empty - return true; - - case KEY_F3: // Toggle HUD - CV_SetValue(&cv_showhud, !cv_showhud.value); - return true; - - case KEY_F4: // Sound Volume - if (modeattacking) - return true; - M_StartControlPanel(); - M_Options(0); - currentMenu = &OP_SoundOptionsDef; - itemOn = 0; - return true; - -#ifndef DC - case KEY_F5: // Video Mode - if (modeattacking) - return true; - M_StartControlPanel(); - M_Options(0); - M_VideoModeMenu(0); - return true; -#endif - - case KEY_F6: // Empty - return true; - - case KEY_F7: // Options - if (modeattacking) - return true; - M_StartControlPanel(); - M_Options(0); - M_SetupNextMenu(&OP_MainDef); - return true; - - // Screenshots on F8 now handled elsewhere - // Same with Moviemode on F9 - - case KEY_F10: // Quit SRB2 - M_QuitSRB2(0); - return true; - - case KEY_F11: // Gamma Level - CV_AddValue(&cv_globalgamma, 1); - return true; - - // Spymode on F12 handled in game logic - - case KEY_ESCAPE: // Pop up menu - if (chat_on) - { - HU_clearChatChars(); - chat_on = false; - } - else - M_StartControlPanel(); - return true; - } - noFurtherInput = false; // turns out we didn't care - return false; - } - - if ((ch == gamecontrol[gc_brake][0] || ch == gamecontrol[gc_brake][1]) && ch >= KEY_MOUSE1) // do this here, otherwise brake opens the menu mid-game - ch = KEY_ESCAPE; - - routine = currentMenu->menuitems[itemOn].itemaction; - - // Handle menuitems which need a specific key handling - if (routine && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_KEYHANDLER) - { - if (shiftdown && ch >= 32 && ch <= 127) - ch = shiftxform[ch]; - routine(ch); - return true; - } - - if (currentMenu->menuitems[itemOn].status == IT_MSGHANDLER) - { - if (currentMenu->menuitems[itemOn].alphaKey != MM_EVENTHANDLER) - { - if (ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER) - { - if (routine) - routine(ch); - M_StopMessage(0); - noFurtherInput = true; - return true; - } - return true; - } - else - { - // dirty hack: for customising controls, I want only buttons/keys, not moves - if (ev->type == ev_mouse || ev->type == ev_mouse2 || ev->type == ev_joystick - || ev->type == ev_joystick2 || ev->type == ev_joystick3 || ev->type == ev_joystick4) - return true; - if (routine) - { - void (*otherroutine)(event_t *sev) = currentMenu->menuitems[itemOn].itemaction; - otherroutine(ev); //Alam: what a hack - } - return true; - } - } - - // BP: one of the more big hack i have never made - if (routine && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR) - { - if ((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_STRING) - { - - if (shiftdown && ch >= 32 && ch <= 127) - ch = shiftxform[ch]; - if (M_ChangeStringCvar(ch)) - return true; - else - routine = NULL; - } - else - routine = M_ChangeCvar; - } - - if (currentMenu == &PlaybackMenuDef && !con_destlines) - { - playback_last_menu_interaction_leveltime = leveltime; - // Flip left/right with up/down for the playback menu, since it's a horizontal icon row. - switch (ch) - { - case KEY_LEFTARROW: ch = KEY_UPARROW; break; - case KEY_UPARROW: ch = KEY_RIGHTARROW; break; - case KEY_RIGHTARROW: ch = KEY_DOWNARROW; break; - case KEY_DOWNARROW: ch = KEY_LEFTARROW; break; - - // arbitrary keyboard shortcuts because fuck you - - case '\'': // toggle freecam - M_PlaybackToggleFreecam(0); - break; - - case ']': // ffw / advance frame (depends on if paused or not) - if (paused) - M_PlaybackAdvance(0); - else - M_PlaybackFastForward(0); - break; - - case '[': // rewind /backupframe, uses the same function - M_PlaybackRewind(0); - break; - - case '\\': // pause - M_PlaybackPause(0); - break; - - // viewpoints, an annoyance (tm) - case '-': // viewpoint minus - M_PlaybackSetViews(-1); // yeah lol. - break; - - case '=': // viewpoint plus - M_PlaybackSetViews(1); // yeah lol. - break; - - // switch viewpoints: - case '1': // viewpoint for p1 (also f12) - // maximum laziness: - if (!demo.freecam) - G_AdjustView(1, 1, true); - break; - case '2': // viewpoint for p2 - if (!demo.freecam) - G_AdjustView(2, 1, true); - break; - case '3': // viewpoint for p3 - if (!demo.freecam) - G_AdjustView(3, 1, true); - break; - case '4': // viewpoint for p4 - if (!demo.freecam) - G_AdjustView(4, 1, true); - break; - - default: break; - } - } - - // Keys usable within menu - switch (ch) - { - case KEY_DOWNARROW: - M_NextOpt(); - S_StartSound(NULL, sfx_menu1); - /*if (currentMenu == &SP_PlayerDef) - { - Z_Free(char_notes); - char_notes = NULL; - }*/ - return true; - - case KEY_UPARROW: - M_PrevOpt(); - S_StartSound(NULL, sfx_menu1); - /*if (currentMenu == &SP_PlayerDef) - { - Z_Free(char_notes); - char_notes = NULL; - }*/ - return true; - - case KEY_LEFTARROW: - if (routine && ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_ARROWS - || (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR)) - { - if (currentMenu != &OP_SoundOptionsDef || itemOn > 3) - S_StartSound(NULL, sfx_menu1); - routine(0); - } - return true; - - case KEY_RIGHTARROW: - if (routine && ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_ARROWS - || (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR)) - { - if (currentMenu != &OP_SoundOptionsDef || itemOn > 3) - S_StartSound(NULL, sfx_menu1); - routine(1); - } - return true; - - case KEY_ENTER: - noFurtherInput = true; - currentMenu->lastOn = itemOn; - - if (currentMenu == &PlaybackMenuDef) - { - boolean held = (boolean)playback_enterheld; - if (held) - return true; - playback_enterheld = 3; - } - - if (routine) - { - if (((currentMenu->menuitems[itemOn].status & IT_TYPE)==IT_CALL - || (currentMenu->menuitems[itemOn].status & IT_TYPE)==IT_SUBMENU) - && (currentMenu->menuitems[itemOn].status & IT_CALLTYPE)) - { - if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && majormods) - { - S_StartSound(NULL, sfx_menu1); - M_StartMessage(M_GetText("This cannot be done with complex addons\nor in a cheated game.\n\n(Press a key)\n"), NULL, MM_NOTHING); - return true; - } - } - S_StartSound(NULL, sfx_menu1); - switch (currentMenu->menuitems[itemOn].status & IT_TYPE) - { - case IT_CVAR: - case IT_ARROWS: - routine(1); // right arrow - break; - case IT_CALL: - routine(itemOn); - break; - case IT_SUBMENU: - currentMenu->lastOn = itemOn; - M_SetupNextMenu((menu_t *)currentMenu->menuitems[itemOn].itemaction); - break; - } - } - return true; - - case KEY_ESCAPE: - //case KEY_JOY1 + 2: - noFurtherInput = true; - currentMenu->lastOn = itemOn; - if (currentMenu->prevMenu) - { - //If we entered the game search menu, but didn't enter a game, - //make sure the game doesn't still think we're in a netgame. - if (!Playing() && netgame && multiplayer) - { - MSCloseUDPSocket(); // Clean up so we can re-open the connection later. - netgame = false; - multiplayer = false; - } - - if (currentMenu == &SP_TimeAttackDef) //|| currentMenu == &SP_NightsAttackDef - { - // D_StartTitle does its own wipe, since GS_TIMEATTACK is now a complete gamestate. - menuactive = false; - D_StartTitle(); - } - else - M_SetupNextMenu(currentMenu->prevMenu); - } - else - M_ClearMenus(true); - - return true; - - case KEY_BACKSPACE: - if ((currentMenu->menuitems[itemOn].status) == IT_CONTROL) - { - // detach any keys associated with the game control - G_ClearControlKeys(setupcontrols, currentMenu->menuitems[itemOn].alphaKey); - S_StartSound(NULL, sfx_shldls); - return true; - } - - if (routine && ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_ARROWS - || (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR)) - { - consvar_t *cv = (consvar_t *)currentMenu->menuitems[itemOn].itemaction; - - if (cv == &cv_chooseskin - || cv == &cv_dummystaff - || cv == &cv_nextmap - || cv == &cv_newgametype) - return true; - - if (currentMenu != &OP_SoundOptionsDef || itemOn > 3) - S_StartSound(NULL, sfx_menu1); - routine(-1); - return true; - } - - // Why _does_ backspace go back anyway? - //currentMenu->lastOn = itemOn; - //if (currentMenu->prevMenu) - // M_SetupNextMenu(currentMenu->prevMenu); - return false; - - default: - break; - } - - return true; -} - -// special responder for demos -boolean M_DemoResponder(event_t *ev) -{ - - INT32 ch = -1; // cur event data - boolean eatinput = false; // :omnom: - - //should be accounted for beforehand but just to be safe... - if (!demo.playback || demo.title) - return false; - - if (noFurtherInput) - { - // Ignore input after enter/escape/other buttons - // (but still allow shift keyup so caps doesn't get stuck) - return false; - } - else if (ev->type == ev_keydown && !con_destlines) // not while the console is on please - { - ch = ev->data1; - // since this is ONLY for demos, there isn't MUCH for us to do. - // mirrored from m_responder - - switch (ch) - { - // arbitrary keyboard shortcuts because fuck you - - case '\'': // toggle freecam - M_PlaybackToggleFreecam(0); - eatinput = true; - break; - - case ']': // ffw / advance frame (depends on if paused or not) - if (paused) - M_PlaybackAdvance(0); - else - M_PlaybackFastForward(0); - eatinput = true; - break; - - case '[': // rewind /backupframe, uses the same function - M_PlaybackRewind(0); - break; - - case '\\': // pause - M_PlaybackPause(0); - eatinput = true; - break; - - // viewpoints, an annoyance (tm) - case '-': // viewpoint minus - M_PlaybackSetViews(-1); // yeah lol. - eatinput = true; - break; - - case '=': // viewpoint plus - M_PlaybackSetViews(1); // yeah lol. - eatinput = true; - break; - - // switch viewpoints: - case '1': // viewpoint for p1 (also f12) - // maximum laziness: - if (!demo.freecam) - G_AdjustView(1, 1, true); - break; - case '2': // viewpoint for p2 - if (!demo.freecam) - G_AdjustView(2, 1, true); - break; - case '3': // viewpoint for p3 - if (!demo.freecam) - G_AdjustView(3, 1, true); - break; - case '4': // viewpoint for p4 - if (!demo.freecam) - G_AdjustView(4, 1, true); - break; - - default: break; - } - - } - return eatinput; -} - - -// -// M_Drawer -// Called after the view has been rendered, -// but before it has been blitted. -// -void M_Drawer(void) -{ - if (currentMenu == &MessageDef) - menuactive = true; - - if (menuactive) - { - // now that's more readable with a faded background (yeah like Quake...) - if (!WipeInAction && currentMenu != &PlaybackMenuDef) // Replay playback has its own background - V_DrawFadeScreen(0xFF00, 16); - - if (currentMenu->drawroutine) - { - M_GetGametypeColor(); - currentMenu->drawroutine(); // call current menu Draw routine - } - - // Draw version down in corner - // ... but only in the MAIN MENU. I'm a picky bastard. - if (currentMenu == &MainDef) - { - if (customversionstring[0] != '\0') - { - V_DrawThinString(vid.dupx, vid.height - 20*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT, "Mod version:"); - V_DrawThinString(vid.dupx, vid.height - 10*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, customversionstring); - } - else - { -#ifdef DEVELOP // Development -- show revision / branch info - V_DrawThinString(vid.dupx, vid.height - 20*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, compbranch); - V_DrawThinString(vid.dupx, vid.height - 10*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, comprevision); -#else // Regular build - V_DrawThinString(vid.dupx, vid.height - 10*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, va("%s", VERSIONSTRING)); -#endif - } - } - } - - // focus lost notification goes on top of everything, even the former everything - if (window_notinfocus && cv_showfocuslost.value) - { - M_DrawTextBox((BASEVIDWIDTH/2) - (60), (BASEVIDHEIGHT/2) - (16), 13, 2); - if (gamestate == GS_LEVEL && (P_AutoPause() || paused)) - V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), highlightflags, "Game Paused"); - else - V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), highlightflags, "Focus Lost"); - } -} - -// -// M_StartControlPanel -// -void M_StartControlPanel(void) -{ - // intro might call this repeatedly - if (menuactive) - { - CON_ToggleOff(); // move away console - return; - } - - menuactive = true; - - if (demo.playback) - { - currentMenu = &PlaybackMenuDef; - playback_last_menu_interaction_leveltime = leveltime; - } - else if (!Playing()) - { - // Secret menu! - //MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); - - currentMenu = &MainDef; -#ifdef TESTERS - itemOn = multiplr; -#else - itemOn = singleplr; -#endif - } - else if (modeattacking) - { - currentMenu = &MAPauseDef; - itemOn = mapause_continue; - } - else if (!(netgame || multiplayer)) // Single Player - { - if (gamestate != GS_LEVEL /*|| ultimatemode*/) // intermission, so gray out stuff. - { - SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA)) ? (IT_GRAYEDOUT) : (IT_DISABLED); - SPauseMenu[spause_retry].status = IT_GRAYEDOUT; - } - else - { - //INT32 numlives = 2; - - SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); - - /*if (&players[consoleplayer]) - { - numlives = players[consoleplayer].lives; - if (players[consoleplayer].playerstate != PST_LIVE) - ++numlives; - } - - // The list of things that can disable retrying is (was?) a little too complex - // for me to want to use the short if statement syntax - if (numlives <= 1 || G_IsSpecialStage(gamemap)) - SPauseMenu[spause_retry].status = (IT_GRAYEDOUT); - else*/ - SPauseMenu[spause_retry].status = (IT_STRING | IT_CALL); - } - - // We can always use level select though. :33 - //SPauseMenu[spause_levelselect].status = (gamecomplete) ? (IT_STRING | IT_CALL) : (IT_DISABLED); - - // And emblem hints. - SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); - - // Shift up Pandora's Box if both pandora and levelselect are active - /*if (SPauseMenu[spause_pandora].status != (IT_DISABLED) - && SPauseMenu[spause_levelselect].status != (IT_DISABLED)) - SPauseMenu[spause_pandora].alphaKey = 24; - else - SPauseMenu[spause_pandora].alphaKey = 32;*/ - - currentMenu = &SPauseDef; - itemOn = spause_continue; - } - else // multiplayer - { - MPauseMenu[mpause_switchmap].status = IT_DISABLED; - MPauseMenu[mpause_addons].status = IT_DISABLED; - MPauseMenu[mpause_scramble].status = IT_DISABLED; - MPauseMenu[mpause_psetupsplit].status = IT_DISABLED; - MPauseMenu[mpause_psetupsplit2].status = IT_DISABLED; - MPauseMenu[mpause_psetupsplit3].status = IT_DISABLED; - MPauseMenu[mpause_psetupsplit4].status = IT_DISABLED; - MPauseMenu[mpause_spectate].status = IT_DISABLED; - MPauseMenu[mpause_entergame].status = IT_DISABLED; - MPauseMenu[mpause_canceljoin].status = IT_DISABLED; - MPauseMenu[mpause_switchteam].status = IT_DISABLED; - MPauseMenu[mpause_switchspectate].status = IT_DISABLED; - MPauseMenu[mpause_psetup].status = IT_DISABLED; - MISC_ChangeTeamMenu[0].status = IT_DISABLED; - MISC_ChangeSpectateMenu[0].status = IT_DISABLED; - // Reset these in case splitscreen messes things up - MPauseMenu[mpause_switchteam].alphaKey = 48; - MPauseMenu[mpause_switchspectate].alphaKey = 48; - MPauseMenu[mpause_options].alphaKey = 64; - MPauseMenu[mpause_title].alphaKey = 80; - MPauseMenu[mpause_quit].alphaKey = 88; - Dummymenuplayer_OnChange(); - - if ((server || IsPlayerAdmin(consoleplayer))) - { - MPauseMenu[mpause_switchmap].status = IT_STRING | IT_CALL; - MPauseMenu[mpause_addons].status = IT_STRING | IT_CALL; - if (G_GametypeHasTeams()) - MPauseMenu[mpause_scramble].status = IT_STRING | IT_SUBMENU; - } - - if (splitscreen) - { - MPauseMenu[mpause_psetupsplit].status = MPauseMenu[mpause_psetupsplit2].status = IT_STRING | IT_CALL; - MISC_ChangeTeamMenu[0].status = MISC_ChangeSpectateMenu[0].status = IT_STRING|IT_CVAR; - - if (netgame) - { - if (G_GametypeHasTeams()) - { - MPauseMenu[mpause_switchteam].status = IT_STRING | IT_SUBMENU; - MPauseMenu[mpause_switchteam].alphaKey += ((splitscreen+1) * 8); - MPauseMenu[mpause_options].alphaKey += 8; - MPauseMenu[mpause_title].alphaKey += 8; - MPauseMenu[mpause_quit].alphaKey += 8; - } - else if (G_GametypeHasSpectators()) - { - MPauseMenu[mpause_switchspectate].status = IT_STRING | IT_SUBMENU; - MPauseMenu[mpause_switchspectate].alphaKey += ((splitscreen+1) * 8); - MPauseMenu[mpause_options].alphaKey += 8; - MPauseMenu[mpause_title].alphaKey += 8; - MPauseMenu[mpause_quit].alphaKey += 8; - } - } - - if (splitscreen > 1) - { - MPauseMenu[mpause_psetupsplit3].status = IT_STRING | IT_CALL; - - MPauseMenu[mpause_options].alphaKey += 8; - MPauseMenu[mpause_title].alphaKey += 8; - MPauseMenu[mpause_quit].alphaKey += 8; - - if (splitscreen > 2) - { - MPauseMenu[mpause_psetupsplit4].status = IT_STRING | IT_CALL; - MPauseMenu[mpause_options].alphaKey += 8; - MPauseMenu[mpause_title].alphaKey += 8; - MPauseMenu[mpause_quit].alphaKey += 8; - } - } - } - else - { - MPauseMenu[mpause_psetup].status = IT_STRING | IT_CALL; - - if (G_GametypeHasTeams()) - MPauseMenu[mpause_switchteam].status = IT_STRING | IT_SUBMENU; - else if (G_GametypeHasSpectators()) - { - if (!players[consoleplayer].spectator) - MPauseMenu[mpause_spectate].status = IT_STRING | IT_CALL; - else if (players[consoleplayer].pflags & PF_WANTSTOJOIN) - MPauseMenu[mpause_canceljoin].status = IT_STRING | IT_CALL; - else - MPauseMenu[mpause_entergame].status = IT_STRING | IT_CALL; - } - else // in this odd case, we still want something to be on the menu even if it's useless - MPauseMenu[mpause_spectate].status = IT_GRAYEDOUT; - } - - currentMenu = &MPauseDef; - itemOn = mpause_continue; - } - - CON_ToggleOff(); // move away console -} - -void M_EndModeAttackRun(void) -{ - M_ModeAttackEndGame(0); -} - -// -// M_ClearMenus -// -void M_ClearMenus(boolean callexitmenufunc) -{ - if (!menuactive) - return; - - if (currentMenu->quitroutine && callexitmenufunc && !currentMenu->quitroutine()) - return; // we can't quit this menu (also used to set parameter from the menu) - -#ifndef DC // Save the config file. I'm sick of crashing the game later and losing all my changes! - COM_BufAddText(va("saveconfig \"%s\" -silent\n", configfile)); -#endif //Alam: But not on the Dreamcast's VMUs - - if (currentMenu == &MessageDef) // Oh sod off! - currentMenu = &MainDef; // Not like it matters - menuactive = false; -} - -// -// M_SetupNextMenu -// -void M_SetupNextMenu(menu_t *menudef) -{ - INT16 i; - - if (currentMenu->quitroutine) - { - // If you're going from a menu to itself, why are you running the quitroutine? You're not quitting it! -SH - if (currentMenu != menudef && !currentMenu->quitroutine()) - return; // we can't quit this menu (also used to set parameter from the menu) - } - currentMenu = menudef; - itemOn = currentMenu->lastOn; - - // in case of... - if (itemOn >= currentMenu->numitems) - itemOn = currentMenu->numitems - 1; - - // the curent item can be disabled, - // this code go up until an enabled item found - if ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_SPACE) - { - for (i = 0; i < currentMenu->numitems; i++) - { - if ((currentMenu->menuitems[i].status & IT_TYPE) != IT_SPACE) - { - itemOn = i; - break; - } - } - } -} - -// -// M_Ticker -// -void M_Ticker(void) -{ - // reset input trigger - noFurtherInput = false; - - if (dedicated) - return; - - if (--skullAnimCounter <= 0) - skullAnimCounter = 8; - - if (currentMenu == &PlaybackMenuDef) - { - if (playback_enterheld > 0) - playback_enterheld--; - } - else - playback_enterheld = 0; - - //added : 30-01-98 : test mode for five seconds - if (vidm_testingmode > 0) - { - // restore the previous video mode - if (--vidm_testingmode == 0) - setmodeneeded = vidm_previousmode + 1; - } -} - -// -// M_Init -// -void M_Init(void) -{ - UINT8 i; - - COM_AddCommand("manual", Command_Manual_f); - - CV_RegisterVar(&cv_nextmap); - CV_RegisterVar(&cv_newgametype); - CV_RegisterVar(&cv_chooseskin); - CV_RegisterVar(&cv_autorecord); - - if (dedicated) - return; - - // Menu hacks - CV_RegisterVar(&cv_dummymenuplayer); - CV_RegisterVar(&cv_dummyteam); - CV_RegisterVar(&cv_dummyspectate); - CV_RegisterVar(&cv_dummyscramble); - CV_RegisterVar(&cv_dummyrings); - CV_RegisterVar(&cv_dummylives); - CV_RegisterVar(&cv_dummycontinues); - //CV_RegisterVar(&cv_dummymares); - CV_RegisterVar(&cv_dummystaff); - - CV_RegisterVar(&cv_dummygpdifficulty); - CV_RegisterVar(&cv_dummygpencore); - CV_RegisterVar(&cv_dummygpcup); - - quitmsg[QUITMSG] = M_GetText("Eggman's tied explosives\nto your girlfriend, and\nwill activate them if\nyou press the 'Y' key!\nPress 'N' to save her!\n\n(Press 'Y' to quit)"); - quitmsg[QUITMSG1] = M_GetText("What would Tails say if\nhe saw you quitting the game?\n\n(Press 'Y' to quit)"); - quitmsg[QUITMSG2] = M_GetText("Hey!\nWhere do ya think you're goin'?\n\n(Press 'Y' to quit)"); - quitmsg[QUITMSG3] = M_GetText("Forget your studies!\nPlay some more!\n\n(Press 'Y' to quit)"); - quitmsg[QUITMSG4] = M_GetText("You're trying to say you\nlike Sonic R better than\nthis, aren't you?\n\n(Press 'Y' to quit)"); - quitmsg[QUITMSG5] = M_GetText("Don't leave yet -- there's a\nsuper emerald around that corner!\n\n(Press 'Y' to quit)"); - quitmsg[QUITMSG6] = M_GetText("You'd rather work than play?\n\n(Press 'Y' to quit)"); - quitmsg[QUITMSG7] = M_GetText("Go ahead and leave. See if I care...\n*sniffle*\n\n(Press 'Y' to quit)"); - - quitmsg[QUIT2MSG] = M_GetText("If you leave now,\nEggman will take over the world!\n\n(Press 'Y' to quit)"); - quitmsg[QUIT2MSG1] = M_GetText("On your mark,\nget set,\nhit the 'N' key!\n\n(Press 'Y' to quit)"); - quitmsg[QUIT2MSG2] = M_GetText("Aw c'mon, just\na few more laps!\n\n(Press 'Y' to quit)"); - quitmsg[QUIT2MSG3] = M_GetText("Did you get all those Chaos Emeralds?\n\n(Press 'Y' to quit)"); - quitmsg[QUIT2MSG4] = M_GetText("If you leave, I'll use\nmy Jawz on you!\n\n(Press 'Y' to quit)"); - quitmsg[QUIT2MSG5] = M_GetText("Don't go!\nYou might find the hidden\nlevels!\n\n(Press 'Y' to quit)"); - quitmsg[QUIT2MSG6] = M_GetText("Hit the 'N' key, Sonic!\nThe 'N' key!\n\n(Press 'Y' to quit)"); - - quitmsg[QUIT3MSG] = M_GetText("Are you really going to give up?\nWe certainly would never give you up.\n\n(Press 'Y' to quit)"); - quitmsg[QUIT3MSG1] = M_GetText("Come on, just ONE more netgame!\n\n(Press 'Y' to quit)"); - quitmsg[QUIT3MSG2] = M_GetText("Press 'N' to unlock\nthe Golden Kart!\n\n(Press 'Y' to quit)"); - quitmsg[QUIT3MSG3] = M_GetText("Couldn't handle\nthe banana meta?\n\n(Press 'Y' to quit)"); - quitmsg[QUIT3MSG4] = M_GetText("Every time you press 'Y', an\nSRB2Kart Developer cries...\n\n(Press 'Y' to quit)"); - quitmsg[QUIT3MSG5] = M_GetText("You'll be back to play soon, though...\n...right?\n\n(Press 'Y' to quit)"); - quitmsg[QUIT3MSG6] = M_GetText("Aww, is Eggman's Nightclub too\ndifficult for you?\n\n(Press 'Y' to quit)"); - - // Setup PlayerMenu table - for (i = 0; i < MAXSKINS; i++) - { - PlayerMenu[i].status = (i == 0 ? IT_CALL : IT_DISABLED); - PlayerMenu[i].patch = PlayerMenu[i].text = NULL; - PlayerMenu[i].itemaction = M_ChoosePlayer; - PlayerMenu[i].alphaKey = 0; - } - -#ifdef HWRENDER - // Permanently hide some options based on render mode - if (rendermode == render_soft) - OP_VideoOptionsMenu[op_video_ogl].status = IT_DISABLED; -#endif - -#ifndef NONET - CV_RegisterVar(&cv_serversort); -#endif -} - -void M_InitCharacterTables(void) -{ - UINT8 i; - - // Setup PlayerMenu table - for (i = 0; i < MAXSKINS; i++) - { - PlayerMenu[i].status = (i < 4 ? IT_CALL : IT_DISABLED); - PlayerMenu[i].patch = PlayerMenu[i].text = NULL; - PlayerMenu[i].itemaction = M_ChoosePlayer; - PlayerMenu[i].alphaKey = 0; - } - - // Setup description table - for (i = 0; i < MAXSKINS; i++) - { - if (i == 0) - { - strcpy(description[i].notes, "\x82Sonic\x80 is the fastest of the three, but also the hardest to control. Beginners beware, but experts will find Sonic very powerful.\n\n\x82""Ability:\x80 Speed Thok\nDouble jump to zoom forward with a huge burst of speed.\n\n\x82Tip:\x80 Simply letting go of forward does not slow down in SRB2. To slow down, hold the opposite direction."); - strcpy(description[i].picname, ""); - strcpy(description[i].skinname, "sonic"); - } - else if (i == 1) - { - strcpy(description[i].notes, "\x82Tails\x80 is the most mobile of the three, but has the slowest speed. Because of his mobility, he's well-\nsuited to beginners.\n\n\x82""Ability:\x80 Fly\nDouble jump to start flying for a limited time. Repetitively hit the jump button to ascend.\n\n\x82Tip:\x80 To quickly descend while flying, hit the spin button."); - strcpy(description[i].picname, ""); - strcpy(description[i].skinname, "tails"); - } - else if (i == 2) - { - strcpy(description[i].notes, "\x82Knuckles\x80 is well-\nrounded and can destroy breakable walls simply by touching them, but he can't jump as high as the other two.\n\n\x82""Ability:\x80 Glide & Climb\nDouble jump to glide in the air as long as jump is held. Glide into a wall to climb it.\n\n\x82Tip:\x80 Press spin while climbing to jump off the wall; press jump instead to jump off\nand face away from\nthe wall."); - strcpy(description[i].picname, ""); - strcpy(description[i].skinname, "knuckles"); - } - else if (i == 3) - { - strcpy(description[i].notes, "\x82Sonic & Tails\x80 team up to take on Dr. Eggman!\nControl Sonic while Tails desperately struggles to keep up.\n\nPlayer 2 can control Tails directly by setting the controls in the options menu.\nTails's directional controls are relative to Player 1's camera.\n\nTails can pick up Sonic while flying and carry him around."); - strcpy(description[i].picname, "CHRS&T"); - strcpy(description[i].skinname, "sonic&tails"); - } - else - { - strcpy(description[i].notes, "???"); - strcpy(description[i].picname, ""); - strcpy(description[i].skinname, ""); - } - } -} - -// ========================================================================== -// SPECIAL MENU OPTION DRAW ROUTINES GO HERE -// ========================================================================== - -// Converts a string into question marks. -// Used for the secrets menu, to hide yet-to-be-unlocked stuff. -static const char *M_CreateSecretMenuOption(const char *str) -{ - static char qbuf[32]; - int i; - - for (i = 0; i < 31; ++i) - { - if (!str[i]) - { - qbuf[i] = '\0'; - return qbuf; - } - else if (str[i] != ' ') - qbuf[i] = '?'; - else - qbuf[i] = ' '; - } - - qbuf[31] = '\0'; - return qbuf; -} - -static void M_DrawThermo(INT32 x, INT32 y, consvar_t *cv) -{ - INT32 xx = x, i; - lumpnum_t leftlump, rightlump, centerlump[2], cursorlump; - patch_t *p; - - leftlump = W_GetNumForName("M_THERML"); - rightlump = W_GetNumForName("M_THERMR"); - centerlump[0] = W_GetNumForName("M_THERMM"); - centerlump[1] = W_GetNumForName("M_THERMM"); - cursorlump = W_GetNumForName("M_THERMO"); - - V_DrawScaledPatch(xx, y, 0, p = W_CachePatchNum(leftlump,PU_CACHE)); - xx += SHORT(p->width) - SHORT(p->leftoffset); - for (i = 0; i < 16; i++) - { - V_DrawScaledPatch(xx, y, V_WRAPX, W_CachePatchNum(centerlump[i & 1], PU_CACHE)); - xx += 8; - } - V_DrawScaledPatch(xx, y, 0, W_CachePatchNum(rightlump, PU_CACHE)); - - xx = (cv->value - cv->PossibleValue[0].value) * (15*8) / - (cv->PossibleValue[1].value - cv->PossibleValue[0].value); - - V_DrawScaledPatch((x + 8) + xx, y, 0, W_CachePatchNum(cursorlump, PU_CACHE)); -} - -// A smaller 'Thermo', with range given as percents (0-100) -static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) -{ - INT32 i; - INT32 range; - patch_t *p; - - for (i = 0; cv->PossibleValue[i+1].strvalue; i++); - - x = BASEVIDWIDTH - x - SLIDER_WIDTH; - - if (ontop) - { - V_DrawCharacter(x - 16 - (skullAnimCounter/5), y, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(x+(SLIDER_RANGE*8) + 8 + (skullAnimCounter/5), y, - '\x1D' | highlightflags, false); // right arrow - } - - if ((range = atoi(cv->defaultvalue)) != cv->value) - { - range = ((range - cv->PossibleValue[0].value) * 100 / - (cv->PossibleValue[1].value - cv->PossibleValue[0].value)); - - if (range < 0) - range = 0; - if (range > 100) - range = 100; - - // draw the default - p = W_CachePatchName("M_SLIDEC", PU_CACHE); - V_DrawScaledPatch(x - 4 + (((SLIDER_RANGE)*8 + 4)*range)/100, y, 0, p); - } - - V_DrawScaledPatch(x - 8, y, 0, W_CachePatchName("M_SLIDEL", PU_CACHE)); - - p = W_CachePatchName("M_SLIDEM", PU_CACHE); - for (i = 0; i < SLIDER_RANGE; i++) - V_DrawScaledPatch (x+i*8, y, 0,p); - - p = W_CachePatchName("M_SLIDER", PU_CACHE); - V_DrawScaledPatch(x+SLIDER_RANGE*8, y, 0, p); - - range = ((cv->value - cv->PossibleValue[0].value) * 100 / - (cv->PossibleValue[1].value - cv->PossibleValue[0].value)); - - if (range < 0) - range = 0; - if (range > 100) - range = 100; - - // draw the slider cursor - p = W_CachePatchName("M_SLIDEC", PU_CACHE); - V_DrawScaledPatch(x - 4 + (((SLIDER_RANGE)*8 + 4)*range)/100, y, 0, p); -} - -// -// Draw a textbox, like Quake does, because sometimes it's difficult -// to read the text with all the stuff in the background... -// -void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines) -{ - // Solid color textbox. - V_DrawFill(x+5, y+5, width*8+6, boxlines*8+6, 159); - //V_DrawFill(x+8, y+8, width*8, boxlines*8, 31); -/* - patch_t *p; - INT32 cx, cy, n; - INT32 step, boff; - - step = 8; - boff = 8; - - // draw left side - cx = x; - cy = y; - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TL], PU_CACHE)); - cy += boff; - p = W_CachePatchNum(viewborderlump[BRDR_L], PU_CACHE); - for (n = 0; n < boxlines; n++) - { - V_DrawScaledPatch(cx, cy, V_WRAPY, p); - cy += step; - } - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BL], PU_CACHE)); - - // draw middle - V_DrawFlatFill(x + boff, y + boff, width*step, boxlines*step, st_borderpatchnum); - - cx += boff; - cy = y; - while (width > 0) - { - V_DrawScaledPatch(cx, cy, V_WRAPX, W_CachePatchNum(viewborderlump[BRDR_T], PU_CACHE)); - V_DrawScaledPatch(cx, y + boff + boxlines*step, V_WRAPX, W_CachePatchNum(viewborderlump[BRDR_B], PU_CACHE)); - width--; - cx += step; - } - - // draw right side - cy = y; - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TR], PU_CACHE)); - cy += boff; - p = W_CachePatchNum(viewborderlump[BRDR_R], PU_CACHE); - for (n = 0; n < boxlines; n++) - { - V_DrawScaledPatch(cx, cy, V_WRAPY, p); - cy += step; - } - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BR], PU_CACHE)); -*/ -} - -// -// Draw border for the savegame description -// -/*static void M_DrawSaveLoadBorder(INT32 x,INT32 y) -{ - INT32 i; - - V_DrawScaledPatch (x-8,y+7,0,W_CachePatchName("M_LSLEFT",PU_CACHE)); - - for (i = 0;i < 24;i++) - { - V_DrawScaledPatch (x,y+7,0,W_CachePatchName("M_LSCNTR",PU_CACHE)); - x += 8; - } - - V_DrawScaledPatch (x,y+7,0,W_CachePatchName("M_LSRGHT",PU_CACHE)); -}*/ - -// horizontally centered text -static void M_CentreText(INT32 y, const char *string) -{ - INT32 x; - //added : 02-02-98 : centre on 320, because V_DrawString centers on vid.width... - x = (BASEVIDWIDTH - V_StringWidth(string, V_OLDSPACING))>>1; - V_DrawString(x,y,V_OLDSPACING,string); -} - -// -// M_DrawMapEmblems -// -// used by pause & statistics to draw a row of emblems for a map -// -static void M_DrawMapEmblems(INT32 mapnum, INT32 x, INT32 y) -{ - UINT8 lasttype = UINT8_MAX, curtype; - emblem_t *emblem = M_GetLevelEmblems(mapnum); - - while (emblem) - { - switch (emblem->type) - { - case ET_TIME: //case ET_SCORE: case ET_RINGS: - curtype = 1; break; - /*case ET_NGRADE: case ET_NTIME: - curtype = 2; break;*/ - default: - curtype = 0; break; - } - - // Shift over if emblem is of a different discipline - if (lasttype != UINT8_MAX && lasttype != curtype) - x -= 4; - lasttype = curtype; - - if (emblem->collected) - V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_MENUCACHE)); - else - V_DrawSmallScaledPatch(x, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); - - emblem = M_GetLevelEmblems(-1); - x -= 8; - } -} - -static void M_DrawMenuTitle(void) -{ - if (currentMenu->menutitlepic) - { - patch_t *p = W_CachePatchName(currentMenu->menutitlepic, PU_CACHE); - - if (p->height > 24) // title is larger than normal - { - INT32 xtitle = (BASEVIDWIDTH - (SHORT(p->width)/2))/2; - INT32 ytitle = (30 - (SHORT(p->height)/2))/2; - - if (xtitle < 0) - xtitle = 0; - if (ytitle < 0) - ytitle = 0; - - V_DrawSmallScaledPatch(xtitle, ytitle, 0, p); - } - else - { - INT32 xtitle = (BASEVIDWIDTH - SHORT(p->width))/2; - INT32 ytitle = (30 - SHORT(p->height))/2; - - if (xtitle < 0) - xtitle = 0; - if (ytitle < 0) - ytitle = 0; - - V_DrawScaledPatch(xtitle, ytitle, 0, p); - } - } -} - -static void M_DrawGenericMenu(void) -{ - INT32 x, y, w, i, cursory = 0; - - // DRAW MENU - x = currentMenu->x; - y = currentMenu->y; - - // draw title (or big pic) - M_DrawMenuTitle(); - - for (i = 0; i < currentMenu->numitems; i++) - { - if (i == itemOn) - cursory = y; - switch (currentMenu->menuitems[i].status & IT_DISPLAY) - { - case IT_PATCH: - if (currentMenu->menuitems[i].patch && currentMenu->menuitems[i].patch[0]) - { - if (currentMenu->menuitems[i].status & IT_CENTER) - { - patch_t *p; - p = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, y, 0, p); - } - else - { - V_DrawScaledPatch(x, y, 0, - W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE)); - } - } - /* FALLTHRU */ - case IT_NOTHING: - case IT_DYBIGSPACE: - y = currentMenu->y+currentMenu->menuitems[i].alphaKey;//+= LINEHEIGHT; - break; - case IT_BIGSLIDER: - M_DrawThermo(x, y, (consvar_t *)currentMenu->menuitems[i].itemaction); - y += LINEHEIGHT; - break; - case IT_STRING: - case IT_WHITESTRING: - if (currentMenu->menuitems[i].alphaKey) - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - if (i == itemOn) - cursory = y; - - if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) - V_DrawString(x, y, 0, currentMenu->menuitems[i].text); - else - V_DrawString(x, y, highlightflags, currentMenu->menuitems[i].text); - - // Cvar specific handling - switch (currentMenu->menuitems[i].status & IT_TYPE) - case IT_CVAR: - { - consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction; - switch (currentMenu->menuitems[i].status & IT_CVARTYPE) - { - case IT_CV_SLIDER: - M_DrawSlider(x, y, cv, (i == itemOn)); - case IT_CV_NOPRINT: // color use this - case IT_CV_INVISSLIDER: // monitor toggles use this - break; - case IT_CV_STRING: - M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1); - V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, cv->string); - if (skullAnimCounter < 4 && i == itemOn) - V_DrawCharacter(x + 8 + V_StringWidth(cv->string, 0), y + 12, - '_' | 0x80, false); - y += 16; - break; - default: - w = V_StringWidth(cv->string, 0); - V_DrawString(BASEVIDWIDTH - x - w, y, - ((cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv) ? warningflags : highlightflags), cv->string); - if (i == itemOn) - { - V_DrawCharacter(BASEVIDWIDTH - x - 10 - w - (skullAnimCounter/5), y, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y, - '\x1D' | highlightflags, false); // right arrow - } - break; - } - break; - } - y += STRINGHEIGHT; - break; - case IT_STRING2: - V_DrawString(x, y, 0, currentMenu->menuitems[i].text); - /* FALLTHRU */ - case IT_DYLITLSPACE: - y += SMALLLINEHEIGHT; - break; - case IT_GRAYPATCH: - if (currentMenu->menuitems[i].patch && currentMenu->menuitems[i].patch[0]) - V_DrawMappedPatch(x, y, 0, - W_CachePatchName(currentMenu->menuitems[i].patch,PU_CACHE), graymap); - y += LINEHEIGHT; - break; - case IT_TRANSTEXT: - if (currentMenu->menuitems[i].alphaKey) - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - /* FALLTHRU */ - case IT_TRANSTEXT2: - V_DrawString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text); - y += SMALLLINEHEIGHT; - break; - case IT_QUESTIONMARKS: - if (currentMenu->menuitems[i].alphaKey) - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - - V_DrawString(x, y, V_TRANSLUCENT|V_OLDSPACING, M_CreateSecretMenuOption(currentMenu->menuitems[i].text)); - y += SMALLLINEHEIGHT; - break; - case IT_HEADERTEXT: // draws 16 pixels to the left, in yellow text - if (currentMenu->menuitems[i].alphaKey) - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - - V_DrawString(x-16, y, highlightflags, currentMenu->menuitems[i].text); - y += SMALLLINEHEIGHT; - break; - } - } - - // DRAW THE SKULL CURSOR - if (((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == IT_PATCH) - || ((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == IT_NOTHING)) - { - V_DrawScaledPatch(currentMenu->x + SKULLXOFF, cursory - 5, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); - } - else - { - V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); - V_DrawString(currentMenu->x, cursory, highlightflags, currentMenu->menuitems[itemOn].text); - } -} - -static void M_DrawGenericBackgroundMenu(void) -{ - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - M_DrawGenericMenu(); -} - -static void M_DrawPauseMenu(void) -{ -#if 0 - if (!netgame && !multiplayer && (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING)) - { - emblem_t *emblem_detail[3] = {NULL, NULL, NULL}; - char emblem_text[3][20]; - INT32 i; - - M_DrawTextBox(27, 16, 32, 6); - - // Draw any and all emblems at the top. - M_DrawMapEmblems(gamemap, 272, 28); - - if (strlen(mapheaderinfo[gamemap-1]->zonttl) > 0) - { - if (strlen(mapheaderinfo[gamemap-1]->actnum) > 0) - V_DrawString(40, 28, highlightflags, va("%s %s %s", mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->zonttl, mapheaderinfo[gamemap-1]->actnum)); - else - V_DrawString(40, 28, highlightflags, va("%s %s", mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->zonttl)); - } - else - { - if (strlen(mapheaderinfo[gamemap-1]->actnum) > 0) - V_DrawString(40, 28, highlightflags, va("%s %s", mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->actnum)); - else - V_DrawString(40, 28, highlightflags, mapheaderinfo[gamemap-1]->lvlttl); - } - - // Set up the detail boxes. - { - emblem_t *emblem = M_GetLevelEmblems(gamemap); - while (emblem) - { - INT32 emblemslot; - char targettext[9], currenttext[9]; - - switch (emblem->type) - { - /*case ET_SCORE: - snprintf(targettext, 9, "%d", emblem->var); - snprintf(currenttext, 9, "%u", G_GetBestScore(gamemap)); - - targettext[8] = 0; - currenttext[8] = 0; - - emblemslot = 0; - break;*/ - case ET_TIME: - emblemslot = emblem->var; // dumb hack - snprintf(targettext, 9, "%i:%02i.%02i", - G_TicsToMinutes((tic_t)emblemslot, false), - G_TicsToSeconds((tic_t)emblemslot), - G_TicsToCentiseconds((tic_t)emblemslot)); - - emblemslot = (INT32)G_GetBestTime(gamemap); // dumb hack pt ii - if ((tic_t)emblemslot == UINT32_MAX) - snprintf(currenttext, 9, "-:--.--"); - else - snprintf(currenttext, 9, "%i:%02i.%02i", - G_TicsToMinutes((tic_t)emblemslot, false), - G_TicsToSeconds((tic_t)emblemslot), - G_TicsToCentiseconds((tic_t)emblemslot)); - - targettext[8] = 0; - currenttext[8] = 0; - - emblemslot = 1; - break; - /*case ET_RINGS: - snprintf(targettext, 9, "%d", emblem->var); - snprintf(currenttext, 9, "%u", G_GetBestRings(gamemap)); - - targettext[8] = 0; - currenttext[8] = 0; - - emblemslot = 2; - break; - case ET_NGRADE: - snprintf(targettext, 9, "%u", P_GetScoreForGrade(gamemap, 0, emblem->var)); - snprintf(currenttext, 9, "%u", G_GetBestNightsScore(gamemap, 0)); - - targettext[8] = 0; - currenttext[8] = 0; - - emblemslot = 1; - break; - case ET_NTIME: - emblemslot = emblem->var; // dumb hack pt iii - snprintf(targettext, 9, "%i:%02i.%02i", - G_TicsToMinutes((tic_t)emblemslot, false), - G_TicsToSeconds((tic_t)emblemslot), - G_TicsToCentiseconds((tic_t)emblemslot)); - - emblemslot = (INT32)G_GetBestNightsTime(gamemap, 0); // dumb hack pt iv - if ((tic_t)emblemslot == UINT32_MAX) - snprintf(currenttext, 9, "-:--.--"); - else - snprintf(currenttext, 9, "%i:%02i.%02i", - G_TicsToMinutes((tic_t)emblemslot, false), - G_TicsToSeconds((tic_t)emblemslot), - G_TicsToCentiseconds((tic_t)emblemslot)); - - targettext[8] = 0; - currenttext[8] = 0; - - emblemslot = 2; - break;*/ - default: - goto bademblem; - } - if (emblem_detail[emblemslot]) - goto bademblem; - - emblem_detail[emblemslot] = emblem; - snprintf(emblem_text[emblemslot], 20, "%8s /%8s", currenttext, targettext); - emblem_text[emblemslot][19] = 0; - - bademblem: - emblem = M_GetLevelEmblems(-1); - } - } - for (i = 0; i < 3; ++i) - { - emblem_t *emblem = emblem_detail[i]; - if (!emblem) - continue; - - if (emblem->collected) - V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_MENUCACHE)); - else - V_DrawSmallScaledPatch(40, 44 + (i*8), 0, W_CachePatchName("NEEDIT", PU_CACHE)); - - switch (emblem->type) - { - /*case ET_SCORE: - case ET_NGRADE: - V_DrawString(56, 44 + (i*8), highlightflags, "SCORE:"); - break;*/ - case ET_TIME: - //case ET_NTIME: - V_DrawString(56, 44 + (i*8), highlightflags, "TIME:"); - break; - /*case ET_RINGS: - V_DrawString(56, 44 + (i*8), highlightflags, "RINGS:"); - break;*/ - } - V_DrawRightAlignedString(284, 44 + (i*8), V_MONOSPACE, emblem_text[i]); - } - } -#endif - - M_DrawGenericMenu(); -} - -static void M_DrawCenteredMenu(void) -{ - INT32 x, y, i, cursory = 0; - - // DRAW MENU - x = currentMenu->x; - y = currentMenu->y; - - // draw title (or big pic) - M_DrawMenuTitle(); - - for (i = 0; i < currentMenu->numitems; i++) - { - if (i == itemOn) - cursory = y; - switch (currentMenu->menuitems[i].status & IT_DISPLAY) - { - case IT_PATCH: - if (currentMenu->menuitems[i].patch && currentMenu->menuitems[i].patch[0]) - { - if (currentMenu->menuitems[i].status & IT_CENTER) - { - patch_t *p; - p = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, y, 0, p); - } - else - { - V_DrawScaledPatch(x, y, 0, - W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE)); - } - } - /* FALLTHRU */ - case IT_NOTHING: - case IT_DYBIGSPACE: - y += LINEHEIGHT; - break; - case IT_BIGSLIDER: - M_DrawThermo(x, y, (consvar_t *)currentMenu->menuitems[i].itemaction); - y += LINEHEIGHT; - break; - case IT_STRING: - case IT_WHITESTRING: - if (currentMenu->menuitems[i].alphaKey) - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - if (i == itemOn) - cursory = y; - - if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) - V_DrawCenteredString(x, y, 0, currentMenu->menuitems[i].text); - else - V_DrawCenteredString(x, y, highlightflags, currentMenu->menuitems[i].text); - - // Cvar specific handling - switch(currentMenu->menuitems[i].status & IT_TYPE) - case IT_CVAR: - { - consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction; - switch(currentMenu->menuitems[i].status & IT_CVARTYPE) - { - case IT_CV_SLIDER: - M_DrawSlider(x, y, cv, (i == itemOn)); - case IT_CV_NOPRINT: // color use this - break; - case IT_CV_STRING: - M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1); - V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, cv->string); - if (skullAnimCounter < 4 && i == itemOn) - V_DrawCharacter(x + 8 + V_StringWidth(cv->string, 0), y + 12, - '_' | 0x80, false); - y += 16; - break; - default: - V_DrawString(BASEVIDWIDTH - x - V_StringWidth(cv->string, 0), y, - ((cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv) ? warningflags : highlightflags), cv->string); - break; - } - break; - } - y += STRINGHEIGHT; - break; - case IT_STRING2: - V_DrawCenteredString(x, y, 0, currentMenu->menuitems[i].text); - /* FALLTHRU */ - case IT_DYLITLSPACE: - y += SMALLLINEHEIGHT; - break; - case IT_QUESTIONMARKS: - if (currentMenu->menuitems[i].alphaKey) - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - - V_DrawCenteredString(x, y, V_TRANSLUCENT|V_OLDSPACING, M_CreateSecretMenuOption(currentMenu->menuitems[i].text)); - y += SMALLLINEHEIGHT; - break; - case IT_GRAYPATCH: - if (currentMenu->menuitems[i].patch && currentMenu->menuitems[i].patch[0]) - V_DrawMappedPatch(x, y, 0, - W_CachePatchName(currentMenu->menuitems[i].patch,PU_CACHE), graymap); - y += LINEHEIGHT; - break; - case IT_TRANSTEXT: - if (currentMenu->menuitems[i].alphaKey) - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - /* FALLTHRU */ - case IT_TRANSTEXT2: - V_DrawCenteredString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text); - y += SMALLLINEHEIGHT; - break; - } - } - - // DRAW THE SKULL CURSOR - if (((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == IT_PATCH) - || ((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == IT_NOTHING)) - { - V_DrawScaledPatch(x + SKULLXOFF, cursory - 5, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); - } - else - { - V_DrawScaledPatch(x - V_StringWidth(currentMenu->menuitems[itemOn].text, 0)/2 - 24, cursory, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); - V_DrawCenteredString(x, cursory, highlightflags, currentMenu->menuitems[itemOn].text); - } -} - -// -// M_StringHeight -// -// Find string height from hu_font chars -// -static inline size_t M_StringHeight(const char *string) -{ - size_t h = 8, i; - - for (i = 0; i < strlen(string); i++) - if (string[i] == '\n') - h += 8; - - return h; -} - -// ========================================================================== -// Extraneous menu patching functions -// ========================================================================== - -// -// M_PatchSkinNameTable -// -// Like M_PatchLevelNameTable, but for cv_chooseskin -// -static void M_PatchSkinNameTable(void) -{ - INT32 j; - - memset(skins_cons_t, 0, sizeof (skins_cons_t)); - - for (j = 0; j < MAXSKINS; j++) - { - if (skins[j].name[0] != '\0') - { - skins_cons_t[j].strvalue = skins[j].name; - skins_cons_t[j].value = j+1; - } - else - { - skins_cons_t[j].strvalue = NULL; - skins_cons_t[j].value = 0; - break; - } - } - - j = R_SkinAvailable(cv_skin.string); - if (j == -1) - j = 0; - - CV_SetValue(&cv_chooseskin, j+1); // This causes crash sometimes?! - - return; -} - -// -// M_PrepareCupList -// -static void M_PrepareCupList(void) -{ - cupheader_t *cup = kartcupheaders; - INT32 i = 0; - - memset(dummygpcup_cons_t, 0, sizeof (dummygpcup_cons_t)); - - while (cup != NULL) - { - dummygpcup_cons_t[i].strvalue = cup->name; - dummygpcup_cons_t[i].value = i+1; - // this will probably crash or do something stupid at over 50 cups, - // but this is all behavior that gets completely overwritten in new-menus, so I'm not worried - i++; - cup = cup->next; - } - - for (; i < 50; i++) - { - dummygpcup_cons_t[i].strvalue = NULL; - dummygpcup_cons_t[i].value = 0; - } - - CV_SetValue(&cv_dummygpcup, 1); // This causes crash sometimes?! -} - -// Call before showing any level-select menus -static void M_PrepareLevelSelect(void) -{ - if (levellistmode != LLM_CREATESERVER) - CV_SetValue(&cv_nextmap, M_GetFirstLevelInList()); - else - Newgametype_OnChange(); // Make sure to start on an appropriate map if wads have been added -} - -// -// M_CanShowLevelInList -// -// Determines whether to show a given map in the various level-select lists. -// Set gt = -1 to ignore gametype. -// -boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt) -{ - // Random map! - if (mapnum == -1) - return (gamestate != GS_TIMEATTACK && !modeattacking); - - // Does the map exist? - if (!mapheaderinfo[mapnum]) - return false; - - // Does the map have a name? - if (!mapheaderinfo[mapnum]->lvlttl[0]) - return false; - - switch (levellistmode) - { - case LLM_CREATESERVER: - // Should the map be hidden? - if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU && mapnum+1 != gamemap) - return false; - - if (M_MapLocked(mapnum+1)) - return false; // not unlocked - - /*if (gt == GT_COOP && (mapheaderinfo[mapnum]->typeoflevel & TOL_COOP)) - return true; - - if (gt == GT_COMPETITION && (mapheaderinfo[mapnum]->typeoflevel & TOL_COMPETITION)) - return true; - - if (gt == GT_CTF && (mapheaderinfo[mapnum]->typeoflevel & TOL_CTF)) - return true; - - if ((gt == GT_TAG || gt == GT_HIDEANDSEEK) && (mapheaderinfo[mapnum]->typeoflevel & TOL_TAG)) - return true;*/ - - if ((gt == GT_MATCH || gt == GT_TEAMMATCH) && (mapheaderinfo[mapnum]->typeoflevel & TOL_MATCH)) - return true; - - if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE)) - return true; - - return false; - - /*case LLM_LEVELSELECT: - if (mapheaderinfo[mapnum]->levelselect != maplistoption) - return false; - - if (M_MapLocked(mapnum+1)) - return false; // not unlocked - - return true;*/ - case LLM_TIMEATTACK: - case LLM_BREAKTHECAPSULES: - /*if (!(mapheaderinfo[mapnum]->menuflags & LF2_RECORDATTACK)) - return false;*/ - - if ((levellistmode == LLM_TIMEATTACK && !(mapheaderinfo[mapnum]->typeoflevel & TOL_RACE)) - || (levellistmode == LLM_BREAKTHECAPSULES && !(mapheaderinfo[mapnum]->typeoflevel & TOL_MATCH))) - return false; - - if (M_MapLocked(mapnum+1)) - return false; // not unlocked - - if (M_SecretUnlocked(SECRET_HELLATTACK)) - return true; // now you're in hell - - if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU) - return false; // map hell - - /*if (mapheaderinfo[mapnum]->menuflags & LF2_NOVISITNEEDED) - return true; - - if (!mapvisited[mapnum]) - return false;*/ - - return true; - default: - return false; - } - - // Hmm? Couldn't decide? - return false; -} - -static INT32 M_CountLevelsToShowInList(void) -{ - INT32 mapnum, count = 0; - - for (mapnum = 0; mapnum < NUMMAPS; mapnum++) - if (M_CanShowLevelInList(mapnum, -1)) - count++; - - return count; -} - -static INT32 M_GetFirstLevelInList(void) -{ - INT32 mapnum; - - for (mapnum = 0; mapnum < NUMMAPS; mapnum++) - if (M_CanShowLevelInList(mapnum, -1)) - return mapnum + 1; - - return 1; -} - -// ================================================== -// MESSAGE BOX (aka: a hacked, cobbled together menu) -// ================================================== -static void M_DrawMessageMenu(void); - -// Because this is just a hack-ish 'menu', I'm not putting this with the others -static menuitem_t MessageMenu[] = -{ - // TO HACK - {0,NULL, NULL, NULL,0} -}; - -menu_t MessageDef = -{ - NULL, // title - 1, // # of menu items - NULL, // previous menu (TO HACK) - MessageMenu, // menuitem_t -> - M_DrawMessageMenu, // drawing routine -> - 0, 0, // x, y (TO HACK) - 0, // lastOn, flags (TO HACK) - NULL -}; - - -void M_StartMessage(const char *string, void *routine, - menumessagetype_t itemtype) -{ - size_t max = 0, start = 0, i, strlines; - static char *message = NULL; - Z_Free(message); - message = Z_StrDup(string); - DEBFILE(message); - - // Rudementary word wrapping. - // Simple and effective. Does not handle nonuniform letter sizes, colors, etc. but who cares. - strlines = 0; - for (i = 0; message[i]; i++) - { - if (message[i] == ' ') - { - start = i; - max += 4; - } - else if (message[i] == '\n') - { - strlines = i; - start = 0; - max = 0; - continue; - } - else - max += 8; - - // Start trying to wrap if presumed length exceeds the screen width. - if (max >= BASEVIDWIDTH && start > 0) - { - message[start] = '\n'; - max -= (start-strlines)*8; - strlines = start; - start = 0; - } - } - - start = 0; - max = 0; - - M_StartControlPanel(); // can't put menuactive to true - - if (currentMenu == &MessageDef) // Prevent recursion - MessageDef.prevMenu = ((demo.playback) ? &PlaybackMenuDef : &MainDef); - else - MessageDef.prevMenu = currentMenu; - - MessageDef.menuitems[0].text = message; - MessageDef.menuitems[0].alphaKey = (UINT8)itemtype; - if (!routine && itemtype != MM_NOTHING) itemtype = MM_NOTHING; - switch (itemtype) - { - case MM_NOTHING: - MessageDef.menuitems[0].status = IT_MSGHANDLER; - MessageDef.menuitems[0].itemaction = M_StopMessage; - break; - case MM_YESNO: - MessageDef.menuitems[0].status = IT_MSGHANDLER; - MessageDef.menuitems[0].itemaction = routine; - break; - case MM_EVENTHANDLER: - MessageDef.menuitems[0].status = IT_MSGHANDLER; - MessageDef.menuitems[0].itemaction = routine; - break; - } - //added : 06-02-98: now draw a textbox around the message - // compute lenght max and the numbers of lines - for (strlines = 0; *(message+start); strlines++) - { - for (i = 0;i < strlen(message+start);i++) - { - if (*(message+start+i) == '\n') - { - if (i > max) - max = i; - start += i; - i = (size_t)-1; //added : 07-02-98 : damned! - start++; - break; - } - } - - if (i == strlen(message+start)) - start += i; - } - - MessageDef.x = (INT16)((BASEVIDWIDTH - 8*max-16)/2); - MessageDef.y = (INT16)((BASEVIDHEIGHT - M_StringHeight(message))/2); - - MessageDef.lastOn = (INT16)((strlines<<8)+max); - - //M_SetupNextMenu(); - currentMenu = &MessageDef; - itemOn = 0; -} - -#define MAXMSGLINELEN 256 - -static void M_DrawMessageMenu(void) -{ - INT32 y = currentMenu->y; - size_t i, start = 0; - INT16 max; - char string[MAXMSGLINELEN]; - INT32 mlines; - const char *msg = currentMenu->menuitems[0].text; - - mlines = currentMenu->lastOn>>8; - max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8); - - // hack: draw RA background in RA menus - if (gamestate == GS_TIMEATTACK) - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - - M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines); - - while (*(msg+start)) - { - size_t len = strlen(msg+start); - - for (i = 0; i < len; i++) - { - if (*(msg+start+i) == '\n') - { - memset(string, 0, MAXMSGLINELEN); - if (i >= MAXMSGLINELEN) - { - CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg); - return; - } - else - { - strncpy(string,msg+start, i); - string[i] = '\0'; - start += i; - i = (size_t)-1; //added : 07-02-98 : damned! - start++; - } - break; - } - } - - if (i == strlen(msg+start)) - { - if (i >= MAXMSGLINELEN) - { - CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg); - return; - } - else - { - strcpy(string, msg + start); - start += i; - } - } - - V_DrawString((BASEVIDWIDTH - V_StringWidth(string, 0))/2,y,V_ALLOWLOWERCASE,string); - y += 8; //SHORT(hu_font[0]->height); - } -} - -// default message handler -static void M_StopMessage(INT32 choice) -{ - (void)choice; - if (menuactive) - M_SetupNextMenu(MessageDef.prevMenu); -} - -// ========= -// IMAGEDEFS -// ========= - -// Draw an Image Def. Aka, Help images. -// Defines what image is used in (menuitem_t)->text. -// You can even put multiple images in one menu! -static void M_DrawImageDef(void) -{ - patch_t *patch = W_CachePatchName(currentMenu->menuitems[itemOn].text,PU_CACHE); - if (patch->width <= BASEVIDWIDTH) - V_DrawScaledPatch(0,0,0,patch); - else - V_DrawSmallScaledPatch(0,0,0,patch); - - if (currentMenu->menuitems[itemOn].alphaKey) - { - V_DrawString(2,BASEVIDHEIGHT-10, V_YELLOWMAP, va("%d", (itemOn<<1)-1)); // intentionally not highlightflags, unlike below - V_DrawRightAlignedString(BASEVIDWIDTH-2,BASEVIDHEIGHT-10, V_YELLOWMAP, va("%d", itemOn<<1)); // ditto - } - else - { - INT32 x = BASEVIDWIDTH>>1, y = (BASEVIDHEIGHT>>1) - 4; - x += (itemOn ? 1 : -1)*((BASEVIDWIDTH>>2) + 10); - V_DrawCenteredString(x, y-10, highlightflags, "USE ARROW KEYS"); - V_DrawCharacter(x - 10 - (skullAnimCounter/5), y, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(x + 2 + (skullAnimCounter/5), y, - '\x1D' | highlightflags, false); // right arrow - V_DrawCenteredString(x, y+10, highlightflags, "TO LEAF THROUGH"); - } -} - -// Handles the ImageDefs. Just a specialized function that -// uses left and right movement. -static void M_HandleImageDef(INT32 choice) -{ - boolean exitmenu = false; - - switch (choice) - { - case KEY_RIGHTARROW: - if (itemOn >= (INT16)(currentMenu->numitems-1)) - break; - S_StartSound(NULL, sfx_menu1); - itemOn++; - break; - - case KEY_LEFTARROW: - if (!itemOn) - break; - - S_StartSound(NULL, sfx_menu1); - itemOn--; - break; - - case KEY_ESCAPE: - case KEY_ENTER: - exitmenu = true; - break; - } - - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} - -// ====================== -// MISC MAIN MENU OPTIONS -// ====================== - -static void M_AddonsOptions(INT32 choice) -{ - (void)choice; - Addons_option_Onchange(); - - M_SetupNextMenu(&OP_AddonsOptionsDef); -} - -#define LOCATIONSTRING1 "Visit \x83SRB2.ORG/MODS\x80 to get & make addons!" -#define LOCATIONSTRING2 "Visit \x88SRB2.ORG/MODS\x80 to get & make addons!" - -static void M_Addons(INT32 choice) -{ - const char *pathname = "."; - - (void)choice; - -#if 1 - if (cv_addons_option.value == 0) - pathname = usehome ? srb2home : srb2path; - else if (cv_addons_option.value == 1) - pathname = srb2home; - else if (cv_addons_option.value == 2) - pathname = srb2path; - else -#endif - if (cv_addons_option.value == 3 && *cv_addons_folder.string != '\0') - pathname = cv_addons_folder.string; - - strlcpy(menupath, pathname, 1024); - menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath) + 1; - - if (menupath[menupathindex[menudepthleft]-2] != PATHSEP[0]) - { - menupath[menupathindex[menudepthleft]-1] = PATHSEP[0]; - menupath[menupathindex[menudepthleft]] = 0; - } - else - --menupathindex[menudepthleft]; - - if (!preparefilemenu(false, false)) - { - M_StartMessage(va("No files/folders found.\n\n%s\n\n(Press a key)\n", (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)),NULL,MM_NOTHING); - return; - } - else - dir_on[menudepthleft] = 0; - - if (addonsp[0]) // never going to have some provided but not all, saves individually checking - { - size_t i; - for (i = 0; i < NUM_EXT+5; i++) - W_UnlockCachedPatch(addonsp[i]); - } - - addonsp[EXT_FOLDER] = W_CachePatchName("M_FFLDR", PU_STATIC); - addonsp[EXT_UP] = W_CachePatchName("M_FBACK", PU_STATIC); - addonsp[EXT_NORESULTS] = W_CachePatchName("M_FNOPE", PU_STATIC); - addonsp[EXT_TXT] = W_CachePatchName("M_FTXT", PU_STATIC); - addonsp[EXT_CFG] = W_CachePatchName("M_FCFG", PU_STATIC); - addonsp[EXT_WAD] = W_CachePatchName("M_FWAD", PU_STATIC); -#ifdef USE_KART - addonsp[EXT_KART] = W_CachePatchName("M_FKART", PU_STATIC); -#endif - addonsp[EXT_PK3] = W_CachePatchName("M_FPK3", PU_STATIC); - addonsp[EXT_SOC] = W_CachePatchName("M_FSOC", PU_STATIC); - addonsp[EXT_LUA] = W_CachePatchName("M_FLUA", PU_STATIC); - addonsp[NUM_EXT] = W_CachePatchName("M_FUNKN", PU_STATIC); - addonsp[NUM_EXT+1] = W_CachePatchName("M_FSEL", PU_STATIC); - addonsp[NUM_EXT+2] = W_CachePatchName("M_FLOAD", PU_STATIC); - addonsp[NUM_EXT+3] = W_CachePatchName("M_FSRCH", PU_STATIC); - addonsp[NUM_EXT+4] = W_CachePatchName("M_FSAVE", PU_STATIC); - - MISC_AddonsDef.prevMenu = currentMenu; - M_SetupNextMenu(&MISC_AddonsDef); -} - -#define width 4 -#define vpadding 27 -#define h (BASEVIDHEIGHT-(2*vpadding)) -#define NUMCOLOURS 8 // when toast's coding it's british english hacker fucker -static void M_DrawTemperature(INT32 x, fixed_t t) -{ - INT32 y; - - // bounds check - if (t > FRACUNIT) - t = FRACUNIT; - /*else if (t < 0) -- not needed - t = 0;*/ - - // scale - if (t > 1) - t = (FixedMul(h<>FRACBITS); - - // border - V_DrawFill(x - 1, vpadding, 1, h, 0); - V_DrawFill(x + width, vpadding, 1, h, 0); - V_DrawFill(x - 1, vpadding-1, width+2, 1, 0); - V_DrawFill(x - 1, vpadding+h, width+2, 1, 0); - - // bar itself - y = h; - if (t) - for (t = h - t; y > 0; y--) - { - UINT8 colours[NUMCOLOURS] = {135, 133, 92, 77, 114, 178, 161, 162}; - UINT8 c; - if (y <= t) break; - if (y+vpadding >= BASEVIDHEIGHT/2) - c = 185; - else - c = colours[(NUMCOLOURS*(y-1))/(h/2)]; - V_DrawFill(x, y-1 + vpadding, width, 1, c); - } - - // fill the rest of the backing - if (y) - V_DrawFill(x, vpadding, width, y, 30); -} -#undef width -#undef vpadding -#undef h -#undef NUMCOLOURS - -static char *M_AddonsHeaderPath(void) -{ - UINT32 len; - static char header[1024]; - - strlcpy(header, va("%s folder%s", cv_addons_option.string, menupath+menupathindex[menudepth-1]-1), 1024); - len = strlen(header); - if (len > 34) - { - len = len-34; - header[len] = header[len+1] = header[len+2] = '.'; - } - else - len = 0; - - return header+len; -} - -#define UNEXIST S_StartSound(NULL, sfx_s26d);\ - M_SetupNextMenu(MISC_AddonsDef.prevMenu);\ - M_StartMessage(va("\x82%s\x80\nThis folder no longer exists!\nAborting to main menu.\n\n(Press a key)\n", M_AddonsHeaderPath()),NULL,MM_NOTHING) - -#define CLEARNAME Z_Free(refreshdirname);\ - refreshdirname = NULL - -static boolean prevmajormods = false; - -static void M_AddonsClearName(INT32 choice) -{ - if (!majormods || prevmajormods) - { - CLEARNAME; - } - M_StopMessage(choice); -} - -// returns whether to do message draw -static boolean M_AddonsRefresh(void) -{ - if ((refreshdirmenu & REFRESHDIR_NORMAL) && !preparefilemenu(true, false)) - { - UNEXIST; - if (refreshdirname) - { - CLEARNAME; - } - return true; - } - - if (!majormods && prevmajormods) - prevmajormods = false; - - if ((refreshdirmenu & REFRESHDIR_ADDFILE) || (majormods && !prevmajormods)) - { - char *message = NULL; - - if (refreshdirmenu & REFRESHDIR_NOTLOADED) - { - S_StartSound(NULL, sfx_s26d); - if (refreshdirmenu & REFRESHDIR_MAX) - message = va("%c%s\x80\nMaximum number of addons reached.\nA file could not be loaded.\nIf you wish to play with this addon, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); - else - message = va("%c%s\x80\nA file was not loaded.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); - } - else if (refreshdirmenu & (REFRESHDIR_WARNING|REFRESHDIR_ERROR)) - { - S_StartSound(NULL, sfx_s224); - message = va("%c%s\x80\nA file was loaded with %s.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings")); - } - else if (majormods && !prevmajormods) - { - S_StartSound(NULL, sfx_s221); - message = va("%c%s\x80\nGameplay has now been modified.\nIf you wish to play Record Attack mode, restart the game to clear existing addons.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); - prevmajormods = majormods; - } - - if (message) - { - M_StartMessage(message,M_AddonsClearName,MM_EVENTHANDLER); - return true; - } - - S_StartSound(NULL, sfx_s221); - CLEARNAME; - } - - return false; -} - -static void M_DrawAddons(void) -{ - INT32 x, y; - ssize_t i, m; - const UINT8 *flashcol = NULL; - UINT8 hilicol; - - // hack - need to refresh at end of frame to handle addfile... - if (refreshdirmenu & M_AddonsRefresh()) - { - M_DrawMessageMenu(); - return; - } - - if (Playing()) - V_DrawCenteredString(BASEVIDWIDTH/2, 5, warningflags, "Adding files mid-game may cause problems."); - else - V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)); - - if (numwadfiles <= mainwads+1) - y = 0; - else if (numwadfiles >= MAX_WADFILES) - y = FRACUNIT; - else - { - y = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))< FRACUNIT) // happens because of how we're shrinkin' it a little - y = FRACUNIT; - } - - M_DrawTemperature(BASEVIDWIDTH - 19 - 5, y); - - // DRAW MENU - x = currentMenu->x; - y = currentMenu->y + 1; - - hilicol = V_GetStringColormap(highlightflags)[0]; - - V_DrawString(x-21, (y - 16) + (lsheadingheight - 12), highlightflags|V_ALLOWLOWERCASE, M_AddonsHeaderPath()); - V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), MAXSTRINGLENGTH*8+6, 1, hilicol); - V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), MAXSTRINGLENGTH*8+6, 1, 30); - - m = (BASEVIDHEIGHT - currentMenu->y + 2) - (y - 1); - V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, m, 159); - - // scrollbar! - if (sizedirmenu <= (2*numaddonsshown + 1)) - i = 0; - else - { - ssize_t q = m; - m = ((2*numaddonsshown + 1) * m)/sizedirmenu; - if (dir_on[menudepthleft] <= numaddonsshown) // all the way up - i = 0; - else if (sizedirmenu <= (dir_on[menudepthleft] + numaddonsshown + 1)) // all the way down - i = q-m; - else - i = ((dir_on[menudepthleft] - numaddonsshown) * (q-m))/(sizedirmenu - (2*numaddonsshown + 1)); - } - - V_DrawFill(x + MAXSTRINGLENGTH*8+5 - 21, (y - 1) + i, 1, m, hilicol); - - // get bottom... - m = dir_on[menudepthleft] + numaddonsshown + 1; - if (m > (ssize_t)sizedirmenu) - m = sizedirmenu; - - // then compute top and adjust bottom if needed! - if (m < (2*numaddonsshown + 1)) - { - m = min(sizedirmenu, 2*numaddonsshown + 1); - i = 0; - } - else - i = m - (2*numaddonsshown + 1); - - if (i != 0) - V_DrawString(19, y+4 - (skullAnimCounter/5), highlightflags, "\x1A"); - - if (skullAnimCounter < 4) - flashcol = V_GetStringColormap(highlightflags); - - for (; i < m; i++) - { - UINT32 flags = V_ALLOWLOWERCASE; - if (y > BASEVIDHEIGHT) break; - if (dirmenu[i]) -#define type (UINT8)(dirmenu[i][DIR_TYPE]) - { - if (type & EXT_LOADED) - { - flags |= V_TRANSLUCENT; - V_DrawSmallScaledPatch(x-(16+4), y, V_TRANSLUCENT, addonsp[(type & ~EXT_LOADED)]); - V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[NUM_EXT+2]); - } - else - V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[(type & ~EXT_LOADED)]); - - if ((size_t)i == dir_on[menudepthleft]) - { - V_DrawFixedPatch((x-(16+4))< (charsonside*2 + 3)) - V_DrawString(x, y+4, flags, va("%.*s...%s", charsonside, dirmenu[i]+DIR_STRING, dirmenu[i]+DIR_STRING+dirmenu[i][DIR_LEN]-(charsonside+1))); -#undef charsonside - else - V_DrawString(x, y+4, flags, dirmenu[i]+DIR_STRING); - } -#undef type - y += 16; - } - - if (m != (ssize_t)sizedirmenu) - V_DrawString(19, y-12 + (skullAnimCounter/5), highlightflags, "\x1B"); - - y = BASEVIDHEIGHT - currentMenu->y + 1; - - M_DrawTextBox(x - (21 + 5), y, MAXSTRINGLENGTH, 1); - if (menusearch[0]) - V_DrawString(x - 18, y + 8, V_ALLOWLOWERCASE, menusearch+1); - else - V_DrawString(x - 18, y + 8, V_ALLOWLOWERCASE|V_TRANSLUCENT, "Type to search..."); - if (skullAnimCounter < 4) - V_DrawCharacter(x - 18 + V_StringWidth(menusearch+1, 0), y + 8, - '_' | 0x80, false); - - x -= (21 + 5 + 16); - V_DrawSmallScaledPatch(x, y + 4, (menusearch[0] ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+3]); - - x = BASEVIDWIDTH - x - 16; - V_DrawSmallScaledPatch(x, y + 4, ((!majormods) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]); - - if (modifiedgame) - V_DrawSmallScaledPatch(x, y + 4, 0, addonsp[NUM_EXT+2]); -} - -static void M_AddonExec(INT32 ch) -{ - if (ch != 'y' && ch != KEY_ENTER) - return; - - S_StartSound(NULL, sfx_zoom); - COM_BufAddText(va("exec \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); -} - -#define len menusearch[0] -static boolean M_ChangeStringAddons(INT32 choice) -{ - if (shiftdown && choice >= 32 && choice <= 127) - choice = shiftxform[choice]; - - switch (choice) - { - case KEY_DEL: - if (len) - { - len = menusearch[1] = 0; - return true; - } - break; - case KEY_BACKSPACE: - if (len) - { - menusearch[1+--len] = 0; - return true; - } - break; - default: - if (choice >= 32 && choice <= 127) - { - if (len < MAXSTRINGLENGTH - 1) - { - menusearch[1+len++] = (char)choice; - menusearch[1+len] = 0; - return true; - } - } - break; - } - return false; -} -#undef len - -static void M_HandleAddons(INT32 choice) -{ - boolean exitmenu = false; // exit to previous menu - - if (M_ChangeStringAddons(choice)) - { - char *tempname = NULL; - if (dirmenu && dirmenu[dir_on[menudepthleft]]) - tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL -#if 0 // much slower - if (!preparefilemenu(true, false)) - { - UNEXIST; - return; - } -#else // streamlined - searchfilemenu(tempname); -#endif - } - - switch (choice) - { - case KEY_DOWNARROW: - if (dir_on[menudepthleft] < sizedirmenu-1) - dir_on[menudepthleft]++; - S_StartSound(NULL, sfx_menu1); - break; - case KEY_UPARROW: - if (dir_on[menudepthleft]) - dir_on[menudepthleft]--; - S_StartSound(NULL, sfx_menu1); - break; - case KEY_PGDN: - { - UINT8 i; - for (i = numaddonsshown; i && (dir_on[menudepthleft] < sizedirmenu-1); i--) - dir_on[menudepthleft]++; - } - S_StartSound(NULL, sfx_menu1); - break; - case KEY_PGUP: - { - UINT8 i; - for (i = numaddonsshown; i && (dir_on[menudepthleft]); i--) - dir_on[menudepthleft]--; - } - S_StartSound(NULL, sfx_menu1); - break; - case KEY_ENTER: - { - boolean refresh = true; - if (!dirmenu[dir_on[menudepthleft]]) - S_StartSound(NULL, sfx_s26d); - else - { - switch (dirmenu[dir_on[menudepthleft]][DIR_TYPE]) - { - case EXT_FOLDER: - strcpy(&menupath[menupathindex[menudepthleft]],dirmenu[dir_on[menudepthleft]]+DIR_STRING); - if (menudepthleft) - { - menupathindex[--menudepthleft] = strlen(menupath); - menupath[menupathindex[menudepthleft]] = 0; - - if (!preparefilemenu(false, false)) - { - S_StartSound(NULL, sfx_s224); - M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); - menupath[menupathindex[++menudepthleft]] = 0; - - if (!preparefilemenu(true, false)) - { - UNEXIST; - return; - } - } - else - { - S_StartSound(NULL, sfx_menu1); - dir_on[menudepthleft] = 1; - } - refresh = false; - } - else - { - S_StartSound(NULL, sfx_s26d); - M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); - menupath[menupathindex[menudepthleft]] = 0; - } - break; - case EXT_UP: - S_StartSound(NULL, sfx_menu1); - menupath[menupathindex[++menudepthleft]] = 0; - if (!preparefilemenu(false, false)) - { - UNEXIST; - return; - } - break; - case EXT_TXT: - M_StartMessage(va("%c%s\x80\nThis file may not be a console script.\nAttempt to run anyways? \n\n(Press 'Y' to confirm)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),M_AddonExec,MM_YESNO); - break; - case EXT_CFG: - M_AddonExec(KEY_ENTER); - break; - case EXT_LUA: -#ifndef HAVE_BLUA - S_StartSound(NULL, sfx_s26d); - M_StartMessage(va("%c%s\x80\nThis version of SRB2Kart does not\nhave support for .lua files.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),NULL,MM_NOTHING); - break; -#endif - // else intentional fallthrough - case EXT_SOC: - case EXT_WAD: -#ifdef USE_KART - case EXT_KART: -#endif - case EXT_PK3: - COM_BufAddText(va("addfile \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); - break; - default: - S_StartSound(NULL, sfx_s26d); - } - } - if (refresh) - refreshdirmenu |= REFRESHDIR_NORMAL; - } - break; - - case KEY_ESCAPE: - exitmenu = true; - break; - - default: - break; - } - if (exitmenu) - { - closefilemenu(true); - - // Secret menu! - //MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); - - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} - -// ---- REPLAY HUT ----- -menudemo_t *demolist; - -#define DF_ENCORE 0x40 -static INT16 replayScrollTitle = 0; -static SINT8 replayScrollDelay = TICRATE, replayScrollDir = 1; - -static void PrepReplayList(void) -{ - size_t i; - - if (demolist) - Z_Free(demolist); - - demolist = Z_Calloc(sizeof(menudemo_t) * sizedirmenu, PU_STATIC, NULL); - - for (i = 0; i < sizedirmenu; i++) - { - if (dirmenu[i][DIR_TYPE] == EXT_UP) - { - demolist[i].type = MD_SUBDIR; - sprintf(demolist[i].title, "UP"); - } - else if (dirmenu[i][DIR_TYPE] == EXT_FOLDER) - { - demolist[i].type = MD_SUBDIR; - strncpy(demolist[i].title, dirmenu[i] + DIR_STRING, 64); - } - else - { - demolist[i].type = MD_NOTLOADED; - snprintf(demolist[i].filepath, 255, "%s%s", menupath, dirmenu[i] + DIR_STRING); - sprintf(demolist[i].title, "....."); - } - } -} - -void M_ReplayHut(INT32 choice) -{ - (void)choice; - - if (!demo.inreplayhut) - { - snprintf(menupath, 1024, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home); - menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath); - } - if (!preparefilemenu(false, true)) - { - M_StartMessage("No replays found.\n\n(Press a key)\n", NULL, MM_NOTHING); - return; - } - else if (!demo.inreplayhut) - dir_on[menudepthleft] = 0; - demo.inreplayhut = true; - - replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; - - PrepReplayList(); - - menuactive = true; - M_SetupNextMenu(&MISC_ReplayHutDef); - G_SetGamestate(GS_TIMEATTACK); - - demo.rewinding = false; - CL_ClearRewinds(); - - S_ChangeMusicInternal("replst", true); -} - -static void M_HandleReplayHutList(INT32 choice) -{ - switch (choice) - { - case KEY_UPARROW: - if (dir_on[menudepthleft]) - dir_on[menudepthleft]--; - else - return; - //M_PrevOpt(); - - S_StartSound(NULL, sfx_menu1); - replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; - break; - - case KEY_DOWNARROW: - if (dir_on[menudepthleft] < sizedirmenu-1) - dir_on[menudepthleft]++; - else - return; - //itemOn = 0; // Not M_NextOpt because that would take us to the extra dummy item - - S_StartSound(NULL, sfx_menu1); - replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; - break; - - case KEY_ESCAPE: - M_QuitReplayHut(); - break; - - case KEY_ENTER: - switch (dirmenu[dir_on[menudepthleft]][DIR_TYPE]) - { - case EXT_FOLDER: - strcpy(&menupath[menupathindex[menudepthleft]],dirmenu[dir_on[menudepthleft]]+DIR_STRING); - if (menudepthleft) - { - menupathindex[--menudepthleft] = strlen(menupath); - menupath[menupathindex[menudepthleft]] = 0; - - if (!preparefilemenu(false, true)) - { - S_StartSound(NULL, sfx_s224); - M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); - menupath[menupathindex[++menudepthleft]] = 0; - - if (!preparefilemenu(true, true)) - { - M_QuitReplayHut(); - return; - } - } - else - { - S_StartSound(NULL, sfx_menu1); - dir_on[menudepthleft] = 1; - PrepReplayList(); - } - } - else - { - S_StartSound(NULL, sfx_s26d); - M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); - menupath[menupathindex[menudepthleft]] = 0; - } - break; - case EXT_UP: - S_StartSound(NULL, sfx_menu1); - menupath[menupathindex[++menudepthleft]] = 0; - if (!preparefilemenu(false, true)) - { - M_QuitReplayHut(); - return; - } - PrepReplayList(); - break; - default: - // We can't just use M_SetupNextMenu because that'll run ReplayDef's quitroutine and boot us back to the title screen! - currentMenu->lastOn = itemOn; - currentMenu = &MISC_ReplayStartDef; - - replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; - - switch (demolist[dir_on[menudepthleft]].addonstatus) - { - case DFILE_ERROR_CANNOTLOAD: - // Only show "Watch Replay Without Addons" - MISC_ReplayStartMenu[0].status = IT_DISABLED; - MISC_ReplayStartMenu[1].status = IT_CALL|IT_STRING; - //MISC_ReplayStartMenu[1].alphaKey = 0; - MISC_ReplayStartMenu[2].status = IT_DISABLED; - itemOn = 1; - break; - - case DFILE_ERROR_NOTLOADED: - case DFILE_ERROR_INCOMPLETEOUTOFORDER: - // Show "Load Addons and Watch Replay" and "Watch Replay Without Addons" - MISC_ReplayStartMenu[0].status = IT_CALL|IT_STRING; - MISC_ReplayStartMenu[1].status = IT_CALL|IT_STRING; - //MISC_ReplayStartMenu[1].alphaKey = 10; - MISC_ReplayStartMenu[2].status = IT_DISABLED; - itemOn = 0; - break; - - case DFILE_ERROR_EXTRAFILES: - case DFILE_ERROR_OUTOFORDER: - default: - // Show "Watch Replay" - MISC_ReplayStartMenu[0].status = IT_DISABLED; - MISC_ReplayStartMenu[1].status = IT_DISABLED; - MISC_ReplayStartMenu[2].status = IT_CALL|IT_STRING; - //MISC_ReplayStartMenu[2].alphaKey = 0; - itemOn = 2; - break; - } - } - - break; - } -} - -#define SCALEDVIEWWIDTH (vid.width/vid.dupx) -#define SCALEDVIEWHEIGHT (vid.height/vid.dupy) -static void DrawReplayHutReplayInfo(void) -{ - lumpnum_t lumpnum; - patch_t *patch; - UINT8 *colormap; - INT32 x, y, w, h; - - switch (demolist[dir_on[menudepthleft]].type) - { - case MD_NOTLOADED: - V_DrawCenteredString(160, 40, V_SNAPTOTOP, "Loading replay information..."); - break; - - case MD_INVALID: - V_DrawCenteredString(160, 40, V_SNAPTOTOP|warningflags, "This replay cannot be played."); - break; - - case MD_SUBDIR: - break; // Can't think of anything to draw here right now - - case MD_OUTDATED: - V_DrawThinString(17, 64, V_SNAPTOTOP|V_ALLOWLOWERCASE|V_TRANSLUCENT|highlightflags, "Recorded on an outdated version."); - /*fallthru*/ - default: - // Draw level stuff - x = 15; y = 15; - - // A 160x100 image of the level as entry MAPxxP - //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(demolist[dir_on[menudepthleft]].map))); - if (lumpnum != LUMPERROR) - patch = W_CachePatchNum(lumpnum, PU_CACHE); - else - patch = W_CachePatchName("M_NOLVL", PU_CACHE); - - if (!(demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) - V_DrawSmallScaledPatch(x, y, V_SNAPTOTOP, patch); - else - { - w = SHORT(patch->width); - h = SHORT(patch->height); - V_DrawSmallScaledPatch(x+(w>>1), y, V_SNAPTOTOP|V_FLIP, patch); - - { - static angle_t rubyfloattime = 0; - const fixed_t rubyheight = FINESINE(rubyfloattime>>ANGLETOFINESHIFT); - V_DrawFixedPatch((x+(w>>2))<>2))<width), y+20, V_SNAPTOTOP, patch, colormap); - - break; - } -} - -static void M_DrawReplayHut(void) -{ - INT32 x, y, cursory = 0; - INT16 i; - INT16 replaylistitem = currentMenu->numitems-2; - boolean processed_one_this_frame = false; - - static UINT16 replayhutmenuy = 0; - - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - - if (cv_vhseffect.value) - V_DrawVhsEffect(false); - - // Draw menu choices - x = currentMenu->x; - y = currentMenu->y; - - if (itemOn > replaylistitem) - { - itemOn = replaylistitem; - dir_on[menudepthleft] = sizedirmenu-1; - replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; - } - else if (itemOn < replaylistitem) - { - dir_on[menudepthleft] = 0; - replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; - } - - if (itemOn == replaylistitem) - { - INT32 maxy; - // Scroll menu items if needed - cursory = y + currentMenu->menuitems[replaylistitem].alphaKey + dir_on[menudepthleft]*10; - maxy = y + currentMenu->menuitems[replaylistitem].alphaKey + sizedirmenu*10; - - if (cursory > maxy - 20) - cursory = maxy - 20; - - if (cursory - replayhutmenuy > SCALEDVIEWHEIGHT-50) - replayhutmenuy += (cursory-SCALEDVIEWHEIGHT-replayhutmenuy + 51)/2; - else if (cursory - replayhutmenuy < 110) - replayhutmenuy += (max(0, cursory-110)-replayhutmenuy - 1)/2; - } - else - replayhutmenuy /= 2; - - y -= replayhutmenuy; - - // Draw static menu items - for (i = 0; i < replaylistitem; i++) - { - INT32 localy = y + currentMenu->menuitems[i].alphaKey; - - if (localy < 65) - continue; - - if (i == itemOn) - cursory = localy; - - if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) - V_DrawString(x, localy, V_SNAPTOTOP|V_SNAPTOLEFT, currentMenu->menuitems[i].text); - else - V_DrawString(x, localy, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags, currentMenu->menuitems[i].text); - } - - y += currentMenu->menuitems[replaylistitem].alphaKey; - - for (i = 0; i < (INT16)sizedirmenu; i++) - { - INT32 localy = y+i*10; - INT32 localx = x; - - if (localy < 65) - continue; - if (localy >= SCALEDVIEWHEIGHT) - break; - - if (demolist[i].type == MD_NOTLOADED && !processed_one_this_frame) - { - processed_one_this_frame = true; - G_LoadDemoInfo(&demolist[i]); - } - - if (demolist[i].type == MD_SUBDIR) - { - localx += 8; - V_DrawScaledPatch(x - 4, localy, V_SNAPTOTOP|V_SNAPTOLEFT, W_CachePatchName(dirmenu[i][DIR_TYPE] == EXT_UP ? "M_RBACK" : "M_RFLDR", PU_CACHE)); - } - - if (itemOn == replaylistitem && i == (INT16)dir_on[menudepthleft]) - { - cursory = localy; - - if (replayScrollDelay) - replayScrollDelay--; - else if (replayScrollDir > 0) - { - if (replayScrollTitle < (V_StringWidth(demolist[i].title, 0) - (SCALEDVIEWWIDTH - (x<<1)))<<1) - replayScrollTitle++; - else - { - replayScrollDelay = TICRATE; - replayScrollDir = -1; - } - } - else - { - if (replayScrollTitle > 0) - replayScrollTitle--; - else - { - replayScrollDelay = TICRATE; - replayScrollDir = 1; - } - } - - V_DrawString(localx - (replayScrollTitle>>1), localy, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags|V_ALLOWLOWERCASE, demolist[i].title); - } - else - V_DrawString(localx, localy, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, demolist[i].title); - } - - // Draw scrollbar - y = sizedirmenu*10 + currentMenu->menuitems[replaylistitem].alphaKey + 30; - if (y > SCALEDVIEWHEIGHT-80) - { - V_DrawFill(BASEVIDWIDTH-4, 75, 4, SCALEDVIEWHEIGHT-80, V_SNAPTOTOP|V_SNAPTORIGHT|159); - V_DrawFill(BASEVIDWIDTH-3, 76 + (SCALEDVIEWHEIGHT-80) * replayhutmenuy / y, 2, (((SCALEDVIEWHEIGHT-80) * (SCALEDVIEWHEIGHT-80))-1) / y - 1, V_SNAPTOTOP|V_SNAPTORIGHT|149); - } - - // Draw the cursor - V_DrawScaledPatch(currentMenu->x - 24, cursory, V_SNAPTOTOP|V_SNAPTOLEFT, - W_CachePatchName("M_CURSOR", PU_CACHE)); - V_DrawString(currentMenu->x, cursory, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags, currentMenu->menuitems[itemOn].text); - - // Now draw some replay info! - V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|159); - - if (itemOn == replaylistitem) - { - DrawReplayHutReplayInfo(); - } -} - -static void M_DrawReplayStartMenu(void) -{ - const char *warning; - UINT8 i; - - M_DrawGenericBackgroundMenu(); - -#define STARTY 62-(replayScrollTitle>>1) - // Draw rankings beyond first - for (i = 1; i < MAXPLAYERS && demolist[dir_on[menudepthleft]].standings[i].ranking; i++) - { - patch_t *patch; - UINT8 *colormap; - - V_DrawRightAlignedString(BASEVIDWIDTH-100, STARTY + i*20, V_SNAPTOTOP|highlightflags, va("%2d", demolist[dir_on[menudepthleft]].standings[i].ranking)); - V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20, V_SNAPTOTOP|V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].standings[i].name); - - if (demolist[dir_on[menudepthleft]].standings[i].timeorscore == UINT32_MAX-1) - V_DrawThinString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, "NO CONTEST"); - else if (demolist[dir_on[menudepthleft]].gametype == GT_RACE) - V_DrawRightAlignedString(BASEVIDWIDTH-40, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d'%02d\"%02d", - G_TicsToMinutes(demolist[dir_on[menudepthleft]].standings[i].timeorscore, true), - G_TicsToSeconds(demolist[dir_on[menudepthleft]].standings[i].timeorscore), - G_TicsToCentiseconds(demolist[dir_on[menudepthleft]].standings[i].timeorscore) - )); - else - V_DrawString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d", demolist[dir_on[menudepthleft]].standings[i].timeorscore)); - - // Character face! - if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[i].skin].facerank) != LUMPERROR) - { - patch = facerankprefix[demolist[dir_on[menudepthleft]].standings[i].skin]; - colormap = R_GetTranslationColormap( - demolist[dir_on[menudepthleft]].standings[i].skin, - demolist[dir_on[menudepthleft]].standings[i].color, - GTC_MENUCACHE); - } - else - { - patch = W_CachePatchName("M_NORANK", PU_CACHE); - colormap = R_GetTranslationColormap( - TC_RAINBOW, - demolist[dir_on[menudepthleft]].standings[i].color, - GTC_MENUCACHE); - } - - V_DrawMappedPatch(BASEVIDWIDTH-5 - SHORT(patch->width), STARTY + i*20, V_SNAPTOTOP, patch, colormap); - } -#undef STARTY - - // Handle scrolling rankings - if (replayScrollDelay) - replayScrollDelay--; - else if (replayScrollDir > 0) - { - if (replayScrollTitle < (i*20 - SCALEDVIEWHEIGHT + 100)<<1) - replayScrollTitle++; - else - { - replayScrollDelay = TICRATE; - replayScrollDir = -1; - } - } - else - { - if (replayScrollTitle > 0) - replayScrollTitle--; - else - { - replayScrollDelay = TICRATE; - replayScrollDir = 1; - } - } - - V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|159); - DrawReplayHutReplayInfo(); - - V_DrawString(10, 72, V_SNAPTOTOP|highlightflags|V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].title); - - // Draw a warning prompt if needed - switch (demolist[dir_on[menudepthleft]].addonstatus) - { - case DFILE_ERROR_CANNOTLOAD: - warning = "Some addons in this replay cannot be loaded.\nYou can watch anyway, but desyncs may occur."; - break; - - case DFILE_ERROR_NOTLOADED: - case DFILE_ERROR_INCOMPLETEOUTOFORDER: - warning = "Loading addons will mark your game as modified, and Record Attack may be unavailable.\nYou can watch without loading addons, but desyncs may occur."; - break; - - case DFILE_ERROR_EXTRAFILES: - warning = "You have addons loaded that were not present in this replay.\nYou can watch anyway, but desyncs may occur."; - break; - - case DFILE_ERROR_OUTOFORDER: - warning = "You have this replay's addons loaded, but they are out of order.\nYou can watch anyway, but desyncs may occur."; - break; - - default: - return; - } - - V_DrawSmallString(4, BASEVIDHEIGHT-14, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, warning); -} - -static boolean M_QuitReplayHut(void) -{ - // D_StartTitle does its own wipe, since GS_TIMEATTACK is now a complete gamestate. - menuactive = false; - D_StartTitle(); - - if (demolist) - Z_Free(demolist); - demolist = NULL; - - demo.inreplayhut = false; - - return true; -} - -static void M_HutStartReplay(INT32 choice) -{ - (void)choice; - - M_ClearMenus(false); - demo.loadfiles = (itemOn == 0); - demo.ignorefiles = (itemOn != 0); - - G_DoPlayDemo(demolist[dir_on[menudepthleft]].filepath); -} - -void M_SetPlaybackMenuPointer(void) -{ - itemOn = playback_pause; -} - -static void M_DrawPlaybackMenu(void) -{ - INT16 i; - patch_t *icon; - UINT8 *activemap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GOLD, GTC_MENUCACHE); - UINT32 transmap = max(0, (INT32)(leveltime - playback_last_menu_interaction_leveltime - 4*TICRATE)) / 5; - transmap = min(8, transmap) << V_ALPHASHIFT; - - if (leveltime - playback_last_menu_interaction_leveltime >= 6*TICRATE) - playback_last_menu_interaction_leveltime = leveltime - 6*TICRATE; - - // Toggle items - if (paused && !demo.rewinding) - { - PlaybackMenu[playback_pause].status = PlaybackMenu[playback_fastforward].status = PlaybackMenu[playback_rewind].status = IT_DISABLED; - PlaybackMenu[playback_resume].status = PlaybackMenu[playback_advanceframe].status = PlaybackMenu[playback_backframe].status = IT_CALL|IT_STRING; - - if (itemOn >= playback_rewind && itemOn <= playback_fastforward) - itemOn += playback_backframe - playback_rewind; - } - else - { - PlaybackMenu[playback_pause].status = PlaybackMenu[playback_fastforward].status = PlaybackMenu[playback_rewind].status = IT_CALL|IT_STRING; - PlaybackMenu[playback_resume].status = PlaybackMenu[playback_advanceframe].status = PlaybackMenu[playback_backframe].status = IT_DISABLED; - - if (itemOn >= playback_backframe && itemOn <= playback_advanceframe) - itemOn -= playback_backframe - playback_rewind; - } - - if (modeattacking) - { - for (i = playback_viewcount; i <= playback_view4; i++) - PlaybackMenu[i].status = IT_DISABLED; - PlaybackMenu[playback_freecamera].alphaKey = 72; - PlaybackMenu[playback_quit].alphaKey = 88; - - currentMenu->x = BASEVIDWIDTH/2 - 52; - } - else - { - PlaybackMenu[playback_viewcount].status = IT_ARROWS|IT_STRING; - - for (i = 0; i <= r_splitscreen; i++) - PlaybackMenu[playback_view1+i].status = IT_ARROWS|IT_STRING; - for (i = r_splitscreen+1; i < 4; i++) - PlaybackMenu[playback_view1+i].status = IT_DISABLED; - - PlaybackMenu[playback_freecamera].alphaKey = 156; - PlaybackMenu[playback_quit].alphaKey = 172; - currentMenu->x = BASEVIDWIDTH/2 - 88; - } - - // wip - //M_DrawTextBox(currentMenu->x-68, currentMenu->y-7, 15, 15); - //M_DrawCenteredMenu(); - - for (i = 0; i < currentMenu->numitems; i++) - { - UINT8 *inactivemap = NULL; - - if (i >= playback_view1 && i <= playback_view4) - { - if (modeattacking) continue; - - if (r_splitscreen >= i - playback_view1) - { - INT32 ply = displayplayers[i - playback_view1]; - - icon = facerankprefix[players[ply].skin]; - if (i != itemOn) - inactivemap = R_GetTranslationColormap(players[ply].skin, players[ply].skincolor, GTC_MENUCACHE); - } - else if (currentMenu->menuitems[i].patch && W_CheckNumForName(currentMenu->menuitems[i].patch) != LUMPERROR) - icon = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); - else - icon = W_CachePatchName("PLAYRANK", PU_CACHE); // temp - } - else if (currentMenu->menuitems[i].status == IT_DISABLED) - continue; - else if (currentMenu->menuitems[i].patch && W_CheckNumForName(currentMenu->menuitems[i].patch) != LUMPERROR) - icon = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); - else - icon = W_CachePatchName("PLAYRANK", PU_CACHE); // temp - - if ((i == playback_fastforward && cv_playbackspeed.value > 1) || (i == playback_rewind && demo.rewinding)) - V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, transmap|V_SNAPTOTOP, icon, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JAWZ, GTC_MENUCACHE)); - else - V_DrawMappedPatch(currentMenu->x + currentMenu->menuitems[i].alphaKey, currentMenu->y, transmap|V_SNAPTOTOP, icon, (i == itemOn) ? activemap : inactivemap); - - if (i == itemOn) - { - V_DrawCharacter(currentMenu->x + currentMenu->menuitems[i].alphaKey + 4, currentMenu->y + 14, - '\x1A' | transmap|V_SNAPTOTOP|highlightflags, false); - - V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 18, transmap|V_SNAPTOTOP|V_ALLOWLOWERCASE, currentMenu->menuitems[i].text); - - if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_ARROWS) - { - char *str; - - if (!(i == playback_viewcount && r_splitscreen == 3)) - V_DrawCharacter(BASEVIDWIDTH/2 - 4, currentMenu->y + 28 - (skullAnimCounter/5), - '\x1A' | transmap|V_SNAPTOTOP|highlightflags, false); // up arrow - - if (!(i == playback_viewcount && r_splitscreen == 0)) - V_DrawCharacter(BASEVIDWIDTH/2 - 4, currentMenu->y + 48 + (skullAnimCounter/5), - '\x1B' | transmap|V_SNAPTOTOP|highlightflags, false); // down arrow - - switch (i) - { - case playback_viewcount: - str = va("%d", r_splitscreen+1); - break; - - case playback_view1: - case playback_view2: - case playback_view3: - case playback_view4: - str = player_names[displayplayers[i - playback_view1]]; // 0 to 3 - break; - - default: // shouldn't ever be reached but whatever - continue; - } - - V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 38, transmap|V_SNAPTOTOP|V_ALLOWLOWERCASE|highlightflags, str); - } - } - } -} - -static void M_PlaybackRewind(INT32 choice) -{ - static tic_t lastconfirmtime; - - (void)choice; - - if (!demo.rewinding) - { - if (paused) - { - G_ConfirmRewind(leveltime-1); - paused = true; - S_PauseAudio(); - } - else - demo.rewinding = paused = true; - } - else if (lastconfirmtime + TICRATE/2 < I_GetTime()) - { - lastconfirmtime = I_GetTime(); - G_ConfirmRewind(leveltime); - } - - CV_SetValue(&cv_playbackspeed, 1); -} - -static void M_PlaybackPause(INT32 choice) -{ - (void)choice; - - paused = !paused; - - if (demo.rewinding) - { - G_ConfirmRewind(leveltime); - paused = true; - S_PauseAudio(); - } - else if (paused) - S_PauseAudio(); - else - S_ResumeAudio(); - - CV_SetValue(&cv_playbackspeed, 1); -} - -static void M_PlaybackFastForward(INT32 choice) -{ - (void)choice; - - if (demo.rewinding) - { - G_ConfirmRewind(leveltime); - paused = false; - S_ResumeAudio(); - } - CV_SetValue(&cv_playbackspeed, cv_playbackspeed.value == 1 ? 4 : 1); -} - -static void M_PlaybackAdvance(INT32 choice) -{ - (void)choice; - - paused = false; - TryRunTics(1); - paused = true; -} - - -static void M_PlaybackSetViews(INT32 choice) -{ - - if (demo.freecam) - return; // not here. - - if (choice > 0) - { - if (r_splitscreen < 3) - G_AdjustView(r_splitscreen + 2, 0, true); - } - else if (r_splitscreen) - { - r_splitscreen--; - R_ExecuteSetViewSize(); - } -} - -static void M_PlaybackAdjustView(INT32 choice) -{ - G_AdjustView(itemOn - playback_viewcount, (choice > 0) ? 1 : -1, true); -} - -// this one's rather tricky -static void M_PlaybackToggleFreecam(INT32 choice) -{ - (void)choice; - M_ClearMenus(true); - - // remove splitscreen: - splitscreen = 0; - R_ExecuteSetViewSize(); - - P_InitCameraCmd(); // init camera controls - if (!demo.freecam) // toggle on - { - demo.freecam = true; - democam.cam = &camera[0]; // this is rather useful - } - else // toggle off - { - demo.freecam = false; - // reset democam vars: - democam.cam = NULL; - democam.turnheld = false; - democam.keyboardlook = false; // reset only these. localangle / aiming gets set before the cam does anything anyway - } -} - - -static void M_PlaybackQuit(INT32 choice) -{ - (void)choice; - G_StopDemo(); - - if (demo.inreplayhut) - M_ReplayHut(choice); - else if (modeattacking) - { - M_EndModeAttackRun(); - S_ChangeMusicInternal("racent", true); - } - else - D_StartTitle(); -} - -static void M_PandorasBox(INT32 choice) -{ - (void)choice; - CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].health - 1, 0)); - CV_StealthSetValue(&cv_dummylives, players[consoleplayer].lives); - CV_StealthSetValue(&cv_dummycontinues, players[consoleplayer].continues); - M_SetupNextMenu(&SR_PandoraDef); -} - -static boolean M_ExitPandorasBox(void) -{ - if (cv_dummyrings.value != max(players[consoleplayer].health - 1, 0)) - COM_ImmedExecute(va("setrings %d", cv_dummyrings.value)); - if (cv_dummylives.value != players[consoleplayer].lives) - COM_ImmedExecute(va("setlives %d", cv_dummylives.value)); - if (cv_dummycontinues.value != players[consoleplayer].continues) - COM_ImmedExecute(va("setcontinues %d", cv_dummycontinues.value)); - return true; -} - -static void M_ChangeLevel(INT32 choice) -{ - char mapname[6]; - (void)choice; - - strlcpy(mapname, G_BuildMapName(cv_nextmap.value), sizeof (mapname)); - strlwr(mapname); - mapname[5] = '\0'; - - M_ClearMenus(true); - COM_BufAddText(va("map %s -gametype \"%s\"\n", mapname, cv_newgametype.string)); -} - -static void M_ConfirmSpectate(INT32 choice) -{ - (void)choice; - // We allow switching to spectator even if team changing is not allowed - M_ClearMenus(true); - COM_ImmedExecute("changeteam spectator"); -} - -static void M_ConfirmEnterGame(INT32 choice) -{ - (void)choice; - if (!cv_allowteamchange.value) - { - M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); - return; - } - M_ClearMenus(true); - COM_ImmedExecute("changeteam playing"); -} - -static void M_ConfirmTeamScramble(INT32 choice) -{ - (void)choice; - M_ClearMenus(true); - - COM_ImmedExecute(va("teamscramble %d", cv_dummyscramble.value+1)); -} - -static void M_ConfirmTeamChange(INT32 choice) -{ - (void)choice; - - if (cv_dummymenuplayer.value > splitscreen+1) - return; - - if (!cv_allowteamchange.value && cv_dummyteam.value) - { - M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); - return; - } - - M_ClearMenus(true); - - switch (cv_dummymenuplayer.value) - { - case 1: - default: - COM_ImmedExecute(va("changeteam %s", cv_dummyteam.string)); - break; - case 2: - COM_ImmedExecute(va("changeteam2 %s", cv_dummyteam.string)); - break; - case 3: - COM_ImmedExecute(va("changeteam3 %s", cv_dummyteam.string)); - break; - case 4: - COM_ImmedExecute(va("changeteam4 %s", cv_dummyteam.string)); - break; - } -} - -static void M_ConfirmSpectateChange(INT32 choice) -{ - (void)choice; - - if (cv_dummymenuplayer.value > splitscreen+1) - return; - - if (!cv_allowteamchange.value && cv_dummyspectate.value) - { - M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); - return; - } - - M_ClearMenus(true); - - switch (cv_dummymenuplayer.value) - { - case 1: - default: - COM_ImmedExecute(va("changeteam %s", cv_dummyspectate.string)); - break; - case 2: - COM_ImmedExecute(va("changeteam2 %s", cv_dummyspectate.string)); - break; - case 3: - COM_ImmedExecute(va("changeteam3 %s", cv_dummyspectate.string)); - break; - case 4: - COM_ImmedExecute(va("changeteam4 %s", cv_dummyspectate.string)); - break; - } -} - -static void M_Options(INT32 choice) -{ - (void)choice; - - // if the player is not admin or server, disable gameplay & server options - OP_MainMenu[4].status = OP_MainMenu[5].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); - - OP_MainMenu[8].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); // Play credits - OP_DataOptionsMenu[3].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); // Erase data - - OP_GameOptionsMenu[3].status = - (M_SecretUnlocked(SECRET_ENCORE)) ? (IT_CVAR|IT_STRING) : IT_SECRET; // cv_kartencore - - OP_MainDef.prevMenu = currentMenu; - M_SetupNextMenu(&OP_MainDef); -} - -static void M_Manual(INT32 choice) -{ - (void)choice; - - MISC_HelpDef.prevMenu = (choice == INT32_MAX ? NULL : currentMenu); - M_SetupNextMenu(&MISC_HelpDef); -} - -static void M_RetryResponse(INT32 ch) -{ - if (ch != 'y' && ch != KEY_ENTER) - return; - - if (!&players[consoleplayer] || netgame || multiplayer) // Should never happen! - return; - - M_ClearMenus(true); - G_SetRetryFlag(); -} - -static void M_Retry(INT32 choice) -{ - (void)choice; - M_StartMessage(M_GetText("Start this race over?\n\n(Press 'Y' to confirm)\n"),M_RetryResponse,MM_YESNO); -} - -static void M_SelectableClearMenus(INT32 choice) -{ - (void)choice; - M_ClearMenus(true); -} - -// ====== -// CHEATS -// ====== - -static void M_UltimateCheat(INT32 choice) -{ - (void)choice; - I_Quit(); -} - -static void M_GetAllEmeralds(INT32 choice) -{ - (void)choice; - - emeralds = ((EMERALD7)*2)-1; - M_StartMessage(M_GetText("You now have all 7 emeralds.\nUse them wisely.\nWith great power comes great ring drain.\n"),NULL,MM_NOTHING); - - G_SetGameModified(multiplayer, true); -} - -static void M_DestroyRobotsResponse(INT32 ch) -{ - if (ch != 'y' && ch != KEY_ENTER) - return; - - // Destroy all robots - P_DestroyRobots(); - - G_SetGameModified(multiplayer, true); -} - -static void M_DestroyRobots(INT32 choice) -{ - (void)choice; - - M_StartMessage(M_GetText("Do you want to destroy all\nrobots in the current level?\n\n(Press 'Y' to confirm)\n"),M_DestroyRobotsResponse,MM_YESNO); -} - -/*static void M_LevelSelectWarp(INT32 choice) -{ - boolean fromloadgame = (currentMenu == &SP_LevelSelectDef); - - (void)choice; - - if (W_CheckNumForName(G_BuildMapName(cv_nextmap.value)) == LUMPERROR) - { -// CONS_Alert(CONS_WARNING, "Internal game map '%s' not found\n", G_BuildMapName(cv_nextmap.value)); - return; - } - - startmap = (INT16)(cv_nextmap.value); - - fromlevelselect = true; - - if (fromloadgame) - G_LoadGame((UINT32)cursaveslot, startmap); - else - { - cursaveslot = -1; - M_SetupChoosePlayer(0); - } -}*/ - -// ======== -// SKY ROOM -// ======== - -UINT8 skyRoomMenuTranslations[MAXUNLOCKABLES]; - -static char *M_GetConditionString(condition_t cond) -{ - switch(cond.type) - { - case UC_PLAYTIME: - return va("Play for %i:%02i:%02i", - G_TicsToHours(cond.requirement), - G_TicsToMinutes(cond.requirement, false), - G_TicsToSeconds(cond.requirement)); - case UC_MATCHESPLAYED: - return va("Play %d matches", cond.requirement); - case UC_POWERLEVEL: - return va("Reach power level %d in %s", cond.requirement, (cond.extrainfo1 == PWRLV_BATTLE ? "Battle" : "Race")); - case UC_GAMECLEAR: - if (cond.requirement > 1) - return va("Beat game %d times", cond.requirement); - else - return va("Beat the game"); - case UC_ALLEMERALDS: - if (cond.requirement > 1) - return va("Beat game w/ all emeralds %d times", cond.requirement); - else - return va("Beat game w/ all emeralds"); - case UC_OVERALLTIME: - return va("Get overall time of %i:%02i:%02i", - G_TicsToHours(cond.requirement), - G_TicsToMinutes(cond.requirement, false), - G_TicsToSeconds(cond.requirement)); - case UC_MAPVISITED: - return va("Visit %s", G_BuildMapTitle(cond.requirement-1)); - case UC_MAPBEATEN: - return va("Beat %s", G_BuildMapTitle(cond.requirement-1)); - case UC_MAPALLEMERALDS: - return va("Beat %s w/ all emeralds", G_BuildMapTitle(cond.requirement-1)); - case UC_MAPTIME: - return va("Beat %s in %i:%02i.%02i", G_BuildMapTitle(cond.extrainfo1-1), - G_TicsToMinutes(cond.requirement, true), - G_TicsToSeconds(cond.requirement), - G_TicsToCentiseconds(cond.requirement)); - case UC_TOTALEMBLEMS: - return va("Get %d medals", cond.requirement); - case UC_EXTRAEMBLEM: - return va("Get \"%s\" medal", extraemblems[cond.requirement-1].name); - default: - return NULL; - } -} - -#define NUMCHECKLIST 23 -static void M_DrawChecklist(void) -{ - UINT32 i, line = 0, c; - INT32 lastid; - boolean secret = false; - - for (i = 0; i < MAXUNLOCKABLES; i++) - { - const char *secretname; - - secret = (!M_Achieved(unlockables[i].showconditionset - 1) && !unlockables[i].unlocked); - - if (unlockables[i].name[0] == 0 || unlockables[i].nochecklist - || !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS - || (unlockables[i].type == SECRET_HELLATTACK && secret)) // TODO: turn this into an unlockable setting instead of tying it to Hell Attack - continue; - - ++line; - secretname = M_CreateSecretMenuOption(unlockables[i].name); - - V_DrawString(8, (line*8), V_RETURN8|(unlockables[i].unlocked ? recommendedflags : warningflags), (secret ? secretname : unlockables[i].name)); - - if (conditionSets[unlockables[i].conditionset - 1].numconditions) - { - c = 0; - lastid = -1; - - for (c = 0; c < conditionSets[unlockables[i].conditionset - 1].numconditions; c++) - { - condition_t cond = conditionSets[unlockables[i].conditionset - 1].condition[c]; - UINT8 achieved = M_CheckCondition(&cond); - char *str = M_GetConditionString(cond); - const char *secretstr = M_CreateSecretMenuOption(str); - - if (!str) - continue; - - ++line; - - if (lastid == -1 || cond.id != (UINT32)lastid) - { - V_DrawString(16, (line*8), V_MONOSPACE|V_ALLOWLOWERCASE|(achieved ? highlightflags : 0), "*"); - V_DrawString(32, (line*8), V_MONOSPACE|V_ALLOWLOWERCASE|(achieved ? highlightflags : 0), (secret ? secretstr : str)); - } - else - { - V_DrawString(32, (line*8), V_MONOSPACE|V_ALLOWLOWERCASE|(achieved ? highlightflags : 0), (secret ? "?" : "&")); - V_DrawString(48, (line*8), V_MONOSPACE|V_ALLOWLOWERCASE|(achieved ? highlightflags : 0), (secret ? secretstr : str)); - } - - lastid = cond.id; - } - } - - ++line; - - if (line >= NUMCHECKLIST) - break; - } -} -#undef NUMCHECKLIST - -#define NUMHINTS 5 -static void M_EmblemHints(INT32 choice) -{ - (void)choice; - SR_EmblemHintMenu[0].status = (M_SecretUnlocked(SECRET_ITEMFINDER)) ? (IT_CVAR|IT_STRING) : (IT_SECRET); - M_SetupNextMenu(&SR_EmblemHintDef); - itemOn = 1; // always start on back. -} - -static void M_DrawEmblemHints(void) -{ - INT32 i, j = 0; - UINT32 collected = 0; - emblem_t *emblem; - const char *hint; - - for (i = 0; i < numemblems; i++) - { - emblem = &emblemlocations[i]; - if (emblem->level != gamemap || emblem->type > ET_SKIN) - continue; - - if (emblem->collected) - { - collected = recommendedflags; - V_DrawMappedPatch(12, 12+(28*j), 0, W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_MENUCACHE)); - } - else - { - collected = 0; - V_DrawScaledPatch(12, 12+(28*j), 0, W_CachePatchName("NEEDIT", PU_CACHE)); - } - - if (emblem->hint[0]) - hint = emblem->hint; - else - hint = M_GetText("No hints available."); - hint = V_WordWrap(40, BASEVIDWIDTH-12, 0, hint); - V_DrawString(40, 8+(28*j), V_RETURN8|V_ALLOWLOWERCASE|collected, hint); - - if (++j >= NUMHINTS) - break; - } - if (!j) - V_DrawCenteredString(160, 48, highlightflags, "No hidden medals on this map."); - - M_DrawGenericMenu(); -} - -static void M_DrawSkyRoom(void) -{ - INT32 i, y = 0; - INT32 lengthstring = 0; - - M_DrawGenericMenu(); - - if (currentMenu == &OP_SoundOptionsDef) - { - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, - currentMenu->y+currentMenu->menuitems[0].alphaKey, - (sound_disabled ? warningflags : highlightflags), - (sound_disabled ? "OFF" : "ON")); - - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, - currentMenu->y+currentMenu->menuitems[2].alphaKey, - (digital_disabled ? warningflags : highlightflags), - (digital_disabled ? "OFF" : "ON")); - - /*V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, - currentMenu->y+currentMenu->menuitems[5].alphaKey, - (midi_disabled ? warningflags : highlightflags), - (midi_disabled ? "OFF" : "ON"));*/ - - if (itemOn == 0) - lengthstring = 8*(sound_disabled ? 3 : 2); - else if (itemOn == 2) - lengthstring = 8*(digital_disabled ? 3 : 2); - /*else if (itemOn == 5) - lengthstring = 8*(midi_disabled ? 3 : 2);*/ - } - - for (i = 0; i < currentMenu->numitems; ++i) - { - if (currentMenu->menuitems[i].itemaction == M_HandleSoundTest) - { - y = currentMenu->menuitems[i].alphaKey; - break; - } - } - - if (y) - { - y += currentMenu->y; - - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, y, highlightflags, cv_soundtest.string); - if (cv_soundtest.value) - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, y + 8, highlightflags, S_sfx[cv_soundtest.value].name); - - if (i == itemOn) - lengthstring = V_StringWidth(cv_soundtest.string, 0); - } - - if (lengthstring) - { - V_DrawCharacter(BASEVIDWIDTH - currentMenu->x - 10 - lengthstring - (skullAnimCounter/5), currentMenu->y+currentMenu->menuitems[itemOn].alphaKey, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - currentMenu->x + 2 + (skullAnimCounter/5), currentMenu->y+currentMenu->menuitems[itemOn].alphaKey, - '\x1D' | highlightflags, false); // right arrow - } -} - -static void M_HandleSoundTest(INT32 choice) -{ - boolean exitmenu = false; // exit to previous menu - - switch (choice) - { - case KEY_DOWNARROW: - M_NextOpt(); - S_StartSound(NULL, sfx_menu1); - break; - case KEY_UPARROW: - M_PrevOpt(); - S_StartSound(NULL, sfx_menu1); - break; - case KEY_BACKSPACE: - case KEY_ESCAPE: - exitmenu = true; - break; - - case KEY_RIGHTARROW: - CV_AddValue(&cv_soundtest, 1); - break; - case KEY_LEFTARROW: - CV_AddValue(&cv_soundtest, -1); - break; - case KEY_ENTER: - S_StopSounds(); - S_StartSound(NULL, cv_soundtest.value); - break; - - default: - break; - } - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} - -// Entering secrets menu -/*static void M_SecretsMenu(INT32 choice) -{ - INT32 i, j, ul; - UINT8 done[MAXUNLOCKABLES]; - UINT16 curheight; - - (void)choice; - - // Clear all before starting - for (i = 1; i < MAXUNLOCKABLES+1; ++i) - SR_MainMenu[i].status = IT_DISABLED; - - memset(skyRoomMenuTranslations, 0, sizeof(skyRoomMenuTranslations)); - memset(done, 0, sizeof(done)); - - for (i = 1; i < MAXUNLOCKABLES+1; ++i) - { - curheight = UINT16_MAX; - ul = -1; - - // Autosort unlockables - for (j = 0; j < MAXUNLOCKABLES; ++j) - { - if (!unlockables[j].height || done[j] || unlockables[j].type < 0) - continue; - - if (unlockables[j].height < curheight) - { - curheight = unlockables[j].height; - ul = j; - } - } - if (ul < 0) - break; - - done[ul] = true; - - skyRoomMenuTranslations[i-1] = (UINT8)ul; - SR_MainMenu[i].text = unlockables[ul].name; - SR_MainMenu[i].alphaKey = (UINT8)unlockables[ul].height; - - if (unlockables[ul].type == SECRET_HEADER) - { - SR_MainMenu[i].status = IT_HEADER; - continue; - } - - SR_MainMenu[i].status = IT_SECRET; - - if (unlockables[ul].unlocked) - { - switch (unlockables[ul].type) - { - case SECRET_LEVELSELECT: - SR_MainMenu[i].status = IT_STRING|IT_CALL; - SR_MainMenu[i].itemaction = M_CustomLevelSelect; - break; - case SECRET_WARP: - SR_MainMenu[i].status = IT_STRING|IT_CALL; - SR_MainMenu[i].itemaction = M_CustomWarp; - break; - case SECRET_CREDITS: - SR_MainMenu[i].status = IT_STRING|IT_CALL; - SR_MainMenu[i].itemaction = M_Credits; - break; - case SECRET_SOUNDTEST: - SR_MainMenu[i].status = IT_STRING|IT_KEYHANDLER; - SR_MainMenu[i].itemaction = M_HandleSoundTest; - default: - break; - } - } - } - - M_SetupNextMenu(&SR_MainDef); -}*/ - -// ================== -// NEW GAME FUNCTIONS -// ================== - -/*INT32 ultimate_selectable = false; - -static void M_NewGame(void) -{ - fromlevelselect = false; - - startmap = spstage_start; - CV_SetValue(&cv_newgametype, GT_RACE); // SRB2kart - - M_SetupChoosePlayer(0); -}*/ - -/*static void M_CustomWarp(INT32 choice) -{ - INT32 ul = skyRoomMenuTranslations[choice-1]; - - startmap = (INT16)(unlockables[ul].variable); - - M_SetupChoosePlayer(0); -}*/ - -static void M_Credits(INT32 choice) -{ - (void)choice; - cursaveslot = -2; - M_ClearMenus(true); - F_StartCredits(); -} - -/*static void M_CustomLevelSelect(INT32 choice) -{ - INT32 ul = skyRoomMenuTranslations[choice-1]; - - SR_LevelSelectDef.prevMenu = currentMenu; - levellistmode = LLM_LEVELSELECT; - maplistoption = (UINT8)(unlockables[ul].variable); - if (M_CountLevelsToShowInList() == 0) - { - M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING); - return; - } - - M_PrepareLevelSelect(); - M_SetupNextMenu(&SR_LevelSelectDef); -}*/ - -// ================== -// SINGLE PLAYER MENU -// ================== - -static void M_SinglePlayerMenu(INT32 choice) -{ - (void)choice; - - SP_MainMenu[spgrandprix].status = IT_CALL|IT_STRING; - SP_MainMenu[sptimeattack].status = - (M_SecretUnlocked(SECRET_TIMEATTACK)) ? IT_CALL|IT_STRING : IT_SECRET; - SP_MainMenu[spbreakthecapsules].status = - (M_SecretUnlocked(SECRET_BREAKTHECAPSULES)) ? IT_CALL|IT_STRING : IT_SECRET; - - M_SetupNextMenu(&SP_MainDef); -} - -/*static void M_LoadGameLevelSelect(INT32 choice) -{ - (void)choice; - levellistmode = LLM_LEVELSELECT; - maplistoption = 1; - if (M_CountLevelsToShowInList() == 0) - { - M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING); - return; - } - - SP_LevelSelectDef.prevMenu = currentMenu; - - M_PrepareLevelSelect(); - M_SetupNextMenu(&SP_LevelSelectDef); -}*/ - -// ============== -// LOAD GAME MENU -// ============== - -/*static INT32 saveSlotSelected = 0; -static short menumovedir = 0; - -static void M_DrawLoadGameData(void) -{ - INT32 ecks; - INT32 i; - - ecks = SP_LoadDef.x + 24; - M_DrawTextBox(SP_LoadDef.x-12,144, 24, 4); - - if (saveSlotSelected == NOSAVESLOT) // last slot is play without saving - { - if (ultimate_selectable) - { - V_DrawCenteredString(ecks + 68, 144, V_ORANGEMAP, "ULTIMATE MODE"); - V_DrawCenteredString(ecks + 68, 156, 0, "NO RINGS, NO ONE-UPS,"); - V_DrawCenteredString(ecks + 68, 164, 0, "NO CONTINUES, ONE LIFE,"); - V_DrawCenteredString(ecks + 68, 172, 0, "FINAL DESTINATION."); - } - else - { - V_DrawCenteredString(ecks + 68, 144, V_ORANGEMAP, "PLAY WITHOUT SAVING"); - V_DrawCenteredString(ecks + 68, 156, 0, "THIS GAME WILL NOT BE"); - V_DrawCenteredString(ecks + 68, 164, 0, "SAVED, BUT YOU CAN STILL"); - V_DrawCenteredString(ecks + 68, 172, 0, "GET MEDALS AND SECRETS."); - } - return; - } - - if (savegameinfo[saveSlotSelected].lives == -42) // Empty - { - V_DrawCenteredString(ecks + 68, 160, 0, "NO DATA"); - return; - } - - if (savegameinfo[saveSlotSelected].lives == -666) // savegame is bad - { - V_DrawCenteredString(ecks + 68, 144, warningflags, "CORRUPT SAVE FILE"); - V_DrawCenteredString(ecks + 68, 156, 0, "THIS SAVE FILE"); - V_DrawCenteredString(ecks + 68, 164, 0, "CAN NOT BE LOADED."); - V_DrawCenteredString(ecks + 68, 172, 0, "DELETE USING BACKSPACE."); - return; - } - - // Draw the back sprite, it looks ugly if we don't - V_DrawScaledPatch(SP_LoadDef.x, 144+8, 0, livesback); - if (savegameinfo[saveSlotSelected].skincolor == 0) - V_DrawScaledPatch(SP_LoadDef.x,144+8,0,W_CachePatchName(skins[savegameinfo[saveSlotSelected].skinnum].face, PU_CACHE)); - else - { - UINT8 *colormap = R_GetTranslationColormap(savegameinfo[saveSlotSelected].skinnum, savegameinfo[saveSlotSelected].skincolor, GTC_MENUCACHE); - V_DrawMappedPatch(SP_LoadDef.x,144+8,0,W_CachePatchName(skins[savegameinfo[saveSlotSelected].skinnum].face, PU_CACHE), colormap); - } - - V_DrawString(ecks + 12, 152, 0, savegameinfo[saveSlotSelected].playername); - -#ifdef SAVEGAMES_OTHERVERSIONS - if (savegameinfo[saveSlotSelected].gamemap & 16384) - V_DrawCenteredString(ecks + 68, 144, warningflags, "OUTDATED SAVE FILE!"); -#endif - - if (savegameinfo[saveSlotSelected].gamemap & 8192) - V_DrawString(ecks + 12, 160, recommendedflags, "CLEAR!"); - else - V_DrawString(ecks + 12, 160, 0, va("%s", savegameinfo[saveSlotSelected].levelname)); - - // Use the big face pic for lives, duh. :3 - V_DrawScaledPatch(ecks + 12, 175, 0, W_CachePatchName("STLIVEX", PU_HUDGFX)); - V_DrawTallNum(ecks + 40, 172, 0, savegameinfo[saveSlotSelected].lives); - - // Absolute ridiculousness, condensed into another function. - V_DrawContinueIcon(ecks + 58, 182, 0, savegameinfo[saveSlotSelected].skinnum, savegameinfo[saveSlotSelected].skincolor); - V_DrawScaledPatch(ecks + 68, 175, 0, W_CachePatchName("STLIVEX", PU_HUDGFX)); - V_DrawTallNum(ecks + 96, 172, 0, savegameinfo[saveSlotSelected].continues); - - for (i = 0; i < 7; ++i) - { - if (savegameinfo[saveSlotSelected].numemeralds & (1 << i)) - V_DrawScaledPatch(ecks + 104 + (i * 8), 172, 0, tinyemeraldpics[i]); - } -} - -#define LOADBARHEIGHT SP_LoadDef.y + (LINEHEIGHT * (j+1)) + ymod -#define CURSORHEIGHT SP_LoadDef.y + (LINEHEIGHT*3) - 1 -static void M_DrawLoad(void) -{ - INT32 i, j; - INT32 ymod = 0, offset = 0; - - M_DrawMenuTitle(); - - if (menumovedir != 0) //movement illusion - { - ymod = (-(LINEHEIGHT/4))*menumovedir; - offset = ((menumovedir > 0) ? -1 : 1); - } - - V_DrawCenteredString(BASEVIDWIDTH/2, 40, 0, "Press backspace to delete a save."); - - for (i = MAXSAVEGAMES + saveSlotSelected - 2 + offset, j = 0;i <= MAXSAVEGAMES + saveSlotSelected + 2 + offset; i++, j++) - { - if ((menumovedir < 0 && j == 4) || (menumovedir > 0 && j == 0)) - continue; //this helps give the illusion of movement - - M_DrawSaveLoadBorder(SP_LoadDef.x, LOADBARHEIGHT); - - if ((i%MAXSAVEGAMES) == NOSAVESLOT) // play without saving - { - if (ultimate_selectable) - V_DrawCenteredString(SP_LoadDef.x+92, LOADBARHEIGHT - 1, V_ORANGEMAP, "ULTIMATE MODE"); - else - V_DrawCenteredString(SP_LoadDef.x+92, LOADBARHEIGHT - 1, V_ORANGEMAP, "PLAY WITHOUT SAVING"); - continue; - } - - if (savegameinfo[i%MAXSAVEGAMES].lives == -42) - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, V_TRANSLUCENT, "NO DATA"); - else if (savegameinfo[i%MAXSAVEGAMES].lives == -666) - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, warningflags, "CORRUPT SAVE FILE"); - else if (savegameinfo[i%MAXSAVEGAMES].gamemap & 8192) - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, recommendedflags, "CLEAR!"); - else - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, 0, va("%s", savegameinfo[i%MAXSAVEGAMES].levelname)); - - //Draw the save slot number on the right side - V_DrawRightAlignedString(SP_LoadDef.x+192, LOADBARHEIGHT - 1, 0, va("%d",(i%MAXSAVEGAMES) + 1)); - } - - //Draw cursors on both sides. - V_DrawScaledPatch( 32, CURSORHEIGHT, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); - V_DrawScaledPatch(274, CURSORHEIGHT, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); - - M_DrawLoadGameData(); - - //finishing the movement illusion - if (menumovedir) - menumovedir += ((menumovedir > 0) ? 1 : -1); - if (abs(menumovedir) > 3) - menumovedir = 0; -} -#undef LOADBARHEIGHT -#undef CURSORHEIGHT - -// -// User wants to load this game -// -static void M_LoadSelect(INT32 choice) -{ - (void)choice; - - if (saveSlotSelected == NOSAVESLOT) //last slot is play without saving - { - M_NewGame(); - cursaveslot = -1; - return; - } - - if (!FIL_ReadFileOK(va(savegamename, saveSlotSelected))) - { - // This slot is empty, so start a new game here. - M_NewGame(); - } - else if (savegameinfo[saveSlotSelected].gamemap & 8192) // Completed - M_LoadGameLevelSelect(saveSlotSelected + 1); - else - G_LoadGame((UINT32)saveSlotSelected, 0); - - cursaveslot = saveSlotSelected; -} - -#define VERSIONSIZE 16 -#define BADSAVE { savegameinfo[slot].lives = -666; Z_Free(savebuffer); return; } -#define CHECKPOS if (save_p >= end_p) BADSAVE -// Reads the save file to list lives, level, player, etc. -// Tails 05-29-2003 -static void M_ReadSavegameInfo(UINT32 slot) -{ - size_t length; - char savename[255]; - UINT8 *savebuffer; - UINT8 *end_p; // buffer end point, don't read past here - UINT8 *save_p; - INT32 fake; // Dummy variable - char temp[sizeof(timeattackfolder)]; - char vcheck[VERSIONSIZE]; -#ifdef SAVEGAMES_OTHERVERSIONS - boolean oldversion = false; -#endif - - sprintf(savename, savegamename, slot); - - length = FIL_ReadFile(savename, &savebuffer); - if (length == 0) - { - savegameinfo[slot].lives = -42; - return; - } - - end_p = savebuffer + length; - - // skip the description field - save_p = savebuffer; - - // Version check - memset(vcheck, 0, sizeof (vcheck)); - sprintf(vcheck, "version %d", VERSION); - if (strcmp((const char *)save_p, (const char *)vcheck)) - { -#ifdef SAVEGAMES_OTHERVERSIONS - oldversion = true; -#else - BADSAVE // Incompatible versions? -#endif - } - save_p += VERSIONSIZE; - - // dearchive all the modifications - // P_UnArchiveMisc() - - CHECKPOS - fake = READINT16(save_p); - - if (((fake-1) & 8191) >= NUMMAPS) BADSAVE - - if(!mapheaderinfo[(fake-1) & 8191]) - { - savegameinfo[slot].levelname[0] = '\0'; - savegameinfo[slot].actnum = 0; - } - else - { - strcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl); - savegameinfo[slot].actnum = 0; //mapheaderinfo[(fake-1) & 8191]->actnum - } - -#ifdef SAVEGAMES_OTHERVERSIONS - if (oldversion) - { - if (fake == 24) //meh, let's count old Clear! saves too - fake |= 8192; - fake |= 16384; // marker for outdated version - } -#endif - savegameinfo[slot].gamemap = fake; - - CHECKPOS - fake = READUINT16(save_p)-357; // emeralds - - savegameinfo[slot].numemeralds = (UINT8)fake; - - CHECKPOS - READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to - - if (strcmp(temp, timeattackfolder)) BADSAVE - - // P_UnArchivePlayer() - CHECKPOS - savegameinfo[slot].skincolor = READUINT8(save_p); - CHECKPOS - savegameinfo[slot].skinnum = READUINT8(save_p); - - CHECKPOS - (void)READINT32(save_p); // Score - - CHECKPOS - savegameinfo[slot].lives = READINT32(save_p); // lives - CHECKPOS - savegameinfo[slot].continues = READINT32(save_p); // continues - - if (fake & (1<<10)) - { - CHECKPOS - savegameinfo[slot].botskin = READUINT8(save_p); - if (savegameinfo[slot].botskin-1 >= numskins) - savegameinfo[slot].botskin = 0; - CHECKPOS - savegameinfo[slot].botcolor = READUINT8(save_p); // because why not. - } - else - savegameinfo[slot].botskin = 0; - - if (savegameinfo[slot].botskin) - snprintf(savegameinfo[slot].playername, 36, "%s & %s", - skins[savegameinfo[slot].skinnum].realname, - skins[savegameinfo[slot].botskin-1].realname); - else - strcpy(savegameinfo[slot].playername, skins[savegameinfo[slot].skinnum].realname); - - savegameinfo[slot].playername[31] = 0; - - // File end marker check - CHECKPOS - if (READUINT8(save_p) != 0x1d) BADSAVE; - - // done - Z_Free(savebuffer); -} -#undef CHECKPOS -#undef BADSAVE - -// -// M_ReadSaveStrings -// read the strings from the savegame files -// and put it in savegamestrings global variable -// -static void M_ReadSaveStrings(void) -{ - FILE *handle; - UINT32 i; - char name[256]; - - for (i = 0; i < MAXSAVEGAMES; i++) - { - snprintf(name, sizeof name, savegamename, i); - name[sizeof name - 1] = '\0'; - - handle = fopen(name, "rb"); - if (handle == NULL) - { - savegameinfo[i].lives = -42; - continue; - } - fclose(handle); - M_ReadSavegameInfo(i); - } -} - -// -// User wants to delete this game -// -static void M_SaveGameDeleteResponse(INT32 ch) -{ - char name[256]; - - if (ch != 'y' && ch != KEY_ENTER) - return; - - // delete savegame - snprintf(name, sizeof name, savegamename, saveSlotSelected); - name[sizeof name - 1] = '\0'; - remove(name); - - // Refresh savegame menu info - M_ReadSaveStrings(); -} - -static void M_HandleLoadSave(INT32 choice) -{ - boolean exitmenu = false; // exit to previous menu - - switch (choice) - { - case KEY_DOWNARROW: - S_StartSound(NULL, sfx_menu1); - ++saveSlotSelected; - if (saveSlotSelected >= MAXSAVEGAMES) - saveSlotSelected -= MAXSAVEGAMES; - menumovedir = 1; - break; - - case KEY_UPARROW: - S_StartSound(NULL, sfx_menu1); - --saveSlotSelected; - if (saveSlotSelected < 0) - saveSlotSelected += MAXSAVEGAMES; - menumovedir = -1; - break; - - case KEY_ENTER: - S_StartSound(NULL, sfx_menu1); - if (savegameinfo[saveSlotSelected].lives != -666) // don't allow loading of "bad saves" - M_LoadSelect(saveSlotSelected); - break; - - case KEY_ESCAPE: - exitmenu = true; - break; - - case KEY_BACKSPACE: - S_StartSound(NULL, sfx_menu1); - // Don't allow people to 'delete' "Play without Saving." - // Nor allow people to 'delete' slots with no saves in them. - if (saveSlotSelected != NOSAVESLOT && savegameinfo[saveSlotSelected].lives != -42) - M_StartMessage(M_GetText("Are you sure you want to delete\nthis save game?\n\n(Press 'Y' to confirm)\n"),M_SaveGameDeleteResponse,MM_YESNO); - break; - } - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} - -// -// Selected from SRB2 menu -// -static void M_LoadGame(INT32 choice) -{ - (void)choice; - - M_ReadSaveStrings(); - M_SetupNextMenu(&SP_LoadDef); -} - -// -// Used by cheats to force the save menu to a specific spot. -// -void M_ForceSaveSlotSelected(INT32 sslot) -{ - // Already there? Out of bounds? Whatever, then! - if (sslot == saveSlotSelected || sslot >= MAXSAVEGAMES) - return; - - // Figure out whether to display up movement or down movement - menumovedir = (saveSlotSelected - sslot) > 0 ? -1 : 1; - if (abs(saveSlotSelected - sslot) > (MAXSAVEGAMES>>1)) - menumovedir *= -1; - - saveSlotSelected = sslot; -} - -// ================ -// CHARACTER SELECT -// ================ - -static void M_SetupChoosePlayer(INT32 choice) -{ - (void)choice; - - if (mapheaderinfo[startmap-1] && mapheaderinfo[startmap-1]->forcecharacter[0] != '\0') - { - M_ChoosePlayer(0); //oh for crying out loud just get STARTED, it doesn't matter! - return; - } - - if (Playing() == false) - { - S_StopMusic(); - S_ChangeMusicInternal("chrsel", true); - } - - SP_PlayerDef.prevMenu = currentMenu; - M_SetupNextMenu(&SP_PlayerDef); - char_scroll = itemOn*128*FRACUNIT; // finish scrolling the menu - Z_Free(char_notes); - char_notes = NULL; -} - -// Draw the choose player setup menu, had some fun with player anim -static void M_DrawSetupChoosePlayerMenu(void) -{ - const INT32 my = 24; - patch_t *patch; - INT32 i, o, j; - char *picname; - - // Black BG - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - //V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - - // Character select profile images!1 - M_DrawTextBox(0, my, 16, 20); - - if (abs(itemOn*128*FRACUNIT - char_scroll) > 256*FRACUNIT) - char_scroll = itemOn*128*FRACUNIT; - else if (itemOn*128*FRACUNIT - char_scroll > 128*FRACUNIT) - char_scroll += 48*FRACUNIT; - else if (itemOn*128*FRACUNIT - char_scroll < -128*FRACUNIT) - char_scroll -= 48*FRACUNIT; - else if (itemOn*128*FRACUNIT > char_scroll+16*FRACUNIT) - char_scroll += 16*FRACUNIT; - else if (itemOn*128*FRACUNIT < char_scroll-16*FRACUNIT) - char_scroll -= 16*FRACUNIT; - else // close enough. - char_scroll = itemOn*128*FRACUNIT; // just be exact now. - i = (char_scroll+16*FRACUNIT)/(128*FRACUNIT); - o = ((char_scroll/FRACUNIT)+16)%128; - - // prev character - if (i-1 >= 0 && PlayerMenu[i-1].status != IT_DISABLED - && o < 32) - { - picname = description[i-1].picname; - if (picname[0] == '\0') - { - picname = strtok(Z_StrDup(description[i-1].skinname), "&"); - for (j = 0; j < numskins; j++) - if (stricmp(skins[j].name, picname) == 0) - { - Z_Free(picname); - picname = skins[j].charsel; - break; - } - if (j == numskins) // AAAAAAAAAA - picname = skins[0].charsel; - } - patch = W_CachePatchName(picname, PU_CACHE); - if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<height) - 64 + o*2, SHORT(patch->width), SHORT(patch->height)); - else - V_DrawCroppedPatch(8<height) - 32 + o, SHORT(patch->width), SHORT(patch->height)); - W_UnlockCachedPatch(patch); - } - - // next character - if (i+1 < currentMenu->numitems && PlayerMenu[i+1].status != IT_DISABLED - && o < 128) - { - picname = description[i+1].picname; - if (picname[0] == '\0') - { - picname = strtok(Z_StrDup(description[i+1].skinname), "&"); - for (j = 0; j < numskins; j++) - if (stricmp(skins[j].name, picname) == 0) - { - Z_Free(picname); - picname = skins[j].charsel; - break; - } - if (j == numskins) // AAAAAAAAAA - picname = skins[0].charsel; - } - patch = W_CachePatchName(picname, PU_CACHE); - if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<width), o*2); - else - V_DrawCroppedPatch(8<width), o); - W_UnlockCachedPatch(patch); - } - - // current character - if (i < currentMenu->numitems && PlayerMenu[i].status != IT_DISABLED) - { - picname = description[i].picname; - if (picname[0] == '\0') - { - picname = strtok(Z_StrDup(description[i].skinname), "&"); - for (j = 0; j < numskins; j++) - if (stricmp(skins[j].name, picname) == 0) - { - Z_Free(picname); - picname = skins[j].charsel; - break; - } - if (j == numskins) // AAAAAAAAAA - picname = skins[0].charsel; - } - patch = W_CachePatchName(picname, PU_CACHE); - if (o >= 0 && o <= 32) - { - if (SHORT(patch->width) >= 256) - V_DrawSmallScaledPatch(8, my + 40 - o, 0, patch); - else - V_DrawScaledPatch(8, my + 40 - o, 0, patch); - } - else - { - if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<width), SHORT(patch->height)); - else - V_DrawCroppedPatch(8<width), SHORT(patch->height)); - } - W_UnlockCachedPatch(patch); - } - - // draw title (or big pic) - M_DrawMenuTitle(); - - // Character description - M_DrawTextBox(136, my, 21, 20); - if (!char_notes) - char_notes = V_WordWrap(0, 21*8, V_ALLOWLOWERCASE, description[itemOn].notes); - V_DrawString(146, my + 9, V_RETURN8|V_ALLOWLOWERCASE, char_notes); -} - -// Chose the player you want to use Tails 03-02-2002 -static void M_ChoosePlayer(INT32 choice) -{ - char *skin1,*skin2; - INT32 skinnum; - //boolean ultmode = (ultimate_selectable && SP_PlayerDef.prevMenu == &SP_LoadDef && saveSlotSelected == NOSAVESLOT); - - // skip this if forcecharacter - if (mapheaderinfo[startmap-1] && mapheaderinfo[startmap-1]->forcecharacter[0] == '\0') - { - // M_SetupChoosePlayer didn't call us directly, that means we've been properly set up. - char_scroll = itemOn*128*FRACUNIT; // finish scrolling the menu - M_DrawSetupChoosePlayerMenu(); // draw the finally selected character one last time for the fadeout - } - M_ClearMenus(true); - - skin1 = strtok(description[choice].skinname, "&"); - skin2 = strtok(NULL, "&"); - - if (skin2) { - // this character has a second skin - skinnum = R_SkinAvailable(skin1); - botskin = (UINT8)(R_SkinAvailable(skin2)+1); - botingame = true; - - botcolor = skins[botskin-1].prefcolor; - - // undo the strtok - description[choice].skinname[strlen(skin1)] = '&'; - } else { - skinnum = R_SkinAvailable(description[choice].skinname); - botingame = false; - botskin = 0; - botcolor = 0; - } - - if (startmap != spstage_start) - cursaveslot = -1; - - lastmapsaved = 0; - gamecomplete = false; - - G_DeferedInitNew(false, G_BuildMapName(startmap), (UINT8)skinnum, 0, fromlevelselect); - COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this -}*/ - -// =============== -// STATISTICS MENU -// =============== - -static INT32 statsLocation; -static INT32 statsMax; -static INT16 statsMapList[NUMMAPS+1]; - -static void M_Statistics(INT32 choice) -{ - INT16 i, j = 0; - - (void)choice; - - memset(statsMapList, 0, sizeof(statsMapList)); - - for (i = 0; i < NUMMAPS; i++) - { - if (!mapheaderinfo[i] || mapheaderinfo[i]->lvlttl[0] == '\0') - continue; - - if (!(mapheaderinfo[i]->typeoflevel & TOL_RACE) // TOL_SP - || (mapheaderinfo[i]->menuflags & (LF2_HIDEINSTATS|LF2_HIDEINMENU))) - continue; - - if (M_MapLocked(i+1)) // !mapvisited[i] - continue; - - statsMapList[j++] = i; - } - statsMapList[j] = -1; - statsMax = j - 11 + numextraemblems; - statsLocation = 0; - - if (statsMax < 0) - statsMax = 0; - - M_SetupNextMenu(&SP_LevelStatsDef); -} - -static void M_DrawStatsMaps(int location) -{ - INT32 y = 88, i = -1; - INT16 mnum; - extraemblem_t *exemblem; - boolean dotopname = true, dobottomarrow = (location < statsMax); - - if (location) - V_DrawCharacter(10, y-(skullAnimCounter/5), - '\x1A' | highlightflags, false); // up arrow - - while (statsMapList[++i] != -1) - { - if (location) - { - --location; - continue; - } - else if (dotopname) - { - V_DrawString(20, y, highlightflags, "LEVEL NAME"); - V_DrawString(256, y, highlightflags, "MEDALS"); - y += 8; - dotopname = false; - } - - mnum = statsMapList[i]; - M_DrawMapEmblems(mnum+1, 295, y); - - if (mapheaderinfo[mnum]->levelflags & LF_NOZONE) - V_DrawString(20, y, 0, va("%s %s", - mapheaderinfo[mnum]->lvlttl, - mapheaderinfo[mnum]->actnum)); - else - V_DrawString(20, y, 0, va("%s %s %s", - mapheaderinfo[mnum]->lvlttl, - (mapheaderinfo[mnum]->zonttl[0] ? mapheaderinfo[mnum]->zonttl : "ZONE"), - mapheaderinfo[mnum]->actnum)); - - y += 8; - - if (y >= BASEVIDHEIGHT-8) - goto bottomarrow; - } - if (dotopname && !location) - { - V_DrawString(20, y, highlightflags, "LEVEL NAME"); - V_DrawString(256, y, highlightflags, "MEDALS"); - y += 8; - } - else if (location) - --location; - - // Extra Emblems - for (i = -2; i < numextraemblems; ++i) - { - if (i == -1) - { - V_DrawString(20, y, highlightflags, "EXTRA MEDALS"); - if (location) - { - y += 8; - location++; - } - } - if (location) - { - --location; - continue; - } - - if (i >= 0) - { - exemblem = &extraemblems[i]; - - if (exemblem->collected) - V_DrawSmallMappedPatch(295, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetExtraEmblemColor(exemblem), GTC_MENUCACHE)); - else - V_DrawSmallScaledPatch(295, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); - - V_DrawString(20, y, 0, va("%s", exemblem->description)); - } - - y += 8; - - if (y >= BASEVIDHEIGHT-8) - goto bottomarrow; - } -bottomarrow: - if (dobottomarrow) - V_DrawCharacter(10, y-8 + (skullAnimCounter/5), - '\x1B' | highlightflags, false); // down arrow -} - -static void M_DrawLevelStats(void) -{ - char beststr[40]; - - tic_t besttime = 0; - - INT32 i; - INT32 mapsunfinished = 0; - - M_DrawMenuTitle(); - - V_DrawString(20, 24, highlightflags, "Total Play Time:"); - V_DrawCenteredString(BASEVIDWIDTH/2, 32, 0, va("%i hours, %i minutes, %i seconds", - G_TicsToHours(totalplaytime), - G_TicsToMinutes(totalplaytime, false), - G_TicsToSeconds(totalplaytime))); - - V_DrawString(20, 42, highlightflags, "Total Matches:"); - V_DrawRightAlignedString(BASEVIDWIDTH-16, 42, 0, va("%i played", matchesplayed)); - - V_DrawString(20, 52, highlightflags, "Online Power Level:"); - V_DrawRightAlignedString(BASEVIDWIDTH-16, 52, 0, va("Race: %i", vspowerlevel[PWRLV_RACE])); - V_DrawRightAlignedString(BASEVIDWIDTH-16, 60, 0, va("Battle: %i", vspowerlevel[PWRLV_BATTLE])); - - for (i = 0; i < NUMMAPS; i++) - { - if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK)) - continue; - - if (!mainrecords[i] || mainrecords[i]->time <= 0) - { - mapsunfinished++; - continue; - } - - besttime += mainrecords[i]->time; - } - - V_DrawString(20, 70, highlightflags, "Combined time records:"); - - sprintf(beststr, "%i:%02i:%02i.%02i", G_TicsToHours(besttime), G_TicsToMinutes(besttime, false), G_TicsToSeconds(besttime), G_TicsToCentiseconds(besttime)); - V_DrawRightAlignedString(BASEVIDWIDTH-16, 70, (mapsunfinished ? warningflags : 0), beststr); - - if (mapsunfinished) - V_DrawRightAlignedString(BASEVIDWIDTH-16, 78, warningflags, va("(%d unfinished)", mapsunfinished)); - else - V_DrawRightAlignedString(BASEVIDWIDTH-16, 78, recommendedflags, "(complete)"); - - V_DrawString(32, 78, V_ALLOWLOWERCASE, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems)); - V_DrawSmallScaledPatch(20, 78, 0, W_CachePatchName("GOTITA", PU_STATIC)); - - M_DrawStatsMaps(statsLocation); -} - -// Handle statistics. -static void M_HandleLevelStats(INT32 choice) -{ - boolean exitmenu = false; // exit to previous menu - - switch (choice) - { - case KEY_DOWNARROW: - S_StartSound(NULL, sfx_menu1); - if (statsLocation < statsMax) - ++statsLocation; - break; - - case KEY_UPARROW: - S_StartSound(NULL, sfx_menu1); - if (statsLocation) - --statsLocation; - break; - - case KEY_PGDN: - S_StartSound(NULL, sfx_menu1); - statsLocation += (statsLocation+13 >= statsMax) ? statsMax-statsLocation : 13; - break; - - case KEY_PGUP: - S_StartSound(NULL, sfx_menu1); - statsLocation -= (statsLocation < 13) ? statsLocation : 13; - break; - - case KEY_ESCAPE: - exitmenu = true; - break; - } - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} - -static void M_GrandPrixTemp(INT32 choice) -{ - (void)choice; - M_PatchSkinNameTable(); - M_PrepareCupList(); - M_SetupNextMenu(&SP_GrandPrixTempDef); -} - -// Start Grand Prix! -static void M_StartGrandPrix(INT32 choice) -{ - cupheader_t *gpcup = kartcupheaders; - - (void)choice; - - if (gpcup == NULL) - { - // welp - I_Error("No cup definitions for GP\n"); - return; - } - - M_ClearMenus(true); - - memset(&grandprixinfo, 0, sizeof(struct grandprixinfo)); - - switch (cv_dummygpdifficulty.value) - { - case 0: - grandprixinfo.gamespeed = KARTSPEED_EASY; - break; - case 1: - default: - grandprixinfo.gamespeed = KARTSPEED_NORMAL; - break; - case 2: - grandprixinfo.gamespeed = KARTSPEED_HARD; - break; - case 3: - grandprixinfo.gamespeed = KARTSPEED_HARD; - grandprixinfo.masterbots = true; - break; - - } - - grandprixinfo.encore = (boolean)(cv_dummygpencore.value); - - while (gpcup != NULL && gpcup->id != cv_dummygpcup.value-1) - { - gpcup = gpcup->next; - } - - if (gpcup == NULL) - { - gpcup = kartcupheaders; - } - - grandprixinfo.cup = gpcup; - - grandprixinfo.gp = true; - grandprixinfo.roundnum = 1; - grandprixinfo.wonround = false; - - grandprixinfo.initalize = true; - - G_DeferedInitNew( - false, - G_BuildMapName(grandprixinfo.cup->levellist[0] + 1), - (UINT8)(cv_chooseskin.value - 1), - (UINT8)(cv_splitplayers.value - 1), - false - ); -} - -// =========== -// MODE ATTACK -// =========== - -// Drawing function for Time Attack -void M_DrawTimeAttackMenu(void) -{ - INT32 i, x, y, cursory = 0; - UINT16 dispstatus; - - //S_ChangeMusicInternal("racent", true); // Eww, but needed for when user hits escape during demo playback - - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - - M_DrawMenuTitle(); - if (currentMenu == &SP_TimeAttackDef) - M_DrawLevelSelectOnly(true, false); - - // draw menu (everything else goes on top of it) - // Sadly we can't just use generic mode menus because we need some extra hacks - x = currentMenu->x; - y = currentMenu->y; - - // Character face! - if (W_CheckNumForName(skins[cv_chooseskin.value-1].facewant) != LUMPERROR) - { - UINT8 *colormap = R_GetTranslationColormap(cv_chooseskin.value-1, cv_playercolor.value, GTC_MENUCACHE); - V_DrawMappedPatch(BASEVIDWIDTH-x - SHORT(facewantprefix[cv_chooseskin.value-1]->width), y, 0, facewantprefix[cv_chooseskin.value-1], colormap); - } - - for (i = 0; i < currentMenu->numitems; ++i) - { - dispstatus = (currentMenu->menuitems[i].status & IT_DISPLAY); - if (dispstatus != IT_STRING && dispstatus != IT_WHITESTRING) - continue; - - y = currentMenu->y+currentMenu->menuitems[i].alphaKey; - if (i == itemOn) - cursory = y; - - V_DrawString(x, y, (dispstatus == IT_WHITESTRING) ? highlightflags : 0 , currentMenu->menuitems[i].text); - - // Cvar specific handling - if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_CVAR) - { - consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction; - if (currentMenu->menuitems[i].status & IT_CV_STRING) - { - M_DrawTextBox(x + 32, y - 8, MAXPLAYERNAME, 1); - V_DrawString(x + 40, y, V_ALLOWLOWERCASE, cv->string); - if (itemOn == i && skullAnimCounter < 4) // blink cursor - V_DrawCharacter(x + 40 + V_StringWidth(cv->string, V_ALLOWLOWERCASE), y, '_',false); - } - else - { - const char *str = ((cv == &cv_chooseskin) ? skins[cv_chooseskin.value-1].realname : cv->string); - INT32 soffset = 40, strw = V_StringWidth(str, 0); - - // hack to keep the menu from overlapping the level icon - if (currentMenu != &SP_TimeAttackDef || cv == &cv_nextmap) - soffset = 0; - - // Should see nothing but strings - V_DrawString(BASEVIDWIDTH - x - soffset - strw, y, highlightflags, str); - - if (i == itemOn) - { - V_DrawCharacter(BASEVIDWIDTH - x - soffset - 10 - strw - (skullAnimCounter/5), y, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - x - soffset + 2 + (skullAnimCounter/5), y, - '\x1D' | highlightflags, false); // right arrow - } - } - } - else if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_KEYHANDLER && cv_dummystaff.value) // bad hacky assumption: IT_KEYHANDLER is assumed to be staff ghost selector - { - INT32 strw = V_StringWidth(dummystaffname, V_ALLOWLOWERCASE); - V_DrawString(BASEVIDWIDTH - x - strw, y, highlightflags|V_ALLOWLOWERCASE, dummystaffname); - if (i == itemOn) - { - V_DrawCharacter(BASEVIDWIDTH - x - 10 - strw - (skullAnimCounter/5), y, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y, - '\x1D' | highlightflags, false); // right arrow - } - } - } - - x = currentMenu->x; - y = currentMenu->y; - - // DRAW THE SKULL CURSOR - V_DrawScaledPatch(x - 24, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); - V_DrawString(x, cursory, highlightflags, currentMenu->menuitems[itemOn].text); - - // Level record list - if (cv_nextmap.value) - { - INT32 dupadjust = (vid.width/vid.dupx); - tic_t lap = 0, time = 0; - if (mainrecords[cv_nextmap.value-1]) - { - lap = mainrecords[cv_nextmap.value-1]->lap; - time = mainrecords[cv_nextmap.value-1]->time; - } - - V_DrawFill((BASEVIDWIDTH - dupadjust)>>1, 78, dupadjust, 36, 159); - - if (levellistmode != LLM_BREAKTHECAPSULES) - { - V_DrawRightAlignedString(149, 80, highlightflags, "BEST LAP:"); - K_drawKartTimestamp(lap, 19, 86, 0, 2); - } - - V_DrawRightAlignedString(292, 80, highlightflags, "BEST TIME:"); - K_drawKartTimestamp(time, 162, 86, cv_nextmap.value, 1); - } - /*{ - char beststr[40]; - emblem_t *em; - - if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->time) - sprintf(beststr, "(none)"); - else - sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(mainrecords[cv_nextmap.value-1]->time, true), - G_TicsToSeconds(mainrecords[cv_nextmap.value-1]->time), - G_TicsToCentiseconds(mainrecords[cv_nextmap.value-1]->time)); - - V_DrawString(64, y+48, highlightflags, "BEST TIME:"); - V_DrawRightAlignedString(BASEVIDWIDTH - 64 - 24 - 8, y+48, V_ALLOWLOWERCASE, beststr); - - if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->lap) - sprintf(beststr, "(none)"); - else - sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(mainrecords[cv_nextmap.value-1]->lap, true), - G_TicsToSeconds(mainrecords[cv_nextmap.value-1]->lap), - G_TicsToCentiseconds(mainrecords[cv_nextmap.value-1]->lap)); - - V_DrawString(64, y+56, highlightflags, "BEST LAP:"); - V_DrawRightAlignedString(BASEVIDWIDTH - 64 - 24 - 8, y+56, V_ALLOWLOWERCASE, beststr); - - // Draw record emblems. - em = M_GetLevelEmblems(cv_nextmap.value); - while (em) - { - switch (em->type) - { - case ET_TIME: break; - default: - goto skipThisOne; - } - - if (em->collected) - V_DrawMappedPatch(BASEVIDWIDTH - 64 - 24, y+48, 0, W_CachePatchName(M_GetEmblemPatch(em), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_MENUCACHE)); - else - V_DrawScaledPatch(BASEVIDWIDTH - 64 - 24, y+48, 0, W_CachePatchName("NEEDIT", PU_CACHE)); - - skipThisOne: - em = M_GetLevelEmblems(-1); - } - }*/ - - // ALWAYS DRAW player name, level name, skin and color even when not on this menu! - if (currentMenu != &SP_TimeAttackDef) - { - consvar_t *ncv; - - for (i = 0; i < 4; ++i) - { - y = currentMenu->y+SP_TimeAttackMenu[i].alphaKey; - V_DrawString(x, y, V_TRANSLUCENT, SP_TimeAttackMenu[i].text); - ncv = (consvar_t *)SP_TimeAttackMenu[i].itemaction; - if (SP_TimeAttackMenu[i].status & IT_CV_STRING) - { - M_DrawTextBox(x + 32, y - 8, MAXPLAYERNAME, 1); - V_DrawString(x + 40, y, V_TRANSLUCENT|V_ALLOWLOWERCASE, ncv->string); - } - else - { - const char *str = ((ncv == &cv_chooseskin) ? skins[cv_chooseskin.value-1].realname : ncv->string); - INT32 soffset = 40, strw = V_StringWidth(str, 0); - - // hack to keep the menu from overlapping the level icon - if (ncv == &cv_nextmap) - soffset = 0; - - // Should see nothing but strings - V_DrawString(BASEVIDWIDTH - x - soffset - strw, y, highlightflags|V_TRANSLUCENT, str); - } - } - } -} - -// Going to Time Attack menu... -static void M_TimeAttack(INT32 choice) -{ - (void)choice; - - memset(skins_cons_t, 0, sizeof (skins_cons_t)); - - levellistmode = LLM_TIMEATTACK; // Don't be dependent on cv_newgametype - - if (M_CountLevelsToShowInList() == 0) - { - M_StartMessage(M_GetText("No levels found for Time Attack.\n"),NULL,MM_NOTHING); - return; - } - - M_PatchSkinNameTable(); - - M_PrepareLevelSelect(); - M_SetupNextMenu(&SP_TimeAttackDef); - - G_SetGamestate(GS_TIMEATTACK); - - if (cv_nextmap.value) - Nextmap_OnChange(); - else - CV_AddValue(&cv_nextmap, 1); - - itemOn = tastart; // "Start" is selected. - - S_ChangeMusicInternal("racent", true); -} - -// Same as above, but sets a different levellistmode. Should probably be merged... -static void M_BreakTheCapsules(INT32 choice) -{ - (void)choice; - - memset(skins_cons_t, 0, sizeof (skins_cons_t)); - - levellistmode = LLM_BREAKTHECAPSULES; // Don't be dependent on cv_newgametype - - if (M_CountLevelsToShowInList() == 0) - { - M_StartMessage(M_GetText("No levels found for Break the Capsules.\n"),NULL,MM_NOTHING); - return; - } - - M_PatchSkinNameTable(); - - M_PrepareLevelSelect(); - M_SetupNextMenu(&SP_TimeAttackDef); - - G_SetGamestate(GS_TIMEATTACK); - - if (cv_nextmap.value) - Nextmap_OnChange(); - else - CV_AddValue(&cv_nextmap, 1); - - itemOn = tastart; // "Start" is selected. - - S_ChangeMusicInternal("racent", true); -} - -static boolean M_QuitTimeAttackMenu(void) -{ - // you know what? always putting these in the buffer won't hurt anything. - COM_BufAddText(va("skin \"%s\"\n", cv_chooseskin.string)); - return true; -} - -// Drawing function for Nights Attack -/*void M_DrawNightsAttackMenu(void) -{ - patch_t *PictureOfLevel; - lumpnum_t lumpnum; - char beststr[40]; - - S_ChangeMusicInternal("racent", true); // Eww, but needed for when user hits escape during demo playback - - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - - // draw menu (everything else goes on top of it) - M_DrawGenericMenu(); - - // A 160x100 image of the level as entry MAPxxP - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); - - if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); - else - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); - - V_DrawSmallScaledPatch(90, 28, 0, PictureOfLevel); - - // Level record list - if (cv_nextmap.value) - { - emblem_t *em; - INT32 yHeight; - - UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0); - UINT8 bestgrade = G_GetBestNightsGrade(cv_nextmap.value, cv_dummymares.value); - UINT32 bestscore = G_GetBestNightsScore(cv_nextmap.value, cv_dummymares.value); - tic_t besttime = G_GetBestNightsTime(cv_nextmap.value, cv_dummymares.value); - - if (P_HasGrades(cv_nextmap.value, 0)) - V_DrawScaledPatch(200, 28 + 8, 0, ngradeletters[bestoverall]); - - if (currentMenu == &SP_NightsAttackDef) - { - if (P_HasGrades(cv_nextmap.value, cv_dummymares.value)) - { - V_DrawString(160-88, 112, highlightflags, "BEST GRADE:"); - V_DrawSmallScaledPatch(160 + 86 - (ngradeletters[bestgrade]->width/2), - 112 + 8 - (ngradeletters[bestgrade]->height/2), - 0, ngradeletters[bestgrade]); - } - - if (!bestscore) - sprintf(beststr, "(none)"); - else - sprintf(beststr, "%u", bestscore); - - V_DrawString(160 - 88, 122, highlightflags, "BEST SCORE:"); - V_DrawRightAlignedString(160 + 88, 122, V_ALLOWLOWERCASE, beststr); - - if (besttime == UINT32_MAX) - sprintf(beststr, "(none)"); - else - sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(besttime, true), - G_TicsToSeconds(besttime), - G_TicsToCentiseconds(besttime)); - - V_DrawString(160-88, 132, highlightflags, "BEST TIME:"); - V_DrawRightAlignedString(160+88, 132, V_ALLOWLOWERCASE, beststr); - - if (cv_dummymares.value == 0) { - // Draw record emblems. - em = M_GetLevelEmblems(cv_nextmap.value); - while (em) - { - switch (em->type) - { - case ET_NGRADE: yHeight = 112; break; - case ET_NTIME: yHeight = 132; break; - default: - goto skipThisOne; - } - - if (em->collected) - V_DrawSmallMappedPatch(160+88, yHeight, 0, W_CachePatchName(M_GetEmblemPatch(em), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_MENUCACHE)); - else - V_DrawSmallScaledPatch(160+88, yHeight, 0, W_CachePatchName("NEEDIT", PU_CACHE)); - - skipThisOne: - em = M_GetLevelEmblems(-1); - } - } - } - // ALWAYS DRAW level name even when not on this menu! - else - { - consvar_t *ncv; - INT32 x = SP_NightsAttackDef.x; - INT32 y = SP_NightsAttackDef.y; - - ncv = (consvar_t *)SP_NightsAttackMenu[0].itemaction; - V_DrawString(x, y + SP_NightsAttackMenu[0].alphaKey, V_TRANSLUCENT, SP_NightsAttackMenu[0].text); - V_DrawString(BASEVIDWIDTH - x - V_StringWidth(ncv->string, 0), - y + SP_NightsAttackMenu[0].alphaKey, highlightflags|V_TRANSLUCENT, ncv->string); - } - } -}*/ - -// Going to Nights Attack menu... -/*static void M_BreakTheCapsules(INT32 choice) -{ - (void)choice; - - memset(skins_cons_t, 0, sizeof (skins_cons_t)); - - levellistmode = LLM_BREAKTHECAPSULES; // Don't be dependent on cv_newgametype - - if (M_CountLevelsToShowInList() == 0) - { - M_StartMessage(M_GetText("No NiGHTS-attackable levels found.\n"),NULL,MM_NOTHING); - return; - } - - // This is really just to make sure Sonic is the played character, just in case - M_PatchSkinNameTable(); - - M_PrepareLevelSelect(); - M_SetupNextMenu(&SP_NightsAttackDef); - Nextmap_OnChange(); - - itemOn = nastart; // "Start" is selected. - - G_SetGamestate(GS_TIMEATTACK); - S_ChangeMusicInternal("racent", true); -}*/ - -// Player has selected the "START" from the nights attack screen -/*static void M_ChooseNightsAttack(INT32 choice) -{ - char nameofdemo[256]; - (void)choice; - emeralds = 0; - M_ClearMenus(true); - modeattacking = ATTACKING_CAPSULES; - - I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); - I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); - - snprintf(nameofdemo, sizeof nameofdemo, "replay"PATHSEP"%s"PATHSEP"%s-last", timeattackfolder, G_BuildMapName(cv_nextmap.value)); - - if (!cv_autorecord.value) - remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo)); - else - G_RecordDemo(nameofdemo); - - G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), 0, 0, false); -}*/ - -// Player has selected the "START" from the time attack screen -static void M_ChooseTimeAttack(INT32 choice) -{ - char *gpath; - const size_t glen = strlen("media")+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; - char nameofdemo[256]; - (void)choice; - emeralds = 0; - M_ClearMenus(true); - modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD); - - gpath = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s", - srb2home, timeattackfolder); - M_MkdirEach(gpath, M_PathParts(gpath) - 3, 0755); - - if ((gpath = malloc(glen)) == NULL) - I_Error("Out of memory for replay filepath\n"); - - sprintf(gpath,"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value)); - snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, cv_chooseskin.string); - - if (!cv_autorecord.value) - remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo)); - else - G_RecordDemo(nameofdemo); - - G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), (UINT8)(cv_chooseskin.value-1), 0, false); -} - -static void M_HandleStaffReplay(INT32 choice) -{ - boolean exitmenu = false; // exit to previous menu - lumpnum_t l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value)); - - switch (choice) - { - case KEY_DOWNARROW: - M_NextOpt(); - S_StartSound(NULL, sfx_menu1); - break; - case KEY_UPARROW: - M_PrevOpt(); - S_StartSound(NULL, sfx_menu1); - break; - case KEY_BACKSPACE: - case KEY_ESCAPE: - exitmenu = true; - break; - case KEY_RIGHTARROW: - CV_AddValue(&cv_dummystaff, 1); - S_StartSound(NULL, sfx_menu1); - break; - case KEY_LEFTARROW: - CV_AddValue(&cv_dummystaff, -1); - S_StartSound(NULL, sfx_menu1); - break; - case KEY_ENTER: - if (l == LUMPERROR) - break; - M_ClearMenus(true); - modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD); - demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed - G_DoPlayDemo(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value)); - break; - default: - break; - } - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} - -// Player has selected the "REPLAY" from the time attack screen -static void M_ReplayTimeAttack(INT32 choice) -{ - const char *which; - M_ClearMenus(true); - modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD); // set modeattacking before G_DoPlayDemo so the map loader knows - demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed - - if (currentMenu == &SP_ReplayDef) - { - switch(choice) { - default: - case 0: // best time - which = "time-best"; - break; - case 1: // best lap - which = "lap-best"; - break; - case 2: // last - which = "last"; - break; - case 3: // guest - // srb2/replay/main/map01-guest.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); - return; - } - // srb2/replay/main/map01-sonic-time-best.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which)); - } - /*else if (currentMenu == &SP_NightsReplayDef) - { - switch(choice) { - default: - case 0: // best score - which = "score-best"; - break; - case 1: // best time - which = "time-best"; - break; - case 2: // last - which = "last"; - break; - case 3: // staff - return; // M_HandleStaffReplay - case 4: // guest - which = "guest"; - break; - } - // srb2/replay/main/map01-score-best.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which)); - }*/ -} - -static void M_EraseGuest(INT32 choice) -{ - const char *rguest = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); - (void)choice; - if (FIL_FileExists(rguest)) - remove(rguest); - /*if (currentMenu == &SP_NightsGuestReplayDef) - M_SetupNextMenu(&SP_NightsAttackDef); - else*/ - M_SetupNextMenu(&SP_TimeAttackDef); - CV_AddValue(&cv_nextmap, -1); - CV_AddValue(&cv_nextmap, 1); - M_StartMessage(M_GetText("Guest replay data erased.\n"),NULL,MM_NOTHING); -} - -static void M_OverwriteGuest(const char *which) -{ - char *rguest = Z_StrDup(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); - UINT8 *buf; - size_t len; - len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which), &buf); - if (!len) { - return; - } - if (FIL_FileExists(rguest)) { - M_StopMessage(0); - remove(rguest); - } - FIL_WriteFile(rguest, buf, len); - Z_Free(rguest); - /*if (currentMenu == &SP_NightsGuestReplayDef) - M_SetupNextMenu(&SP_NightsAttackDef); - else*/ - M_SetupNextMenu(&SP_TimeAttackDef); - CV_AddValue(&cv_nextmap, -1); - CV_AddValue(&cv_nextmap, 1); - M_StartMessage(M_GetText("Guest replay data saved.\n"),NULL,MM_NOTHING); -} - -static void M_OverwriteGuest_Time(INT32 choice) -{ - (void)choice; - M_OverwriteGuest("time-best"); -} - -static void M_OverwriteGuest_Lap(INT32 choice) -{ - (void)choice; - M_OverwriteGuest("lap-best"); -} - -/* SRB2Kart -static void M_OverwriteGuest_Score(INT32 choice) -{ - (void)choice; - M_OverwriteGuest("score-best"); -} - -static void M_OverwriteGuest_Rings(INT32 choice) -{ - (void)choice; - M_OverwriteGuest("rings-best"); -}*/ - -static void M_OverwriteGuest_Last(INT32 choice) -{ - (void)choice; - M_OverwriteGuest("last"); -} - -static void M_SetGuestReplay(INT32 choice) -{ - void (*which)(INT32); - switch(choice) - { - case 0: // best time - which = M_OverwriteGuest_Time; - break; - case 1: // best lap - which = M_OverwriteGuest_Lap; - break; - case 2: // last - which = M_OverwriteGuest_Last; - break; - case 3: // guest - default: - M_StartMessage(M_GetText("Are you sure you want to\ndelete the guest replay data?\n\n(Press 'Y' to confirm)\n"),M_EraseGuest,MM_YESNO); - return; - } - if (FIL_FileExists(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)))) - M_StartMessage(M_GetText("Are you sure you want to\noverwrite the guest replay data?\n\n(Press 'Y' to confirm)\n"),which,MM_YESNO); - else - which(0); -} - -void M_ModeAttackRetry(INT32 choice) -{ - (void)choice; - G_CheckDemoStatus(); // Cancel recording - if (modeattacking) - M_ChooseTimeAttack(0); -} - -static void M_ModeAttackEndGame(INT32 choice) -{ - (void)choice; - G_CheckDemoStatus(); // Cancel recording - - if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING) - Command_ExitGame_f(); - - M_StartControlPanel(); - - if (modeattacking) - currentMenu = &SP_TimeAttackDef; - - itemOn = currentMenu->lastOn; - G_SetGamestate(GS_TIMEATTACK); - modeattacking = ATTACKING_NONE; - S_ChangeMusicInternal("racent", true); - // Update replay availability. - CV_AddValue(&cv_nextmap, 1); - CV_AddValue(&cv_nextmap, -1); -} - -// ======== -// END GAME -// ======== - -static void M_ExitGameResponse(INT32 ch) -{ - if (ch != 'y' && ch != KEY_ENTER) - return; - - //Command_ExitGame_f(); - G_SetExitGameFlag(); - M_ClearMenus(true); -} - -static void M_EndGame(INT32 choice) -{ - (void)choice; - if (demo.playback) - return; - - if (!Playing()) - return; - - M_StartMessage(M_GetText("Are you sure you want to end the game?\n\n(Press 'Y' to confirm)\n"), M_ExitGameResponse, MM_YESNO); -} - -//=========================================================================== -// Connect Menu -//=========================================================================== - -#define SERVERHEADERHEIGHT 44 -#define SERVERLINEHEIGHT 12 - -#define S_LINEY(n) currentMenu->y + SERVERHEADERHEIGHT + (n * SERVERLINEHEIGHT) - -#ifndef NONET -static UINT32 localservercount; - -static void M_HandleServerPage(INT32 choice) -{ - boolean exitmenu = false; // exit to previous menu - - switch (choice) - { - case KEY_DOWNARROW: - M_NextOpt(); - S_StartSound(NULL, sfx_menu1); - break; - case KEY_UPARROW: - M_PrevOpt(); - S_StartSound(NULL, sfx_menu1); - break; - case KEY_BACKSPACE: - case KEY_ESCAPE: - exitmenu = true; - break; - - case KEY_ENTER: - case KEY_RIGHTARROW: - S_StartSound(NULL, sfx_menu1); - if ((serverlistpage + 1) * SERVERS_PER_PAGE < serverlistcount) - serverlistpage++; - break; - case KEY_LEFTARROW: - S_StartSound(NULL, sfx_menu1); - if (serverlistpage > 0) - serverlistpage--; - break; - - default: - break; - } - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} - -static void M_Connect(INT32 choice) -{ - // do not call menuexitfunc - M_ClearMenus(false); - - COM_BufAddText(va("connect node %d\n", serverlist[choice-FIRSTSERVERLINE + serverlistpage * SERVERS_PER_PAGE].node)); -} - -static void M_Refresh(INT32 choice) -{ - (void)choice; - - // Display a little "please wait" message. - M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "Searching for servers..."); - V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait."); - I_OsPolling(); - I_UpdateNoBlit(); - if (rendermode == render_soft) - I_FinishUpdate(); // page flip or blit buffer - - // note: this is the one case where 0 is a valid room number - // because it corresponds to "All" - CL_UpdateServerList(!(ms_RoomId < 0), ms_RoomId); - - // first page of servers - serverlistpage = 0; -} - -static INT32 menuRoomIndex = 0; - -static void M_DrawRoomMenu(void) -{ - const char *rmotd; - - // use generic drawer for cursor, items and title - M_DrawGenericMenu(); - - V_DrawString(currentMenu->x - 16, currentMenu->y, highlightflags, M_GetText("Select a room")); - - M_DrawTextBox(144, 24, 20, 20); - - if (itemOn == 0) - rmotd = M_GetText("Don't connect to the Master Server."); - else - rmotd = room_list[itemOn-1].motd; - - rmotd = V_WordWrap(0, 20*8, 0, rmotd); - V_DrawString(144+8, 32, V_ALLOWLOWERCASE|V_RETURN8, rmotd); -} - -static void M_DrawConnectMenu(void) -{ - UINT16 i; - const char *gt = "Unknown"; - const char *spd = ""; - const char *pwr = "----"; - INT32 numPages = (serverlistcount+(SERVERS_PER_PAGE-1))/SERVERS_PER_PAGE; - - for (i = FIRSTSERVERLINE; i < min(localservercount, SERVERS_PER_PAGE)+FIRSTSERVERLINE; i++) - MP_ConnectMenu[i].status = IT_STRING | IT_SPACE; - - if (!numPages) - numPages = 1; - - // Room name - if (ms_RoomId < 0) - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ConnectMenu[mp_connect_room].alphaKey, - highlightflags, (itemOn == mp_connect_room) ? "" : ""); - else - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, - highlightflags, room_list[menuRoomIndex].name); -#undef mp_server_room - } -#endif -} - -static void M_MapChange(INT32 choice) -{ - (void)choice; - - levellistmode = LLM_CREATESERVER; - - CV_SetValue(&cv_newgametype, gametype); - CV_SetValue(&cv_nextmap, gamemap); - - M_PrepareLevelSelect(); - M_SetupNextMenu(&MISC_ChangeLevelDef); -} - -#ifndef TESTERS -static void M_StartOfflineServerMenu(INT32 choice) -{ - (void)choice; - levellistmode = LLM_CREATESERVER; - M_PrepareLevelSelect(); - M_SetupNextMenu(&MP_OfflineServerDef); -} -#endif - -#ifndef NONET -#ifndef TESTERS -static void M_StartServerMenu(INT32 choice) -{ - (void)choice; - levellistmode = LLM_CREATESERVER; - M_PrepareLevelSelect(); - ms_RoomId = -1; - M_SetupNextMenu(&MP_ServerDef); - -} -#endif - -// ============== -// CONNECT VIA IP -// ============== - -static char setupm_ip[28]; -#endif -static UINT8 setupm_pselect = 1; - -// Draw the funky Connect IP menu. Tails 11-19-2002 -// So much work for such a little thing! -static void M_DrawMPMainMenu(void) -{ - INT32 x = currentMenu->x; - INT32 y = currentMenu->y; - - // use generic drawer for cursor, items and title - M_DrawGenericMenu(); - -#ifndef NOMENUHOST -#if MAXPLAYERS != 16 -Update the maxplayers label... -#endif - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+MP_MainMenu[4].alphaKey, - ((itemOn == 4) ? highlightflags : 0), "(2-16 players)"); -#endif - -#ifndef TESTERS - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+MP_MainMenu[5].alphaKey, - ((itemOn == 5) ? highlightflags : 0), - "(2-4 players)" - ); -#endif - -#ifndef NONET - y += MP_MainMenu[8].alphaKey; - - V_DrawFill(x+5, y+4+5, /*16*8 + 6,*/ BASEVIDWIDTH - 2*(x+5), 8+6, 159); - - // draw name string - V_DrawString(x+8,y+12, V_ALLOWLOWERCASE, setupm_ip); - - // draw text cursor for name - if (itemOn == 8 - && skullAnimCounter < 4) //blink cursor - V_DrawCharacter(x+8+V_StringWidth(setupm_ip, V_ALLOWLOWERCASE),y+12,'_',false); -#endif - - // character bar, ripped off the color bar :V - { -#define iconwidth 32 -#define spacingwidth 32 -#define incrwidth (iconwidth + spacingwidth) - UINT8 i = 0, pskin, pcol; - // player arrangement width, but there's also a chance i'm a furry, shhhhhh - const INT32 paw = iconwidth + 3*incrwidth; - INT32 trans = 0; - UINT8 *colmap; - x = BASEVIDWIDTH/2 - paw/2; - y = currentMenu->y + 32; - - while (++i <= 4) - { - switch (i) - { - default: - pskin = R_SkinAvailable(cv_skin.string); - pcol = cv_playercolor.value; - break; - case 2: - pskin = R_SkinAvailable(cv_skin2.string); - pcol = cv_playercolor2.value; - break; - case 3: - pskin = R_SkinAvailable(cv_skin3.string); - pcol = cv_playercolor3.value; - break; - case 4: - pskin = R_SkinAvailable(cv_skin4.string); - pcol = cv_playercolor4.value; - break; - } - - if (pskin >= MAXSKINS) - pskin = 0; - - if (!trans && i > cv_splitplayers.value) - trans = V_TRANSLUCENT; - - colmap = R_GetTranslationColormap(pskin, pcol, GTC_MENUCACHE); - - V_DrawFixedPatch(x< 7) - cursorframe = 0; - V_DrawFixedPatch(x< 1) - { - if (--setupm_pselect < 1) - setupm_pselect = cv_splitplayers.value; - S_StartSound(NULL,sfx_menu1); // Tails - } - break; - - case KEY_RIGHTARROW: - if (cv_splitplayers.value > 1) - { - if (++setupm_pselect > cv_splitplayers.value) - setupm_pselect = 1; - S_StartSound(NULL,sfx_menu1); // Tails - } - break; - - case KEY_DOWNARROW: - M_NextOpt(); - S_StartSound(NULL,sfx_menu1); // Tails - break; - - case KEY_UPARROW: - M_PrevOpt(); - S_StartSound(NULL,sfx_menu1); // Tails - break; - - case KEY_ENTER: - { - S_StartSound(NULL,sfx_menu1); // Tails - currentMenu->lastOn = itemOn; - switch (setupm_pselect) - { - case 2: - M_SetupMultiPlayer2(0); - return; - case 3: - M_SetupMultiPlayer3(0); - return; - case 4: - M_SetupMultiPlayer4(0); - return; - default: - M_SetupMultiPlayer(0); - return; - } - break; - } - - case KEY_ESCAPE: - exitmenu = true; - break; - } - - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu (currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} - -#ifndef NONET - -// Tails 11-19-2002 -static void M_ConnectIP(INT32 choice) -{ - (void)choice; - - if (*setupm_ip == 0) - { - M_StartMessage("You must specify an IP address.\n", NULL, MM_NOTHING); - return; - } - - M_ClearMenus(true); - - COM_BufAddText(va("connect \"%s\"\n", setupm_ip)); - - // A little "please wait" message. - M_DrawTextBox(56, BASEVIDHEIGHT/2-12, 24, 2); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "Connecting to server..."); - I_OsPolling(); - I_UpdateNoBlit(); - if (rendermode == render_soft) - I_FinishUpdate(); // page flip or blit buffer -} - -// Tails 11-19-2002 -static void M_HandleConnectIP(INT32 choice) -{ - size_t l; - boolean exitmenu = false; // exit to previous menu and send name change - - switch (choice) - { - case KEY_DOWNARROW: - M_NextOpt(); - S_StartSound(NULL,sfx_menu1); // Tails - break; - - case KEY_UPARROW: - M_PrevOpt(); - S_StartSound(NULL,sfx_menu1); // Tails - break; - - case KEY_ENTER: - S_StartSound(NULL,sfx_menu1); // Tails - currentMenu->lastOn = itemOn; - M_ConnectIP(1); - break; - - case KEY_ESCAPE: - exitmenu = true; - break; - - case KEY_BACKSPACE: - if ((l = strlen(setupm_ip)) != 0) - { - S_StartSound(NULL,sfx_menu1); // Tails - setupm_ip[l-1] = 0; - } - break; - - case KEY_DEL: - if (setupm_ip[0]) - { - S_StartSound(NULL,sfx_menu1); // Tails - setupm_ip[0] = 0; - } - break; - - default: - l = strlen(setupm_ip); - if (l >= 28-1) - break; - - // Rudimentary number and period enforcing - also allows letters so hostnames can be used instead - if ((choice >= '-' && choice <= ':') || (choice >= 'A' && choice <= 'Z') || (choice >= 'a' && choice <= 'z')) - { - S_StartSound(NULL,sfx_menu1); // Tails - setupm_ip[l] = (char)choice; - setupm_ip[l+1] = 0; - } - else if (choice >= 199 && choice <= 211 && choice != 202 && choice != 206) //numpad too! - { - char keypad_translation[] = {'7','8','9','-','4','5','6','+','1','2','3','0','.'}; - choice = keypad_translation[choice - 199]; - S_StartSound(NULL,sfx_menu1); // Tails - setupm_ip[l] = (char)choice; - setupm_ip[l+1] = 0; - } - break; - } - - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu (currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} -#endif //!NONET - -// ======================== -// MULTIPLAYER PLAYER SETUP -// ======================== -// Tails 03-02-2002 - -static INT32 multi_tics; -static state_t *multi_state; - -// this is set before entering the MultiPlayer setup menu, -// for either player 1 or 2 -static char setupm_name[MAXPLAYERNAME+1]; -static player_t *setupm_player; -static consvar_t *setupm_cvskin; -static consvar_t *setupm_cvcolor; -static consvar_t *setupm_cvname; -static INT32 setupm_fakeskin; -static INT32 setupm_fakecolor; - -static void M_DrawSetupMultiPlayerMenu(void) -{ - INT32 mx, my, st, flags = 0; - spritedef_t *sprdef; - spriteframe_t *sprframe; - patch_t *statbg = W_CachePatchName("K_STATBG", PU_CACHE); - patch_t *statlr = W_CachePatchName("K_STATLR", PU_CACHE); - patch_t *statud = W_CachePatchName("K_STATUD", PU_CACHE); - patch_t *statdot = W_CachePatchName("K_SDOT0", PU_CACHE); - patch_t *patch; - UINT8 frame; - UINT8 speed; - UINT8 weight; - UINT8 i; - const UINT8 *flashcol = V_GetStringColormap(highlightflags); - INT32 statx, staty; - - mx = MP_PlayerSetupDef.x; - my = MP_PlayerSetupDef.y; - - statx = (BASEVIDWIDTH - mx - 118); - staty = (my+62); - - // use generic drawer for cursor, items and title - M_DrawGenericMenu(); - - // draw name string - M_DrawTextBox(mx + 32, my - 8, MAXPLAYERNAME, 1); - V_DrawString(mx + 40, my, V_ALLOWLOWERCASE, setupm_name); - - // draw text cursor for name - if (!itemOn && skullAnimCounter < 4) // blink cursor - V_DrawCharacter(mx + 40 + V_StringWidth(setupm_name, V_ALLOWLOWERCASE), my, '_',false); - - // draw skin string - st = V_StringWidth(skins[setupm_fakeskin].realname, 0); - V_DrawString(BASEVIDWIDTH - mx - st, my + 16, - ((MP_PlayerSetupMenu[2].status & IT_TYPE) == IT_SPACE ? V_TRANSLUCENT : 0)|highlightflags|V_ALLOWLOWERCASE, - skins[setupm_fakeskin].realname); - if (itemOn == 1) - { - V_DrawCharacter(BASEVIDWIDTH - mx - 10 - st - (skullAnimCounter/5), my + 16, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - mx + 2 + (skullAnimCounter/5), my + 16, - '\x1D' | highlightflags, false); // right arrow - } - - // draw the name of the color you have chosen - // Just so people don't go thinking that "Default" is Green. - st = V_StringWidth(KartColor_Names[setupm_fakecolor], 0); - V_DrawString(BASEVIDWIDTH - mx - st, my + 152, highlightflags|V_ALLOWLOWERCASE, KartColor_Names[setupm_fakecolor]); // SRB2kart - if (itemOn == 2) - { - V_DrawCharacter(BASEVIDWIDTH - mx - 10 - st - (skullAnimCounter/5), my + 152, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - mx + 2 + (skullAnimCounter/5), my + 152, - '\x1D' | highlightflags, false); // right arrow - } - - // SRB2Kart: draw the stat backer - // labels - V_DrawThinString(statx+16, staty, V_6WIDTHSPACE|highlightflags, "Acceleration"); - V_DrawThinString(statx+91, staty, V_6WIDTHSPACE|highlightflags, "Max Speed"); - V_DrawThinString(statx, staty+12, V_6WIDTHSPACE|highlightflags, "Handling"); - V_DrawThinString(statx+7, staty+77, V_6WIDTHSPACE|highlightflags, "Weight"); - // label arrows - V_DrawFixedPatch((statx+64)<= MAXSKINCOLORS) - col -= MAXSKINCOLORS-1; - x += w; - } - } -#undef indexwidth - - // character bar, ripped off the color bar :V - if (setupm_fakecolor) // inverse should never happen -#define iconwidth 32 - { - const INT32 icons = 4; - INT32 k = -icons; - INT16 col = setupm_fakeskin - icons; - INT32 x = BASEVIDWIDTH/2 - ((icons+1)*24) - 4; - fixed_t scale = FRACUNIT/2; - INT32 offx = 8, offy = 8; - patch_t *cursor; - static UINT8 cursorframe = 0; - patch_t *face; - UINT8 *colmap; - - if (skullAnimCounter % 4 == 0) - cursorframe++; - if (cursorframe > 7) - cursorframe = 0; - - cursor = W_CachePatchName(va("K_BHILI%d", cursorframe+1), PU_CACHE); - - if (col < 0) - col += numskins; - while (k <= icons) - { - if (!(k++)) - { - scale = FRACUNIT; - face = facewantprefix[col]; - offx = 12; - offy = 0; - } - else - { - scale = FRACUNIT/2; - face = facerankprefix[col]; - offx = 8; - offy = 8; - } - colmap = R_GetTranslationColormap(col, setupm_fakecolor, GTC_MENUCACHE); - V_DrawFixedPatch((x+offx)<= numskins) - col -= numskins; - x += FixedMul(iconwidth<nextstate; - if (st != S_NULL) - multi_state = &states[st]; - multi_tics = multi_state->tics; - if (multi_tics == -1) - multi_tics = 15; - } - - // skin 0 is default player sprite - if (R_SkinAvailable(skins[setupm_fakeskin].name) != -1) - sprdef = &skins[R_SkinAvailable(skins[setupm_fakeskin].name)].spritedef; - else - sprdef = &skins[0].spritedef; - - if (!sprdef->numframes) // No frames ?? - return; // Can't render! - - frame = multi_state->frame & FF_FRAMEMASK; - if (frame >= sprdef->numframes) // Walking animation missing - frame = 0; // Try to use standing frame - - sprframe = &sprdef->spriteframes[frame]; - patch = W_CachePatchNum(sprframe->lumppat[1], PU_CACHE); - if (sprframe->flip & 1) // Only for first sprite - flags |= V_FLIP; // This sprite is left/right flipped! - - // draw box around guy - V_DrawFill(mx + 43 - (charw/2), my+65, charw, 84, 159); - - // draw player sprite - if (setupm_fakecolor) // inverse should never happen - { - UINT8 *colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor, GTC_MENUCACHE); - - if (skins[setupm_fakeskin].flags & SF_HIRES) - { - V_DrawFixedPatch((mx+43)< 127 || itemOn != 0) - break; - l = strlen(setupm_name); - if (l < MAXPLAYERNAME) - { - S_StartSound(NULL,sfx_menu1); // Tails - setupm_name[l] =(char)choice; - setupm_name[l+1] =0; - } - break; - } - - // check skin - if (setupm_fakeskin < 0) - setupm_fakeskin = numskins-1; - if (setupm_fakeskin > numskins-1) - setupm_fakeskin = 0; - - // check color - if (setupm_fakecolor < 1) - setupm_fakecolor = MAXSKINCOLORS-1; - if (setupm_fakecolor > MAXSKINCOLORS-1) - setupm_fakecolor = 1; - - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu (currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} - -// start the multiplayer setup menu -static void M_SetupMultiPlayer(INT32 choice) -{ - (void)choice; - - multi_state = &states[mobjinfo[MT_PLAYER].seestate]; - multi_tics = multi_state->tics; - strcpy(setupm_name, cv_playername.string); - - // set for player 1 - setupm_player = &players[consoleplayer]; - setupm_cvskin = &cv_skin; - setupm_cvcolor = &cv_playercolor; - setupm_cvname = &cv_playername; - - // For whatever reason this doesn't work right if you just use ->value - setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); - if (setupm_fakeskin == -1) - setupm_fakeskin = 0; - setupm_fakecolor = setupm_cvcolor->value; - - // disable skin changes if we can't actually change skins - if (!CanChangeSkin(consoleplayer)) - MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); - else - MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING); - - MP_PlayerSetupDef.prevMenu = currentMenu; - M_SetupNextMenu(&MP_PlayerSetupDef); -} - -// start the multiplayer setup menu, for secondary player (splitscreen mode) -static void M_SetupMultiPlayer2(INT32 choice) -{ - (void)choice; - - multi_state = &states[mobjinfo[MT_PLAYER].seestate]; - multi_tics = multi_state->tics; - strcpy (setupm_name, cv_playername2.string); - - // set for splitscreen secondary player - setupm_player = &players[g_localplayers[1]]; - setupm_cvskin = &cv_skin2; - setupm_cvcolor = &cv_playercolor2; - setupm_cvname = &cv_playername2; - - // For whatever reason this doesn't work right if you just use ->value - setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); - if (setupm_fakeskin == -1) - setupm_fakeskin = 0; - setupm_fakecolor = setupm_cvcolor->value; - - // disable skin changes if we can't actually change skins - if (splitscreen && !CanChangeSkin(g_localplayers[1])) - MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); - else - MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); - - MP_PlayerSetupDef.prevMenu = currentMenu; - M_SetupNextMenu(&MP_PlayerSetupDef); -} - -// start the multiplayer setup menu, for third player (splitscreen mode) -static void M_SetupMultiPlayer3(INT32 choice) -{ - (void)choice; - - multi_state = &states[mobjinfo[MT_PLAYER].seestate]; - multi_tics = multi_state->tics; - strcpy(setupm_name, cv_playername3.string); - - // set for splitscreen third player - setupm_player = &players[g_localplayers[2]]; - setupm_cvskin = &cv_skin3; - setupm_cvcolor = &cv_playercolor3; - setupm_cvname = &cv_playername3; - - // For whatever reason this doesn't work right if you just use ->value - setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); - if (setupm_fakeskin == -1) - setupm_fakeskin = 0; - setupm_fakecolor = setupm_cvcolor->value; - - // disable skin changes if we can't actually change skins - if (splitscreen > 1 && !CanChangeSkin(g_localplayers[2])) - MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); - else - MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); - - MP_PlayerSetupDef.prevMenu = currentMenu; - M_SetupNextMenu(&MP_PlayerSetupDef); -} - -// start the multiplayer setup menu, for third player (splitscreen mode) -static void M_SetupMultiPlayer4(INT32 choice) -{ - (void)choice; - - multi_state = &states[mobjinfo[MT_PLAYER].seestate]; - multi_tics = multi_state->tics; - strcpy(setupm_name, cv_playername4.string); - - // set for splitscreen fourth player - setupm_player = &players[g_localplayers[3]]; - setupm_cvskin = &cv_skin4; - setupm_cvcolor = &cv_playercolor4; - setupm_cvname = &cv_playername4; - - // For whatever reason this doesn't work right if you just use ->value - setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); - if (setupm_fakeskin == -1) - setupm_fakeskin = 0; - setupm_fakecolor = setupm_cvcolor->value; - - // disable skin changes if we can't actually change skins - if (splitscreen > 2 && !CanChangeSkin(g_localplayers[3])) - MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); - else - MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); - - MP_PlayerSetupDef.prevMenu = currentMenu; - M_SetupNextMenu(&MP_PlayerSetupDef); -} - -static boolean M_QuitMultiPlayerMenu(void) -{ - size_t l; - // send name if changed - if (strcmp(setupm_name, setupm_cvname->string)) - { - // remove trailing whitespaces - for (l= strlen(setupm_name)-1; - (signed)l >= 0 && setupm_name[l] ==' '; l--) - setupm_name[l] =0; - COM_BufAddText (va("%s \"%s\"\n",setupm_cvname->name,setupm_name)); - } - // you know what? always putting these in the buffer won't hurt anything. - COM_BufAddText (va("%s \"%s\"\n",setupm_cvskin->name,skins[setupm_fakeskin].name)); - COM_BufAddText (va("%s %d\n",setupm_cvcolor->name,setupm_fakecolor)); - return true; -} - -// ================= -// DATA OPTIONS MENU -// ================= -static UINT8 erasecontext = 0; - -static void M_EraseDataResponse(INT32 ch) -{ - UINT8 i; - - if (ch != 'y' && ch != KEY_ENTER) - return; - - S_StartSound(NULL, sfx_itrole); // bweh heh heh - - // Delete the data - if (erasecontext == 2) - { - // SRB2Kart: This actually needs to be done FIRST, so that you don't immediately regain playtime/matches secrets - totalplaytime = 0; - matchesplayed = 0; - for (i = 0; i < PWRLV_NUMTYPES; i++) - vspowerlevel[i] = PWRLVRECORD_START; - F_StartIntro(); - } - if (erasecontext != 1) - G_ClearRecords(); - if (erasecontext != 0) - M_ClearSecrets(); - M_ClearMenus(true); -} - -static void M_EraseData(INT32 choice) -{ - const char *eschoice, *esstr = M_GetText("Are you sure you want to erase\n%s?\n\n(Press 'Y' to confirm)\n"); - - erasecontext = (UINT8)choice; - - if (choice == 0) - eschoice = M_GetText("Record Attack data"); - else if (choice == 1) - eschoice = M_GetText("Secrets data"); - else - eschoice = M_GetText("ALL game data"); - - M_StartMessage(va(esstr, eschoice),M_EraseDataResponse,MM_YESNO); -} - -static void M_ScreenshotOptions(INT32 choice) -{ - (void)choice; - Screenshot_option_Onchange(); - Moviemode_mode_Onchange(); - - M_SetupNextMenu(&OP_ScreenshotOptionsDef); -} - -// ============= -// JOYSTICK MENU -// ============= - -// Start the controls menu, setting it up for either the console player, -// or the secondary splitscreen player - -static void M_DrawJoystick(void) -{ - INT32 i, compareval4, compareval3, compareval2, compareval; - - M_DrawGenericMenu(); - - for (i = 0; i < 8; i++) - { - M_DrawTextBox(OP_JoystickSetDef.x-8, OP_JoystickSetDef.y+LINEHEIGHT*i-12, 28, 1); - //M_DrawSaveLoadBorder(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i); - -#ifdef JOYSTICK_HOTPLUG - if (atoi(cv_usejoystick4.string) > I_NumJoys()) - compareval4 = atoi(cv_usejoystick4.string); - else - compareval4 = cv_usejoystick4.value; - - if (atoi(cv_usejoystick3.string) > I_NumJoys()) - compareval3 = atoi(cv_usejoystick3.string); - else - compareval3 = cv_usejoystick3.value; - - if (atoi(cv_usejoystick2.string) > I_NumJoys()) - compareval2 = atoi(cv_usejoystick2.string); - else - compareval2 = cv_usejoystick2.value; - - if (atoi(cv_usejoystick.string) > I_NumJoys()) - compareval = atoi(cv_usejoystick.string); - else - compareval = cv_usejoystick.value; -#else - compareval4 = cv_usejoystick4.value; - compareval3 = cv_usejoystick3.value; - compareval2 = cv_usejoystick2.value; - compareval = cv_usejoystick.value -#endif - - if ((setupcontrolplayer == 4 && (i == compareval4)) - || (setupcontrolplayer == 3 && (i == compareval3)) - || (setupcontrolplayer == 2 && (i == compareval2)) - || (setupcontrolplayer == 1 && (i == compareval))) - V_DrawString(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i-4,V_GREENMAP,joystickInfo[i]); - else - V_DrawString(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i-4,0,joystickInfo[i]); - } -} - -void M_SetupJoystickMenu(INT32 choice) -{ - INT32 i = 0; - const char *joyNA = "Unavailable"; - INT32 n = I_NumJoys(); - (void)choice; - - strcpy(joystickInfo[i], "None"); - - for (i = 1; i < 8; i++) - { - if (i <= n && (I_GetJoyName(i)) != NULL) - strncpy(joystickInfo[i], I_GetJoyName(i), 28); - else - strcpy(joystickInfo[i], joyNA); - -#ifdef JOYSTICK_HOTPLUG - // We use cv_usejoystick.string as the USER-SET var - // and cv_usejoystick.value as the INTERNAL var - // - // In practice, if cv_usejoystick.string == 0, this overrides - // cv_usejoystick.value and always disables - // - // Update cv_usejoystick.string here so that the user can - // properly change this value. - if (i == cv_usejoystick.value) - CV_SetValue(&cv_usejoystick, i); - if (i == cv_usejoystick2.value) - CV_SetValue(&cv_usejoystick2, i); - if (i == cv_usejoystick3.value) - CV_SetValue(&cv_usejoystick3, i); - if (i == cv_usejoystick4.value) - CV_SetValue(&cv_usejoystick4, i); -#endif - } - - M_SetupNextMenu(&OP_JoystickSetDef); -} - -static void M_Setup1PJoystickMenu(INT32 choice) -{ - setupcontrolplayer = 1; - OP_JoystickSetDef.prevMenu = &OP_Joystick1Def; - M_SetupJoystickMenu(choice); -} - -static void M_Setup2PJoystickMenu(INT32 choice) -{ - setupcontrolplayer = 2; - OP_JoystickSetDef.prevMenu = &OP_Joystick2Def; - M_SetupJoystickMenu(choice); -} - -static void M_Setup3PJoystickMenu(INT32 choice) -{ - setupcontrolplayer = 3; - OP_JoystickSetDef.prevMenu = &OP_Joystick3Def; - M_SetupJoystickMenu(choice); -} - -static void M_Setup4PJoystickMenu(INT32 choice) -{ - setupcontrolplayer = 4; - OP_JoystickSetDef.prevMenu = &OP_Joystick4Def; - M_SetupJoystickMenu(choice); -} - -static void M_AssignJoystick(INT32 choice) -{ -#ifdef JOYSTICK_HOTPLUG - INT32 oldchoice, oldstringchoice; - INT32 numjoys = I_NumJoys(); - - if (setupcontrolplayer == 4) - { - oldchoice = oldstringchoice = atoi(cv_usejoystick4.string) > numjoys ? atoi(cv_usejoystick4.string) : cv_usejoystick4.value; - CV_SetValue(&cv_usejoystick4, choice); - - // Just in case last-minute changes were made to cv_usejoystick.value, - // update the string too - // But don't do this if we're intentionally setting higher than numjoys - if (choice <= numjoys) - { - CV_SetValue(&cv_usejoystick4, cv_usejoystick4.value); - - // reset this so the comparison is valid - if (oldchoice > numjoys) - oldchoice = cv_usejoystick4.value; - - if (oldchoice != choice) - { - if (choice && oldstringchoice > numjoys) // if we did not select "None", we likely selected a used device - CV_SetValue(&cv_usejoystick4, (oldstringchoice > numjoys ? oldstringchoice : oldchoice)); - - if (oldstringchoice == - (atoi(cv_usejoystick4.string) > numjoys ? atoi(cv_usejoystick4.string) : cv_usejoystick4.value)) - M_StartMessage("This joystick is used by another\n" - "player. Reset the joystick\n" - "for that player first.\n\n" - "(Press a key)\n", NULL, MM_NOTHING); - } - } - } - else if (setupcontrolplayer == 3) - { - oldchoice = oldstringchoice = atoi(cv_usejoystick3.string) > numjoys ? atoi(cv_usejoystick3.string) : cv_usejoystick3.value; - CV_SetValue(&cv_usejoystick3, choice); - - // Just in case last-minute changes were made to cv_usejoystick.value, - // update the string too - // But don't do this if we're intentionally setting higher than numjoys - if (choice <= numjoys) - { - CV_SetValue(&cv_usejoystick3, cv_usejoystick3.value); - - // reset this so the comparison is valid - if (oldchoice > numjoys) - oldchoice = cv_usejoystick3.value; - - if (oldchoice != choice) - { - if (choice && oldstringchoice > numjoys) // if we did not select "None", we likely selected a used device - CV_SetValue(&cv_usejoystick3, (oldstringchoice > numjoys ? oldstringchoice : oldchoice)); - - if (oldstringchoice == - (atoi(cv_usejoystick3.string) > numjoys ? atoi(cv_usejoystick3.string) : cv_usejoystick3.value)) - M_StartMessage("This joystick is used by another\n" - "player. Reset the joystick\n" - "for that player first.\n\n" - "(Press a key)\n", NULL, MM_NOTHING); - } - } - } - else if (setupcontrolplayer == 2) - { - oldchoice = oldstringchoice = atoi(cv_usejoystick2.string) > numjoys ? atoi(cv_usejoystick2.string) : cv_usejoystick2.value; - CV_SetValue(&cv_usejoystick2, choice); - - // Just in case last-minute changes were made to cv_usejoystick.value, - // update the string too - // But don't do this if we're intentionally setting higher than numjoys - if (choice <= numjoys) - { - CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value); - - // reset this so the comparison is valid - if (oldchoice > numjoys) - oldchoice = cv_usejoystick2.value; - - if (oldchoice != choice) - { - if (choice && oldstringchoice > numjoys) // if we did not select "None", we likely selected a used device - CV_SetValue(&cv_usejoystick2, (oldstringchoice > numjoys ? oldstringchoice : oldchoice)); - - if (oldstringchoice == - (atoi(cv_usejoystick2.string) > numjoys ? atoi(cv_usejoystick2.string) : cv_usejoystick2.value)) - M_StartMessage("This joystick is used by another\n" - "player. Reset the joystick\n" - "for that player first.\n\n" - "(Press a key)\n", NULL, MM_NOTHING); - } - } - } - else if (setupcontrolplayer == 1) - { - oldchoice = oldstringchoice = atoi(cv_usejoystick.string) > numjoys ? atoi(cv_usejoystick.string) : cv_usejoystick.value; - CV_SetValue(&cv_usejoystick, choice); - - // Just in case last-minute changes were made to cv_usejoystick.value, - // update the string too - // But don't do this if we're intentionally setting higher than numjoys - if (choice <= numjoys) - { - CV_SetValue(&cv_usejoystick, cv_usejoystick.value); - - // reset this so the comparison is valid - if (oldchoice > numjoys) - oldchoice = cv_usejoystick.value; - - if (oldchoice != choice) - { - if (choice && oldstringchoice > numjoys) // if we did not select "None", we likely selected a used device - CV_SetValue(&cv_usejoystick, (oldstringchoice > numjoys ? oldstringchoice : oldchoice)); - - if (oldstringchoice == - (atoi(cv_usejoystick.string) > numjoys ? atoi(cv_usejoystick.string) : cv_usejoystick.value)) - M_StartMessage("This joystick is used by another\n" - "player. Reset the joystick\n" - "for that player first.\n\n" - "(Press a key)\n", NULL, MM_NOTHING); - } - } - } -#else - if (setupcontrolplayer == 4) - CV_SetValue(&cv_usejoystick4, choice); - else if (setupcontrolplayer == 3) - CV_SetValue(&cv_usejoystick3, choice); - else if (setupcontrolplayer == 2) - CV_SetValue(&cv_usejoystick2, choice); - else if (setupcontrolplayer == 1) - CV_SetValue(&cv_usejoystick, choice); -#endif -} - -// ============= -// CONTROLS MENU -// ============= - -static void M_Setup1PControlsMenu(INT32 choice) -{ - (void)choice; - setupcontrolplayer = 1; - setupcontrols = gamecontrol; // was called from main Options (for console player, then) - currentMenu->lastOn = itemOn; - - // Set proper gamepad options - OP_AllControlsMenu[0].itemaction = &OP_Joystick1Def; - - // Unhide P1-only controls - OP_AllControlsMenu[15].status = IT_CONTROL; // Chat - //OP_AllControlsMenu[16].status = IT_CONTROL; // Team-chat - OP_AllControlsMenu[16].status = IT_CONTROL; // Rankings - //OP_AllControlsMenu[17].status = IT_CONTROL; // Viewpoint - // 18 is Reset Camera, 19 is Toggle Chasecam - OP_AllControlsMenu[20].status = IT_CONTROL; // Pause - OP_AllControlsMenu[21].status = IT_CONTROL; // Screenshot - OP_AllControlsMenu[22].status = IT_CONTROL; // GIF - OP_AllControlsMenu[23].status = IT_CONTROL; // System Menu - OP_AllControlsMenu[24].status = IT_CONTROL; // Console - /*OP_AllControlsMenu[25].status = IT_HEADER; // Spectator Controls header - OP_AllControlsMenu[26].status = IT_SPACE; // Spectator Controls space - OP_AllControlsMenu[27].status = IT_CONTROL; // Spectate - OP_AllControlsMenu[28].status = IT_CONTROL; // Look Up - OP_AllControlsMenu[29].status = IT_CONTROL; // Look Down - OP_AllControlsMenu[30].status = IT_CONTROL; // Center View - */ - - M_SetupNextMenu(&OP_AllControlsDef); -} - -static void M_Setup2PControlsMenu(INT32 choice) -{ - (void)choice; - setupcontrolplayer = 2; - setupcontrols = gamecontrolbis; - currentMenu->lastOn = itemOn; - - // Set proper gamepad options - OP_AllControlsMenu[0].itemaction = &OP_Joystick2Def; - - // Hide P1-only controls - OP_AllControlsMenu[15].status = IT_GRAYEDOUT2; // Chat - //OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Team-chat - OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Rankings - //OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint - // 18 is Reset Camera, 19 is Toggle Chasecam - OP_AllControlsMenu[20].status = IT_GRAYEDOUT2; // Pause - OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // Screenshot - OP_AllControlsMenu[22].status = IT_GRAYEDOUT2; // GIF - OP_AllControlsMenu[23].status = IT_GRAYEDOUT2; // System Menu - OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Console - /*OP_AllControlsMenu[25].status = IT_GRAYEDOUT2; // Spectator Controls header - OP_AllControlsMenu[26].status = IT_GRAYEDOUT2; // Spectator Controls space - OP_AllControlsMenu[27].status = IT_GRAYEDOUT2; // Spectate - OP_AllControlsMenu[28].status = IT_GRAYEDOUT2; // Look Up - OP_AllControlsMenu[29].status = IT_GRAYEDOUT2; // Look Down - OP_AllControlsMenu[30].status = IT_GRAYEDOUT2; // Center View - */ - - M_SetupNextMenu(&OP_AllControlsDef); -} - -static void M_Setup3PControlsMenu(INT32 choice) -{ - (void)choice; - setupcontrolplayer = 3; - setupcontrols = gamecontrol3; - currentMenu->lastOn = itemOn; - - // Set proper gamepad options - OP_AllControlsMenu[0].itemaction = &OP_Joystick3Def; - - // Hide P1-only controls - OP_AllControlsMenu[15].status = IT_GRAYEDOUT2; // Chat - //OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Team-chat - OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Rankings - //OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint - // 18 is Reset Camera, 19 is Toggle Chasecam - OP_AllControlsMenu[20].status = IT_GRAYEDOUT2; // Pause - OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // Screenshot - OP_AllControlsMenu[22].status = IT_GRAYEDOUT2; // GIF - OP_AllControlsMenu[23].status = IT_GRAYEDOUT2; // System Menu - OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Console - /*OP_AllControlsMenu[25].status = IT_GRAYEDOUT2; // Spectator Controls header - OP_AllControlsMenu[26].status = IT_GRAYEDOUT2; // Spectator Controls space - OP_AllControlsMenu[27].status = IT_GRAYEDOUT2; // Spectate - OP_AllControlsMenu[28].status = IT_GRAYEDOUT2; // Look Up - OP_AllControlsMenu[29].status = IT_GRAYEDOUT2; // Look Down - OP_AllControlsMenu[30].status = IT_GRAYEDOUT2; // Center View - */ - - M_SetupNextMenu(&OP_AllControlsDef); -} - -static void M_Setup4PControlsMenu(INT32 choice) -{ - (void)choice; - setupcontrolplayer = 4; - setupcontrols = gamecontrol4; - currentMenu->lastOn = itemOn; - - // Set proper gamepad options - OP_AllControlsMenu[0].itemaction = &OP_Joystick4Def; - - // Hide P1-only controls - OP_AllControlsMenu[15].status = IT_GRAYEDOUT2; // Chat - //OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Team-chat - OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Rankings - //OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint - // 18 is Reset Camera, 19 is Toggle Chasecam - OP_AllControlsMenu[20].status = IT_GRAYEDOUT2; // Pause - OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // Screenshot - OP_AllControlsMenu[22].status = IT_GRAYEDOUT2; // GIF - OP_AllControlsMenu[23].status = IT_GRAYEDOUT2; // System Menu - OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Console - /*OP_AllControlsMenu[25].status = IT_GRAYEDOUT2; // Spectator Controls header - OP_AllControlsMenu[26].status = IT_GRAYEDOUT2; // Spectator Controls space - OP_AllControlsMenu[27].status = IT_GRAYEDOUT2; // Spectate - OP_AllControlsMenu[28].status = IT_GRAYEDOUT2; // Look Up - OP_AllControlsMenu[29].status = IT_GRAYEDOUT2; // Look Down - OP_AllControlsMenu[30].status = IT_GRAYEDOUT2; // Center View - */ - - M_SetupNextMenu(&OP_AllControlsDef); -} - -#define controlheight 18 - -// Draws the Customise Controls menu -static void M_DrawControl(void) -{ - char tmp[50]; - INT32 x, y, i, max, cursory = 0, iter; - INT32 keys[2]; - - x = currentMenu->x; - y = currentMenu->y; - - /*i = itemOn - (controlheight/2); - if (i < 0) - i = 0; - */ - - iter = (controlheight/2); - for (i = itemOn; ((iter || currentMenu->menuitems[i].status == IT_GRAYEDOUT2) && i > 0); i--) - { - if (currentMenu->menuitems[i].status != IT_GRAYEDOUT2) - iter--; - } - if (currentMenu->menuitems[i].status == IT_GRAYEDOUT2) - i--; - - iter += (controlheight/2); - for (max = itemOn; (iter && max < currentMenu->numitems); max++) - { - if (currentMenu->menuitems[max].status != IT_GRAYEDOUT2) - iter--; - } - - if (iter) - { - iter += (controlheight/2); - for (i = itemOn; ((iter || currentMenu->menuitems[i].status == IT_GRAYEDOUT2) && i > 0); i--) - { - if (currentMenu->menuitems[i].status != IT_GRAYEDOUT2) - iter--; - } - } - - /*max = i + controlheight; - if (max > currentMenu->numitems) - { - max = currentMenu->numitems; - if (max < controlheight) - i = 0; - else - i = max - controlheight; - }*/ - - // draw title (or big pic) - M_DrawMenuTitle(); - - M_CentreText(28, - (setupcontrolplayer > 1 ? va("\x86""Set controls for ""\x82""Player %d", setupcontrolplayer) : - "\x86""Press ""\x82""ENTER""\x86"" to change, ""\x82""BACKSPACE""\x86"" to clear")); - - if (i) - V_DrawCharacter(currentMenu->x - 16, y-(skullAnimCounter/5), - '\x1A' | highlightflags, false); // up arrow - if (max != currentMenu->numitems) - V_DrawCharacter(currentMenu->x - 16, y+(SMALLLINEHEIGHT*(controlheight-1))+(skullAnimCounter/5) + (skullAnimCounter/5), - '\x1B' | highlightflags, false); // down arrow - - for (; i < max; i++) - { - if (currentMenu->menuitems[i].status == IT_GRAYEDOUT2) - continue; - - if (i == itemOn) - cursory = y; - - if (currentMenu->menuitems[i].status == IT_CONTROL) - { - V_DrawString(x, y, ((i == itemOn) ? highlightflags : 0), currentMenu->menuitems[i].text); - keys[0] = setupcontrols[currentMenu->menuitems[i].alphaKey][0]; - keys[1] = setupcontrols[currentMenu->menuitems[i].alphaKey][1]; - - tmp[0] ='\0'; - if (keys[0] == KEY_NULL && keys[1] == KEY_NULL) - { - strcpy(tmp, "---"); - } - else - { - if (keys[0] != KEY_NULL) - strcat (tmp, G_KeynumToString (keys[0])); - - if (keys[0] != KEY_NULL && keys[1] != KEY_NULL) - strcat(tmp,", "); - - if (keys[1] != KEY_NULL) - strcat (tmp, G_KeynumToString (keys[1])); - - } - V_DrawRightAlignedString(BASEVIDWIDTH-currentMenu->x, y, highlightflags, tmp); - } - /*else if (currentMenu->menuitems[i].status == IT_GRAYEDOUT2) - V_DrawString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text);*/ - else if ((currentMenu->menuitems[i].status == IT_HEADER) && (i != max-1)) - V_DrawString(19, y+6, highlightflags, currentMenu->menuitems[i].text); - else if (currentMenu->menuitems[i].status & IT_STRING) - V_DrawString(x, y, ((i == itemOn) ? highlightflags : 0), currentMenu->menuitems[i].text); - - y += SMALLLINEHEIGHT; - } - - V_DrawScaledPatch(currentMenu->x - 20, cursory, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); -} - -#undef controlheight - -static INT32 controltochange; -static char controltochangetext[33]; - -static void M_ChangecontrolResponse(event_t *ev) -{ - INT32 control; - INT32 found; - INT32 ch = ev->data1; - - // ESCAPE cancels; dummy out PAUSE - if (ch != KEY_ESCAPE && ch != KEY_PAUSE) - { - - switch (ev->type) - { - // ignore mouse/joy movements, just get buttons - case ev_mouse: - case ev_mouse2: - case ev_joystick: - case ev_joystick2: - case ev_joystick3: - case ev_joystick4: - ch = KEY_NULL; // no key - break; - - // keypad arrows are converted for the menu in cursor arrows - // so use the event instead of ch - case ev_keydown: - ch = ev->data1; - break; - - default: - break; - } - - control = controltochange; - - // check if we already entered this key - found = -1; - if (setupcontrols[control][0] ==ch) - found = 0; - else if (setupcontrols[control][1] ==ch) - found = 1; - if (found >= 0) - { - // replace mouse and joy clicks by double clicks - if (ch >= KEY_MOUSE1 && ch <= KEY_MOUSE1+MOUSEBUTTONS) - setupcontrols[control][found] = ch-KEY_MOUSE1+KEY_DBLMOUSE1; - else if (ch >= KEY_JOY1 && ch <= KEY_JOY1+JOYBUTTONS) - setupcontrols[control][found] = ch-KEY_JOY1+KEY_DBLJOY1; - else if (ch >= KEY_2MOUSE1 && ch <= KEY_2MOUSE1+MOUSEBUTTONS) - setupcontrols[control][found] = ch-KEY_2MOUSE1+KEY_DBL2MOUSE1; - else if (ch >= KEY_2JOY1 && ch <= KEY_2JOY1+JOYBUTTONS) - setupcontrols[control][found] = ch-KEY_2JOY1+KEY_DBL2JOY1; - else if (ch >= KEY_3JOY1 && ch <= KEY_3JOY1+JOYBUTTONS) - setupcontrols[control][found] = ch-KEY_3JOY1+KEY_DBL3JOY1; - else if (ch >= KEY_4JOY1 && ch <= KEY_4JOY1+JOYBUTTONS) - setupcontrols[control][found] = ch-KEY_4JOY1+KEY_DBL4JOY1; - } - else - { - // check if change key1 or key2, or replace the two by the new - found = 0; - if (setupcontrols[control][0] == KEY_NULL) - found++; - if (setupcontrols[control][1] == KEY_NULL) - found++; - if (found == 2) - { - found = 0; - setupcontrols[control][1] = KEY_NULL; //replace key 1,clear key2 - } - (void)G_CheckDoubleUsage(ch, true); - setupcontrols[control][found] = ch; - } - S_StartSound(NULL, sfx_s221); - } - else if (ch == KEY_PAUSE) - { - // This buffer assumes a 125-character message plus a 32-character control name (per controltochangetext buffer size) - static char tmp[158]; - menu_t *prev = currentMenu->prevMenu; - - if (controltochange == gc_pause) - sprintf(tmp, M_GetText("The \x82Pause Key \x80is enabled, but \nyou may select another key. \n\nHit another key for\n%s\nESC for Cancel"), - controltochangetext); - else - sprintf(tmp, M_GetText("The \x82Pause Key \x80is enabled, but \nit is not configurable. \n\nHit another key for\n%s\nESC for Cancel"), - controltochangetext); - - M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER); - currentMenu->prevMenu = prev; - - S_StartSound(NULL, sfx_s3k42); - return; - } - else - S_StartSound(NULL, sfx_s224); - - M_StopMessage(0); -} - -static void M_ChangeControl(INT32 choice) -{ - // This buffer assumes a 35-character message (per below) plus a max control name limit of 32 chars (per controltochangetext) - // If you change the below message, then change the size of this buffer! - static char tmp[68]; - - controltochange = currentMenu->menuitems[choice].alphaKey; - sprintf(tmp, M_GetText("Hit the new key for\n%s\nESC for Cancel"), - currentMenu->menuitems[choice].text); - strlcpy(controltochangetext, currentMenu->menuitems[choice].text, 33); - - M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER); -} - -static void M_ResetControlsResponse(INT32 ch) -{ - INT32 i; - - if (ch != 'y' && ch != KEY_ENTER) - return; - - // clear all controls - for (i = 0; i < num_gamecontrols; i++) - { - switch (setupcontrolplayer) - { - case 4: - G_ClearControlKeys(gamecontrol4, i); - break; - case 3: - G_ClearControlKeys(gamecontrol3, i); - break; - case 2: - G_ClearControlKeys(gamecontrolbis, i); - break; - case 1: - default: - G_ClearControlKeys(gamecontrol, i); - break; - } - } - - // Setup original defaults - G_Controldefault(setupcontrolplayer); - - // Setup gamepad option defaults (yucky) - switch (setupcontrolplayer) - { - case 4: - CV_StealthSet(&cv_usejoystick4, cv_usejoystick4.defaultvalue); - CV_StealthSet(&cv_turnaxis4, cv_turnaxis4.defaultvalue); - CV_StealthSet(&cv_moveaxis4, cv_moveaxis4.defaultvalue); - CV_StealthSet(&cv_brakeaxis4, cv_brakeaxis4.defaultvalue); - CV_StealthSet(&cv_aimaxis4, cv_aimaxis4.defaultvalue); - CV_StealthSet(&cv_lookaxis4, cv_lookaxis4.defaultvalue); - CV_StealthSet(&cv_fireaxis4, cv_fireaxis4.defaultvalue); - CV_StealthSet(&cv_driftaxis4, cv_driftaxis4.defaultvalue); - break; - case 3: - CV_StealthSet(&cv_usejoystick3, cv_usejoystick3.defaultvalue); - CV_StealthSet(&cv_turnaxis3, cv_turnaxis3.defaultvalue); - CV_StealthSet(&cv_moveaxis3, cv_moveaxis3.defaultvalue); - CV_StealthSet(&cv_brakeaxis3, cv_brakeaxis3.defaultvalue); - CV_StealthSet(&cv_aimaxis3, cv_aimaxis3.defaultvalue); - CV_StealthSet(&cv_lookaxis3, cv_lookaxis3.defaultvalue); - CV_StealthSet(&cv_fireaxis3, cv_fireaxis3.defaultvalue); - CV_StealthSet(&cv_driftaxis3, cv_driftaxis3.defaultvalue); - break; - case 2: - CV_StealthSet(&cv_usejoystick2, cv_usejoystick2.defaultvalue); - CV_StealthSet(&cv_turnaxis2, cv_turnaxis2.defaultvalue); - CV_StealthSet(&cv_moveaxis2, cv_moveaxis2.defaultvalue); - CV_StealthSet(&cv_brakeaxis2, cv_brakeaxis2.defaultvalue); - CV_StealthSet(&cv_aimaxis2, cv_aimaxis2.defaultvalue); - CV_StealthSet(&cv_lookaxis2, cv_lookaxis2.defaultvalue); - CV_StealthSet(&cv_fireaxis2, cv_fireaxis2.defaultvalue); - CV_StealthSet(&cv_driftaxis2, cv_driftaxis2.defaultvalue); - break; - case 1: - default: - CV_StealthSet(&cv_usejoystick, cv_usejoystick.defaultvalue); - CV_StealthSet(&cv_turnaxis, cv_turnaxis.defaultvalue); - CV_StealthSet(&cv_moveaxis, cv_moveaxis.defaultvalue); - CV_StealthSet(&cv_brakeaxis, cv_brakeaxis.defaultvalue); - CV_StealthSet(&cv_aimaxis, cv_aimaxis.defaultvalue); - CV_StealthSet(&cv_lookaxis, cv_lookaxis.defaultvalue); - CV_StealthSet(&cv_fireaxis, cv_fireaxis.defaultvalue); - CV_StealthSet(&cv_driftaxis, cv_driftaxis.defaultvalue); - break; - } - - S_StartSound(NULL, sfx_s224); -} - -static void M_ResetControls(INT32 choice) -{ - (void)choice; - M_StartMessage(va(M_GetText("Reset Player %d's controls to defaults?\n\n(Press 'Y' to confirm)\n"), setupcontrolplayer), M_ResetControlsResponse, MM_YESNO); -} - -// ===== -// SOUND -// ===== - -/*static void M_RestartAudio(void) -{ - COM_ImmedExecute("restartaudio"); -}*/ - -// =============== -// VIDEO MODE MENU -// =============== - -//added : 30-01-98: -#define MAXCOLUMNMODES 12 //max modes displayed in one column -#define MAXMODEDESCS (MAXCOLUMNMODES*3) - -static modedesc_t modedescs[MAXMODEDESCS]; - -static void M_VideoModeMenu(INT32 choice) -{ - INT32 i, j, vdup, nummodes, width, height; - const char *desc; - - (void)choice; - - memset(modedescs, 0, sizeof(modedescs)); - -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) - VID_PrepareModeList(); // FIXME: hack -#endif - vidm_nummodes = 0; - vidm_selected = 0; - nummodes = VID_NumModes(); - -#ifdef _WINDOWS - // clean that later: skip windowed mode 0, video modes menu only shows FULL SCREEN modes - if (nummodes <= NUMSPECIALMODES) - i = 0; // unless we have nothing - else - i = NUMSPECIALMODES; -#else - // DOS does not skip mode 0, because mode 0 is ALWAYS present - i = 0; -#endif - for (; i < nummodes && vidm_nummodes < MAXMODEDESCS; i++) - { - desc = VID_GetModeName(i); - if (desc) - { - vdup = 0; - - // when a resolution exists both under VGA and VESA, keep the - // VESA mode, which is always a higher modenum - for (j = 0; j < vidm_nummodes; j++) - { - if (!strcmp(modedescs[j].desc, desc)) - { - // mode(0): 320x200 is always standard VGA, not vesa - if (modedescs[j].modenum) - { - modedescs[j].modenum = i; - vdup = 1; - - if (i == vid.modenum) - vidm_selected = j; - } - else - vdup = 1; - - break; - } - } - - if (!vdup) - { - modedescs[vidm_nummodes].modenum = i; - modedescs[vidm_nummodes].desc = desc; - - if (i == vid.modenum) - vidm_selected = vidm_nummodes; - - // Pull out the width and height - sscanf(desc, "%u%*c%u", &width, &height); - - // Show multiples of 320x200 as green. - if (SCR_IsAspectCorrect(width, height)) - modedescs[vidm_nummodes].goodratio = 1; - - vidm_nummodes++; - } - } - } - - vidm_column_size = (vidm_nummodes+2) / 3; - - M_SetupNextMenu(&OP_VideoModeDef); -} - -static void M_DrawVideoMenu(void) -{ - M_DrawGenericMenu(); - - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + OP_VideoOptionsMenu[0].alphaKey, - (SCR_IsAspectCorrect(vid.width, vid.height) ? recommendedflags : highlightflags), - va("%dx%d", vid.width, vid.height)); -} - -static void M_DrawHUDOptions(void) -{ - const char *str0 = ")"; - const char *str1 = " Warning highlight"; - const char *str2 = ","; - const char *str3 = "Good highlight"; - INT32 x = BASEVIDWIDTH - currentMenu->x + 2, y = currentMenu->y + 105; - INT32 w0 = V_StringWidth(str0, 0), w1 = V_StringWidth(str1, 0), w2 = V_StringWidth(str2, 0), w3 = V_StringWidth(str3, 0); - - M_DrawGenericMenu(); - - x -= w0; - V_DrawString(x, y, highlightflags, str0); - x -= w1; - V_DrawString(x, y, warningflags, str1); - x -= w2; - V_DrawString(x, y, highlightflags, str2); - x -= w3; - V_DrawString(x, y, recommendedflags, str3); - V_DrawRightAlignedString(x, y, highlightflags, "("); -} - -// Draw the video modes list, a-la-Quake -static void M_DrawVideoMode(void) -{ - INT32 i, j, row, col; - - // draw title - M_DrawMenuTitle(); - - V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y, - highlightflags, "Choose mode, reselect to change default"); - - row = 41; - col = OP_VideoModeDef.y + 14; - for (i = 0; i < vidm_nummodes; i++) - { - if (i == vidm_selected) - V_DrawString(row, col, highlightflags, modedescs[i].desc); - // Show multiples of 320x200 as green. - else - V_DrawString(row, col, (modedescs[i].goodratio) ? recommendedflags : 0, modedescs[i].desc); - - col += 8; - if ((i % vidm_column_size) == (vidm_column_size-1)) - { - row += 7*13; - col = OP_VideoModeDef.y + 14; - } - } - - if (vidm_testingmode > 0) - { - INT32 testtime = (vidm_testingmode/TICRATE) + 1; - - M_CentreText(OP_VideoModeDef.y + 116, - va("Previewing mode %c%dx%d", - (SCR_IsAspectCorrect(vid.width, vid.height)) ? 0x83 : 0x80, - vid.width, vid.height)); - M_CentreText(OP_VideoModeDef.y + 138, - "Press ENTER again to keep this mode"); - M_CentreText(OP_VideoModeDef.y + 150, - va("Wait %d second%s", testtime, (testtime > 1) ? "s" : "")); - M_CentreText(OP_VideoModeDef.y + 158, - "or press ESC to return"); - - } - else - { - M_CentreText(OP_VideoModeDef.y + 116, - va("Current mode is %c%dx%d", - (SCR_IsAspectCorrect(vid.width, vid.height)) ? 0x83 : 0x80, - vid.width, vid.height)); - M_CentreText(OP_VideoModeDef.y + 124, - va("Default mode is %c%dx%d", - (SCR_IsAspectCorrect(cv_scr_width.value, cv_scr_height.value)) ? 0x83 : 0x80, - cv_scr_width.value, cv_scr_height.value)); - - V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 138, - recommendedflags, "Marked modes are recommended."); - V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 146, - highlightflags, "Other modes may have visual errors."); - V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 158, - highlightflags, "Larger modes may have performance issues."); - } - - // Draw the cursor for the VidMode menu - i = 41 - 10 + ((vidm_selected / vidm_column_size)*7*13); - j = OP_VideoModeDef.y + 14 + ((vidm_selected % vidm_column_size)*8); - - V_DrawScaledPatch(i - 8, j, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); -} - -// special menuitem key handler for video mode list -static void M_HandleVideoMode(INT32 ch) -{ - if (vidm_testingmode > 0) switch (ch) - { - // change back to the previous mode quickly - case KEY_ESCAPE: - setmodeneeded = vidm_previousmode + 1; - vidm_testingmode = 0; - break; - - case KEY_ENTER: - S_StartSound(NULL, sfx_menu1); - vidm_testingmode = 0; // stop testing - } - - else switch (ch) - { - case KEY_DOWNARROW: - S_StartSound(NULL, sfx_menu1); - if (++vidm_selected >= vidm_nummodes) - vidm_selected = 0; - break; - - case KEY_UPARROW: - S_StartSound(NULL, sfx_menu1); - if (--vidm_selected < 0) - vidm_selected = vidm_nummodes - 1; - break; - - case KEY_LEFTARROW: - S_StartSound(NULL, sfx_menu1); - vidm_selected -= vidm_column_size; - if (vidm_selected < 0) - vidm_selected = (vidm_column_size*3) + vidm_selected; - if (vidm_selected >= vidm_nummodes) - vidm_selected = vidm_nummodes - 1; - break; - - case KEY_RIGHTARROW: - S_StartSound(NULL, sfx_menu1); - vidm_selected += vidm_column_size; - if (vidm_selected >= (vidm_column_size*3)) - vidm_selected %= vidm_column_size; - if (vidm_selected >= vidm_nummodes) - vidm_selected = vidm_nummodes - 1; - break; - - case KEY_ENTER: - S_StartSound(NULL, sfx_menu1); - if (vid.modenum == modedescs[vidm_selected].modenum) - SCR_SetDefaultMode(); - else - { - vidm_testingmode = 15*TICRATE; - vidm_previousmode = vid.modenum; - if (!setmodeneeded) // in case the previous setmode was not finished - setmodeneeded = modedescs[vidm_selected].modenum + 1; - } - break; - - case KEY_ESCAPE: // this one same as M_Responder - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu); - else - M_ClearMenus(true); - break; - - default: - break; - } -} - -// =============== -// Monitor Toggles -// =============== - -static tic_t shitsfree = 0; - -static void M_DrawMonitorToggles(void) -{ - const INT32 edges = 4; - const INT32 height = 4; - const INT32 spacing = 35; - const INT32 column = itemOn/height; - //const INT32 row = itemOn%height; - INT32 leftdraw, rightdraw, totaldraw; - INT32 x = currentMenu->x, y = currentMenu->y+(spacing/4); - INT32 onx = 0, ony = 0; - consvar_t *cv; - INT32 i, translucent, drawnum; - - M_DrawMenuTitle(); - - // Find the available space around column - leftdraw = rightdraw = column; - totaldraw = 0; - for (i = 0; (totaldraw < edges*2 && i < edges*4); i++) - { - if (rightdraw+1 < (currentMenu->numitems/height)+1) - { - rightdraw++; - totaldraw++; - } - if (leftdraw-1 >= 0) - { - leftdraw--; - totaldraw++; - } - } - - for (i = leftdraw; i <= rightdraw; i++) - { - INT32 j; - - for (j = 0; j < height; j++) - { - const INT32 thisitem = (i*height)+j; - - if (thisitem >= currentMenu->numitems) - continue; - - if (thisitem == itemOn) - { - onx = x; - ony = y; - y += spacing; - continue; - } - -#ifdef ITEMTOGGLEBOTTOMRIGHT - if (currentMenu->menuitems[thisitem].alphaKey == 255) - { - V_DrawScaledPatch(x, y, V_TRANSLUCENT, W_CachePatchName("K_ISBG", PU_CACHE)); - continue; - } -#endif - if (currentMenu->menuitems[thisitem].alphaKey == 0) - { - V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBG", PU_CACHE)); - V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISTOGL", PU_CACHE)); - continue; - } - - cv = KartItemCVars[currentMenu->menuitems[thisitem].alphaKey-1]; - translucent = (cv->value ? 0 : V_TRANSLUCENT); - - switch (currentMenu->menuitems[thisitem].alphaKey) - { - case KRITEM_DUALJAWZ: - drawnum = 2; - break; - case KRITEM_TRIPLESNEAKER: - case KRITEM_TRIPLEBANANA: - case KRITEM_TRIPLEORBINAUT: - drawnum = 3; - break; - case KRITEM_QUADORBINAUT: - drawnum = 4; - break; - case KRITEM_TENFOLDBANANA: - drawnum = 10; - break; - default: - drawnum = 0; - break; - } - - if (cv->value) - V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBG", PU_CACHE)); - else - V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBGD", PU_CACHE)); - - if (drawnum != 0) - { - V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISMUL", PU_CACHE)); - V_DrawScaledPatch(x, y, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[thisitem].alphaKey, true), PU_CACHE)); - V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|translucent, va("x%d", drawnum)); - } - else - V_DrawScaledPatch(x, y, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[thisitem].alphaKey, true), PU_CACHE)); - - y += spacing; - } - - x += spacing; - y = currentMenu->y+(spacing/4); - } - - { -#ifdef ITEMTOGGLEBOTTOMRIGHT - if (currentMenu->menuitems[itemOn].alphaKey == 255) - { - V_DrawScaledPatch(onx-1, ony-2, V_TRANSLUCENT, W_CachePatchName("K_ITBG", PU_CACHE)); - if (shitsfree) - { - INT32 trans = V_TRANSLUCENT; - if (shitsfree-1 > TICRATE-5) - trans = ((10-TICRATE)+shitsfree-1)<menuitems[itemOn].alphaKey == 0) - { - V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE)); - V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITTOGL", PU_CACHE)); - } - else - { - cv = KartItemCVars[currentMenu->menuitems[itemOn].alphaKey-1]; - translucent = (cv->value ? 0 : V_TRANSLUCENT); - - switch (currentMenu->menuitems[itemOn].alphaKey) - { - case KRITEM_DUALJAWZ: - drawnum = 2; - break; - case KRITEM_TRIPLESNEAKER: - case KRITEM_TRIPLEBANANA: - drawnum = 3; - break; - case KRITEM_TENFOLDBANANA: - drawnum = 10; - break; - default: - drawnum = 0; - break; - } - - if (cv->value) - V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE)); - else - V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBGD", PU_CACHE)); - - if (drawnum != 0) - { - V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITMUL", PU_CACHE)); - V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[itemOn].alphaKey, false), PU_CACHE)); - V_DrawScaledPatch(onx+27, ony+39, translucent, W_CachePatchName("K_ITX", PU_CACHE)); - V_DrawKartString(onx+37, ony+34, translucent, va("%d", drawnum)); - } - else - V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[itemOn].alphaKey, false), PU_CACHE)); - } - } - - if (shitsfree) - shitsfree--; - - V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y, highlightflags, va("* %s *", currentMenu->menuitems[itemOn].text)); -} - -static void M_HandleMonitorToggles(INT32 choice) -{ - const INT32 width = 6, height = 4; - INT32 column = itemOn/height, row = itemOn%height; - INT16 next; - UINT8 i; - boolean exitmenu = false; - - switch (choice) - { - case KEY_RIGHTARROW: - S_StartSound(NULL, sfx_menu1); - column++; - if (((column*height)+row) >= currentMenu->numitems) - column = 0; - next = min(((column*height)+row), currentMenu->numitems-1); - itemOn = next; - break; - - case KEY_LEFTARROW: - S_StartSound(NULL, sfx_menu1); - column--; - if (column < 0) - column = width-1; - if (((column*height)+row) >= currentMenu->numitems) - column--; - next = max(((column*height)+row), 0); - if (next >= currentMenu->numitems) - next = currentMenu->numitems-1; - itemOn = next; - break; - - case KEY_DOWNARROW: - S_StartSound(NULL, sfx_menu1); - row = (row+1) % height; - if (((column*height)+row) >= currentMenu->numitems) - row = 0; - next = min(((column*height)+row), currentMenu->numitems-1); - itemOn = next; - break; - - case KEY_UPARROW: - S_StartSound(NULL, sfx_menu1); - row = (row-1) % height; - if (row < 0) - row = height-1; - if (((column*height)+row) >= currentMenu->numitems) - row--; - next = max(((column*height)+row), 0); - if (next >= currentMenu->numitems) - next = currentMenu->numitems-1; - itemOn = next; - break; - - case KEY_ENTER: -#ifdef ITEMTOGGLEBOTTOMRIGHT - if (currentMenu->menuitems[itemOn].alphaKey == 255) - { - //S_StartSound(NULL, sfx_s26d); - if (!shitsfree) - { - shitsfree = TICRATE; - S_StartSound(NULL, sfx_itfree); - } - } - else -#endif - if (currentMenu->menuitems[itemOn].alphaKey == 0) - { - INT32 v = cv_sneaker.value; - S_StartSound(NULL, sfx_s1b4); - for (i = 0; i < NUMKARTRESULTS-1; i++) - { - if (KartItemCVars[i]->value == v) - CV_AddValue(KartItemCVars[i], 1); - } - } - else - { - S_StartSound(NULL, sfx_s1ba); - CV_AddValue(KartItemCVars[currentMenu->menuitems[itemOn].alphaKey-1], 1); - } - break; - - case KEY_ESCAPE: - exitmenu = true; - break; - } - - if (exitmenu) - { - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu); - else - M_ClearMenus(true); - } -} - -// ========= -// Quit Game -// ========= -static INT32 quitsounds[] = -{ - // holy shit we're changing things up! - // srb2kart: you ain't seen nothing yet - sfx_kc2e, - sfx_kc2f, - sfx_cdfm01, - sfx_ddash, - sfx_s3ka2, - sfx_s3k49, - sfx_slip, - sfx_tossed, - sfx_s3k7b, - sfx_itrolf, - sfx_itrole, - sfx_cdpcm9, - sfx_s3k4e, - sfx_s259, - sfx_3db06, - sfx_s3k3a, - sfx_peel, - sfx_cdfm28, - sfx_s3k96, - sfx_s3kc0s, - sfx_cdfm39, - sfx_hogbom, - sfx_kc5a, - sfx_kc46, - sfx_s3k92, - sfx_s3k42, - sfx_kpogos, - sfx_screec -}; - -void M_QuitResponse(INT32 ch) -{ - tic_t ptime; - INT32 mrand; - - if (ch != 'y' && ch != KEY_ENTER) - return; - if (!(netgame || cv_debug)) - { - mrand = M_RandomKey(sizeof(quitsounds)/sizeof(INT32)); - if (quitsounds[mrand]) S_StartSound(NULL, quitsounds[mrand]); - - //added : 12-02-98: do that instead of I_WaitVbl which does not work - ptime = I_GetTime() + NEWTICRATE*2; // Shortened the quit time, used to be 2 seconds Tails 03-26-2001 - while (ptime > I_GetTime()) - { - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - V_DrawSmallScaledPatch(0, 0, 0, W_CachePatchName("GAMEQUIT", PU_CACHE)); // Demo 3 Quit Screen Tails 06-16-2001 - I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001 - I_Sleep(); - } - } - I_Quit(); -} - -static void M_QuitSRB2(INT32 choice) -{ - // We pick index 0 which is language sensitive, or one at random, - // between 1 and maximum number. - (void)choice; - M_StartMessage(quitmsg[M_RandomKey(NUM_QUITMESSAGES)], M_QuitResponse, MM_YESNO); -} - -#ifdef HWRENDER -// ===================================================================== -// OpenGL specific options -// ===================================================================== - -// ===================== -// M_OGL_DrawColorMenu() -// ===================== -static void M_OGL_DrawColorMenu(void) -{ - INT32 mx, my; - - mx = currentMenu->x; - my = currentMenu->y; - M_DrawGenericMenu(); // use generic drawer for cursor, items and title - V_DrawString(mx, my + currentMenu->menuitems[0].alphaKey - 10, - highlightflags, "Gamma correction"); -} -#endif