Refactor and rework viewserver

Thanks to the srb2 classic team and luigi budd for the original version
This commit is contained in:
NepDisk 2025-06-09 15:43:05 -04:00
parent 56edab2480
commit 7c712836f3
10 changed files with 481 additions and 60 deletions

View file

@ -154,6 +154,8 @@ static boolean cl_redownloadinggamestate = false;
static UINT8 localtextcmd[MAXSPLITSCREENPLAYERS][MAXTEXTCMD];
static tic_t neededtic;
SINT8 servernode = 0; // the number of the server node
SINT8 joinnode = 0; // used for CL_VIEWSERVER
char connectedservername[MAXSERVERNAME+1];
/// \brief do we accept new players?
/// \todo WORK!
@ -541,27 +543,6 @@ void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum)
static INT16 Consistancy(void);
typedef enum
{
CL_SEARCHING,
CL_CHECKFILES,
CL_DOWNLOADFILES,
CL_DOWNLOADFAILED,
CL_ASKJOIN,
CL_LOADFILES,
CL_SETUPFILES,
CL_WAITJOINRESPONSE,
CL_DOWNLOADSAVEGAME,
CL_CONNECTED,
CL_ABORTED,
CL_ASKFULLFILELIST,
CL_CONFIRMCONNECT,
#ifdef HAVE_CURL
CL_PREPAREHTTPFILES,
CL_DOWNLOADHTTPFILES,
#endif
} cl_mode_t;
static void GetPackets(void);
static cl_mode_t cl_mode = CL_SEARCHING;
@ -572,6 +553,34 @@ char http_source[MAX_MIRROR_LENGTH];
static UINT16 cl_lastcheckedfilecount = 0; // used for full file list
static const char* servmus_1 = "SRVMS1";
static const char* servmus_2 = "SRVMS2";
// "SRVMS3" allows for the music position to be kept between servmus_1 and servmus_3
// also takes priority over servmus_2
static const char* servmus_3 = "SRVMS3";
static void ChangeServMusic(const char* musname, boolean fallback, boolean keepPos)
{
if (S_MusicExists(musname))
if (keepPos)
S_ChangeMusicEx(musname,0,true, S_GetMusicPosition(), 0,0);
else
S_ChangeMusicInternal(musname,true);
else if (fallback)
S_ChangeMusicInternal("BLANCD",true);
}
// Let external code read and modify this stuff.
INT32 GetClientMode(void)
{
return cl_mode;
}
void ChangeClientMode(INT32 mode)
{
cl_mode = mode;
}
//
// CL_DrawConnectionStatus
//
@ -589,6 +598,7 @@ static inline void CL_DrawConnectionStatus(void)
#ifdef HAVE_CURL
&& cl_mode != CL_DOWNLOADHTTPFILES
#endif
&& cl_mode != CL_VIEWSERVER
)
{
INT32 i, animtime = ((ccstime / 4) & 15) + 16;
@ -703,6 +713,14 @@ static inline void CL_DrawConnectionStatus(void)
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24, MENUCAPS|V_20TRANS|V_MONOSPACE,
va(" %2u/%2u Files",loadcompletednum,fileneedednum));
}
else if (cl_mode == CL_VIEWSERVER)
{
if (!menustack[0])
{
M_StartControlPanel();
M_EnterMenu(MN_VIEWSERVER, true, 0);
}
}
else if (lastfilenum != -1)
{
INT32 dldlength;
@ -944,7 +962,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
else
netbuffer->u.serverinfo.refusereason = 0;
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[prefgametype],
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype],
sizeof netbuffer->u.serverinfo.gametypename);
netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
@ -1043,20 +1061,16 @@ static void SV_SendPlayerInfo(INT32 node)
for (i = 0; i < MSCOMPAT_MAXPLAYERS; i++)
{
if (i >= MAXPLAYERS)
{
netbuffer->u.playerinfo[i].num = 255; // Master Server compat
continue;
}
if (!playeringame[i])
if (i >= MAXPLAYERS || playernode[i] == UINT8_MAX || !playeringame[i])
{
netbuffer->u.playerinfo[i].num = 255; // This slot is empty.
continue;
}
netbuffer->u.playerinfo[i].num = i;
strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1);
memset(netbuffer->u.playerinfo[i].name, 0x00, sizeof(netbuffer->u.playerinfo[i].name));
memcpy(netbuffer->u.playerinfo[i].name, player_names[i], sizeof(player_names[i]));
netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0';
//fetch IP address
@ -1603,6 +1617,10 @@ static boolean CL_FinishedFileList(void)
"Press ACCEL to continue or BRAKE to cancel.\n\n"
), M_ConfirmConnect, MM_EVENTHANDLER);
cl_mode = CL_CONFIRMCONNECT;
if (S_MusicExists(servmus_3))
ChangeServMusic(servmus_3, true,true);
else
ChangeServMusic(servmus_2, false,false);
}
else
cl_mode = CL_LOADFILES;
@ -1672,6 +1690,11 @@ static boolean CL_FinishedFileList(void)
Z_Free(downloadsize);
cl_mode = CL_CONFIRMCONNECT;
if (S_MusicExists(servmus_3))
ChangeServMusic(servmus_3, true,true);
else
ChangeServMusic(servmus_2, false,false);
}
#ifdef HAVE_CURL
else
@ -1771,7 +1794,8 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
return true;
}
cl_mode = CL_CHECKFILES;
cl_mode = CL_VIEWSERVER; //cl_mode = CL_CHECKFILES;
ChangeServMusic(servmus_1, true,false);
}
else
{
@ -1816,7 +1840,10 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
case CL_ASKFULLFILELIST:
if (cl_lastcheckedfilecount == UINT16_MAX) // All files retrieved
cl_mode = CL_CHECKFILES;
{
cl_mode = CL_VIEWSERVER; //cl_mode = CL_CHECKFILES;
ChangeServMusic(servmus_1, true,false);
}
else if (fileneedednum != cl_lastcheckedfilecount || I_GetTime() >= *asksent)
{
if (CL_AskFileList(fileneedednum))
@ -2002,8 +2029,15 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
else
continue;
if (key == KEY_ESCAPE || G_ControlBoundToKey(0, gc_brake, key, true))
cl_mode = CL_ABORTED;
if (cl_mode == CL_VIEWSERVER && menustack[0])
{
M_Responder(ev);
}
else
{
if (key == KEY_ESCAPE || G_ControlBoundToKey(0, gc_brake, key, true))
cl_mode = CL_ABORTED;
}
}
}
@ -4331,31 +4365,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
switch (netbuffer->packettype)
{
case PT_ASKINFOVIAMS:
#if 0
if (server && serverrunning)
{
INT32 clientnode;
if (ms_RoomId < 0) // ignore if we're not actually on the MS right now
{
Net_CloseConnection(node); // and yes, close connection
return;
}
clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr);
if (clientnode != -1)
{
SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time));
SV_SendPlayerInfo(clientnode); // Send extra info
Net_CloseConnection(clientnode);
// Don't close connection to MS...
}
else
Net_CloseConnection(node); // ...unless the IP address is not valid
}
else
Net_CloseConnection(node); // you're not supposed to get it, so ignore it
#else
Net_CloseConnection(node);
#endif
break;
case PT_TELLFILESNEEDED:
@ -4536,6 +4546,9 @@ static void HandlePacketFromAwayNode(SINT8 node)
case PT_CLIENTCMD:
break; // This is not an "unknown packet"
case PT_PLAYERINFO:
break;
case PT_SERVERTICS:
// Do not remove my own server (we have just get a out of order packet)
if (node == servernode)

View file

@ -471,6 +471,28 @@ void SendNetXCmdForPlayer(UINT8 playerid, netxcmd_t id, const void *param, size_
#define SendNetXCmd(id, param, nparam) SendNetXCmdForPlayer(0, id, param, nparam) // Shortcut for P1
void SendKick(UINT8 playernum, UINT8 msg);
typedef enum
{
CL_SEARCHING,
CL_CHECKFILES,
CL_DOWNLOADFILES,
CL_DOWNLOADFAILED,
CL_ASKJOIN,
CL_LOADFILES,
CL_SETUPFILES,
CL_WAITJOINRESPONSE,
CL_DOWNLOADSAVEGAME,
CL_CONNECTED,
CL_ABORTED,
CL_ASKFULLFILELIST,
CL_CONFIRMCONNECT,
CL_VIEWSERVER,
#ifdef HAVE_CURL
CL_PREPAREHTTPFILES,
CL_DOWNLOADHTTPFILES,
#endif
} cl_mode_t;
// Create any new ticcmds and broadcast to other players.
void NetKeepAlive(void);
void NetUpdate(void);
@ -530,6 +552,10 @@ extern char motd[254], server_context[8];
extern UINT8 playernode[MAXPLAYERS];
/* consoleplayer of this player (splitscreen) */
extern UINT8 playerconsole[MAXPLAYERS];
extern SINT8 joinnode;
INT32 GetClientMode(void);
void ChangeClientMode(INT32 mode);
INT32 D_NumPlayers(void);
boolean D_IsPlayerHumanAndGaming(INT32 player_number);

View file

@ -748,6 +748,8 @@ struct menu_routine_s const MENU_ROUTINES[] = {
{ "ASSIGNJOYSTICK", &MR_AssignJoystick },
{ "HANDLEMONITORTOGGLES", &MR_HandleMonitorToggles },
{ "RESTARTAUDIO", &MR_RestartAudio },
{ "QUITVIEWSERVER", &MR_QuitViewServer },
{ "HANDLEVIEWSERVER", &MR_HandleViewServer },
#ifdef HAVE_DISCORDRPC
{ "HANDLEDISCORDREQUESTS", &MR_HandleDiscordRequests },
#endif
@ -776,7 +778,7 @@ struct menu_drawer_s const MENU_DRAWERS[] = {
{ "DRAWCONTROL", &M_DrawControl },
{ "DRAWJOYSTICK", &M_DrawJoystick },
{ "DRAWMONITORTOGGLES", &M_DrawMonitorToggles },
{ "DRAWCONNECTMENU", &M_DrawConnectMenu },
{ "DRAWVIEWSERVER", &M_DrawViewServer },
#ifdef HAVE_DISCORDRPC
{ "DRAWDISCORDREQUESTS", &M_DrawDiscordRequests },
#endif

View file

@ -103,7 +103,7 @@ extern "C" {
// Special Hashing.
//#define NOMD5
//#define NOFILEHASH
#define NOFILEHASH
// Uncheck this to compile debugging code
//#define RANGECHECK

View file

@ -919,6 +919,8 @@ static const char *blancredits[] = {
"\"Lactozilla\"",
"\"xyzzy\"",
"\"SuperJustinBros\"",
"SRB2Classic Team",
"\"luigi budd\"",
"",
"\1Ring Racers Programming",
"Kart Krew Dev",

View file

@ -768,6 +768,31 @@ INT32 G_MapNumber(const char * name)
#endif
}
/** Returns the map number from level title.
*
* \param name Map name;
* \return Map number.
* \sa G_BuildMapName, nextmapspecial_t
*/
INT32 G_LevelTitleToMapNum(const char * leveltitle)
{
INT32 map;
for (map = 0; map < nummapheaders; ++map)
{
if (!strcasecmp(leveltitle, mapheaderinfo[map]->lvlttl))
{
return map;
}
if (!strcasecmp(leveltitle, va("%s %s", mapheaderinfo[map]->lvlttl, mapheaderinfo[map]->actnum)))
{
return map;
}
}
return INT32_MIN;
}
// convert kart map number to native map number
INT16 G_KartMapToNative(INT16 mapnum)
{

View file

@ -100,6 +100,7 @@ void weaponPrefChange4(void);
const char *G_BuildMapName(INT32 map);
INT32 G_MapNumber(const char *mapname);
INT32 G_LevelTitleToMapNum(const char * leveltitle);
INT16 G_KartMapToNative(INT16 mapnum);
INT16 G_NativeMapToKart(INT16 mapnum);

View file

@ -77,6 +77,7 @@ _(MISC_REPLAYSTART)
_(AD_MAIN)
// MISC
_(VIEWSERVER)
_(HELP)
_(SPAUSE)
_(MPAUSE)

View file

@ -268,6 +268,8 @@ static INT16 M_GetMenuIndex(menutype_t type, const char *name)
#define M_SetItemArgument(t, n, v) (M_GetMenuItem(t, n)->argument = v)
#define M_SetItemX(t, n, v) (M_GetMenuItem(t, n)->x = v)
#define M_SetItemY(t, n, v) (M_GetMenuItem(t, n)->y = v)
#define M_SetItemText(t, n, s) (M_GetMenuItem(t, n)->text = s)
#define M_GetItemX(t, n) (M_GetMenuItem(t, n)->x)
#define M_GetItemY(t, n) (M_GetMenuItem(t, n)->y)
static void M_ChangeItemStatus(menutype_t type, const char *name, UINT16 flag, boolean cond)
@ -7744,6 +7746,352 @@ INT32 MR_HandleMonitorToggles(INT32 choice)
return true;
}
INT32 MR_QuitViewServer(INT32 choice)
{
(void)choice;
D_QuitNetGame();
CL_Reset();
return true;
}
static boolean viewserver_showaddons = false;
static INT32 viewserver_scroll = 0;
static INT16 viewserver_animcount = 8;
INT32 MR_HandleViewServer(INT32 choice)
{
switch (choice)
{
case KEY_ENTER:
S_StartSound(NULL, sfx_menu1);
ChangeClientMode(CL_CHECKFILES);
M_ClearMenus(false);
return true;
break;
case KEY_SPACE:
S_StartSound(NULL, sfx_menu1);
viewserver_showaddons = !viewserver_showaddons;
return true;
break;
case KEY_UPARROW:
case KEY_DOWNARROW:
if (viewserver_showaddons && fileneedednum > 22)
{
if (choice == KEY_UPARROW)
viewserver_scroll -= 1;
else if (choice == KEY_DOWNARROW)
viewserver_scroll += 1;
S_StartSound(NULL, sfx_menu1);
if (viewserver_scroll < 0) viewserver_scroll = 0;
if (viewserver_scroll >= fileneedednum - 22) viewserver_scroll = fileneedednum -22;
return true;
}
break;
default:
break;
}
return false;
}
void M_DrawViewServer(void)
{
UINT32 ping = (UINT32)serverlist[joinnode].info.time;
UINT8 kartvars = serverlist[joinnode].info.kartvars;
const char *speedstring = "Auto";
const char *serverstring = "Listen";
const char *maptitle = serverlist[joinnode].info.maptitle;
INT32 mapnum = G_LevelTitleToMapNum(maptitle);
patch_t *current_map;
V_DrawFill(M_GetItemX(MN_VIEWSERVER, "TOPBOXXY"), M_GetItemY(MN_VIEWSERVER, "TOPBOXXY"), M_GetItemX(MN_VIEWSERVER, "TOPBOXWH"), M_GetItemY(MN_VIEWSERVER, "TOPBOXWH"), 159);
V_DrawThinString(M_GetItemX(MN_VIEWSERVER, "SERVERNAME"), M_GetItemY(MN_VIEWSERVER, "SERVERNAME"), V_ALLOWLOWERCASE, va("%s", serverlist[joinnode].info.servername));
if (mapnum == INT32_MIN)
{
V_DrawSmallScaledPatch(10, 18, 0, W_CachePatchName("RANDOMLV", PU_CACHE));
}
else
{
fixed_t scale = M_GetMapThumbnail(mapnum, &current_map)/4;
V_DrawFixedPatch(10<<FRACBITS, 18<<FRACBITS, scale, 0, current_map, NULL);
}
switch (kartvars & SV_SPEEDMASK)
{
case KARTSPEED_EASY:
speedstring = "Easy";
break;
case KARTSPEED_NORMAL:
speedstring = "Normal";
break;
case KARTSPEED_HARD:
speedstring = "Hard";
break;
}
if (kartvars & SV_DEDICATED)
{
serverstring = "Dedicated";
}
V_DrawThinString(M_GetItemX(MN_VIEWSERVER, "SERVERPING"), M_GetItemY(MN_VIEWSERVER, "SERVERPING"), V_ALLOWLOWERCASE, va("Ping: %s%ums", (ping < 128 ? "\x83" : (ping < 256 ? "\x82" : "\x85")), ping));
V_DrawThinString(M_GetItemX(MN_VIEWSERVER, "SERVERMAP"), M_GetItemY(MN_VIEWSERVER, "SERVERMAP"), V_ALLOWLOWERCASE, va("%s", serverlist[joinnode].info.maptitle));
V_DrawThinString(M_GetItemX(MN_VIEWSERVER, "SERVERGAMETYPE"), M_GetItemY(MN_VIEWSERVER, "SERVERGAMETYPE"), V_ALLOWLOWERCASE, va("%s: %s", serverlist[joinnode].info.gametypename, speedstring));
if (fileneedednum > 0)
{
V_DrawThinString(M_GetItemX(MN_VIEWSERVER, "SERVERADDON"), M_GetItemY(MN_VIEWSERVER, "SERVERADDON"), V_ALLOWLOWERCASE|warningflags, va("%i Addons", fileneedednum));
}
else
{
V_DrawThinString(M_GetItemX(MN_VIEWSERVER, "SERVERADDON"), M_GetItemY(MN_VIEWSERVER, "SERVERADDON"), V_ALLOWLOWERCASE|highlightflags, "Vanilla");
}
if (serverlist[joinnode].info.cheatsenabled)
{
V_DrawRightAlignedThinString(M_GetItemX(MN_VIEWSERVER, "SERVERCHEATS"), M_GetItemY(MN_VIEWSERVER, "SERVERCHEATS"), V_ALLOWLOWERCASE|recommendedflags, "Cheats");
}
V_DrawRightAlignedThinString(M_GetItemX(MN_VIEWSERVER, "SERVERDEDICATED"), M_GetItemY(MN_VIEWSERVER, "SERVERDEDICATED"), V_ALLOWLOWERCASE|recommendedflags, va("%s Server", serverstring));
V_DrawFill(M_GetItemX(MN_VIEWSERVER, "MIDBOXXY"), M_GetItemY(MN_VIEWSERVER, "MIDBOXXY"), M_GetItemX(MN_VIEWSERVER, "MIDBOXWH"), M_GetItemY(MN_VIEWSERVER, "MIDBOXWH"), 159);
if (!viewserver_showaddons)
{
INT32 i;
INT32 count = 0;
INT32 x = 14;
INT32 y = 84;
char player_name[MAXPLAYERNAME+1];
plrinfo *playerinfo = netbuffer->u.playerinfo;
UINT8 playeramount = serverlist[joinnode].info.numberofplayer;
UINT8 maxplayer = serverlist[joinnode].info.maxplayer;
V_DrawString(12, 74, V_ALLOWLOWERCASE|highlightflags, "Players");
V_DrawRightAlignedString(BASEVIDWIDTH - 12, 74, V_ALLOWLOWERCASE|highlightflags, va("%i / %i", playeramount, maxplayer));
if (playeramount > 0)
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (playerinfo[i].num < 255)
{
if (playeramount <= 16)
{
UINT8 skinum = playerinfo[i].skin;
INT32 flags = 0;
if (R_SkinAvailable(skins[skinum].name) == -1)
{
INT32 statuscolor = 1;
if (playerinfo[i].team == 0) { statuscolor = 112; } // playing
if (playerinfo[i].team == 1) { statuscolor = 35; } // ctf red team
if (playerinfo[i].team == 2) { statuscolor = 152; } // ctf blue team
if (playerinfo[i].team == 255) { statuscolor = 16; flags |= V_40TRANS; } // spectator or non-team
V_DrawFill(x, y+5, 16, 16, statuscolor);
}
else
{
patch_t *facerank = faceprefix[skinum][FACE_RANK];
UINT8 *colormap = R_GetTranslationColormap(skinum, skins[skinum].prefcolor, GTC_MENUCACHE);
if (playerinfo[i].team == 255)
{
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GREY, GTC_MENUCACHE);
flags |= V_40TRANS;
}
V_DrawFixedPatch(x<<FRACBITS, (y+5)<<FRACBITS, FRACUNIT, flags, facerank, colormap);
}
strlcpy(player_name, playerinfo[i].name, 12);
V_DrawThinString(x + 20, y + 3 + 5, flags|V_ALLOWLOWERCASE|V_6WIDTHSPACE, player_name);
y += 22;
count++;
if ((count == 4) || (count == 8) || (count == 12))
{
x += 74;
y = 84;
}
}
else
{
INT32 statuscolor = 1;
strlcpy(player_name, playerinfo[i].name, 12);
V_DrawThinString(x + 10, y, V_ALLOWLOWERCASE|V_6WIDTHSPACE, player_name);
if (playerinfo[i].team == 0) { statuscolor = 112; } // playing
if (playerinfo[i].team == 1) { statuscolor = 35; } // ctf red team
if (playerinfo[i].team == 2) { statuscolor = 152; } // ctf blue team
if (playerinfo[i].team == 255) { statuscolor = 16; } // spectator or non-team
V_DrawFill(x, y, 7, 7, 31);
V_DrawFill(x, y, 6, 6, statuscolor);
y += 9;
count++;
if ((count == 11) || (count == 22))
{
x += 104;
y = 84;
}
}
}
}
}
}
else
{
INT32 i;
INT32 count = 0;
INT32 x = 14;
INT32 y = 84;
boolean small_mode = fileneedednum <= 11;
char file_name[MAX_WADPATH+1];
V_DrawString(12, 74, V_ALLOWLOWERCASE|highlightflags, "Addons");
#define maxcharlen (20 + 3) // 3 for the 3 dots
#define charsonside 10
for (i = viewserver_scroll; i < fileneedednum; i++)
{
if (i & 1)
V_DrawFill(x,y-1,
(small_mode) ? 292 : 146, 9,
156
);
fileneeded_t addon_file = fileneeded[i];
strncpy(file_name, addon_file.filename, MAX_WADPATH);
if ((UINT8)(strlen(file_name)+1) > maxcharlen && !small_mode)
V_DrawThinString(x, y, V_ALLOWLOWERCASE|V_6WIDTHSPACE,
va("\x82[#%d]\x80: %.*s...%s",i+1, charsonside, file_name, file_name+strlen(file_name)-((charsonside+1)))
);
else
{
V_DrawThinString(x, y, V_ALLOWLOWERCASE|V_6WIDTHSPACE,
va("\x82[#%d]\x80: %s",i+1, file_name)
);
// make sure we have the space
if (small_mode)
{
float file_size = ((float)addon_file.totalsize);
UINT8 size_mode = 0; // regular bytes
//in megabytes
if (file_size >= (1024.0f * 1024.0f))
{
size_mode = 1;
file_size /= (1024.0f * 1024.0f);
}
// KB
else if (file_size >= 1024.0f)
{
size_mode = 2;
file_size /= 1024.0f;
}
V_DrawRightAlignedThinString(x + 292,
y, highlightflags|V_ALLOWLOWERCASE,
// "~" since its approx this size, we mightve lost some
// accuracy from only having 4 bytes carry the size
va("(~%.1f%s)", file_size, size_mode == 0 ? "b" : (size_mode == 2 ? "kb" : "mb"))
);
}
}
y += 9;
count++;
if (count == 11)
{
x = BASEVIDWIDTH/2;
y = 84;
}
// Cannot draw any more
if (count == 22)
break;
}
// reiterate again!!! Yes!!! Yay!!!
{
UINT32 totalsize = 0;
UINT8 size_mode = 0; // regular bytes
for (INT32 j = 0; j < fileneedednum; j++)
totalsize += fileneeded[j].totalsize;
totalsize = (float)totalsize;
//in megabytes
if (totalsize >= (1024.0f * 1024.0f))
{
size_mode = 1;
totalsize /= (1024.0f * 1024.0f);
}
// KB
else if (totalsize >= 1024.0f)
{
size_mode = 2;
totalsize /= 1024.0f;
}
V_DrawRightAlignedThinString(BASEVIDWIDTH - 22, 74,
V_ALLOWLOWERCASE|highlightflags,
va("~%.1f%s total", (float)totalsize, size_mode == 0 ? "b" : (size_mode == 2 ? "kb" : "mb"))
);
}
// draw the little arrows
if (fileneedednum >= 22)
{
// up arrow
if (viewserver_scroll)
V_DrawRightAlignedThinString(BASEVIDWIDTH - 12,
74 - (viewserver_animcount/5), highlightflags,
"\x1A"
);
if (viewserver_scroll != fileneedednum-22)
V_DrawRightAlignedThinString(BASEVIDWIDTH - 12,
y-9 + (viewserver_animcount/5), highlightflags,
"\x1B"
);
}
}
#undef maxcharlen
#undef charsonside
// Buttons
V_DrawFill(8, BASEVIDHEIGHT - 14, BASEVIDWIDTH - 16, 13, 159);
V_DrawThinString(
16, BASEVIDHEIGHT - 11,
V_ALLOWLOWERCASE, "[""\x82""ESC""\x80""] = Return"
);
V_DrawCenteredThinString(
BASEVIDWIDTH/2, BASEVIDHEIGHT - 11,
V_ALLOWLOWERCASE,
va("[""\x82""SPACE""\x80""] = %s", (viewserver_showaddons ? "Players" : "Addons"))
);
V_DrawRightAlignedThinString(
BASEVIDWIDTH - 12, BASEVIDHEIGHT - 11,
V_ALLOWLOWERCASE, "[""\x82""ENTER""\x80""] = Join"
);
}
// =========
// Quit Game
// =========

View file

@ -312,6 +312,8 @@ INT32 MR_ChangeControl(INT32 arg);
INT32 MR_AssignJoystick(INT32 arg);
INT32 MR_HandleMonitorToggles(INT32 choice);
INT32 MR_RestartAudio(INT32 choice);
INT32 MR_QuitViewServer(INT32 choice);
INT32 MR_HandleViewServer(INT32 choice);
#ifdef HAVE_DISCORDRPC
INT32 MR_HandleDiscordRequests(INT32 choice);
#endif
@ -338,6 +340,7 @@ void M_DrawMusicTest(void);
void M_DrawControl(void);
void M_DrawJoystick(void);
void M_DrawMonitorToggles(void);
void M_DrawViewServer(void);
#ifdef HAVE_DISCORDRPC
void M_DrawDiscordRequests(void);
#endif