WIP: server browser (only shows fake servers you can't connect to rn)

This commit is contained in:
SinnamonLat 2022-07-26 23:50:23 +02:00
parent fdf57e59db
commit 2a4c4f86fc
5 changed files with 697 additions and 74 deletions

View file

@ -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.

View file

@ -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);

View file

@ -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[] =
{

View file

@ -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<<FRACBITS, 100<<FRACBITS, FRACUNIT, (!mpmenu.room) ? (5<<V_ALPHASHIFT) : 0, butt2[(!mpmenu.room) ? 1 : 0], NULL);
}
// SERVER BROWSER
void M_DrawMPServerBrowser(void)
{
patch_t *text1 = W_CachePatchName("MENUBGT1", PU_CACHE);
patch_t *text2 = W_CachePatchName("MENUBGT2", PU_CACHE);
patch_t *raceh = W_CachePatchName("M_SERV1", PU_CACHE);
patch_t *batlh = W_CachePatchName("M_SERV2", PU_CACHE);
patch_t *racehs = W_CachePatchName("M_SERV12", PU_CACHE);
patch_t *batlhs = W_CachePatchName("M_SERV22", PU_CACHE);
fixed_t text1loop = SHORT(text1->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);
// bgText<x>Scroll 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!

View file

@ -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))
{