/* m_options.c ** ** New options menu code. ** ** Sorry this got so convoluted. It was originally much cleaner until ** I started adding all sorts of gadgets to the menus. I might someday ** make a project of rewriting the entire menu system using Amiga-style ** taglists to describe each menu item. We'll see... */ #include "m_alloc.h" #include "doomdef.h" #include "dstrings.h" #include "c_consol.h" #include "c_dispch.h" #include "c_bind.h" #include "d_main.h" #include "i_system.h" #include "i_video.h" #include "z_zone.h" #include "v_video.h" #include "v_text.h" #include "w_wad.h" #include "r_local.h" #include "hu_stuff.h" #include "g_game.h" #include "m_argv.h" #include "m_swap.h" #include "s_sound.h" #include "doomstat.h" #include "m_misc.h" // Data. #include "m_menu.h" // // defaulted values // cvar_t *mouseSensitivity; // has default // Show messages has default, 0 = off, 1 = on cvar_t *showMessages; cvar_t *screenblocks; // has default extern BOOL OptionsActive; extern int screenSize; extern short skullAnimCounter; extern cvar_t *cl_run; extern cvar_t *invertmouse; extern cvar_t *lookspring; extern cvar_t *lookstrafe; extern cvar_t *crosshair; extern cvar_t *freelook; void M_ChangeMessages(void); void M_SizeDisplay(float diff); void M_StartControlPanel(void); int M_StringHeight(char *string); void M_ClearMenus (void); static value_t YesNo[2] = { { 0.0, "No" }, { 1.0, "Yes" } }; static value_t NoYes[2] = { { 0.0, "Yes" }, { 1.0, "No" } }; static value_t OnOff[2] = { { 0.0, "Off" }, { 1.0, "On" } }; menu_t *CurrentMenu; int CurrentItem; static BOOL WaitingForKey; static char *OldMessage; static itemtype OldType; /*======================================= * * Options Menu * *=======================================*/ static void CustomizeControls (void); static void GameplayOptions (void); static void VideoOptions (void); static void GoToConsole (void); void Reset2Defaults (void); void Reset2Saved (void); extern cvar_t *snd_MidiVolume; static void SetVidMode (void); static menuitem_t OptionItems[] = { { more, "Customize Controls", NULL, 0.0, 0.0, 0.0, (value_t *)CustomizeControls }, { more, "Go to console", NULL, 0.0, 0.0, 0.0, (value_t *)GoToConsole }, { more, "Gameplay Options", NULL, 0.0, 0.0, 0.0, (value_t *)GameplayOptions }, { more, "Display Options", NULL, 0.0, 0.0, 0.0, (value_t *)VideoOptions }, { more, "Set video mode", NULL, 0.0, 0.0, 0.0, (value_t *)SetVidMode }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { slider, "Mouse speed", &mouseSensitivity, 0.5, 2.5, 0.1, NULL }, { slider, "MIDI music volume", &snd_MidiVolume, 0.0, 1.0, 0.05, NULL }, { slider, "MOD music volume", &snd_MusicVolume, 0.0, 64.0, 1.0, NULL }, { slider, "Sound volume", &snd_SfxVolume, 0.0, 15.0, 1.0, NULL }, { discrete, "Always Run", &cl_run, 2.0, 0.0, 0.0, OnOff }, { discrete, "Always Mouselook", &freelook, 2.0, 0.0, 0.0, OnOff }, { discrete, "Invert Mouse", &invertmouse, 2.0, 0.0, 0.0, OnOff }, { discrete, "Lookspring", &lookspring, 2.0, 0.0, 0.0, OnOff }, { discrete, "Lookstrafe", &lookstrafe, 2.0, 0.0, 0.0, OnOff }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { more, "Reset to defaults", NULL, 0.0, 0.0, 0.0, (value_t *)Reset2Defaults }, { more, "Reset to last saved", NULL, 0.0, 0.0, 0.0, (value_t *)Reset2Saved } }; menu_t OptionMenu = { "M_OPTTTL", 0, 16, 177, OptionItems, }; /*======================================= * * Controls Menu * *=======================================*/ static menuitem_t ControlsItems[] = { { whitetext,"ENTER to change, BACKSPACE to clear", NULL, 0.0, 0.0, 0.0, NULL }, { control, "Attack", NULL, 0.0, 0.0, 0.0, (value_t *)"+attack" }, { control, "Next Weapon", NULL, 0.0, 0.0, 0.0, (value_t *)"weapnext" }, // Was already here { control, "Previous Weapon", NULL, 0.0, 0.0, 0.0, (value_t *)"weapprev" }, // TIJ { control, "Use / Open", NULL, 0.0, 0.0, 0.0, (value_t *)"+use" }, { control, "Jump", NULL, 0.0, 0.0, 0.0, (value_t *)"+jump" }, { control, "Walk forward", NULL, 0.0, 0.0, 0.0, (value_t *)"+forward" }, { control, "Backpedal", NULL, 0.0, 0.0, 0.0, (value_t *)"+back" }, { control, "Turn left", NULL, 0.0, 0.0, 0.0, (value_t *)"+left" }, { control, "Turn right", NULL, 0.0, 0.0, 0.0, (value_t *)"+right" }, { control, "Run", NULL, 0.0, 0.0, 0.0, (value_t *)"+speed" }, { control, "Step left", NULL, 0.0, 0.0, 0.0, (value_t *)"+moveleft" }, { control, "Step right", NULL, 0.0, 0.0, 0.0, (value_t *)"+moveright" }, { control, "Sidestep", NULL, 0.0, 0.0, 0.0, (value_t *)"+strafe" }, { control, "Look up", NULL, 0.0, 0.0, 0.0, (value_t *)"+lookup" }, { control, "Look down", NULL, 0.0, 0.0, 0.0, (value_t *)"+lookdown" }, { control, "Center view", NULL, 0.0, 0.0, 0.0, (value_t *)"centerview" }, { control, "Mouse look", NULL, 0.0, 0.0, 0.0, (value_t *)"+mlook" }, { control, "Keyboard look", NULL, 0.0, 0.0, 0.0, (value_t *)"+klook" }, { control, "Toggle automap", NULL, 0.0, 0.0, 0.0, (value_t *)"togglemap" }, { control, "Chasecam", NULL, 0.0, 0.0, 0.0, (value_t *)"chase" } }; menu_t ControlsMenu = { "M_CONTRO", 1, 21, // TIJ Was: 19 // Now: 21 (2 more Control menu items: Prev and Next Weapon) 0, ControlsItems, }; /*======================================= * * Display Options Menu * *=======================================*/ static void StartMessagesMenu (void); extern cvar_t *am_rotate, *am_overlay, *st_scale, *am_usecustomcolors, *r_detail, *r_stretchsky, *r_columnmethod, *r_drawfuzz, *cl_rockettrails, *cl_pufftype, *cl_bloodtype; static value_t Crosshairs[] = { { 0.0, "None" }, { 1.0, "Cross 1" }, { 2.0, "Cross 2" }, { 3.0, "X" }, { 4.0, "Diamond" }, { 5.0, "Dot" }, { 6.0, "Box" }, { 7.0, "Angle" }, { 8.0, "Big Thing" } }; static value_t DetailModes[] = { { 0.0, "Normal" }, { 1.0, "Double Horizontally" }, { 2.0, "Double Vertically" }, { 3.0, "Double Horiz and Vert" } }; static value_t ColumnMethods[] = { { 0.0, "Original" }, { 1.0, "Optimized" } }; static value_t BloodTypes[] = { { 0.0, "Sprites" }, { 1.0, "Sprites and Particles" }, { 2.0, "Particles" } }; static value_t PuffTypes[] = { { 0.0, "Sprites" }, { 1.0, "Particles" } }; static menuitem_t VideoItems[] = { { more, "Messages", NULL, 0.0, 0.0, 0.0, (value_t *)StartMessagesMenu }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { slider, "Screen size", &screenblocks, 3.0, 12.0, 1.0, NULL }, { slider, "Brightness", (cvar_t **)&gammalevel, 1.0, 3.0, 0.1, NULL }, { discrete, "Crosshair", (cvar_t **)&crosshair, 9.0, 0.0, 0.0, Crosshairs }, { discrete, "Column render mode", (cvar_t **)&r_columnmethod,2.0,0.0, 0.0, ColumnMethods }, { discrete, "Detail mode", (cvar_t **)&r_detail, 4.0, 0.0, 0.0, DetailModes }, { discrete, "Stretch short skies", (cvar_t **)&r_stretchsky, 2.0,0.0, 0.0, OnOff }, { discrete, "Scale status bar", (cvar_t **)&st_scale, 2.0, 0.0, 0.0, OnOff }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { discrete, "Use fuzz effect", (cvar_t **)&r_drawfuzz, 2.0, 0.0, 0.0, YesNo }, { discrete, "Rocket Trails", (cvar_t **)&cl_rockettrails, 2.0, 0.0, 0.0, OnOff }, { discrete, "Blood Type", (cvar_t **)&cl_bloodtype, 3.0, 0.0, 0.0, BloodTypes }, { discrete, "Bullet Puff Type", (cvar_t **)&cl_pufftype, 2.0, 0.0, 0.0, PuffTypes }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { discrete, "Rotate automap", (cvar_t **)&am_rotate, 2.0, 0.0, 0.0, OnOff }, { discrete, "Overlay automap", (cvar_t **)&am_overlay, 2.0, 0.0, 0.0, OnOff }, { discrete, "Standard map colors", (cvar_t **)&am_usecustomcolors, 2.0, 0.0, 0.0, NoYes }, }; menu_t VideoMenu = { "M_VIDEO", 0, 17, 0, VideoItems, }; /*======================================= * * Messages Menu * *=======================================*/ extern cvar_t *con_scaletext, *msg0color, *msg1color, *msg2color, *msg3color, *msg4color, *msgmidcolor, *msglevel; static value_t TextColors[] = { { 0.0, "brick" }, { 1.0, "tan" }, { 2.0, "gray" }, { 3.0, "green" }, { 4.0, "brown" }, { 5.0, "gold" }, { 6.0, "red" }, { 7.0, "blue" } }; static value_t MessageLevels[] = { { 0.0, "Item Pickup" }, { 1.0, "Obituaries" }, { 2.0, "Critical Messages" } }; static menuitem_t MessagesItems[] = { { discrete, "Scale text in high res", (cvar_t **)&con_scaletext,2.0,0.0, 0.0, OnOff }, { discrete, "Minimum message level", (cvar_t **)&msglevel, 3.0, 0.0, 0.0, MessageLevels }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { whitetext, "Message Colors", NULL, 0.0, 0.0, 0.0, NULL }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { cdiscrete, "Item Pickup", (cvar_t **)&msg0color, 8.0, 0.0, 0.0, TextColors }, { cdiscrete, "Obituaries", (cvar_t **)&msg1color, 8.0, 0.0, 0.0, TextColors }, { cdiscrete, "Critical Messages", (cvar_t **)&msg2color, 8.0, 0.0, 0.0, TextColors }, { cdiscrete, "Chat Messages", (cvar_t **)&msg3color, 8.0, 0.0, 0.0, TextColors }, { cdiscrete, "Team Messages", (cvar_t **)&msg4color, 8.0, 0.0, 0.0, TextColors }, { cdiscrete, "Centered Messages", (cvar_t **)&msgmidcolor,8.0, 0.0, 0.0, TextColors } }; menu_t MessagesMenu = { "M_MESS", 0, 11, 0, MessagesItems, }; /*======================================= * * Video Modes Menu * *=======================================*/ extern BOOL setmodeneeded; extern int NewWidth, NewHeight, NewID; extern int DisplayID; extern char *IdStrings[22]; int testingmode; // Holds time to revert to old mode int OldWidth, OldHeight, OldID; float OldFS; static void BuildModesList (int hiwidth, int hiheight, int hi_id); static BOOL GetSelectedSize (int line, int *width, int *height); static void SetModesMenu (int w, int h, int id); // Found in i_video.c. void I_StartModeIterator (int id); BOOL I_NextMode (int *width, int *height); extern cvar_t *vid_defwidth, *vid_defheight, *vid_defid; static cvar_t DummyDepthCvar; static cvar_t *DummyDepthPtr; #ifndef DJGPP extern cvar_t *fullscreen; static cvar_t *DummyFSPtr; static cvar_t DummyFSCvar; #endif static value_t Depths[22]; static char VMEnterText[] = "Press ENTER to set mode"; static char VMTestText[] = "T to test mode for 5 seconds"; static menuitem_t ModesItems[] = { { discrete, "Screen mode", (cvar_t **)&DummyDepthPtr,0.0, 0.0,0.0, Depths }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, #ifdef DJGPP { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, #else { discrete, "Fullscreen", (cvar_t **)&DummyFSPtr,2.0, 0.0, 0.0, YesNo }, #endif { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { screenres,NULL, NULL, 0.0, 0.0, 0.0, NULL }, { screenres,NULL, NULL, 0.0, 0.0, 0.0, NULL }, { screenres,NULL, NULL, 0.0, 0.0, 0.0, NULL }, { screenres,NULL, NULL, 0.0, 0.0, 0.0, NULL }, { screenres,NULL, NULL, 0.0, 0.0, 0.0, NULL }, { screenres,NULL, NULL, 0.0, 0.0, 0.0, NULL }, { screenres,NULL, NULL, 0.0, 0.0, 0.0, NULL }, { screenres,NULL, NULL, 0.0, 0.0, 0.0, NULL }, { screenres,NULL, NULL, 0.0, 0.0, 0.0, NULL }, { whitetext,"Note: Only 8 bpp modes are supported",NULL, 0.0, 0.0, 0.0, NULL }, { redtext, VMEnterText, NULL, 0.0, 0.0, 0.0, NULL }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { redtext, VMTestText, NULL, 0.0, 0.0, 0.0, NULL }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { redtext, NULL, NULL, 0.0, 0.0, 0.0, NULL }, { redtext, NULL, NULL, 0.0, 0.0, 0.0, NULL } }; #define VM_DEPTHITEM 0 #define VM_RESSTART 4 #define VM_ENTERLINE 14 #define VM_TESTLINE 16 #define VM_MAKEDEFLINE 18 #define VM_CURDEFLINE 19 menu_t ModesMenu = { "M_VIDMOD", #ifndef DJGPP 2, #else 4, #endif 20, 130, ModesItems, }; extern byte IdTobpp[22]; static int IdToBpp (int id) { id -= 1000; if (id < 0 || id > 21) return 0; else return IdTobpp[id]; } /*======================================= * * Gameplay Options (dmflags) Menu * *=======================================*/ static cvar_t *flagsvar; static menuitem_t DMFlagsItems[] = { { bitflag, "Falling damage", (cvar_t **)DF_YES_FALLING, 0, 0, 0, (value_t *)&dmflags }, { bitflag, "Weapons stay (DM)", (cvar_t **)DF_WEAPONS_STAY, 0, 0, 0, (value_t *)&dmflags }, { bitflag, "Allow powerups (DM)", (cvar_t **)DF_NO_ITEMS, 1, 0, 0, (value_t *)&dmflags }, { bitflag, "Allow health (DM)", (cvar_t **)DF_NO_HEALTH, 1, 0, 0, (value_t *)&dmflags }, { bitflag, "Allow armor (DM)", (cvar_t **)DF_NO_ARMOR, 1, 0, 0, (value_t *)&dmflags }, { bitflag, "Spawn farthest (DM)", (cvar_t **)DF_SPAWN_FARTHEST, 0, 0, 0, (value_t *)&dmflags }, { bitflag, "Same map (DM)", (cvar_t **)DF_SAME_LEVEL, 0, 0, 0, (value_t *)&dmflags }, { bitflag, "Force respawn (DM)", (cvar_t **)DF_FORCE_RESPAWN, 0, 0, 0, (value_t *)&dmflags }, { bitflag, "Allow exit (DM)", (cvar_t **)DF_NO_EXIT, 1, 0, 0, (value_t *)&dmflags }, { bitflag, "Infinite ammo", (cvar_t **)DF_INFINITE_AMMO, 0, 0, 0, (value_t *)&dmflags }, { bitflag, "No monsters", (cvar_t **)DF_NO_MONSTERS, 0, 0, 0, (value_t *)&dmflags }, { bitflag, "Monsters respawn", (cvar_t **)DF_MONSTERS_RESPAWN, 0, 0, 0, (value_t *)&dmflags }, { bitflag, "Items respawn", (cvar_t **)DF_ITEMS_RESPAWN, 0, 0, 0, (value_t *)&dmflags }, { bitflag, "Fast monsters", (cvar_t **)DF_FAST_MONSTERS, 0, 0, 0, (value_t *)&dmflags }, { bitflag, "Allow jump", (cvar_t **)DF_NO_JUMP, 1, 0, 0, (value_t *)&dmflags }, { bitflag, "Allow freelook", (cvar_t **)DF_NO_FREELOOK, 1, 0, 0, (value_t *)&dmflags }, { bitflag, "Friendly fire", (cvar_t **)DF_NO_FRIENDLY_FIRE, 1, 0, 0, (value_t *)&dmflags }, { redtext, " ", NULL, 0.0, 0.0, 0.0, NULL }, { discrete, "Teamplay", (cvar_t **)&teamplay, 2.0, 0.0, 0.0, OnOff } }; static menu_t DMFlagsMenu = { "M_GMPLAY", 0, 19, 0, DMFlagsItems, }; void M_FreeValues (value_t **values, int num) { int i; if (*values) { for (i = 0; i < num; i++) { if ((*values)[i].name) free ((*values)[i].name); } free (*values); *values = NULL; } } // // Set some stuff up for the video modes menu // static int IDTranslate[22]; void M_OptInit (void) { int currval = 0, dummy1, dummy2, i; char name[24]; DummyDepthPtr = &DummyDepthCvar; #ifndef DJGPP DummyFSPtr = &DummyFSCvar; #endif for (i = 1000; i < 1022; i++) { I_StartModeIterator (i); if (I_NextMode (&dummy1, &dummy2)) { Depths[currval].value = currval; sprintf (name, "%d bit (%s)", IdToBpp (i), IdStrings[i-1000]); Depths[currval].name = copystring (name); IDTranslate[currval] = i; currval++; } } ModesItems[VM_DEPTHITEM].b.min = (float)currval; } // // Toggle messages on/off // void M_ChangeMessages (void) { if (showMessages->value) { Printf (128, "%s\n", MSGOFF); SetCVarFloat (showMessages, 0.0); } else { Printf (128, "%s\n", MSGON); SetCVarFloat (showMessages, 1.0); } } void Cmd_ToggleMessages (player_t *plyr, int argc, char **argv) { M_ChangeMessages (); } void M_SizeDisplay (float diff) { // changing screenblocks automatically resizes the display SetCVarFloat (screenblocks, screenblocks->value + diff); } void Cmd_Sizedown (void *plyr, int argc, char **argv) { M_SizeDisplay (-1.0); S_Sound (NULL, CHAN_VOICE, "plats/pt1_mid", 1, ATTN_NONE); } void Cmd_Sizeup (void *plyr, int argc, char **argv) { M_SizeDisplay(1.0); S_Sound (NULL, CHAN_VOICE, "plats/pt1_mid", 1, ATTN_NONE); } void M_BuildKeyList (menuitem_t *item, int numitems) { int i; for (i = 0; i < numitems; i++, item++) { if (item->type == control) C_GetKeysForCommand (item->e.command, &item->b.key1, &item->c.key2); } } void M_SwitchMenu (menu_t *menu) { int i, widest = 0, thiswidth; menuitem_t *item; MenuStack[MenuStackDepth].menu.new = menu; MenuStack[MenuStackDepth].isNewStyle = true; MenuStack[MenuStackDepth].drawSkull = false; MenuStackDepth++; CurrentMenu = menu; CurrentItem = menu->lastOn; if (!menu->indent) { for (i = 0; i < menu->numitems; i++) { item = menu->items + i; if (item->type != whitetext && item->type != redtext) { thiswidth = V_StringWidth (item->label); if (thiswidth > widest) widest = thiswidth; } } menu->indent = widest + 6; } flagsvar = NULL; } BOOL M_StartOptionsMenu (void) { M_SwitchMenu (&OptionMenu); return true; } void M_DrawSlider (int x, int y, float min, float max, float cur) { float range; int i; range = max - min; if (cur > max) cur = max; else if (cur < min) cur = min; cur -= min; V_DrawPatchClean (x, y, &screen, W_CacheLumpName ("LSLIDE", PU_CACHE)); for (i = 1; i < 11; i++) V_DrawPatchClean (x + i*8, y, &screen, W_CacheLumpName ("MSLIDE", PU_CACHE)); V_DrawPatchClean (x + 88, y, &screen, W_CacheLumpName ("RSLIDE", PU_CACHE)); V_DrawPatchClean (x + 5 + (int)((cur * 78.0) / range), y, &screen, W_CacheLumpName ("CSLIDE", PU_CACHE)); } int M_FindCurVal (float cur, value_t *values, int numvals) { int v; for (v = 0; v < numvals; v++) if (values[v].value == cur) break; return v; } void M_OptDrawer (void) { int color; int y, width, i, x; menuitem_t *item; patch_t *title; title = W_CacheLumpName (CurrentMenu->title, PU_CACHE); V_DrawPatchClean (160-title->width/2,10,&screen,title); // for (i = 0, y = 20 + title->height; i < CurrentMenu->numitems; i++, y += 8) { for (i = 0, y = 15 + title->height; i < CurrentMenu->numitems; i++, y += 8) { // TIJ item = CurrentMenu->items + i; if (item->type != screenres) { width = V_StringWidth (item->label); switch (item->type) { case more: x = CurrentMenu->indent - width; color = CR_GREY; break; case redtext: x = 160 - width / 2; color = CR_RED; break; case whitetext: x = 160 - width / 2; color = CR_GREY; break; case listelement: x = CurrentMenu->indent + 14; color = CR_RED; break; default: x = CurrentMenu->indent - width; color = CR_RED; break; } V_DrawTextCleanMove (color, x, y, item->label); switch (item->type) { case discrete: case cdiscrete: { int v, vals; vals = (int)item->b.min; v = M_FindCurVal ((*item->a.cvar)->value, item->e.values, vals); if (v == vals) { V_DrawTextCleanMove (CR_GREY, CurrentMenu->indent + 14, y, "Unknown"); } else { if (item->type == cdiscrete) V_DrawTextCleanMove (v, CurrentMenu->indent + 14, y, item->e.values[v].name); else V_DrawTextCleanMove (CR_GREY, CurrentMenu->indent + 14, y, item->e.values[v].name); } } break; case slider: M_DrawSlider (CurrentMenu->indent + 14, y, item->b.min, item->c.max, (*item->a.cvar)->value); break; case control: { char description[64]; C_NameKeys (description, item->b.key1, item->c.key2); V_DrawTextCleanMove (CR_GREY, CurrentMenu->indent + 14, y, description); } break; case bitflag: { value_t *value; char *str; if (item->b.min) value = NoYes; else value = YesNo; if (*item->e.flagint & item->a.flagmask) str = value[1].name; else str = value[0].name; V_DrawTextCleanMove (CR_GREY, CurrentMenu->indent + 14, y, str); } break; default: break; } if (i == CurrentItem && (skullAnimCounter < 6 || WaitingForKey)) { V_DrawPatchClean (CurrentMenu->indent + 3, y, &screen, W_CacheLumpName ("LITLCURS", PU_CACHE)); } } else { char *str; for (x = 0; x < 3; x++) { switch (x) { case 0: str = item->b.res1; break; case 1: str = item->c.res2; break; case 2: str = item->d.res3; break; } if (str) { if (x == item->e.highlight) color = CR_GREY; else color = CR_RED; V_DrawTextCleanMove (color, 104 * x + 20, y, str); } } if (i == CurrentItem && ((item->a.selmode != -1 && (skullAnimCounter < 6 || WaitingForKey)) || testingmode)) { V_DrawPatchClean (item->a.selmode * 104 + 8, y, &screen, W_CacheLumpName ("LITLCURS", PU_CACHE)); } } } if (flagsvar) { char flagsblah[64]; sprintf (flagsblah, "%s = %s", flagsvar->name, flagsvar->string); V_DrawTextCleanMove (CR_GREY, 160 - (V_StringWidth (flagsblah) >> 1), 190, flagsblah); } } void M_OptResponder (event_t *ev) { menuitem_t *item; int ch = ev->data1; item = CurrentMenu->items + CurrentItem; if (WaitingForKey) { if (ch != KEY_ESCAPE) { C_ChangeBinding (item->e.command, ch); M_BuildKeyList (CurrentMenu->items, CurrentMenu->numitems); } WaitingForKey = false; CurrentMenu->items[0].label = OldMessage; CurrentMenu->items[0].type = OldType; return; } if (item->type == bitflag && flagsvar && (ch == KEY_LEFTARROW || ch == KEY_RIGHTARROW || ch == KEY_ENTER) && !demoplayback) { int newflags = *item->e.flagint ^ item->a.flagmask; char val[16]; sprintf (val, "%d", newflags); SetCVar (flagsvar, val); return; } switch (ch) { case KEY_DOWNARROW: { int modecol; if (item->type == screenres) { modecol = item->a.selmode; item->a.selmode = -1; } else { modecol = 0; } do { if (++CurrentItem == CurrentMenu->numitems) CurrentItem = 0; } while (CurrentMenu->items[CurrentItem].type == redtext || CurrentMenu->items[CurrentItem].type == whitetext || (CurrentMenu->items[CurrentItem].type == screenres && !CurrentMenu->items[CurrentItem].b.res1)); if (CurrentMenu->items[CurrentItem].type == screenres) CurrentMenu->items[CurrentItem].a.selmode = modecol; S_Sound (NULL, CHAN_VOICE, "plats/pt1_stop", 1, ATTN_NONE); } break; case KEY_UPARROW: { int modecol; if (item->type == screenres) { modecol = item->a.selmode; item->a.selmode = -1; } else { modecol = 0; } do { if (--CurrentItem < 0) CurrentItem = CurrentMenu->numitems - 1; } while (CurrentMenu->items[CurrentItem].type == redtext || CurrentMenu->items[CurrentItem].type == whitetext || (CurrentMenu->items[CurrentItem].type == screenres && !CurrentMenu->items[CurrentItem].b.res1)); if (CurrentMenu->items[CurrentItem].type == screenres) CurrentMenu->items[CurrentItem].a.selmode = modecol; S_Sound (NULL, CHAN_VOICE, "plats/pt1_stop", 1, ATTN_NONE); } break; case KEY_LEFTARROW: switch (item->type) { case slider: { float newval = (*item->a.cvar)->value - item->d.step; if (newval < item->b.min) newval = item->b.min; if (item->e.cfunc) item->e.cfunc (*item->a.cvar, newval); else SetCVarFloat (*item->a.cvar, newval); } S_Sound (NULL, CHAN_VOICE, "plats/pt1_mid", 1, ATTN_NONE); break; case discrete: case cdiscrete: { int cur; int numvals; numvals = (int)item->b.min; cur = M_FindCurVal ((*item->a.cvar)->value, item->e.values, numvals); if (--cur < 0) cur = numvals - 1; SetCVarFloat (*item->a.cvar, item->e.values[cur].value); // Hack hack. Rebuild list of resolutions if (item->e.values == Depths) BuildModesList (screen.width, screen.height, DisplayID); } S_Sound (NULL, CHAN_VOICE, "plats/pt1_mid", 1, ATTN_NONE); break; case screenres: { int col; col = item->a.selmode - 1; if (col < 0) { if (CurrentItem > 0) { if (CurrentMenu->items[CurrentItem - 1].type == screenres) { item->a.selmode = -1; CurrentMenu->items[--CurrentItem].a.selmode = 2; } } } else { item->a.selmode = col; } } S_Sound (NULL, CHAN_VOICE, "plats/pt1_stop", 1, ATTN_NONE); break; default: break; } break; case KEY_RIGHTARROW: switch (item->type) { case slider: { float newval = (*item->a.cvar)->value + item->d.step; if (newval > item->c.max) newval = item->c.max; if (item->e.cfunc) item->e.cfunc (*item->a.cvar, newval); else SetCVarFloat (*item->a.cvar, newval); } S_Sound (NULL, CHAN_VOICE, "plats/pt1_mid", 1, ATTN_NONE); break; case discrete: case cdiscrete: { int cur; int numvals; numvals = (int)item->b.min; cur = M_FindCurVal ((*item->a.cvar)->value, item->e.values, numvals); if (++cur >= numvals) cur = 0; SetCVarFloat (*item->a.cvar, item->e.values[cur].value); // Hack hack. Rebuild list of resolutions if (item->e.values == Depths) BuildModesList (screen.width, screen.height, DisplayID); } S_Sound (NULL, CHAN_VOICE, "plats/pt1_mid", 1, ATTN_NONE); break; case screenres: { int col; col = item->a.selmode + 1; if ((col > 2) || (col == 2 && !item->d.res3) || (col == 1 && !item->c.res2)) { if (CurrentMenu->numitems - 1 > CurrentItem) { if (CurrentMenu->items[CurrentItem + 1].type == screenres) { if (CurrentMenu->items[CurrentItem + 1].b.res1) { item->a.selmode = -1; CurrentMenu->items[++CurrentItem].a.selmode = 0; } } } } else { item->a.selmode = col; } } S_Sound (NULL, CHAN_VOICE, "plats/pt1_stop", 1, ATTN_NONE); break; default: break; } break; case KEY_BACKSPACE: if (item->type == control) { C_UnbindACommand (item->e.command); item->b.key1 = item->c.key2 = 0; } break; case KEY_ENTER: if (CurrentMenu == &ModesMenu) { #ifndef DJGPP SetCVarFloat (fullscreen, DummyFSCvar.value); #endif if (!(item->type == screenres && GetSelectedSize (CurrentItem, &NewWidth, &NewHeight))) { NewWidth = screen.width; NewHeight = screen.height; } NewID = IDTranslate[(int)DummyDepthCvar.value]; setmodeneeded = true; S_Sound (NULL, CHAN_VOICE, "weapons/pistol", 1, ATTN_NONE); SetModesMenu (NewWidth, NewHeight, NewID); } else if (item->type == more && item->e.mfunc) { CurrentMenu->lastOn = CurrentItem; S_Sound (NULL, CHAN_VOICE, "weapons/pistol", 1, ATTN_NONE); item->e.mfunc(); } else if (item->type == discrete || item->type == cdiscrete) { int cur; int numvals; numvals = (int)item->b.min; cur = M_FindCurVal ((*item->a.cvar)->value, item->e.values, numvals); if (++cur >= numvals) cur = 0; SetCVarFloat (*item->a.cvar, item->e.values[cur].value); // Hack hack. Rebuild list of resolutions if (item->e.values == Depths) BuildModesList (screen.width, screen.height, DisplayID); S_Sound (NULL, CHAN_VOICE, "plats/pt1_mid", 1, ATTN_NONE); } else if (item->type == control) { WaitingForKey = true; OldMessage = CurrentMenu->items[0].label; OldType = CurrentMenu->items[0].type; CurrentMenu->items[0].label = "Press new key for control or ESC to cancel"; CurrentMenu->items[0].type = redtext; } else if (item->type == listelement) { CurrentMenu->lastOn = CurrentItem; S_Sound (NULL, CHAN_VOICE, "weapons/pistol", 1, ATTN_NONE); item->e.lfunc (CurrentItem); } else if (item->type == screenres) { } break; case KEY_ESCAPE: CurrentMenu->lastOn = CurrentItem; M_PopMenuStack (); break; default: if (ev->data2 == 't') { // Test selected resolution if (CurrentMenu == &ModesMenu) { #ifndef DJGPP OldFS = fullscreen->value; SetCVarFloat (fullscreen, DummyFSCvar.value); #endif if (!(item->type == screenres && GetSelectedSize (CurrentItem, &NewWidth, &NewHeight))) { NewWidth = screen.width; NewHeight = screen.height; } OldWidth = screen.width; OldHeight = screen.height; OldID = DisplayID; NewID = IDTranslate[(int)DummyDepthCvar.value]; setmodeneeded = true; testingmode = I_GetTime() + 5 * TICRATE; S_Sound (NULL, CHAN_VOICE, "weapons/pistol", 1, ATTN_NONE); SetModesMenu (NewWidth, NewHeight, NewID); } } else if (ev->data2 == 'd' && CurrentMenu == &ModesMenu) { // Make current resolution the default SetCVarFloat (vid_defwidth, (float)screen.width); SetCVarFloat (vid_defheight, (float)screen.height); SetCVar (vid_defid, IdStrings[DisplayID-1000]); SetModesMenu (screen.width, screen.height, DisplayID); } break; } } static void GoToConsole (void) { M_ClearMenus (); C_ToggleConsole (); } static void UpdateStuff (void) { M_SizeDisplay (0.0); } void Reset2Defaults (void) { AddCommandString ("unbindall; binddefaults"); C_SetCVarsToDefaults (); UpdateStuff(); } void Reset2Saved (void) { char *execcommand; char *configfile = GetConfigPath (); execcommand = Malloc (strlen (configfile) + 8); sprintf (execcommand, "exec \"%s\"", configfile); free (configfile); AddCommandString (execcommand); free (execcommand); UpdateStuff(); } static void StartMessagesMenu (void) { M_SwitchMenu (&MessagesMenu); } static void CustomizeControls (void) { M_BuildKeyList (ControlsMenu.items, ControlsMenu.numitems); M_SwitchMenu (&ControlsMenu); } void Cmd_Menu_Keys (void *plyr, int argc, char **argv) { M_StartControlPanel (); S_Sound (NULL, CHAN_VOICE, "switches/normbutn", 1, ATTN_NONE); OptionsActive = true; CustomizeControls(); } static void GameplayOptions (void) { M_SwitchMenu (&DMFlagsMenu); flagsvar = dmflagsvar; } void Cmd_Menu_Gameplay (void *plyr, int argc, char **argv) { M_StartControlPanel (); S_Sound (NULL, CHAN_VOICE, "switches/normbutn", 1, ATTN_NONE); OptionsActive = true; GameplayOptions (); } static void VideoOptions (void) { M_SwitchMenu (&VideoMenu); } void Cmd_Menu_Display (void *plyr, int argc, char **argv) { M_StartControlPanel (); S_Sound (NULL, CHAN_VOICE, "switches/normbutn", 1, ATTN_NONE); OptionsActive = true; M_SwitchMenu (&VideoMenu); } static void BuildModesList (int hiwidth, int hiheight, int hi_id) { char strtemp[32], **str; int i, c; int width, height, showid; showid = IDTranslate[(int)DummyDepthCvar.value]; I_StartModeIterator (showid); for (i = VM_RESSTART; ModesItems[i].type == screenres; i++) { ModesItems[i].e.highlight = -1; for (c = 0; c < 3; c++) { switch (c) { case 0: str = &ModesItems[i].b.res1; break; case 1: str = &ModesItems[i].c.res2; break; case 2: str = &ModesItems[i].d.res3; break; } if (I_NextMode (&width, &height)) { if (/* hi_id == showid && */ width == hiwidth && height == hiheight) ModesItems[i].e.highlight = ModesItems[i].a.selmode = c; sprintf (strtemp, "%dx%d", width, height); ReplaceString (str, strtemp); } else { if (*str) { free (*str); *str = NULL; } } } } } static BOOL GetSelectedSize (int line, int *width, int *height) { int i, stopat; if (ModesItems[line].type != screenres) { return false; } else { I_StartModeIterator (IDTranslate[(int)DummyDepthCvar.value]); stopat = (line - VM_RESSTART) * 3 + ModesItems[line].a.selmode + 1; for (i = 0; i < stopat; i++) if (!I_NextMode (width, height)) return false; } return true; } static int FindId (int id) { int i; for (i = 0; i < 22; i++) { if (IDTranslate[i] == id) return i; } return 0; } static void SetModesMenu (int w, int h, int id) { char strtemp[64]; SetCVarFloat (&DummyDepthCvar, (float)FindId (id)); #ifndef DJGPP SetCVarFloat (&DummyFSCvar, fullscreen->value); #endif if (!testingmode) { if (ModesItems[VM_ENTERLINE].label != VMEnterText) free (ModesItems[VM_ENTERLINE].label); ModesItems[VM_ENTERLINE].label = VMEnterText; ModesItems[VM_TESTLINE].label = VMTestText; sprintf (strtemp, "D to make %dx%d (%s) the default", w, h, IdStrings[id-1000]); ReplaceString (&ModesItems[VM_MAKEDEFLINE].label, strtemp); sprintf (strtemp, "Current default is %dx%d (%s)", (int)vid_defwidth->value, (int)vid_defheight->value, vid_defid->string); ReplaceString (&ModesItems[VM_CURDEFLINE].label, strtemp); } else { sprintf (strtemp, "TESTING %dx%d (%s)", w, h, IdStrings[id-1000]); ModesItems[VM_ENTERLINE].label = copystring (strtemp); ModesItems[VM_TESTLINE].label = "Please wait 5 seconds..."; ModesItems[VM_MAKEDEFLINE].label = copystring (" "); ModesItems[VM_CURDEFLINE].label = copystring (" "); } BuildModesList (w, h, id); } void M_RestoreMode (void) { NewWidth = OldWidth; NewHeight = OldHeight; NewID = OldID; setmodeneeded = true; testingmode = 0; #ifndef DJGPP SetCVarFloat (fullscreen, OldFS); #endif SetModesMenu (OldWidth, OldHeight, OldID); } static void SetVidMode (void) { SetModesMenu (screen.width, screen.height, DisplayID); if (ModesMenu.items[ModesMenu.lastOn].type == screenres) { if (ModesMenu.items[ModesMenu.lastOn].a.selmode == -1) { ModesMenu.items[ModesMenu.lastOn].a.selmode++; } } M_SwitchMenu (&ModesMenu); } void Cmd_Menu_Video (void *plyr, int argc, char **argv) { M_StartControlPanel (); S_Sound (NULL, CHAN_VOICE, "switches/normbutn", 1, ATTN_NONE); OptionsActive = true; SetVidMode (); }