@@ -184,6 +184,8 @@ void create_loading_cvars() {
184184 detour_Cvar_Get::oCvar_Get (" _sofbuddy_tab" , " 0" , 0 , nullptr );
185185 // User preference: keep loading menu input locked (default), or allow interaction.
186186 detour_Cvar_Get::oCvar_Get (" _sofbuddy_loading_lock_input" , " 1" , CVAR_SOFBUDDY_ARCHIVE , nullptr );
187+ detour_Cvar_Get::oCvar_Get (" _sofbuddy_loading_show_mapname" , " 1" , CVAR_SOFBUDDY_ARCHIVE , nullptr );
188+ detour_Cvar_Get::oCvar_Get (" _sofbuddy_loading_show_download" , " 1" , CVAR_SOFBUDDY_ARCHIVE , nullptr );
187189 // User preference: key used to open SoF Buddy menu.
188190 detour_Cvar_Get::oCvar_Get (" _sofbuddy_menu_hotkey" , " F12" , CVAR_SOFBUDDY_ARCHIVE , nullptr );
189191 // Last SoF Buddy tab/page (e.g. sof_buddy/map_debug) restored when opening via F12 (sofbuddy_menu sof_buddy).
@@ -198,11 +200,16 @@ void create_loading_cvars() {
198200 cvar_t * perf = detour_Cvar_Get::oCvar_Get (" _sofbuddy_perf_profile" , " 0" , CVAR_SOFBUDDY_ARCHIVE , sofbuddy_perf_profile_change);
199201 sofbuddy_perf_profile_change (perf);
200202
203+ // FX_Init registers this with flags 0; OR CVAR_ARCHIVE so menu/config.cfg persist changes.
204+ detour_Cvar_Get::oCvar_Get (" fx_maxdebrisonscreen" , " 16" , CVAR_ARCHIVE , nullptr );
201205}
202206
203207constexpr int kSofBuddyCenterPanelVirtualWidth = 640 ;
204- constexpr int kSofBuddyDefaultRow1ContentWidth = 400 ;
205- constexpr int kSofBuddyDefaultRow2ContentWidth = 520 ;
208+ constexpr int kSofBuddyDefaultRow1ContentWidth = 384 ;
209+ constexpr int kSofBuddyDefaultRow2ContentWidth = 384 ;
210+ constexpr int kSofBuddyTabWidthPx = 120 ;
211+ constexpr int kSofBuddyTabGapPx = 12 ;
212+ constexpr int kSofBuddyTabLeftNudgePx = 32 ;
206213
207214cvar_t * _sofbuddy_sb_tabs_row1_content_px = nullptr ;
208215cvar_t * _sofbuddy_sb_tabs_row2_content_px = nullptr ;
@@ -223,12 +230,15 @@ void create_layout_cvars() {
223230 detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_row2_prefix_rmf" , " <blank 36 1>" , kLayoutCvarFlags , nullptr );
224231 detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_row1_suffix_rmf" , " <blank 96 1>" , kLayoutCvarFlags , nullptr );
225232 detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_row2_suffix_rmf" , " <blank 36 1>" , kLayoutCvarFlags , nullptr );
226- _sofbuddy_sb_tabs_row1_content_px = detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_row1_content_px" , " 400 " , kLayoutCvarFlags , nullptr );
227- _sofbuddy_sb_tabs_row2_content_px = detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_row2_content_px" , " 520 " , kLayoutCvarFlags , nullptr );
233+ _sofbuddy_sb_tabs_row1_content_px = detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_row1_content_px" , " 384 " , kLayoutCvarFlags , nullptr );
234+ _sofbuddy_sb_tabs_row2_content_px = detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_row2_content_px" , " 384 " , kLayoutCvarFlags , nullptr );
228235 _sofbuddy_sb_tabs_center_bias_px = detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_center_bias_px" , " 0" , kLayoutCvarFlags , nullptr );
229236 _sofbuddy_sb_tabs_row1_bias_px = detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_row1_bias_px" , " 0" , kLayoutCvarFlags , nullptr );
230237 _sofbuddy_sb_tabs_row2_bias_px = detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_row2_bias_px" , " 0" , kLayoutCvarFlags , nullptr );
231238
239+ // Menu color theme preset index (see kMenuThemes).
240+ detour_Cvar_Get::oCvar_Get (" _sofbuddy_menu_theme" , " 0" , CVAR_SOFBUDDY_ARCHIVE , nullptr );
241+
232242 // SoF default for tip_duration is 2500ms; bump to 5000ms if untouched.
233243 cvar_t * tip_duration = detour_Cvar_Get::oCvar_Get (" tip_duration" , " 2500" , 0 , nullptr );
234244 if (tip_duration && tip_duration->string && std::strcmp (tip_duration->string , " 2500" ) == 0 && detour_Cvar_Set2::oCvar_Set2)
@@ -314,11 +324,11 @@ void update_layout_cvars(bool trigger_reloadall_if_changed) {
314324 const int row1_bias_px = _sofbuddy_sb_tabs_row1_bias_px ? static_cast <int >(_sofbuddy_sb_tabs_row1_bias_px->value + 0 .5f ) : 0 ;
315325 const int row2_bias_px = _sofbuddy_sb_tabs_row2_bias_px ? static_cast <int >(_sofbuddy_sb_tabs_row2_bias_px->value + 0 .5f ) : 0 ;
316326
317- row1_content_px = std::max (64 , std::min (center_panel_px , row1_content_px));
318- row2_content_px = std::max ( 64 , std::min (center_panel_px, row2_content_px)) ;
327+ row1_content_px = std::max (64 , std::min (kSofBuddyCenterPanelVirtualWidth , row1_content_px));
328+ row2_content_px = row1_content_px ;
319329
320- const int row1_prefix_px = std::max (0 , ((center_panel_px - row1_content_px) / 2 ) + center_bias_px + row1_bias_px);
321- const int row2_prefix_px = std::max ( 0 , ((center_panel_px - row2_content_px) / 2 ) + center_bias_px + row2_bias_px) ;
330+ const int row1_prefix_px = std::max (0 , ((kSofBuddyCenterPanelVirtualWidth - row1_content_px) / 2 ) + center_bias_px + row1_bias_px - kSofBuddyTabLeftNudgePx );
331+ const int row2_prefix_px = row1_prefix_px + row2_bias_px - row1_bias_px ;
322332
323333 char row1_rmf[64 ];
324334 char row2_rmf[64 ];
@@ -419,6 +429,69 @@ const char* internal_menus_get_content_inset_tall_rmf(void) {
419429 std::snprintf (buf, sizeof (buf), " <blank %d %d>" , internal_menus_content_inset_px (), internal_menus_menu_vid_h_px ());
420430 return buf;
421431}
432+ // Menu color themes: (bg, fg, secondary/accent, dim, panel) as ABGR (0xAABBGGRR).
433+ // Palettes sourced from popular editor themes (Dracula, Nord, One Dark, Tokyo Night, etc.).
434+ struct MenuTheme { unsigned bg, fg, sec, dim, panel; };
435+ static const MenuTheme kMenuThemes [] = {
436+ {0xff050913 , 0xfff3f7ff , 0xff43ffd0 , 0xff2b3b55 , 0xff101b2b }, // 0 Dark
437+ {0xff000000 , 0xffffffff , 0xff4ad5ff , 0xffa0a0a0 , 0xff161616 }, // 1 Hi Contrast
438+ {0xff00050a , 0xff00b0ff , 0xff7fd2ff , 0xff106aa0 , 0xff000f1a }, // 2 Amber
439+ {0xff001100 , 0xff66ff33 , 0xffc4ff9e , 0xff4f8a2f , 0xff002600 }, // 3 Green
440+ {0xff362b00 , 0xffa1a193 , 0xff98a12a , 0xff756e58 , 0xff423607 }, // 4 Solar Dark
441+ {0xffe3f6fd , 0xff423607 , 0xffd28b26 , 0xffa1a193 , 0xffd5e8ee }, // 5 Solar Light
442+ {0xfff0f5f5 , 0xff1a1a1a , 0xff875f00 , 0xff707070 , 0xffe0e6e6 }, // 6 Paper
443+ {0xff000000 , 0xff00ffff , 0xffffff00 , 0xff00b0b0 , 0xff101010 }, // 7 Hi Yellow
444+ {0xff362a28 , 0xfff2f8f8 , 0xfffde98b , 0xffa47262 , 0xff5a4744 }, // 8 Dracula
445+ {0xff342c28 , 0xffbfb2ab , 0xffefaf61 , 0xff70635c , 0xff2b2521 }, // 9 One Dark
446+ {0xff40342e , 0xfff4efec , 0xffd0c088 , 0xff6a564c , 0xff52423b }, // 10 Nord
447+ {0xff222827 , 0xfff2f8f8 , 0xff2ee2a6 , 0xff5e7175 , 0xff1c1f1e }, // 11 Monokai
448+ {0xff261b1a , 0xfff5cac0 , 0xfff7a27a , 0xff895f56 , 0xff1e1616 }, // 12 Tokyo Night
449+ {0xff2e1e1e , 0xfff4d6cd , 0xfffab489 , 0xff86706c , 0xff251818 }, // 13 Catppuccin
450+ {0xff282828 , 0xffb2dbeb , 0xff98a583 , 0xff748392 , 0xff21201d }, // 14 Gruvbox
451+ {0xff3b352d , 0xffaac6d3 , 0xff80c0a7 , 0xff78847a , 0xff2e2a23 }, // 15 Everforest
452+ {0xff17110d , 0xffd9d1c9 , 0xffffa658 , 0xff9e948b , 0xff221b16 }, // 16 GitHub Dark
453+ {0xff140e0a , 0xffb6bdbf , 0xffe6ba39 , 0xff736a62 , 0xff1a130f }, // 17 Ayu Dark
454+ {0xff3e2d29 , 0xffcdaca6 , 0xffffaa82 , 0xff956e67 , 0xff33221f }, // 18 Palenight
455+ {0xff241719 , 0xfff4dee0 , 0xffe7a7c4 , 0xff866a6e , 0xff2e1d1f }, // 19 Rose Pine
456+ {0xff271601 , 0xffebded6 , 0xffffaa82 , 0xff777763 , 0xff42290b }, // 20 Night Owl
457+ {0xff493519 , 0xffffffff , 0xff00c6ff , 0xffff8800 , 0xff382712 }, // 21 Cobalt2
458+ {0xff3f3f3f , 0xffccdcdc , 0xff809070 , 0xffafaf9f , 0xff333333 }, // 22 Zenburn
459+ {0xff2f1b24 , 0xfff1eff0 , 0xffdb7eff , 0xffbd8b84 , 0xff23141a }, // 23 Synthwave
460+ {0xff08020d , 0xff41ff00 , 0xff33cc00 , 0xff118f00 , 0xff001a00 }, // 24 Matrix
461+ {0xff000000 , 0xffe0e0e0 , 0xff76e600 , 0xff888888 , 0xff0a0a0a }, // 25 OLED
462+ {0xffffffff , 0xff2f2924 , 0xffda6909 , 0xff766d65 , 0xfffaf8f6 }, // 26 GitHub Light
463+ {0xfffafafa , 0xff423a38 , 0xfff27840 , 0xffa7a1a0 , 0xfff0f0f0 }, // 27 One Light
464+ {0xfff5f1ef , 0xff694f4c , 0xfff5661e , 0xffb0a09c , 0xffefe9e6 }, // 28 Cat Latte
465+ {0xfff4efec , 0xff40342e , 0xffac815e , 0xff6a564c , 0xfff0e9e5 }, // 29 Nord Snow
466+ {0xffd8ecf4 , 0xff223443 , 0xff13458b , 0xff556a7a , 0xffcfe3eb }, // 30 Sepia
467+ };
468+ const char * internal_menus_get_theme_tints_rmf (void ) {
469+ static char buf[512 ];
470+ int idx = 0 ;
471+ if (detour_Cvar_Get::oCvar_Get) {
472+ cvar_t * c = detour_Cvar_Get::oCvar_Get (" _sofbuddy_menu_theme" , " 0" , CVAR_SOFBUDDY_ARCHIVE , nullptr );
473+ if (c) idx = static_cast <int >(c->value + 0 .5f );
474+ }
475+ if (idx < 0 || idx >= static_cast <int >(sizeof (kMenuThemes ) / sizeof (kMenuThemes [0 ]))) idx = 0 ;
476+ const MenuTheme& t = kMenuThemes [idx];
477+ std::snprintf (buf, sizeof (buf),
478+ " <tint normaltext 0x%08x><tint hilitetext 0x%08x>"
479+ " <tint sb_bg 0x%08x><tint sb_panel 0x%08x>"
480+ " <tint sb_accent 0x%08x><tint sb_subtle 0x%08x>"
481+ " <tint white 0x%08x><tint cyan 0x%08x>"
482+ " <tint gray 0x%08x><tint orange 0x%08x>" ,
483+ t.fg , t.bg , t.bg , t.panel ,
484+ t.sec , t.dim , t.fg , t.sec ,
485+ t.dim , t.fg );
486+ return buf;
487+ }
488+ const char * internal_menus_get_tabs_row_prefix_rmf (void ) {
489+ if (detour_Cvar_Get::oCvar_Get) {
490+ cvar_t * c = detour_Cvar_Get::oCvar_Get (" _sofbuddy_sb_tabs_row1_prefix_rmf" , " <blank 124 1>" , 0 , nullptr );
491+ if (c && c->string && c->string [0 ]) return c->string ;
492+ }
493+ return " <blank 124 1>" ;
494+ }
422495
423496bool internal_menus_deathmatch_mode_active (void ) {
424497 if (!detour_Cvar_Get::oCvar_Get) return false ;
@@ -456,9 +529,28 @@ const char* internal_menus_loading_menu_name(void) {
456529 return internal_menus_should_lock_loading_input () ? " loading/loading" : " loading/loading_safe" ;
457530}
458531
532+ static std::string loading_display_map_name (const char * map_name) {
533+ if (!map_name || !map_name[0 ]) return map_name ? map_name : " " ;
534+ std::string n (map_name);
535+ std::replace (n.begin (), n.end (), ' \\ ' , ' /' );
536+ while (n.rfind (" ./" , 0 ) == 0 ) n.erase (0 , 2 );
537+ while (!n.empty () && n[0 ] == ' /' ) n.erase (0 , 1 );
538+ if (n.size () >= 5 &&
539+ (n[0 ] == ' m' || n[0 ] == ' M' ) &&
540+ (n[1 ] == ' a' || n[1 ] == ' A' ) &&
541+ (n[2 ] == ' p' || n[2 ] == ' P' ) &&
542+ (n[3 ] == ' s' || n[3 ] == ' S' ) &&
543+ n[4 ] == ' /' ) {
544+ n.erase (0 , 5 );
545+ }
546+ return n;
547+ }
548+
459549void loading_set_current (const char * map_name) {
460550 if (!map_name || !detour_Cvar_Set2::oCvar_Set2) return ;
461- detour_Cvar_Set2::oCvar_Set2 (const_cast <char *>(" _sofbuddy_loading_current" ), const_cast <char *>(map_name), true );
551+ const std::string display = loading_display_map_name (map_name);
552+ detour_Cvar_Set2::oCvar_Set2 (const_cast <char *>(" _sofbuddy_loading_current" ),
553+ const_cast <char *>(display.c_str ()), true );
462554}
463555
464556void loading_reset_current_map_unknown (void ) {
0 commit comments