X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=menu.c;h=7b51ab4cf523f2069b30bfc1734903b04975ff7a;hb=HEAD;hp=38fc7adf64230976109508062a3fdb0170ba81b8;hpb=c5790ebb593767e649ede7ec8c3f38aed3168db3;p=xonotic%2Fdarkplaces.git diff --git a/menu.c b/menu.c index 38fc7adf..6c935ef7 100644 --- a/menu.c +++ b/menu.c @@ -421,6 +421,7 @@ void M_Menu_Main_f(cmd_state_t *cmd) } +static bool mp_failed; static void M_Main_Draw (void) { int f; @@ -433,11 +434,20 @@ static void M_Main_Draw (void) const char *s; M_Background(640, 480); //fall back is always to 640x480, this makes it most readable at that. y = 480/3-16; - s = "You have reached this menu due to missing or unlocatable content/data";M_PrintRed ((640-strlen(s)*8)*0.5, (480/3)-16, s);y+=8; - y+=8; - s = "You may consider adding";M_Print ((640-strlen(s)*8)*0.5, y, s);y+=8; - s = "-basedir /path/to/game";M_Print ((640-strlen(s)*8)*0.5, y, s);y+=8; - s = "to your launch commandline";M_Print ((640-strlen(s)*8)*0.5, y, s);y+=8; + if (mp_failed) + { + s = "The menu QC program has failed.";M_PrintRed ((640-strlen(s)*8)*0.5, y, s);y+=8; + y+=8; + s = "You should find the specific error(s) in the console.";M_Print ((640-strlen(s)*8)*0.5, y, s);y+=8; + } + else + { + s = "The required files were not found.";M_PrintRed ((640-strlen(s)*8)*0.5, y, s);y+=8; + y+=8; + s = "You may consider adding";M_Print ((640-strlen(s)*8)*0.5, y, s);y+=8; + s = "-basedir /path/to/game";M_Print ((640-strlen(s)*8)*0.5, y, s);y+=8; + s = "to your launch commandline.";M_Print ((640-strlen(s)*8)*0.5, y, s);y+=8; + } M_Print (640/2 - 48, 480/2, "Open Console"); //The console usually better shows errors (failures) M_Print (640/2 - 48, 480/2 + 8, "Quit"); M_DrawCharacter(640/2 - 56, 480/2 + (8 * m_main_cursor), 12+((int)(host.realtime*4)&1)); @@ -497,6 +507,8 @@ static void M_Main_Key(cmd_state_t *cmd, int key, int ascii) key_dest = key_game; m_state = m_none; //cls.demonum = m_save_demonum; + //if(!cl_startdemos.integer) + // break; //if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected) // CL_NextDemo (); break; @@ -2816,6 +2828,7 @@ video_resolution_t video_resolutions_hardcoded[] = {"WideScreen 16x9" , 1280, 720, 640, 360, 1 }, {"WideScreen 16x9" , 1360, 768, 680, 384, 1 }, {"WideScreen 16x9" , 1366, 768, 683, 384, 1 }, +{"WideScreen 16x9" , 1600, 900, 640, 360, 1 }, {"WideScreen 16x9" , 1920,1080, 640, 360, 1 }, {"WideScreen 16x9" , 2560,1440, 640, 360, 1 }, {"WideScreen 16x9" , 3840,2160, 640, 360, 1 }, @@ -2830,9 +2843,9 @@ video_resolution_t video_resolutions_hardcoded[] = // this is the number of the default mode (640x480) in the list above int video_resolutions_hardcoded_count = sizeof(video_resolutions_hardcoded) / sizeof(*video_resolutions_hardcoded) - 1; -#define VIDEO_ITEMS 10 +#define VIDEO_ITEMS 11 static int video_cursor = 0; -static int video_cursor_table[VIDEO_ITEMS] = {68, 88, 96, 104, 112, 120, 128, 136, 144, 152}; +static int video_cursor_table[VIDEO_ITEMS] = {68, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160}; static int menu_video_resolution; video_resolution_t *video_resolutions; @@ -2923,7 +2936,7 @@ static void M_Video_Draw (void) // Current and Proposed Resolution M_Print(16, video_cursor_table[t] - 12, " Current Resolution"); - if (vid_supportrefreshrate && vid.mode.userefreshrate && vid.mode.fullscreen) + if (vid.mode.refreshrate && vid.mode.fullscreen && !vid.mode.desktopfullscreen) M_Print(220, video_cursor_table[t] - 12, va(vabuf, sizeof(vabuf), "%dx%d %.2fhz", vid.mode.width, vid.mode.height, vid.mode.refreshrate)); else M_Print(220, video_cursor_table[t] - 12, va(vabuf, sizeof(vabuf), "%dx%d", vid.mode.width, vid.mode.height)); @@ -2938,13 +2951,8 @@ static void M_Video_Draw (void) t++; // Refresh Rate - M_ItemPrint(16, video_cursor_table[t], " Use Refresh Rate", vid_supportrefreshrate); - M_DrawCheckbox(220, video_cursor_table[t], vid_userefreshrate.integer); - t++; - - // Refresh Rate - M_ItemPrint(16, video_cursor_table[t], " Refresh Rate", vid_supportrefreshrate && vid_userefreshrate.integer); - M_DrawSlider(220, video_cursor_table[t], vid_refreshrate.value, 50, 150); + M_ItemPrint(16, video_cursor_table[t], " Refresh Rate", vid_fullscreen.integer && !vid_desktopfullscreen.integer); + M_DrawSlider(220, video_cursor_table[t], vid_refreshrate.value, 50, 480); t++; // Fullscreen @@ -2952,9 +2960,19 @@ static void M_Video_Draw (void) M_DrawCheckbox(220, video_cursor_table[t], vid_fullscreen.integer); t++; + // Desktop Fullscreen + M_ItemPrint(16, video_cursor_table[t], " Desktop Fullscreen", vid_fullscreen.integer); + M_DrawCheckbox(220, video_cursor_table[t], vid_desktopfullscreen.integer); + t++; + + // Display selection (multi-monitor) + M_ItemPrint(16, video_cursor_table[t], " Display/Monitor", vid_info_displaycount.integer > 1); + M_DrawSlider(220, video_cursor_table[t], vid_display.integer, 0, vid_info_displaycount.integer - 1); + t++; + // Vertical Sync M_ItemPrint(16, video_cursor_table[t], " Vertical Sync", true); - M_DrawCheckbox(220, video_cursor_table[t], vid_vsync.integer); + M_DrawSlider(220, video_cursor_table[t], vid_vsync.integer, -1, 1); t++; M_ItemPrint(16, video_cursor_table[t], " Anisotropic Filter", vid.support.ext_texture_filter_anisotropic); @@ -3002,14 +3020,16 @@ static void M_Menu_Video_AdjustSliders (int dir) } else if (video_cursor == t++) Cvar_SetValueQuick (&vid_samples, bound(1, vid_samples.value * (dir > 0 ? 2 : 0.5), 32)); + else if (video_cursor == t++) // allow jumping from the minimum refreshrate to 0 (auto) + Cvar_SetValueQuick (&vid_refreshrate, vid_refreshrate.value <= 50 && dir == -1 ? 0 : bound(50, vid_refreshrate.value + dir, 480)); else if (video_cursor == t++) - Cvar_SetValueQuick (&vid_userefreshrate, !vid_userefreshrate.integer); + Cvar_SetValueQuick (&vid_fullscreen, !vid_fullscreen.integer); else if (video_cursor == t++) - Cvar_SetValueQuick (&vid_refreshrate, bound(50, vid_refreshrate.value + dir, 150)); + Cvar_SetValueQuick (&vid_desktopfullscreen, !vid_desktopfullscreen.integer); else if (video_cursor == t++) - Cvar_SetValueQuick (&vid_fullscreen, !vid_fullscreen.integer); + Cvar_SetValueQuick (&vid_display, bound(0, vid_display.integer + dir, vid_info_displaycount.integer - 1)); else if (video_cursor == t++) - Cvar_SetValueQuick (&vid_vsync, !vid_vsync.integer); + Cvar_SetValueQuick (&vid_vsync, bound(-1, vid_vsync.integer + dir, 1)); else if (video_cursor == t++) Cvar_SetValueQuick (&gl_texture_anisotropy, bound(1, gl_texture_anisotropy.value * (dir < 0 ? 0.5 : 2.0), vid.max_anisotropy)); else if (video_cursor == t++) @@ -3025,12 +3045,12 @@ static void M_Video_Key(cmd_state_t *cmd, int key, int ascii) { case K_ESCAPE: // vid_shared.c has a copy of the current video config. We restore it + Cvar_SetValueQuick(&vid_display, vid.mode.display); Cvar_SetValueQuick(&vid_fullscreen, vid.mode.fullscreen); + Cvar_SetValueQuick(&vid_desktopfullscreen, vid.mode.desktopfullscreen); Cvar_SetValueQuick(&vid_bitsperpixel, vid.mode.bitsperpixel); Cvar_SetValueQuick(&vid_samples, vid.mode.samples); - if (vid_supportrefreshrate) - Cvar_SetValueQuick(&vid_refreshrate, vid.mode.refreshrate); - Cvar_SetValueQuick(&vid_userefreshrate, vid.mode.userefreshrate); + Cvar_SetValueQuick(&vid_refreshrate, vid.mode.refreshrate); S_LocalSound ("sound/misc/menu1.wav"); M_Menu_Options_f(cmd); @@ -3433,7 +3453,7 @@ static void M_LanConfig_Key(cmd_state_t *cmd, int key, int ascii) Cbuf_AddText(cmd, "stopdemo\n"); - Cvar_SetValue(&cvars_all, "port", lanConfig_port); + Cvar_SetValueQuick(&sv_netport, lanConfig_port); if (lanConfig_cursor == 1 || lanConfig_cursor == 2) { @@ -3990,7 +4010,7 @@ void M_GameOptions_Draw (void) if (gamemode == GAME_TRANSFUSION) { if (!coop.integer && !deathmatch.integer) - Cvar_SetValue(&cvars_all, "deathmatch", 1); + Cvar_SetQuick(&deathmatch, "1"); if (deathmatch.integer == 0) M_Print(160, 64, "Cooperative"); else if (deathmatch.integer == 2) @@ -4001,7 +4021,7 @@ void M_GameOptions_Draw (void) else if (gamemode == GAME_BATTLEMECH) { if (!deathmatch.integer) - Cvar_SetValue(&cvars_all, "deathmatch", 1); + Cvar_SetQuick(&deathmatch, "1"); if (deathmatch.integer == 2) M_Print(160, 64, "Rambo Match"); else @@ -4010,7 +4030,7 @@ void M_GameOptions_Draw (void) else { if (!coop.integer && !deathmatch.integer) - Cvar_SetValue(&cvars_all, "deathmatch", 1); + Cvar_SetQuick(&deathmatch, "1"); if (coop.integer) M_Print(160, 64, "Cooperative"); else @@ -4352,7 +4372,7 @@ static void M_GameOptions_Key(cmd_state_t *cmd, int key, int ascii) l = min(l - 1, 37); memcpy(hostnamebuf, hostname.string, l); hostnamebuf[l] = 0; - Cvar_Set(&cvars_all, "hostname", hostnamebuf); + Cvar_SetQuick(&hostname, hostnamebuf); } } break; @@ -4368,7 +4388,7 @@ static void M_GameOptions_Key(cmd_state_t *cmd, int key, int ascii) memcpy(hostnamebuf, hostname.string, l); hostnamebuf[l] = ascii; hostnamebuf[l+1] = 0; - Cvar_Set(&cvars_all, "hostname", hostnamebuf); + Cvar_SetQuick(&hostname, hostnamebuf); } } } @@ -4506,17 +4526,15 @@ static void M_ServerList_Key(cmd_state_t *cmd, int k, int ascii) //============================================================================= /* MODLIST MENU */ -// same limit of mod dirs as in fs.c -#define MODLIST_MAXDIRS 16 -static int modlist_enabled [MODLIST_MAXDIRS]; //array of indexs to modlist +// same limit of mod dirs as in fs.c (allowing that one is used by gamedirname1) +#define MODLIST_MAXDIRS MAX_GAMEDIRS - 1 static int modlist_numenabled; //number of enabled (or in process to be..) mods typedef struct modlist_entry_s { qbool loaded; // used to determine whether this entry is loaded and running - int enabled; // index to array of modlist_enabled - // name of the modification, this is (will...be) displayed on the menu entry + // name of the modification, this is displayed on the menu entry char name[128]; // directory where we will find it char dir[MAX_QPATH]; @@ -4533,17 +4551,15 @@ static void ModList_RebuildList(void) int i,j; stringlist_t list; const char *description; + int desc_len; stringlistinit(&list); listdirectory(&list, fs_basedir, ""); stringlistsort(&list, true); modlist_count = 0; - modlist_numenabled = fs_numgamedirs; + modlist_numenabled = 0; for (i = 0;i < list.numstrings && modlist_count < MODLIST_TOTALSIZE;i++) { - // quickly skip names with dot characters - generally these are files, not directories - if (strchr(list.strings[i], '.')) continue; - // reject any dirs that are part of the base game if (gamedirname1 && !strcasecmp(gamedirname1, list.strings[i])) continue; //if (gamedirname2 && !strcasecmp(gamedirname2, list.strings[i])) continue; @@ -4554,18 +4570,26 @@ static void ModList_RebuildList(void) description = FS_CheckGameDir(list.strings[i]); if (description == NULL || description == fs_checkgamedir_missing) continue; + desc_len = min(strlen(description), sizeof(modlist[modlist_count].name)); + for (j = 0; j < desc_len; ++j) + if (!ISWHITESPACE(description[j])) + { + dp_strlcpy(modlist[modlist_count].name, description, sizeof(modlist[modlist_count].name)); + break; + } + dp_strlcpy (modlist[modlist_count].dir, list.strings[i], sizeof(modlist[modlist_count].dir)); - //check currently loaded mods + + // check if this mod is currently loaded modlist[modlist_count].loaded = false; - if (fs_numgamedirs) - for (j = 0; j < fs_numgamedirs; j++) - if (!strcasecmp(fs_gamedirs[j], modlist[modlist_count].dir)) - { - modlist[modlist_count].loaded = true; - modlist[modlist_count].enabled = j; - modlist_enabled[j] = modlist_count; - break; - } + for (j = 0; j < fs_numgamedirs; j++) + if (!strcasecmp(fs_gamedirs[j], modlist[modlist_count].dir)) + { + modlist[modlist_count].loaded = true; + modlist_numenabled++; + break; + } + modlist_count ++; } stringlistfreecontents(&list); @@ -4575,22 +4599,7 @@ static void ModList_Enable (void) { int i; int numgamedirs; - char gamedirs[MODLIST_MAXDIRS][MAX_QPATH]; - - // copy our mod list into an array for FS_ChangeGameDirs - numgamedirs = modlist_numenabled; - for (i = 0; i < modlist_numenabled; i++) - dp_strlcpy (gamedirs[i], modlist[modlist_enabled[i]].dir,sizeof (gamedirs[i])); - - // this code snippet is from FS_ChangeGameDirs - if (fs_numgamedirs == numgamedirs) - { - for (i = 0;i < numgamedirs;i++) - if (strcasecmp(fs_gamedirs[i], gamedirs[i])) - break; - if (i == numgamedirs) - return; // already using this set of gamedirs, do nothing - } + const char *gamedirs[MODLIST_MAXDIRS]; // this part is basically the same as the FS_GameDir_f function if ((cls.state == ca_connected && !cls.demoplayback) || sv.active) @@ -4600,7 +4609,18 @@ static void ModList_Enable (void) return; } - FS_ChangeGameDirs (modlist_numenabled, gamedirs, true, true); + // copy our mod list into an array for FS_ChangeGameDirs + for (i = 0, numgamedirs = 0; i < modlist_count && numgamedirs < MODLIST_MAXDIRS; i++) + if (modlist[i].loaded) + gamedirs[numgamedirs++] = modlist[i].dir; + // allow disabling all active mods using the menu + if (numgamedirs == 0) + { + numgamedirs = 1; + gamedirs[0] = gamedirname1; + } + + FS_ChangeGameDirs(numgamedirs, gamedirs, true); } void M_Menu_ModList_f(cmd_state_t *cmd) @@ -4615,28 +4635,13 @@ void M_Menu_ModList_f(cmd_state_t *cmd) static void M_Menu_ModList_AdjustSliders (int dir) { - int i; S_LocalSound ("sound/misc/menu3.wav"); // stop adding mods, we reach the limit if (!modlist[modlist_cursor].loaded && (modlist_numenabled == MODLIST_MAXDIRS)) return; + modlist[modlist_cursor].loaded = !modlist[modlist_cursor].loaded; - if (modlist[modlist_cursor].loaded) - { - modlist[modlist_cursor].enabled = modlist_numenabled; - //push the value on the enabled list - modlist_enabled[modlist_numenabled++] = modlist_cursor; - } - else - { - //eliminate the value from the enabled list - for (i = modlist[modlist_cursor].enabled; i < modlist_numenabled; i++) - { - modlist_enabled[i] = modlist_enabled[i+1]; - modlist[modlist_enabled[i]].enabled--; - } - modlist_numenabled--; - } + modlist_numenabled += modlist[modlist_cursor].loaded ? 1 : -1; } static void M_ModList_Draw (void) @@ -4656,8 +4661,12 @@ static void M_ModList_Draw (void) M_PrintRed(432, 32, s_enabled); // Draw a list box with all enabled mods DrawQ_Pic(menu_x + 432, menu_y + 48, NULL, 172, 8 * modlist_numenabled, 0, 0, 0, 0.5, 0); - for (y = 0; y < modlist_numenabled; y++) - M_PrintRed(432, 48 + y * 8, modlist[modlist_enabled[y]].dir); + for (n = 0, y = 48; n < modlist_count; n++) + if (modlist[n].loaded) + { + M_PrintRed(432, y, modlist[n].dir); + y += 8; + } if (*cl_connect_status) M_Print(16, menu_height - 8, cl_connect_status); @@ -4673,8 +4682,10 @@ static void M_ModList_Draw (void) { for (n = start;n < end;n++) { + const char *item_label = (modlist[n].name[0] != '\0') ? modlist[n].name : modlist[n].dir; + DrawQ_Pic(menu_x + 40, menu_y + y, NULL, 360, 8, n == modlist_cursor ? (0.5 + 0.2 * sin(host.realtime * M_PI)) : 0, 0, 0, 0.5, 0); - M_ItemPrint(80, y, modlist[n].dir, true); + M_ItemPrint(80, y, item_label, true); M_DrawCheckbox(48, y, modlist[n].loaded); y +=8; } @@ -4910,8 +4921,6 @@ void M_Draw (void) S_LocalSound ("sound/misc/menu2.wav"); m_entersound = false; } - - S_ExtraUpdate (); } @@ -5215,8 +5224,9 @@ static int m_numrequiredglobals = sizeof(m_required_globals) / sizeof(m_required void MR_SetRouting (qbool forceold); -void MVM_error_cmd(const char *format, ...) DP_FUNC_PRINTF(1); -void MVM_error_cmd(const char *format, ...) +jmp_buf mp_abort; +static void MVM_error_cmd(const char *format, ...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN; +static void MVM_error_cmd(const char *format, ...) { static qbool processingError = false; char errorstring[MAX_INPUTLINE]; @@ -5230,9 +5240,6 @@ void MVM_error_cmd(const char *format, ...) dpvsnprintf (errorstring, sizeof(errorstring), format, argptr); va_end (argptr); - if (host.framecount < 3) - Sys_Error("Menu_Error: %s", errorstring); - Con_Printf(CON_ERROR "Menu_Error: %s\n", errorstring); if(!processingError) @@ -5247,6 +5254,9 @@ void MVM_error_cmd(const char *format, ...) Con_Print("Falling back to engine menu\n"); key_dest = key_game; MR_SetRouting (true); + mp_failed = true; + if (cls.state != ca_connected || key_dest != key_game) // if not disrupting a game + MR_ToggleMenu(1); // ensure error screen appears, eg for: menu_progs ""; menu_restart // reset the active scene, too (to be on the safe side ;)) R_SelectScene( RST_CLIENT ); @@ -5257,8 +5267,8 @@ void MVM_error_cmd(const char *format, ...) // restore configured outfd sys.outfd = outfd; - // Let video start at least - Host_AbortCurrentFrame(); + // no frame abort: menu failure shouldn't interfere with more important VMs + longjmp(mp_abort, 1); } static void MVM_begin_increase_edicts(prvm_prog_t *prog) @@ -5305,6 +5315,9 @@ static void MP_KeyEvent (int key, int ascii, qbool downevent) { prvm_prog_t *prog = MVM_prog; + if (setjmp(mp_abort)) + return; + // pass key prog->globals.fp[OFS_PARM0] = (prvm_vec_t) key; prog->globals.fp[OFS_PARM1] = (prvm_vec_t) ascii; @@ -5323,6 +5336,9 @@ static void MP_Draw (void) if (!prog->loaded) return; + if (setjmp(mp_abort)) + return; + R_SelectScene( RST_MENU ); // reset the temp entities each frame @@ -5353,6 +5369,9 @@ static void MP_ToggleMenu(int mode) { prvm_prog_t *prog = MVM_prog; + if (setjmp(mp_abort)) + return; + prog->globals.fp[OFS_PARM0] = (prvm_vec_t) mode; prog->ExecuteProgram(prog, PRVM_menufunction(m_toggle),"m_toggle(float mode) required"); } @@ -5360,6 +5379,10 @@ static void MP_ToggleMenu(int mode) static void MP_NewMap(void) { prvm_prog_t *prog = MVM_prog; + + if (setjmp(mp_abort)) + return; + if (PRVM_menufunction(m_newmap)) prog->ExecuteProgram(prog, PRVM_menufunction(m_newmap),"m_newmap() required"); } @@ -5368,6 +5391,10 @@ const serverlist_entry_t *serverlist_callbackentry = NULL; static int MP_GetServerListEntryCategory(const serverlist_entry_t *entry) { prvm_prog_t *prog = MVM_prog; + + if (setjmp(mp_abort)) + return 0; + serverlist_callbackentry = entry; if (PRVM_menufunction(m_gethostcachecategory)) { @@ -5385,6 +5412,10 @@ static int MP_GetServerListEntryCategory(const serverlist_entry_t *entry) static void MP_Shutdown (void) { prvm_prog_t *prog = MVM_prog; + + if (setjmp(mp_abort)) + return; + if (prog->loaded) prog->ExecuteProgram(prog, PRVM_menufunction(m_shutdown),"m_shutdown() required"); @@ -5398,6 +5429,10 @@ static void MP_Shutdown (void) static void MP_Init (void) { prvm_prog_t *prog = MVM_prog; + + if (setjmp(mp_abort)) + return; + PRVM_Prog_Init(prog, cmd_local); prog->edictprivate_size = 0; // no private struct used @@ -5478,7 +5513,7 @@ void MR_Restart(void) { if(MR_Shutdown) MR_Shutdown (); - MR_SetRouting (false); + MR_Init(); } static void MR_Restart_f(cmd_state_t *cmd)