From 2a4c4f86fce38189dc73e34ab3acf5a321f719f1 Mon Sep 17 00:00:00 2001 From: SinnamonLat Date: Tue, 26 Jul 2022 23:50:23 +0200 Subject: [PATCH] WIP: server browser (only shows fake servers you can't connect to rn) --- src/doomdef.h | 2 +- src/k_menu.h | 58 ++++- src/k_menudef.c | 28 +++ src/k_menudraw.c | 110 ++++++++- src/k_menufunc.c | 573 +++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 697 insertions(+), 74 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index 78208a25c..08c8fb137 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -162,7 +162,7 @@ extern char logfilename[1024]; // Comment out this line to completely disable update alerts (recommended for testing, but not for release) #ifndef BETAVERSION -#define UPDATE_ALERT +//#define UPDATE_ALERT #endif // The string used in the alert that pops up in the event of an update being available. diff --git a/src/k_menu.h b/src/k_menu.h index e3d678c0d..c018c7614 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -21,6 +21,10 @@ #include "g_demo.h" //menudemo_t #include "k_profiles.h" // profile data & functions #include "g_input.h" // gc_ +#include "i_threads.h" +#include "mserv.h" + +#define SERVERLISTDEBUG // flags for items in the menu // menu handle (what we do when key is pressed @@ -83,6 +87,18 @@ extern I_mutex k_menu_mutex; #endif +// for server threads etc. +typedef enum +{ + M_NOT_WAITING, + + M_WAITING_VERSION, + M_WAITING_SERVERS, +} +M_waiting_mode_t; + +extern M_waiting_mode_t m_waiting_mode; + typedef union { struct menu_s *submenu; // IT_SUBMENU @@ -210,6 +226,9 @@ extern menu_t PLAY_MP_JoinIPDef; extern menuitem_t PLAY_MP_RoomSelect[]; extern menu_t PLAY_MP_RoomSelectDef; +extern menuitem_t PLAY_MP_ServerBrowser[]; +extern menu_t PLAY_MP_ServerBrowserDef; + extern menuitem_t PLAY_BattleGamemodesMenu[]; extern menu_t PLAY_BattleGamemodesDef; @@ -638,6 +657,9 @@ void M_DifficultySelectInputs(INT32 choice); // Keep track of multiplayer menu related data // We'll add more stuff here as we need em... +#define SERVERSPERPAGE 8 +#define SERVERSPACE 18 + extern struct mpmenu_s { UINT8 modechoice; INT16 modewinextend[3][3]; // Used to "extend" the options in the mode select screen. @@ -645,8 +667,14 @@ extern struct mpmenu_s { // See M_OptSelectTick, it'll make more sense there. Sorry if this is a bit of a mess! UINT8 room; - tic_t ticker; + + UINT8 servernum; + UINT8 scrolln; + // max scrolln is always going to be serverlistcount-4 as we can display 8 servers at any time and we start scrolling at half. + + INT16 slide; + } mpmenu; // MP selection @@ -672,6 +700,33 @@ void M_MPRoomSelect(INT32 choice); void M_MPRoomSelectTick(void); void M_MPRoomSelectInit(INT32 choice); +// Server browser hell with threads... +void M_SetWaitingMode(int mode); +int M_GetWaitingMode(void); + +void M_MPServerBrowserTick(void); +boolean M_ServerBrowserInputs(INT32 ch); + +#ifdef MASTERSERVER +#ifdef HAVE_THREADS + +void Spawn_masterserver_thread (const char *name, void (*thread)(int*)); +int Same_instance (int id); + +#endif /*HAVE_THREADS*/ + +void Fetch_servers_thread (int *id); + +#endif /*MASTERSERVER*/ + +void M_RefreshServers(INT32 choice); +void M_ServersMenu(INT32 choice); + +// for debugging purposes... +#ifdef SERVERLISTDEBUG +void M_ServerListFillDebug(void); +#endif + // Options menu: // mode descriptions for video mode menu @@ -914,6 +969,7 @@ void M_DrawMPOptSelect(void); void M_DrawMPHost(void); void M_DrawMPJoinIP(void); void M_DrawMPRoomSelect(void); +void M_DrawMPServerBrowser(void); // Pause menu: void M_DrawPause(void); diff --git a/src/k_menudef.c b/src/k_menudef.c index e732b5e75..bd810c9e0 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -367,6 +367,34 @@ menu_t PLAY_MP_RoomSelectDef = { NULL }; +// SERVER BROWSER +menuitem_t PLAY_MP_ServerBrowser[] = +{ + + {IT_STRING | IT_CVAR, "SORT BY", NULL, // tooltip MUST be null. + NULL, {.cvar = &cv_serversort}, 0, 0}, + + {IT_STRING, "REFRESH", NULL, + NULL, {NULL}, 0, 0}, + + {IT_NOTHING, NULL, NULL, NULL, {NULL}, 0, 0}, +}; + +menu_t PLAY_MP_ServerBrowserDef = { + sizeof (PLAY_MP_ServerBrowser) / sizeof (menuitem_t), + &PLAY_MP_RoomSelectDef, + 0, + PLAY_MP_ServerBrowser, + 32, 36, + 0, 0, + 0, 0, + M_DrawMPServerBrowser, + M_MPServerBrowserTick, + NULL, + NULL, + M_ServerBrowserInputs +}; + // options menu menuitem_t OPTIONS_Main[] = { diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 674c4e150..5fb105090 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -462,10 +462,9 @@ void M_Drawer(void) // static void M_DrawMenuTooltips(void) { - V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("MENUHINT", PU_CACHE), NULL); - if (currentMenu->menuitems[itemOn].tooltip != NULL) { + V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("MENUHINT", PU_CACHE), NULL); V_DrawCenteredThinString(BASEVIDWIDTH/2, 12, V_ALLOWLOWERCASE|V_6WIDTHSPACE, currentMenu->menuitems[itemOn].tooltip); } } @@ -509,6 +508,7 @@ void M_DrawGenericMenu(void) { if (i == itemOn) cursory = y; + switch (currentMenu->menuitems[i].status & IT_DISPLAY) { case IT_PATCH: @@ -625,6 +625,9 @@ void M_DrawGenericMenu(void) } } + if ((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == 0) + cursory = 300; // Put the cursor off screen if we can't even display that option and we're on it, it makes no sense otherwise... + // DRAW THE SKULL CURSOR if (((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == IT_PATCH) || ((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == IT_NOTHING)) @@ -2317,6 +2320,109 @@ void M_DrawMPRoomSelect(void) V_DrawFixedPatch(160<height)*FRACUNIT; + fixed_t text2loop = SHORT(text2->width)*FRACUNIT; + + const UINT8 startx = 18; + const UINT8 basey = 56; + const INT32 starty = basey - 18*mpmenu.scrolln + mpmenu.slide; + INT32 ypos = 0; + UINT8 i; + + // background stuff + V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("BG_MPS3", PU_CACHE), NULL); + + V_DrawFixedPatch(0, (BASEVIDHEIGHT + 16) * FRACUNIT, FRACUNIT, V_TRANSLUCENT, W_CachePatchName("MENUBG2", PU_CACHE), NULL); + + V_DrawFixedPatch(-bgText2Scroll, (BASEVIDHEIGHT-8) * FRACUNIT, + FRACUNIT, V_TRANSLUCENT, text2, NULL); + V_DrawFixedPatch(-bgText2Scroll + text2loop, (BASEVIDHEIGHT-8) * FRACUNIT, + FRACUNIT, V_TRANSLUCENT, text2, NULL); + + V_DrawFixedPatch(8 * FRACUNIT, -bgText1Scroll, + FRACUNIT, V_TRANSLUCENT, text1, NULL); + V_DrawFixedPatch(8 * FRACUNIT, -bgText1Scroll + text1loop, + FRACUNIT, V_TRANSLUCENT, text1, NULL); + + // bgTextScroll is already handled by the menu background. + + // the actual server list. + for (i = 0; i < serverlistcount; i++) + { + + boolean racegt = strcmp(serverlist[i].info.gametypename, "Race") == 0; + INT32 transflag = 0; + INT32 basetransflag = 0; + + if (serverlist[i].info.numberofplayer >= serverlist[i].info.maxplayer) + basetransflag = 5; + + /*if (i < mpmenu.servernum) + // if slide > 0, then we went DOWN in the list and have to fade that server out. + if (mpmenu.slide > 0) + transflag = basetransflag + (18-mpmenu.slide)/2; + else if (mpmenu.slide < 0) + transflag = 10 - basetransflag - (18-mpmenu.slide)/2;*/ + + transflag = basetransflag; + + if (transflag >= 0 && transflag < 10) + { + transflag = transflag << V_ALPHASHIFT; // shift the translucency flag. + + if (itemOn == 2 && mpmenu.servernum == i) + V_DrawFixedPatch(startx*FRACUNIT, (starty + ypos)*FRACUNIT, FRACUNIT, transflag, racegt ? racehs : batlhs, NULL); + else + V_DrawFixedPatch(startx*FRACUNIT, (starty + ypos)*FRACUNIT, FRACUNIT, transflag, racegt ? raceh : batlh, NULL); + + // Server name: + V_DrawString(startx+11, starty + ypos + 6, V_ALLOWLOWERCASE|transflag, serverlist[i].info.servername); + + // Ping: + V_DrawThinString(startx + 191, starty + ypos + 7, V_6WIDTHSPACE|transflag, va("%03d", serverlist[i].info.time)); + + // Playercount + V_DrawThinString(startx + 214, starty + ypos + 7, V_6WIDTHSPACE|transflag, va("%02d/%02d", serverlist[i].info.numberofplayer, serverlist[i].info.maxplayer)); + + // Power Level + V_DrawThinString(startx + 248, starty + ypos, V_6WIDTHSPACE|transflag, va("%04d PLv", serverlist[i].info.avgpwrlv)); + + // game speed if applicable: + if (racegt) + { + UINT8 speed = serverlist[i].info.kartvars & SV_SPEEDMASK; + patch_t *pp = W_CachePatchName(va("M_SDIFF%d", speed), PU_CACHE); + + V_DrawFixedPatch((startx + 251)*FRACUNIT, (starty + ypos + 9)*FRACUNIT, FRACUNIT, transflag, pp, NULL); + } + } + ypos += SERVERSPACE; + } + + // Draw genericmenu ontop! + V_DrawFill(0, 0, 320, 52, 31); + V_DrawFill(0, 53, 320, 1, 31); + V_DrawFill(0, 55, 320, 1, 31); + + V_DrawCenteredGamemodeString(160, 2, V_ALLOWLOWERCASE, 0, "Server Browser"); + + // normal menu options + M_DrawGenericMenu(); + +} + // OPTIONS MENU // Draws the cogs and also the options background! diff --git a/src/k_menufunc.c b/src/k_menufunc.c index ba87477f3..925552aed 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -158,7 +158,7 @@ CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1]; static CV_PossibleValue_t serversort_cons_t[] = { {0,"Ping"}, - {1,"Modified State"}, + {1,"AVG. Power Level"}, {2,"Most Players"}, {3,"Least Players"}, {4,"Max Player Slots"}, @@ -233,6 +233,9 @@ static CV_PossibleValue_t dummymatchbots_cons_t[] = { consvar_t cv_dummymatchbots = CVAR_INIT ("dummymatchbots", "Off", CV_HIDDEN|CV_SAVE, dummymatchbots_cons_t, NULL); // Save this one if you wanna test your stuff without bots for instance +// for server fetch threads... +M_waiting_mode_t m_waiting_mode = M_NOT_WAITING; + // ========================================================================== // CVAR ONCHANGE EVENTS GO HERE // ========================================================================== @@ -426,35 +429,6 @@ void Addons_option_Onchange(void) (cv_addons_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED); } -void M_SortServerList(void) -{ -#if 0 -#ifndef NONET - switch(cv_serversort.value) - { - case 0: // Ping. - qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_time); - break; - case 1: // Modified state. - qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_modified); - break; - case 2: // Most players. - qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_numberofplayer_reverse); - break; - case 3: // Least players. - qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_numberofplayer); - break; - case 4: // Max players. - qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_maxplayer_reverse); - break; - case 5: // Gametype. - qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametype); - break; - } -#endif -#endif -} - static void M_EraseDataResponse(INT32 ch) { UINT8 i; @@ -1415,7 +1389,7 @@ static void M_MenuTypingInput(INT32 key) M_UpdateKeyboardX(); M_SetMenuDelay(pid); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); } else if (menucmd[pid].dpad_ud < 0) // up { @@ -1425,7 +1399,7 @@ static void M_MenuTypingInput(INT32 key) M_UpdateKeyboardX(); M_SetMenuDelay(pid); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); } else if (menucmd[pid].dpad_lr > 0) // right { @@ -1434,7 +1408,7 @@ static void M_MenuTypingInput(INT32 key) menutyping.keyboardx = 0; M_SetMenuDelay(pid); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); } else if (menucmd[pid].dpad_lr < 0) // left { @@ -1445,7 +1419,7 @@ static void M_MenuTypingInput(INT32 key) M_UpdateKeyboardX(); } M_SetMenuDelay(pid); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); } else if (M_MenuConfirmPressed(pid)) { @@ -1470,7 +1444,7 @@ static void M_MenuTypingInput(INT32 key) } M_SetMenuDelay(pid); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); } } } @@ -2497,7 +2471,7 @@ static boolean M_HandleCSelectProfile(setup_player_t *p, UINT8 num) if (p->profilen > maxp) p->profilen = 0; - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } else if (menucmd[num].dpad_ud < 0) @@ -2507,7 +2481,7 @@ static boolean M_HandleCSelectProfile(setup_player_t *p, UINT8 num) else p->profilen--; - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(num); } else if (M_MenuBackPressed(num)) @@ -2841,7 +2815,7 @@ static void M_HandleChooseFollower(setup_player_t *p, UINT8 num) p->followern = -1; M_SetMenuDelay(num); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_GetFollowerState(p); } else if (menucmd[num].dpad_lr < 0 && numfollowers) @@ -2851,7 +2825,7 @@ static void M_HandleChooseFollower(setup_player_t *p, UINT8 num) p->followern = numfollowers-1; M_SetMenuDelay(num); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_GetFollowerState(p); } else if (M_MenuConfirmPressed(num)) @@ -3885,6 +3859,12 @@ void M_MPRoomSelect(INT32 choice) M_GoBack(0); M_SetMenuDelay(pid); } + + else if (M_MenuConfirmPressed(pid)) + { + M_ServersMenu(0); + M_SetMenuDelay(pid); + } } void M_MPRoomSelectTick(void) @@ -3897,10 +3877,463 @@ void M_MPRoomSelectInit(INT32 choice) (void)choice; mpmenu.room = 0; mpmenu.ticker = 0; + mpmenu.servernum = 0; + mpmenu.scrolln = 0; + mpmenu.slide = 0; M_SetupNextMenu(&PLAY_MP_RoomSelectDef, false); } +// MULTIPLAYER ROOM FETCH / REFRESH THREADS + +// depending on mpmenu.room, either allows only unmodded servers or modded ones. Remove others from the list. +// we do this by iterating backwards. +static void M_CleanServerList(void) +{ + UINT8 i = serverlistcount; + + while (i) + { + + if (serverlist[i].info.modifiedgame != mpmenu.room) + { + // move everything after this index 1 slot down... + if (i != serverlistcount) + memcpy(&serverlist[i], &serverlist[i+1], sizeof(serverelem_t)*(serverlistcount-i)); + + serverlistcount--; + } + + i--; + } +} + +void +M_SetWaitingMode (int mode) +{ +#ifdef HAVE_THREADS + I_lock_mutex(&k_menu_mutex); +#endif + { + m_waiting_mode = mode; + } +#ifdef HAVE_THREADS + I_unlock_mutex(k_menu_mutex); +#endif +} + +int +M_GetWaitingMode (void) +{ + int mode; + +#ifdef HAVE_THREADS + I_lock_mutex(&k_menu_mutex); +#endif + { + mode = m_waiting_mode; + } +#ifdef HAVE_THREADS + I_unlock_mutex(k_menu_mutex); +#endif + + return mode; +} + +#ifdef MASTERSERVER +#ifdef HAVE_THREADS +void +Spawn_masterserver_thread (const char *name, void (*thread)(int*)) +{ + int *id = malloc(sizeof *id); + + I_lock_mutex(&ms_QueryId_mutex); + { + *id = ms_QueryId; + } + I_unlock_mutex(ms_QueryId_mutex); + + I_spawn_thread(name, (I_thread_fn)thread, id); +} + +int +Same_instance (int id) +{ + int okay; + + I_lock_mutex(&ms_QueryId_mutex); + { + okay = ( id == ms_QueryId ); + } + I_unlock_mutex(ms_QueryId_mutex); + + return okay; +} +#endif/*HAVE_THREADS*/ + +void +Fetch_servers_thread (int *id) +{ + msg_server_t * server_list; + + (void)id; + + M_SetWaitingMode(M_WAITING_SERVERS); + +#ifdef HAVE_THREADS + server_list = GetShortServersList(*id); +#else + server_list = GetShortServersList(0); +#endif + + if (server_list) + { +#ifdef HAVE_THREADS + if (Same_instance(*id)) +#endif + { + M_SetWaitingMode(M_NOT_WAITING); + +#ifdef HAVE_THREADS + I_lock_mutex(&ms_ServerList_mutex); + { + ms_ServerList = server_list; + } + I_unlock_mutex(ms_ServerList_mutex); +#else + CL_QueryServerList(server_list); + free(server_list); +#endif + } +#ifdef HAVE_THREADS + else + { + free(server_list); + } +#endif + } + +#ifdef HAVE_THREADS + free(id); +#endif +} +#endif/*MASTERSERVER*/ + +// updates serverlist +void M_RefreshServers(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 + +#ifdef MASTERSERVER +#ifdef HAVE_THREADS + Spawn_masterserver_thread("fetch-servers", Fetch_servers_thread); +#else/*HAVE_THREADS*/ + Fetch_servers_thread(NULL); +#endif/*HAVE_THREADS*/ +#else/*MASTERSERVER*/ + CL_UpdateServerList(); +#endif/*MASTERSERVER*/ + +#ifdef SERVERLISTDEBUG + M_ServerListFillDebug(); +#endif + M_CleanServerList(); + M_SortServerList(); + +} + +#ifndef NONET +#ifdef UPDATE_ALERT +static void M_CheckMODVersion(int id) +{ + char updatestring[500]; + const char *updatecheck = GetMODVersion(id); + if(updatecheck) + { + sprintf(updatestring, UPDATE_ALERT_STRING, VERSIONSTRING, updatecheck); +#ifdef HAVE_THREADS + I_lock_mutex(&k_menu_mutex); +#endif + M_StartMessage(updatestring, NULL, MM_NOTHING); +#ifdef HAVE_THREADS + I_unlock_mutex(k_menu_mutex); +#endif + } +} +#endif/*UPDATE_ALERT*/ + +#if defined (UPDATE_ALERT) && defined (HAVE_THREADS) +static void +Check_new_version_thread (int *id) +{ + M_SetWaitingMode(M_WAITING_VERSION); + + M_CheckMODVersion(*id); + + if (Same_instance(*id)) + { + Fetch_servers_thread(id); + } + else + { + free(id); + } +} +#endif/*defined (UPDATE_ALERT) && defined (HAVE_THREADS)*/ + + +// Initializes serverlist when entering the menu... +void M_ServersMenu(INT32 choice) +{ + (void)choice; + // modified game check: no longer handled + // we don't request a restart unless the filelist differs + + mpmenu.servernum = 0; + mpmenu.scrolln = 0; + mpmenu.slide = 0; + + M_SetupNextMenu(&PLAY_MP_ServerBrowserDef, false); + itemOn = 0; + +#if defined (MASTERSERVER) && defined (HAVE_THREADS) + I_lock_mutex(&ms_QueryId_mutex); + { + ms_QueryId++; + } + I_unlock_mutex(ms_QueryId_mutex); + + I_lock_mutex(&ms_ServerList_mutex); + { + if (ms_ServerList) + { + free(ms_ServerList); + ms_ServerList = NULL; + } + } + I_unlock_mutex(ms_ServerList_mutex); + +#ifdef UPDATE_ALERT + Spawn_masterserver_thread("check-new-version", Check_new_version_thread); +#else/*UPDATE_ALERT*/ + Spawn_masterserver_thread("fetch-servers", Fetch_servers_thread); +#endif/*UPDATE_ALERT*/ +#else/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/ +#ifdef UPDATE_ALERT + M_CheckMODVersion(0); +#endif/*UPDATE_ALERT*/ + M_RefreshServers(0); +#endif/*defined (MASTERSERVER) && defined (HAVE_THREADS)*/ + +#ifdef SERVERLISTDEBUG + M_ServerListFillDebug(); +#endif + + M_CleanServerList(); + M_SortServerList(); +} + +#ifdef SERVERLISTDEBUG + +// Fill serverlist with a bunch of garbage to make our life easier in debugging +void M_ServerListFillDebug(void) +{ + UINT8 i = 0; + + serverlistcount = 10; + memset(serverlist, 0, sizeof(serverlist)); // zero out the array for convenience... + + for (i = 0; i < serverlistcount; i++) + { + // We don't really care about the server node for this, let's just fill in the info so that we have a visual... + serverlist[i].info.numberofplayer = min(i, 8); + serverlist[i].info.maxplayer = 8; + + serverlist[i].info.avgpwrlv = P_RandomRange(500, 1500); + serverlist[i].info.time = P_RandomRange(16, 500); // ping + + strcpy(serverlist[i].info.servername, va("Serv %d", i+1)); + + strcpy(serverlist[i].info.gametypename, i & 1 ? "Race" : "Battle"); + + P_RandomRange(0, 5); // change results... + serverlist[i].info.kartvars = P_RandomRange(0, 3) & SV_SPEEDMASK; + + serverlist[i].info.modifiedgame = P_RandomRange(0, 1); + + CONS_Printf("Serv %d | %d...\n", i, serverlist[i].info.modifiedgame); + } +} + +#endif // SERVERLISTDEBUG + +#endif //NONET + +// Ascending order, not descending. +// The casts are safe as long as the caller doesn't do anything stupid. +#define SERVER_LIST_ENTRY_COMPARATOR(key) \ +static int ServerListEntryComparator_##key(const void *entry1, const void *entry2) \ +{ \ + const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2; \ + if (sa->info.key != sb->info.key) \ + return sa->info.key - sb->info.key; \ + return strcmp(sa->info.servername, sb->info.servername); \ +} + +// This does descending instead of ascending. +#define SERVER_LIST_ENTRY_COMPARATOR_REVERSE(key) \ +static int ServerListEntryComparator_##key##_reverse(const void *entry1, const void *entry2) \ +{ \ + const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2; \ + if (sb->info.key != sa->info.key) \ + return sb->info.key - sa->info.key; \ + return strcmp(sb->info.servername, sa->info.servername); \ +} + +SERVER_LIST_ENTRY_COMPARATOR(time) +SERVER_LIST_ENTRY_COMPARATOR(numberofplayer) +SERVER_LIST_ENTRY_COMPARATOR_REVERSE(numberofplayer) +SERVER_LIST_ENTRY_COMPARATOR_REVERSE(maxplayer) +SERVER_LIST_ENTRY_COMPARATOR(avgpwrlv) + + +static int ServerListEntryComparator_gametypename(const void *entry1, const void *entry2) +{ + const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2; + int c; + if (( c = strcasecmp(sa->info.gametypename, sb->info.gametypename) )) + return c; + return strcmp(sa->info.servername, sb->info.servername); \ +} + +void M_SortServerList(void) +{ +#ifndef NONET + switch(cv_serversort.value) + { + case 0: // Ping. + qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_time); + break; + case 1: // AVG. Power Level + qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_avgpwrlv); + break; + case 2: // Most players. + qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_numberofplayer_reverse); + break; + case 3: // Least players. + qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_numberofplayer); + break; + case 4: // Max players. + qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_maxplayer_reverse); + break; + case 5: // Gametype. + qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename); + break; + } +#endif +} + + +// Server browser inputs & ticker +void M_MPServerBrowserTick(void) +{ + mpmenu.slide /= 2; +} + +// Input handler for server browser. +boolean M_ServerBrowserInputs(INT32 ch) +{ + UINT8 pid = 0; + UINT8 maxscroll = serverlistcount-(SERVERSPERPAGE/2); + (void) ch; + + if (!itemOn && menucmd[pid].dpad_ud < 0) + { + M_PrevOpt(); // go to itemOn 2 + if (serverlistcount) + { + UINT8 prevscroll = mpmenu.scrolln; + + mpmenu.servernum = serverlistcount; + mpmenu.scrolln = maxscroll; + mpmenu.slide = SERVERSPACE * (prevscroll - mpmenu.scrolln); + } + else + { + itemOn = 1; // Sike! If there are no servers, go to refresh instead. + } + + return true; // overwrite behaviour. + } + else if (itemOn == 2) // server browser itself... + { + // we have to manually do that here. + if (M_MenuBackPressed(pid)) + { + M_GoBack(0); + M_SetMenuDelay(pid); + } + + else if (menucmd[pid].dpad_ud > 0) // down + { + if (mpmenu.servernum >= serverlistcount-1) + { + UINT8 prevscroll = mpmenu.scrolln; + mpmenu.servernum = 0; + mpmenu.scrolln = 0; + mpmenu.slide = SERVERSPACE * (prevscroll - mpmenu.scrolln); + + M_NextOpt(); // Go back to the top of the real menu. + } + else + { + mpmenu.servernum++; + if (mpmenu.scrolln < maxscroll && mpmenu.servernum > SERVERSPERPAGE/2) + { + mpmenu.scrolln++; + mpmenu.slide += SERVERSPACE; + } + } + S_StartSound(NULL, sfx_s3k5b); + M_SetMenuDelay(pid); + + } + else if (menucmd[pid].dpad_ud < 0) + { + + if (!mpmenu.servernum) + { + M_PrevOpt(); + } + else + { + if (mpmenu.servernum <= serverlistcount-(SERVERSPERPAGE/2) && mpmenu.scrolln) + { + mpmenu.scrolln--; + mpmenu.slide -= SERVERSPACE; + } + + mpmenu.servernum--; + } + S_StartSound(NULL, sfx_s3k5b); + M_SetMenuDelay(pid); + + } + return true; // Overwrite behaviour. + } + return false; // use normal behaviour. +} + + // Options menu: struct optionsmenu_s optionsmenu; @@ -4037,7 +4470,7 @@ boolean M_OptionsInputs(INT32 ch) M_SetMenuDelay(pid); optionsmenu.offset += 48; M_NextOpt(); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); if (itemOn == 0) optionsmenu.offset -= currentMenu->numitems*48; @@ -4050,7 +4483,7 @@ boolean M_OptionsInputs(INT32 ch) M_SetMenuDelay(pid); optionsmenu.offset -= 48; M_PrevOpt(); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); if (itemOn == currentMenu->numitems-1) optionsmenu.offset += currentMenu->numitems*48; @@ -4253,7 +4686,7 @@ void M_HandleProfileSelect(INT32 ch) optionsmenu.offset -= (128 + 128/8)*(maxp+1); } - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -4268,7 +4701,7 @@ void M_HandleProfileSelect(INT32 ch) optionsmenu.offset += (128 + 128/8)*(maxp+1); } - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -4294,7 +4727,7 @@ void M_HandleProfileSelect(INT32 ch) return; } - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_StartEditProfile(MA_YES); } @@ -4472,7 +4905,7 @@ void M_HandleVideoModes(INT32 ch) } else if (M_MenuConfirmPressed(pid)) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); optionsmenu.vidm_testingmode = 0; // stop testing } } @@ -4481,7 +4914,7 @@ void M_HandleVideoModes(INT32 ch) { if (menucmd[pid].dpad_ud > 0) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); if (++optionsmenu.vidm_selected >= optionsmenu.vidm_nummodes) optionsmenu.vidm_selected = 0; @@ -4490,7 +4923,7 @@ void M_HandleVideoModes(INT32 ch) else if (menucmd[pid].dpad_ud < 0) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); if (--optionsmenu.vidm_selected < 0) optionsmenu.vidm_selected = optionsmenu.vidm_nummodes - 1; @@ -4499,7 +4932,7 @@ void M_HandleVideoModes(INT32 ch) else if (menucmd[pid].dpad_lr < 0) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); optionsmenu.vidm_selected -= optionsmenu.vidm_column_size; if (optionsmenu.vidm_selected < 0) optionsmenu.vidm_selected = (optionsmenu.vidm_column_size*3) + optionsmenu.vidm_selected; @@ -4511,7 +4944,7 @@ void M_HandleVideoModes(INT32 ch) else if (menucmd[pid].dpad_lr > 0) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); optionsmenu.vidm_selected += optionsmenu.vidm_column_size; if (optionsmenu.vidm_selected >= (optionsmenu.vidm_column_size*3)) optionsmenu.vidm_selected %= optionsmenu.vidm_column_size; @@ -4524,7 +4957,7 @@ void M_HandleVideoModes(INT32 ch) else if (M_MenuConfirmPressed(pid)) { M_SetMenuDelay(pid); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); if (vid.modenum == optionsmenu.modedescs[optionsmenu.vidm_selected].modenum) SCR_SetDefaultMode(); else @@ -4929,7 +5362,7 @@ void M_HandleItemToggles(INT32 choice) if (menucmd[pid].dpad_lr > 0) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); column++; if (((column*height)+row) >= currentMenu->numitems) column = 0; @@ -4941,7 +5374,7 @@ void M_HandleItemToggles(INT32 choice) else if (menucmd[pid].dpad_lr < 0) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); column--; if (column < 0) column = width-1; @@ -4957,7 +5390,7 @@ void M_HandleItemToggles(INT32 choice) else if (menucmd[pid].dpad_ud > 0) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); row = (row+1) % height; if (((column*height)+row) >= currentMenu->numitems) row = 0; @@ -4969,7 +5402,7 @@ void M_HandleItemToggles(INT32 choice) else if (menucmd[pid].dpad_ud < 0) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); row = (row-1) % height; if (row < 0) row = height-1; @@ -5080,7 +5513,7 @@ void M_HandleProfileErase(INT32 choice) if (menucmd[pid].dpad_ud > 0) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); optionsmenu.eraseprofilen++; if (optionsmenu.eraseprofilen > np) @@ -5090,7 +5523,7 @@ void M_HandleProfileErase(INT32 choice) } else if (menucmd[pid].dpad_ud < 0) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); if (optionsmenu.eraseprofilen == 1) optionsmenu.eraseprofilen = np; @@ -5180,7 +5613,7 @@ boolean M_ExtrasInputs(INT32 ch) { extrasmenu.offset += 48; M_NextOpt(); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); if (itemOn == 0) extrasmenu.offset -= currentMenu->numitems*48; @@ -5193,7 +5626,7 @@ boolean M_ExtrasInputs(INT32 ch) { extrasmenu.offset -= 48; M_PrevOpt(); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); if (itemOn == currentMenu->numitems-1) extrasmenu.offset += currentMenu->numitems*48; @@ -5324,7 +5757,7 @@ boolean M_PauseInputs(INT32 ch) { M_SetMenuDelay(pid); pausemenu.offset -= 50; // Each item is spaced by 50 px - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_PrevOpt(); return true; } @@ -5332,7 +5765,7 @@ boolean M_PauseInputs(INT32 ch) else if (menucmd[pid].dpad_ud > 0) { pausemenu.offset += 50; // Each item is spaced by 50 px - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_NextOpt(); M_SetMenuDelay(pid); return true; @@ -5604,7 +6037,7 @@ void M_HandleReplayHutList(INT32 choice) return; //M_PrevOpt(); - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1; } @@ -5617,7 +6050,7 @@ void M_HandleReplayHutList(INT32 choice) return; //itemOn = 0; // Not M_NextOpt because that would take us to the extra dummy item - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1; } @@ -5654,7 +6087,7 @@ void M_HandleReplayHutList(INT32 choice) } else { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); dir_on[menudepthleft] = 1; M_PrepReplayList(); } @@ -5667,7 +6100,7 @@ void M_HandleReplayHutList(INT32 choice) } break; case EXT_UP: - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); menupath[menupathindex[++menudepthleft]] = 0; if (!preparefilemenu(false, true)) { @@ -5967,14 +6400,14 @@ void M_HandleAddons(INT32 choice) { if (dir_on[menudepthleft] < sizedirmenu-1) dir_on[menudepthleft]++; - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } else if (menucmd[pid].dpad_ud < 0) { if (dir_on[menudepthleft]) dir_on[menudepthleft]--; - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -5984,7 +6417,7 @@ void M_HandleAddons(INT32 choice) for (i = numaddonsshown; i && (dir_on[menudepthleft] < sizedirmenu-1); i--) dir_on[menudepthleft]++; - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -5994,7 +6427,7 @@ void M_HandleAddons(INT32 choice) for (i = numaddonsshown; i && (dir_on[menudepthleft]); i--) dir_on[menudepthleft]--; - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); M_SetMenuDelay(pid); } @@ -6030,7 +6463,7 @@ void M_HandleAddons(INT32 choice) } else { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); dir_on[menudepthleft] = 1; } refresh = false; @@ -6044,7 +6477,7 @@ void M_HandleAddons(INT32 choice) break; case EXT_UP: - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_s3k5b); menupath[menupathindex[++menudepthleft]] = 0; if (!preparefilemenu(false, false)) {