Merge branch 'addons-backport' into '2122-version'

Addons Menu backport to vanilla

See merge request STJr/SRB2!384
This commit is contained in:
Digiku 2018-12-23 18:08:06 -05:00
commit 8d56c2f486
15 changed files with 1280 additions and 134 deletions

View file

@ -33,6 +33,7 @@
#include "i_system.h" #include "i_system.h"
#include "d_main.h" #include "d_main.h"
#include "m_menu.h" #include "m_menu.h"
#include "filesrch.h"
#ifdef _WINDOWS #ifdef _WINDOWS
#include "win32/win_main.h" #include "win32/win_main.h"
@ -1290,12 +1291,15 @@ void CONS_Alert(alerttype_t level, const char *fmt, ...)
switch (level) switch (level)
{ {
case CONS_NOTICE: case CONS_NOTICE:
// no notice for notices, hehe
CONS_Printf("\x83" "%s" "\x80 ", M_GetText("NOTICE:")); CONS_Printf("\x83" "%s" "\x80 ", M_GetText("NOTICE:"));
break; break;
case CONS_WARNING: case CONS_WARNING:
refreshdirmenu |= REFRESHDIR_WARNING;
CONS_Printf("\x82" "%s" "\x80 ", M_GetText("WARNING:")); CONS_Printf("\x82" "%s" "\x80 ", M_GetText("WARNING:"));
break; break;
case CONS_ERROR: case CONS_ERROR:
refreshdirmenu |= REFRESHDIR_ERROR;
CONS_Printf("\x85" "%s" "\x80 ", M_GetText("ERROR:")); CONS_Printf("\x85" "%s" "\x80 ", M_GetText("ERROR:"));
break; break;
} }

View file

@ -309,6 +309,7 @@ typedef struct
} ATTRPACK clientconfig_pak; } ATTRPACK clientconfig_pak;
#define MAXSERVERNAME 32 #define MAXSERVERNAME 32
#define MAXFILENEEDED 915
// This packet is too large // This packet is too large
typedef struct typedef struct
{ {
@ -330,7 +331,7 @@ typedef struct
unsigned char mapmd5[16]; unsigned char mapmd5[16];
UINT8 actnum; UINT8 actnum;
UINT8 iszone; UINT8 iszone;
UINT8 fileneeded[915]; // is filled with writexxx (byteptr.h) UINT8 fileneeded[MAXFILENEEDED]; // is filled with writexxx (byteptr.h)
} ATTRPACK serverinfo_pak; } ATTRPACK serverinfo_pak;
typedef struct typedef struct

View file

@ -74,6 +74,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
#include "m_cond.h" // condition initialization #include "m_cond.h" // condition initialization
#include "fastcmp.h" #include "fastcmp.h"
#include "keys.h" #include "keys.h"
#include "filesrch.h" // refreshdirmenu, mainwadstally
#ifdef CMAKECONFIG #ifdef CMAKECONFIG
#include "config.h" #include "config.h"
@ -583,6 +584,8 @@ void D_SRB2Loop(void)
realtics = entertic - oldentertics; realtics = entertic - oldentertics;
oldentertics = entertic; oldentertics = entertic;
refreshdirmenu = 0; // not sure where to put this, here as good as any?
#ifdef DEBUGFILE #ifdef DEBUGFILE
if (!realtics) if (!realtics)
if (debugload) if (debugload)
@ -847,17 +850,21 @@ static void IdentifyVersion(void)
#if !defined (HAVE_SDL) || defined (HAVE_MIXER) #if !defined (HAVE_SDL) || defined (HAVE_MIXER)
{ {
#define MUSICTEST(str) \
{\
const char *musicpath = va(pandf,srb2waddir,str);\
int ms = W_VerifyNMUSlumps(musicpath); \
if (ms == 1) \
D_AddFile(musicpath); \
else if (ms == 0) \
I_Error("File "str" has been modified with non-music/sound lumps"); \
}
#if defined (DC) && 0 #if defined (DC) && 0
const char *musicfile = "music_dc.dta"; MUSICTEST("music_dc.dta")
#else #else
const char *musicfile = "music.dta"; MUSICTEST("music.dta")
#endif #endif
const char *musicpath = va(pandf,srb2waddir,musicfile);
int ms = W_VerifyNMUSlumps(musicpath); // Don't forget the music!
if (ms == 1)
D_AddFile(musicpath);
else if (ms == 0)
I_Error("File %s has been modified with non-music lumps",musicfile);
} }
#endif #endif
} }
@ -1133,25 +1140,36 @@ void D_SRB2Main(void)
#endif #endif
D_CleanFile(); D_CleanFile();
mainwads = 0;
#ifndef DEVELOP // md5s last updated 12/14/14 #ifndef DEVELOP // md5s last updated 12/14/14
// Check MD5s of autoloaded files // Check MD5s of autoloaded files
W_VerifyFileMD5(0, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad W_VerifyFileMD5(mainwads++, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad
W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta W_VerifyFileMD5(mainwads++, ASSET_HASH_ZONES_DTA); // zones.dta
W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta W_VerifyFileMD5(mainwads++, ASSET_HASH_PLAYER_DTA); // player.dta
W_VerifyFileMD5(3, ASSET_HASH_RINGS_DTA); // rings.dta W_VerifyFileMD5(mainwads++, ASSET_HASH_RINGS_DTA); // rings.dta
#ifdef USE_PATCH_DTA #ifdef USE_PATCH_DTA
W_VerifyFileMD5(4, ASSET_HASH_PATCH_DTA); // patch.dta W_VerifyFileMD5(mainwads++, ASSET_HASH_PATCH_DTA); // patch.dta
#endif #endif
// don't check music.dta because people like to modify it, and it doesn't matter if they do // don't check music.dta because people like to modify it, and it doesn't matter if they do
// ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for.
mainwads++; // music.dta
#else
mainwads++; // srb2.srb/srb2.wad
mainwads++; // zones.dta
mainwads++; // player.dta
mainwads++; // rings.dta
#ifdef USE_PATCH_DTA
mainwads++; // patch.dta
#endif
mainwads++; // music.dta
#endif //ifndef DEVELOP #endif //ifndef DEVELOP
mainwads = 4; // there are 4 wads not to unload mainwadstally = packetsizetally;
#ifdef USE_PATCH_DTA
++mainwads; // patch.dta adds one more
#endif
cht_Init(); cht_Init();

View file

@ -38,6 +38,7 @@
#include "d_main.h" #include "d_main.h"
#include "m_random.h" #include "m_random.h"
#include "f_finale.h" #include "f_finale.h"
#include "filesrch.h"
#include "mserv.h" #include "mserv.h"
#include "md5.h" #include "md5.h"
#include "z_zone.h" #include "z_zone.h"
@ -706,6 +707,14 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_firenaxis); CV_RegisterVar(&cv_firenaxis);
CV_RegisterVar(&cv_firenaxis2); CV_RegisterVar(&cv_firenaxis2);
// filesrch.c
CV_RegisterVar(&cv_addons_option);
CV_RegisterVar(&cv_addons_folder);
CV_RegisterVar(&cv_addons_md5);
CV_RegisterVar(&cv_addons_showall);
CV_RegisterVar(&cv_addons_search_type);
CV_RegisterVar(&cv_addons_search_case);
// WARNING: the order is important when initialising mouse2 // WARNING: the order is important when initialising mouse2
// we need the mouse2port // we need the mouse2port
CV_RegisterVar(&cv_mouse2port); CV_RegisterVar(&cv_mouse2port);
@ -3155,25 +3164,12 @@ static void Command_Addfile(void)
break; break;
++p; ++p;
// check total packet size and no of files currently loaded // check total packet size and no of files currently loaded
// See W_LoadWadFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8)))
{ {
size_t packetsize = 0; CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
serverinfo_pak *dummycheck = NULL; return;
// Shut the compiler up.
(void)dummycheck;
// See W_LoadWadFile in w_wad.c
for (i = 0; i < numwadfiles; i++)
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
packetsize += nameonlylength(fn) + 22;
if ((numwadfiles >= MAX_WADFILES)
|| (packetsize > sizeof(dummycheck->fileneeded)))
{
CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
return;
}
} }
WRITESTRINGN(buf_p,p,240); WRITESTRINGN(buf_p,p,240);
@ -3259,7 +3255,6 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
boolean kick = false; boolean kick = false;
boolean toomany = false; boolean toomany = false;
INT32 i,j; INT32 i,j;
size_t packetsize = 0;
serverinfo_pak *dummycheck = NULL; serverinfo_pak *dummycheck = NULL;
// Shut the compiler up. // Shut the compiler up.
@ -3290,13 +3285,8 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
} }
// See W_LoadWadFile in w_wad.c // See W_LoadWadFile in w_wad.c
for (i = 0; i < numwadfiles; i++)
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
packetsize += nameonlylength(filename) + 22;
if ((numwadfiles >= MAX_WADFILES) if ((numwadfiles >= MAX_WADFILES)
|| (packetsize > sizeof(dummycheck->fileneeded))) || ((packetsizetally + nameonlylength(filename) + 22) > MAXFILENEEDED*sizeof(UINT8)))
toomany = true; toomany = true;
else else
ncs = findfile(filename,md5sum,true); ncs = findfile(filename,md5sum,true);
@ -3526,6 +3516,9 @@ static void Command_Playintro_f(void)
if (netgame) if (netgame)
return; return;
if (dirmenu)
closefilemenu(true);
F_StartIntro(); F_StartIntro();
} }
@ -4083,6 +4076,9 @@ void Command_ExitGame_f(void)
cv_debug = 0; cv_debug = 0;
emeralds = 0; emeralds = 0;
if (dirmenu)
closefilemenu(true);
if (!modeattacking) if (!modeattacking)
D_StartTitle(); D_StartTitle();
} }

View file

@ -104,6 +104,7 @@ INT32 lastfilenum = -1;
/** Fills a serverinfo packet with information about wad files loaded. /** Fills a serverinfo packet with information about wad files loaded.
* *
* \todo Give this function a better name since it is in global scope. * \todo Give this function a better name since it is in global scope.
* Used to have size limiting built in - now handed via W_LoadWadFile in w_wad.c
* *
*/ */
UINT8 *PutFileNeeded(void) UINT8 *PutFileNeeded(void)
@ -112,29 +113,22 @@ UINT8 *PutFileNeeded(void)
UINT8 *p = netbuffer->u.serverinfo.fileneeded; UINT8 *p = netbuffer->u.serverinfo.fileneeded;
char wadfilename[MAX_WADPATH] = ""; char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus; UINT8 filestatus;
size_t bytesused = 0;
for (i = 0; i < numwadfiles; i++) for (i = 0; i < numwadfiles; i++)
{ {
// If it has only music/sound lumps, mark it as unimportant // If it has only music/sound lumps, don't put it in the list
if (W_VerifyNMUSlumps(wadfiles[i]->filename)) if (!wadfiles[i]->important)
filestatus = 0; continue;
else
filestatus = 1; // Important filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS
// Store in the upper four bits // Store in the upper four bits
if (!cv_downloading.value) if (!cv_downloading.value)
filestatus += (2 << 4); // Won't send filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)) else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
filestatus += (0 << 4); // Won't send
else
filestatus += (1 << 4); // Will send if requested filestatus += (1 << 4); // Will send if requested
// else
bytesused += (nameonlylength(wadfilename) + 22); // filestatus += (0 << 4); -- Won't send, too big
// Don't write too far...
if (bytesused > sizeof(netbuffer->u.serverinfo.fileneeded))
I_Error("Too many wad files added to host a game. (%s, stopped on %s)\n", sizeu1(bytesused), wadfilename);
WRITEUINT8(p, filestatus); WRITEUINT8(p, filestatus);
@ -167,7 +161,6 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
{ {
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
filestatus = READUINT8(p); // The first byte is the file status filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].important = (UINT8)(filestatus & 3);
fileneeded[i].willsend = (UINT8)(filestatus >> 4); fileneeded[i].willsend = (UINT8)(filestatus >> 4);
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
fileneeded[i].file = NULL; // The file isn't open yet fileneeded[i].file = NULL; // The file isn't open yet
@ -197,7 +190,7 @@ boolean CL_CheckDownloadable(void)
UINT8 i,dlstatus = 0; UINT8 i,dlstatus = 0;
for (i = 0; i < fileneedednum; i++) for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN && fileneeded[i].important) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
{ {
if (fileneeded[i].willsend == 1) if (fileneeded[i].willsend == 1)
continue; continue;
@ -218,7 +211,7 @@ boolean CL_CheckDownloadable(void)
// not downloadable, put reason in console // not downloadable, put reason in console
CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n")); CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n"));
for (i = 0; i < fileneedednum; i++) for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN && fileneeded[i].important) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
{ {
CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10); CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10);
@ -271,7 +264,7 @@ boolean CL_SendRequestFile(void)
for (i = 0; i < fileneedednum; i++) for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN
&& fileneeded[i].important && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2))
{ {
I_Error("Attempted to download files that were not sendable"); I_Error("Attempted to download files that were not sendable");
} }
@ -280,8 +273,7 @@ boolean CL_SendRequestFile(void)
netbuffer->packettype = PT_REQUESTFILE; netbuffer->packettype = PT_REQUESTFILE;
p = (char *)netbuffer->u.textcmd; p = (char *)netbuffer->u.textcmd;
for (i = 0; i < fileneedednum; i++) for (i = 0; i < fileneedednum; i++)
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD))
&& fileneeded[i].important)
{ {
totalfreespaceneeded += fileneeded[i].totalsize; totalfreespaceneeded += fileneeded[i].totalsize;
nameonly(fileneeded[i].filename); nameonly(fileneeded[i].filename);
@ -339,10 +331,6 @@ INT32 CL_CheckFiles(void)
INT32 ret = 1; INT32 ret = 1;
size_t packetsize = 0; size_t packetsize = 0;
size_t filestoget = 0; size_t filestoget = 0;
serverinfo_pak *dummycheck = NULL;
// Shut the compiler up.
(void)dummycheck;
// if (M_CheckParm("-nofiles")) // if (M_CheckParm("-nofiles"))
// return 1; // return 1;
@ -360,13 +348,7 @@ INT32 CL_CheckFiles(void)
CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n"); CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n");
for (i = 1, j = 1; i < fileneedednum || j < numwadfiles;) for (i = 1, j = 1; i < fileneedednum || j < numwadfiles;)
{ {
if (i < fileneedednum && !fileneeded[i].important) if (j < numwadfiles && !wadfiles[j]->important)
{
// Eh whatever, don't care
++i;
continue;
}
if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename))
{ {
// Unimportant on our side. still don't care. // Unimportant on our side. still don't care.
++j; ++j;
@ -392,8 +374,7 @@ INT32 CL_CheckFiles(void)
} }
// See W_LoadWadFile in w_wad.c // See W_LoadWadFile in w_wad.c
for (i = 0; i < numwadfiles; i++) packetsize = packetsizetally;
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
for (i = 1; i < fileneedednum; i++) for (i = 1; i < fileneedednum; i++)
{ {
@ -411,13 +392,13 @@ INT32 CL_CheckFiles(void)
break; break;
} }
} }
if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important) if (fileneeded[i].status != FS_NOTFOUND)
continue; continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22; packetsize += nameonlylength(fileneeded[i].filename) + 22;
if ((numwadfiles+filestoget >= MAX_WADFILES) if ((numwadfiles+filestoget >= MAX_WADFILES)
|| (packetsize > sizeof(dummycheck->fileneeded))) || (packetsize > MAXFILENEEDED*sizeof(UINT8)))
return 3; return 3;
filestoget++; filestoget++;
@ -449,27 +430,8 @@ void CL_LoadServerFiles(void)
fileneeded[i].status = FS_OPEN; fileneeded[i].status = FS_OPEN;
} }
else if (fileneeded[i].status == FS_MD5SUMBAD) else if (fileneeded[i].status == FS_MD5SUMBAD)
{ I_Error("Wrong version of file %s", fileneeded[i].filename);
// If the file is marked important, don't even bother proceeding. else
if (fileneeded[i].important)
I_Error("Wrong version of important file %s", fileneeded[i].filename);
// If it isn't, no need to worry the user with a console message,
// although it can't hurt to put something in the debug file.
// ...but wait a second. What if the local version is "important"?
if (!W_VerifyNMUSlumps(fileneeded[i].filename))
I_Error("File %s should only contain music and sound effects!",
fileneeded[i].filename);
// Okay, NOW we know it's safe. Whew.
P_AddWadFile(fileneeded[i].filename);
if (fileneeded[i].important)
G_SetGameModified(true);
fileneeded[i].status = FS_OPEN;
DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename));
}
else if (fileneeded[i].important)
{ {
const char *s; const char *s;
switch(fileneeded[i].status) switch(fileneeded[i].status)
@ -939,10 +901,11 @@ void nameonly(char *s)
{ {
ns = &(s[j+1]); ns = &(s[j+1]);
len = strlen(ns); len = strlen(ns);
if (false) #if 0
M_Memcpy(s, ns, len+1); M_Memcpy(s, ns, len+1);
else #else
memmove(s, ns, len+1); memmove(s, ns, len+1);
#endif
return; return;
} }
} }

View file

@ -35,7 +35,6 @@ typedef enum
typedef struct typedef struct
{ {
UINT8 important;
UINT8 willsend; // Is the server willing to send it? UINT8 willsend; // Is the server willing to send it?
char filename[MAX_WADPATH]; char filename[MAX_WADPATH];
UINT8 md5sum[16]; UINT8 md5sum[16];

View file

@ -161,6 +161,9 @@ extern FILE *logstream;
// Comment or uncomment this as necessary. // Comment or uncomment this as necessary.
#define USE_PATCH_DTA #define USE_PATCH_DTA
// Use .kart extension addons
//#define USE_KART
// Modification options // Modification options
// If you want to take advantage of the Master Server's ability to force clients to update // If you want to take advantage of the Master Server's ability to force clients to update
// to the latest version, fill these out. Otherwise, just comment out UPDATE_ALERT and leave // to the latest version, fill these out. Otherwise, just comment out UPDATE_ALERT and leave

View file

@ -31,6 +31,8 @@
#include "filesrch.h" #include "filesrch.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "m_misc.h" #include "m_misc.h"
#include "z_zone.h"
#include "m_menu.h" // Addons_option_Onchange
#if (defined (_WIN32) && !defined (_WIN32_WCE)) && defined (_MSC_VER) && !defined (_XBOX) #if (defined (_WIN32) && !defined (_WIN32_WCE)) && defined (_MSC_VER) && !defined (_XBOX)
@ -255,6 +257,28 @@ readdir (DIR * dirp)
return (struct dirent *) 0; return (struct dirent *) 0;
} }
/*
* rewinddir
*
* Makes the next readdir start from the beginning.
*/
int
rewinddir (DIR * dirp)
{
errno = 0;
/* Check for valid DIR struct. */
if (!dirp)
{
errno = EFAULT;
return -1;
}
dirp->dd_stat = 0;
return 0;
}
/* /*
* closedir * closedir
* *
@ -285,6 +309,41 @@ closedir (DIR * dirp)
return rc; return rc;
} }
#endif #endif
static CV_PossibleValue_t addons_cons_t[] = {{0, "Default"},
#if 1
{1, "HOME"}, {2, "SRB2"},
#endif
{3, "CUSTOM"}, {0, NULL}};
consvar_t cv_addons_option = {"addons_option", "Default", CV_SAVE|CV_CALL, addons_cons_t, Addons_option_Onchange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_addons_folder = {"addons_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t addons_md5_cons_t[] = {{0, "Name"}, {1, "Contents"}, {0, NULL}};
consvar_t cv_addons_md5 = {"addons_md5", "Name", CV_SAVE, addons_md5_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_addons_showall = {"addons_showall", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_addons_search_case = {"addons_search_case", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t addons_search_type_cons_t[] = {{0, "Start"}, {1, "Anywhere"}, {0, NULL}};
consvar_t cv_addons_search_type = {"addons_search_type", "Anywhere", CV_SAVE, addons_search_type_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
char menupath[1024];
size_t menupathindex[menudepth];
size_t menudepthleft = menudepth;
char menusearch[MAXSTRINGLENGTH+1];
char **dirmenu, **coredirmenu; // core only local for this file
size_t sizedirmenu, sizecoredirmenu; // ditto
size_t dir_on[menudepth];
UINT8 refreshdirmenu = 0;
char *refreshdirname = NULL;
size_t packetsizetally = 0;
size_t mainwadstally = 0;
#if defined (_XBOX) && defined (_MSC_VER) #if defined (_XBOX) && defined (_MSC_VER)
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
boolean completepath, int maxsearchdepth) boolean completepath, int maxsearchdepth)
@ -296,6 +355,25 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
completepath = false; completepath = false;
return FS_NOTFOUND; return FS_NOTFOUND;
} }
void closefilemenu(boolean validsize)
{
(void)validsize;
return;
}
void searchfilemenu(char *tempname)
{
(void)tempname;
return;
}
boolean preparefilemenu(boolean samedepth)
{
(void)samedepth;
return false;
}
#elif defined (_WIN32_WCE) #elif defined (_WIN32_WCE)
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
boolean completepath, int maxsearchdepth) boolean completepath, int maxsearchdepth)
@ -346,7 +424,27 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
#endif #endif
return FS_NOTFOUND; return FS_NOTFOUND;
} }
void closefilemenu(boolean validsize)
{
(void)validsize;
return;
}
void searchfilemenu(char *tempname)
{
(void)tempname;
return;
}
boolean preparefilemenu(boolean samedepth)
{
(void)samedepth;
return false;
}
#else #else
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth)
{ {
filestatus_t retval = FS_NOTFOUND; filestatus_t retval = FS_NOTFOUND;
@ -387,25 +485,29 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
{ {
searchpath[searchpathindex[depthleft]]=0; searchpath[searchpathindex[depthleft]]=0;
dent = readdir(dirhandle[depthleft]); dent = readdir(dirhandle[depthleft]);
if (dent)
strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name);
if (!dent) if (!dent)
{
closedir(dirhandle[depthleft++]); closedir(dirhandle[depthleft++]);
else if (dent->d_name[0]=='.' && continue;
}
if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' || (dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' && (dent->d_name[1]=='.' &&
dent->d_name[2]=='\0'))) dent->d_name[2]=='\0')))
{ {
// we don't want to scan uptree // we don't want to scan uptree
continue;
} }
else if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
{ // okay, now we actually want searchpath to incorporate d_name
// was the file (re)moved? can't stat it strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name);
}
if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
; // was the file (re)moved? can't stat it
else if (S_ISDIR(fsstat.st_mode) && depthleft) else if (S_ISDIR(fsstat.st_mode) && depthleft)
{ {
strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name);
searchpathindex[--depthleft] = strlen(searchpath) + 1; searchpathindex[--depthleft] = strlen(searchpath) + 1;
dirhandle[depthleft] = opendir(searchpath); dirhandle[depthleft] = opendir(searchpath);
if (!dirhandle[depthleft]) if (!dirhandle[depthleft])
@ -444,6 +546,365 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
free(searchname); free(searchname);
free(searchpathindex); free(searchpathindex);
free(dirhandle); free(dirhandle);
return retval; return retval;
} }
char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) plus 3 (null terminator, stop, and length including previous two)
"\5.txt", "\5.cfg", // exec
"\5.wad",
#ifdef USE_KART
"\6.kart",
#endif
"\5.pk3", "\5.soc", "\5.lua"}; // addfile
char filenamebuf[MAX_WADFILES][MAX_WADPATH];
static boolean filemenucmp(char *haystack, char *needle)
{
static char localhaystack[128];
strlcpy(localhaystack, haystack, 128);
if (!cv_addons_search_case.value)
strupr(localhaystack);
if (cv_addons_search_type.value)
return (strstr(localhaystack, needle) != 0);
return (!strncmp(localhaystack, needle, menusearch[0]));
}
void closefilemenu(boolean validsize)
{
// search
if (dirmenu)
{
if (dirmenu != coredirmenu)
{
if (dirmenu[0] && ((UINT8)(dirmenu[0][DIR_TYPE]) == EXT_NORESULTS))
{
Z_Free(dirmenu[0]);
dirmenu[0] = NULL;
}
Z_Free(dirmenu);
}
dirmenu = NULL;
sizedirmenu = 0;
}
if (coredirmenu)
{
// core
if (validsize)
{
for (; sizecoredirmenu > 0; sizecoredirmenu--)
{
Z_Free(coredirmenu[sizecoredirmenu-1]);
coredirmenu[sizecoredirmenu-1] = NULL;
}
}
else
sizecoredirmenu = 0;
Z_Free(coredirmenu);
coredirmenu = NULL;
}
if (refreshdirname)
Z_Free(refreshdirname);
refreshdirname = NULL;
}
void searchfilemenu(char *tempname)
{
size_t i, first;
char localmenusearch[MAXSTRINGLENGTH] = "";
if (dirmenu)
{
if (dirmenu != coredirmenu)
{
if (dirmenu[0] && ((UINT8)(dirmenu[0][DIR_TYPE]) == EXT_NORESULTS))
{
Z_Free(dirmenu[0]);
dirmenu[0] = NULL;
}
//Z_Free(dirmenu); -- Z_Realloc later tho...
}
else
dirmenu = NULL;
}
first = (((UINT8)(coredirmenu[0][DIR_TYPE]) == EXT_UP) ? 1 : 0); // skip UP...
if (!menusearch[0])
{
if (dirmenu)
Z_Free(dirmenu);
dirmenu = coredirmenu;
sizedirmenu = sizecoredirmenu;
if (tempname)
{
for (i = first; i < sizedirmenu; i++)
{
if (!strcmp(dirmenu[i]+DIR_STRING, tempname))
{
dir_on[menudepthleft] = i;
break;
}
}
if (i == sizedirmenu)
dir_on[menudepthleft] = first;
Z_Free(tempname);
}
return;
}
strcpy(localmenusearch, menusearch+1);
if (!cv_addons_search_case.value)
strupr(localmenusearch);
sizedirmenu = 0;
for (i = first; i < sizecoredirmenu; i++)
{
if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch))
sizedirmenu++;
}
if (!sizedirmenu) // no results...
{
if ((!(dirmenu = Z_Realloc(dirmenu, sizeof(char *), PU_STATIC, NULL)))
|| !(dirmenu[0] = Z_StrDup(va("%c\13No results...", EXT_NORESULTS))))
I_Error("searchfilemenu(): could not create \"No results...\".");
sizedirmenu = 1;
dir_on[menudepthleft] = 0;
if (tempname)
Z_Free(tempname);
return;
}
if (!(dirmenu = Z_Realloc(dirmenu, sizedirmenu*sizeof(char *), PU_STATIC, NULL)))
I_Error("searchfilemenu(): could not reallocate dirmenu.");
sizedirmenu = 0;
for (i = first; i < sizecoredirmenu; i++)
{
if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch))
{
if (tempname && !strcmp(coredirmenu[i]+DIR_STRING, tempname))
{
dir_on[menudepthleft] = sizedirmenu;
Z_Free(tempname);
tempname = NULL;
}
dirmenu[sizedirmenu++] = coredirmenu[i]; // pointer reuse
}
}
if (tempname)
{
dir_on[menudepthleft] = 0; //first; -- can't be first, causes problems
Z_Free(tempname);
}
}
boolean preparefilemenu(boolean samedepth)
{
DIR *dirhandle;
struct dirent *dent;
struct stat fsstat;
size_t pos = 0, folderpos = 0, numfolders = 0;
char *tempname = NULL;
if (samedepth)
{
if (dirmenu && dirmenu[dir_on[menudepthleft]])
tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL
}
else
menusearch[0] = menusearch[1] = 0; // clear search
if (!(dirhandle = opendir(menupath))) // get directory
{
closefilemenu(true);
return false;
}
for (; sizecoredirmenu > 0; sizecoredirmenu--) // clear out existing items
{
Z_Free(coredirmenu[sizecoredirmenu-1]);
coredirmenu[sizecoredirmenu-1] = NULL;
}
while (true)
{
menupath[menupathindex[menudepthleft]] = 0;
dent = readdir(dirhandle);
if (!dent)
break;
else if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
continue; // we don't want to scan uptree
strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);
if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
; // was the file (re)moved? can't stat it
else // is a file or directory
{
if (!S_ISDIR(fsstat.st_mode)) // file
{
if (!cv_addons_showall.value)
{
size_t len = strlen(dent->d_name)+1;
UINT8 ext;
for (ext = 0; ext < NUM_EXT_TABLE; ext++)
if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison
if (ext == NUM_EXT_TABLE) continue; // not an addfile-able (or exec-able) file
}
}
else // directory
numfolders++;
sizecoredirmenu++;
}
}
if (!sizecoredirmenu)
{
closedir(dirhandle);
closefilemenu(false);
if (tempname)
Z_Free(tempname);
return false;
}
if (menudepthleft != menudepth-1) // Make room for UP...
{
sizecoredirmenu++;
numfolders++;
folderpos++;
}
if (dirmenu && dirmenu == coredirmenu)
dirmenu = NULL;
if (!(coredirmenu = Z_Realloc(coredirmenu, sizecoredirmenu*sizeof(char *), PU_STATIC, NULL)))
{
closedir(dirhandle); // just in case
I_Error("preparefilemenu(): could not reallocate coredirmenu.");
}
rewinddir(dirhandle);
while ((pos+folderpos) < sizecoredirmenu)
{
menupath[menupathindex[menudepthleft]] = 0;
dent = readdir(dirhandle);
if (!dent)
break;
else if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
continue; // we don't want to scan uptree
strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);
if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
; // was the file (re)moved? can't stat it
else // is a file or directory
{
char *temp;
size_t len = strlen(dent->d_name)+1;
UINT8 ext = EXT_FOLDER;
UINT8 folder;
if (!S_ISDIR(fsstat.st_mode)) // file
{
if (!((numfolders+pos) < sizecoredirmenu)) continue; // crash prevention
for (; ext < NUM_EXT_TABLE; ext++)
if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison
if (ext == NUM_EXT_TABLE && !cv_addons_showall.value) continue; // not an addfile-able (or exec-able) file
ext += EXT_START; // moving to be appropriate position
if (ext >= EXT_LOADSTART)
{
size_t i;
for (i = 0; i < numwadfiles; i++)
{
if (!filenamebuf[i][0])
{
strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH);
filenamebuf[i][MAX_WADPATH - 1] = '\0';
nameonly(filenamebuf[i]);
}
if (strcmp(dent->d_name, filenamebuf[i]))
continue;
if (cv_addons_md5.value && !checkfilemd5(menupath, wadfiles[i]->md5sum))
continue;
ext |= EXT_LOADED;
}
}
else if (ext == EXT_TXT)
{
if (!strcmp(dent->d_name, "log.txt") || !strcmp(dent->d_name, "errorlog.txt"))
ext |= EXT_LOADED;
}
if (!strcmp(dent->d_name, configfile))
ext |= EXT_LOADED;
folder = 0;
}
else // directory
len += (folder = 1);
if (len > 255)
len = 255;
if (!(temp = Z_Malloc((len+DIR_STRING+folder) * sizeof (char), PU_STATIC, NULL)))
I_Error("preparefilemenu(): could not create file entry.");
temp[DIR_TYPE] = ext;
temp[DIR_LEN] = (UINT8)(len);
strlcpy(temp+DIR_STRING, dent->d_name, len);
if (folder)
{
strcpy(temp+len, PATHSEP);
coredirmenu[folderpos++] = temp;
}
else
coredirmenu[numfolders + pos++] = temp;
}
}
closedir(dirhandle);
if ((menudepthleft != menudepth-1) // now for UP... entry
&& !(coredirmenu[0] = Z_StrDup(va("%c\5UP...", EXT_UP))))
I_Error("preparefilemenu(): could not create \"UP...\".");
menupath[menupathindex[menudepthleft]] = 0;
sizecoredirmenu = (numfolders+pos); // just in case things shrink between opening and rewind
if (!sizecoredirmenu)
{
dir_on[menudepthleft] = 0;
closefilemenu(false);
return false;
}
searchfilemenu(tempname);
return true;
}
#endif #endif

View file

@ -6,6 +6,9 @@
#include "doomdef.h" #include "doomdef.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "m_menu.h" // MAXSTRINGLENGTH
extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_showall, cv_addons_search_case, cv_addons_search_type;
/** \brief The filesearch function /** \brief The filesearch function
@ -25,4 +28,71 @@
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
boolean completepath, int maxsearchdepth); boolean completepath, int maxsearchdepth);
#define menudepth 20
extern char menupath[1024];
extern size_t menupathindex[menudepth];
extern size_t menudepthleft;
extern char menusearch[MAXSTRINGLENGTH+1];
extern char **dirmenu;
extern size_t sizedirmenu;
extern size_t dir_on[menudepth];
extern UINT8 refreshdirmenu;
extern char *refreshdirname;
extern size_t packetsizetally;
extern size_t mainwadstally;
typedef enum
{
EXT_FOLDER = 0,
EXT_UP,
EXT_NORESULTS,
EXT_START,
EXT_TXT = EXT_START,
EXT_CFG,
EXT_LOADSTART,
EXT_WAD = EXT_LOADSTART,
#ifdef USE_KART
EXT_KART,
#endif
EXT_PK3,
EXT_SOC,
EXT_LUA, // allowed even if not HAVE_BLUA so that we can yell on load attempt
NUM_EXT,
NUM_EXT_TABLE = NUM_EXT-EXT_START,
EXT_LOADED = 0x80
/*
obviously there can only be 0x7F supported extensions in
addons menu because we're cramming this into a char out of
laziness/easy memory allocation (what's the difference?)
and have stolen a bit to show whether it's loaded or not
in practice the size of the data type is probably overkill
toast 02/05/17
*/
} ext_enum;
typedef enum
{
DIR_TYPE = 0,
DIR_LEN,
DIR_STRING
} dirname_enum;
typedef enum
{
REFRESHDIR_NORMAL = 1,
REFRESHDIR_ADDFILE = 2,
REFRESHDIR_WARNING = 4,
REFRESHDIR_ERROR = 8,
REFRESHDIR_NOTLOADED = 16,
REFRESHDIR_MAX = 32
} refreshdir_enum;
void closefilemenu(boolean validsize);
void searchfilemenu(char *tempname);
boolean preparefilemenu(boolean samedepth);
#endif // __FILESRCH_H__ #endif // __FILESRCH_H__

View file

@ -33,6 +33,9 @@
#include "s_sound.h" #include "s_sound.h"
#include "i_system.h" #include "i_system.h"
// Addfile
#include "filesrch.h"
#include "v_video.h" #include "v_video.h"
#include "i_video.h" #include "i_video.h"
#include "keys.h" #include "keys.h"
@ -75,7 +78,6 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
#define SMALLLINEHEIGHT 8 #define SMALLLINEHEIGHT 8
#define SLIDER_RANGE 10 #define SLIDER_RANGE 10
#define SLIDER_WIDTH (8*SLIDER_RANGE+6) #define SLIDER_WIDTH (8*SLIDER_RANGE+6)
#define MAXSTRINGLENGTH 32
#define SERVERS_PER_PAGE 11 #define SERVERS_PER_PAGE 11
typedef enum typedef enum
@ -205,6 +207,8 @@ menu_t MessageDef;
menu_t SPauseDef; menu_t SPauseDef;
#define lsheadingheight 16
// Sky Room // Sky Room
static void M_CustomLevelSelect(INT32 choice); static void M_CustomLevelSelect(INT32 choice);
static void M_CustomWarp(INT32 choice); static void M_CustomWarp(INT32 choice);
@ -298,9 +302,16 @@ menu_t OP_MonitorToggleDef;
static void M_ScreenshotOptions(INT32 choice); static void M_ScreenshotOptions(INT32 choice);
static void M_EraseData(INT32 choice); static void M_EraseData(INT32 choice);
static void M_Addons(INT32 choice);
static void M_AddonsOptions(INT32 choice);
static patch_t *addonsp[NUM_EXT+5];
#define numaddonsshown 4
// Drawing functions // Drawing functions
static void M_DrawGenericMenu(void); static void M_DrawGenericMenu(void);
static void M_DrawCenteredMenu(void); static void M_DrawCenteredMenu(void);
static void M_DrawAddons(void);
static void M_DrawSkyRoom(void); static void M_DrawSkyRoom(void);
static void M_DrawChecklist(void); static void M_DrawChecklist(void);
static void M_DrawEmblemHints(void); static void M_DrawEmblemHints(void);
@ -335,6 +346,7 @@ static boolean M_CancelConnect(void);
#endif #endif
static boolean M_ExitPandorasBox(void); static boolean M_ExitPandorasBox(void);
static boolean M_QuitMultiPlayerMenu(void); static boolean M_QuitMultiPlayerMenu(void);
static void M_HandleAddons(INT32 choice);
static void M_HandleSoundTest(INT32 choice); static void M_HandleSoundTest(INT32 choice);
static void M_HandleImageDef(INT32 choice); static void M_HandleImageDef(INT32 choice);
static void M_HandleLoadSave(INT32 choice); static void M_HandleLoadSave(INT32 choice);
@ -442,10 +454,11 @@ static consvar_t cv_dummymares = {"dummymares", "Overall", CV_HIDEN|CV_CALL, dum
// --------- // ---------
static menuitem_t MainMenu[] = static menuitem_t MainMenu[] =
{ {
{IT_CALL |IT_STRING, NULL, "Secrets", M_SecretsMenu, 84}, {IT_CALL |IT_STRING, NULL, "Secrets", M_SecretsMenu, 76},
{IT_CALL |IT_STRING, NULL, "1 player", M_SinglePlayerMenu, 92}, {IT_CALL |IT_STRING, NULL, "1 player", M_SinglePlayerMenu, 84},
{IT_SUBMENU|IT_STRING, NULL, "multiplayer", &MP_MainDef, 100}, {IT_SUBMENU|IT_STRING, NULL, "multiplayer", &MP_MainDef, 92},
{IT_CALL |IT_STRING, NULL, "options", M_Options, 108}, {IT_CALL |IT_STRING, NULL, "options", M_Options, 100},
{IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108},
{IT_CALL |IT_STRING, NULL, "quit game", M_QuitSRB2, 116}, {IT_CALL |IT_STRING, NULL, "quit game", M_QuitSRB2, 116},
}; };
@ -455,9 +468,15 @@ typedef enum
singleplr, singleplr,
multiplr, multiplr,
options, options,
addons,
quitdoom quitdoom
} main_e; } main_e;
static menuitem_t MISC_AddonsMenu[] =
{
{IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleAddons, 0}, // dummy menuitem for the control func
};
// --------------------------------- // ---------------------------------
// Pause Menu Mode Attacking Edition // Pause Menu Mode Attacking Edition
// --------------------------------- // ---------------------------------
@ -480,6 +499,7 @@ typedef enum
// --------------------- // ---------------------
static menuitem_t MPauseMenu[] = static menuitem_t MPauseMenu[] =
{ {
{IT_STRING | IT_CALL, NULL, "Add-ons...", M_Addons, 8},
{IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16}, {IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16},
{IT_STRING | IT_CALL, NULL, "Switch Map..." , M_MapChange, 24}, {IT_STRING | IT_CALL, NULL, "Switch Map..." , M_MapChange, 24},
@ -499,7 +519,8 @@ static menuitem_t MPauseMenu[] =
typedef enum typedef enum
{ {
mpause_scramble = 0, mpause_addons = 0,
mpause_scramble,
mpause_switchmap, mpause_switchmap,
mpause_continue, mpause_continue,
@ -985,6 +1006,7 @@ static menuitem_t OP_MainMenu[] =
{IT_SUBMENU | IT_STRING, NULL, "Game Options...", &OP_GameOptionsDef, 70}, {IT_SUBMENU | IT_STRING, NULL, "Game Options...", &OP_GameOptionsDef, 70},
{IT_SUBMENU | IT_STRING, NULL, "Server Options...", &OP_ServerOptionsDef, 80}, {IT_SUBMENU | IT_STRING, NULL, "Server Options...", &OP_ServerOptionsDef, 80},
{IT_STRING | IT_CALL, NULL, "Add-on Options...", M_AddonsOptions, 90},
}; };
static menuitem_t OP_ControlsMenu[] = static menuitem_t OP_ControlsMenu[] =
@ -1293,6 +1315,24 @@ static menuitem_t OP_EraseDataMenu[] =
{IT_STRING | IT_CALL, NULL, "\x85" "Erase ALL Data", M_EraseData, 40}, {IT_STRING | IT_CALL, NULL, "\x85" "Erase ALL Data", M_EraseData, 40},
}; };
static menuitem_t OP_AddonsOptionsMenu[] =
{
{IT_HEADER, NULL, "Menu", NULL, 0},
{IT_STRING|IT_CVAR, NULL, "Location", &cv_addons_option, 10},
{IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_addons_folder, 20},
{IT_STRING|IT_CVAR, NULL, "Identify add-ons via", &cv_addons_md5, 48},
{IT_STRING|IT_CVAR, NULL, "Show unsupported file types", &cv_addons_showall, 58},
{IT_HEADER, NULL, "Search", NULL, 76},
{IT_STRING|IT_CVAR, NULL, "Matching", &cv_addons_search_type, 86},
{IT_STRING|IT_CVAR, NULL, "Case-sensitive", &cv_addons_search_case, 96},
};
enum
{
op_addons_folder = 2,
};
static menuitem_t OP_GameOptionsMenu[] = static menuitem_t OP_GameOptionsMenu[] =
{ {
#ifndef NONET #ifndef NONET
@ -1421,6 +1461,18 @@ static menuitem_t OP_MonitorToggleMenu[] =
// Main Menu and related // Main Menu and related
menu_t MainDef = CENTERMENUSTYLE(NULL, MainMenu, NULL, 72); menu_t MainDef = CENTERMENUSTYLE(NULL, MainMenu, NULL, 72);
menu_t MISC_AddonsDef =
{
NULL,
sizeof (MISC_AddonsMenu)/sizeof (menuitem_t),
&MainDef,
MISC_AddonsMenu,
M_DrawAddons,
50, 28,
0,
NULL
};
menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72);
menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72);
menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72);
@ -1431,6 +1483,9 @@ menu_t MISC_ChangeTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ChangeTeamMenu, &MPauseD
menu_t MISC_ChangeLevelDef = MAPICONMENUSTYLE(NULL, MISC_ChangeLevelMenu, &MPauseDef); menu_t MISC_ChangeLevelDef = MAPICONMENUSTYLE(NULL, MISC_ChangeLevelMenu, &MPauseDef);
menu_t MISC_HelpDef = IMAGEDEF(MISC_HelpMenu); menu_t MISC_HelpDef = IMAGEDEF(MISC_HelpMenu);
static INT32 highlightflags, recommendedflags, warningflags;
// Sky Room // Sky Room
menu_t SR_PandoraDef = menu_t SR_PandoraDef =
{ {
@ -1766,6 +1821,7 @@ menu_t OP_OpenGLColorDef =
#endif #endif
menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30);
menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_ScreenshotOptionsMenu, &OP_DataOptionsDef, 30, 30); menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_ScreenshotOptionsMenu, &OP_DataOptionsDef, 30, 30);
menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_MainDef, 30, 30);
menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 60, 30); menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 60, 30);
// ========================================================================== // ==========================================================================
@ -1991,6 +2047,12 @@ void Moviemode_mode_Onchange(void)
OP_ScreenshotOptionsMenu[i].status = IT_STRING|IT_CVAR; OP_ScreenshotOptionsMenu[i].status = IT_STRING|IT_CVAR;
} }
void Addons_option_Onchange(void)
{
OP_AddonsOptionsMenu[op_addons_folder].status =
(cv_addons_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED);
}
// ========================================================================== // ==========================================================================
// END ORGANIZATION STUFF. // END ORGANIZATION STUFF.
// ========================================================================== // ==========================================================================
@ -2621,6 +2683,7 @@ void M_StartControlPanel(void)
else // multiplayer else // multiplayer
{ {
MPauseMenu[mpause_switchmap].status = IT_DISABLED; MPauseMenu[mpause_switchmap].status = IT_DISABLED;
MPauseMenu[mpause_addons].status = IT_DISABLED;
MPauseMenu[mpause_scramble].status = IT_DISABLED; MPauseMenu[mpause_scramble].status = IT_DISABLED;
MPauseMenu[mpause_psetupsplit].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit].status = IT_DISABLED;
MPauseMenu[mpause_psetupsplit2].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit2].status = IT_DISABLED;
@ -2632,6 +2695,7 @@ void M_StartControlPanel(void)
if ((server || IsPlayerAdmin(consoleplayer))) if ((server || IsPlayerAdmin(consoleplayer)))
{ {
MPauseMenu[mpause_switchmap].status = IT_STRING | IT_CALL; MPauseMenu[mpause_switchmap].status = IT_STRING | IT_CALL;
MPauseMenu[mpause_addons].status = IT_STRING | IT_CALL;
if (G_GametypeHasTeams()) if (G_GametypeHasTeams())
MPauseMenu[mpause_scramble].status = IT_STRING | IT_SUBMENU; MPauseMenu[mpause_scramble].status = IT_STRING | IT_SUBMENU;
} }
@ -3871,6 +3935,548 @@ static void M_HandleImageDef(INT32 choice)
// MISC MAIN MENU OPTIONS // MISC MAIN MENU OPTIONS
// ====================== // ======================
static void M_AddonsOptions(INT32 choice)
{
(void)choice;
Addons_option_Onchange();
M_SetupNextMenu(&OP_AddonsOptionsDef);
}
#define LOCATIONSTRING1 "Visit \x83SRB2.ORG/MODS\x80 to get & make add-ons!"
//#define LOCATIONSTRING2 "Visit \x88SRB2.ORG/MODS\x80 to get & make add-ons!"
static void M_Addons(INT32 choice)
{
const char *pathname = ".";
(void)choice;
// If M_GetGameypeColor() is ever ported from Kart, then remove this.
highlightflags = V_YELLOWMAP;
recommendedflags = V_GREENMAP;
warningflags = V_REDMAP;
#if 1
if (cv_addons_option.value == 0)
pathname = usehome ? srb2home : srb2path;
else if (cv_addons_option.value == 1)
pathname = srb2home;
else if (cv_addons_option.value == 2)
pathname = srb2path;
else
#endif
if (cv_addons_option.value == 3 && *cv_addons_folder.string != '\0')
pathname = cv_addons_folder.string;
strlcpy(menupath, pathname, 1024);
menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath) + 1;
if (menupath[menupathindex[menudepthleft]-2] != PATHSEP[0])
{
menupath[menupathindex[menudepthleft]-1] = PATHSEP[0];
menupath[menupathindex[menudepthleft]] = 0;
}
else
--menupathindex[menudepthleft];
if (!preparefilemenu(false))
{
M_StartMessage(va("No files/folders found.\n\n%s\n\n(Press a key)\n",LOCATIONSTRING1),NULL,MM_NOTHING);
// (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1))
return;
}
else
dir_on[menudepthleft] = 0;
if (addonsp[0]) // never going to have some provided but not all, saves individually checking
{
size_t i;
for (i = 0; i < NUM_EXT+5; i++)
W_UnlockCachedPatch(addonsp[i]);
}
addonsp[EXT_FOLDER] = W_CachePatchName("M_FFLDR", PU_STATIC);
addonsp[EXT_UP] = W_CachePatchName("M_FBACK", PU_STATIC);
addonsp[EXT_NORESULTS] = W_CachePatchName("M_FNOPE", PU_STATIC);
addonsp[EXT_TXT] = W_CachePatchName("M_FTXT", PU_STATIC);
addonsp[EXT_CFG] = W_CachePatchName("M_FCFG", PU_STATIC);
addonsp[EXT_WAD] = W_CachePatchName("M_FWAD", PU_STATIC);
#ifdef USE_KART
addonsp[EXT_KART] = W_CachePatchName("M_FKART", PU_STATIC);
#endif
addonsp[EXT_PK3] = W_CachePatchName("M_FPK3", PU_STATIC);
addonsp[EXT_SOC] = W_CachePatchName("M_FSOC", PU_STATIC);
addonsp[EXT_LUA] = W_CachePatchName("M_FLUA", PU_STATIC);
addonsp[NUM_EXT] = W_CachePatchName("M_FUNKN", PU_STATIC);
addonsp[NUM_EXT+1] = W_CachePatchName("M_FSEL", PU_STATIC);
addonsp[NUM_EXT+2] = W_CachePatchName("M_FLOAD", PU_STATIC);
addonsp[NUM_EXT+3] = W_CachePatchName("M_FSRCH", PU_STATIC);
addonsp[NUM_EXT+4] = W_CachePatchName("M_FSAVE", PU_STATIC);
MISC_AddonsDef.prevMenu = currentMenu;
M_SetupNextMenu(&MISC_AddonsDef);
}
#define width 4
#define vpadding 27
#define h (BASEVIDHEIGHT-(2*vpadding))
#define NUMCOLOURS 8 // when toast's coding it's british english hacker fucker
static void M_DrawTemperature(INT32 x, fixed_t t)
{
INT32 y;
// bounds check
if (t > FRACUNIT)
t = FRACUNIT;
/*else if (t < 0) -- not needed
t = 0;*/
// scale
if (t > 1)
t = (FixedMul(h<<FRACBITS, t)>>FRACBITS);
// border
V_DrawFill(x - 1, vpadding, 1, h, 120);
V_DrawFill(x + width, vpadding, 1, h, 120);
V_DrawFill(x - 1, vpadding-1, width+2, 1, 120);
V_DrawFill(x - 1, vpadding+h, width+2, 1, 120);
// bar itself
y = h;
if (t)
for (t = h - t; y > 0; y--)
{
UINT8 colours[NUMCOLOURS] = {135, 133, 92, 77, 114, 178, 161, 162};
UINT8 c;
if (y <= t) break;
if (y+vpadding >= BASEVIDHEIGHT/2)
c = 185;
else
c = colours[(NUMCOLOURS*(y-1))/(h/2)];
V_DrawFill(x, y-1 + vpadding, width, 1, c);
}
// fill the rest of the backing
if (y)
V_DrawFill(x, vpadding, width, y, 30);
}
#undef width
#undef vpadding
#undef h
#undef NUMCOLOURS
static char *M_AddonsHeaderPath(void)
{
UINT32 len;
static char header[1024];
strlcpy(header, va("%s folder%s", cv_addons_option.string, menupath+menupathindex[menudepth-1]-1), 1024);
len = strlen(header);
if (len > 34)
{
len = len-34;
header[len] = header[len+1] = header[len+2] = '.';
}
else
len = 0;
return header+len;
}
#define UNEXIST S_StartSound(NULL, sfx_lose);\
M_SetupNextMenu(MISC_AddonsDef.prevMenu);\
M_StartMessage(va("\x82%s\x80\nThis folder no longer exists!\nAborting to main menu.\n\n(Press a key)\n", M_AddonsHeaderPath()),NULL,MM_NOTHING)
#define CLEARNAME Z_Free(refreshdirname);\
refreshdirname = NULL
static void M_AddonsClearName(INT32 choice)
{
CLEARNAME;
M_StopMessage(choice);
}
// returns whether to do message draw
static boolean M_AddonsRefresh(void)
{
if ((refreshdirmenu & REFRESHDIR_NORMAL) && !preparefilemenu(true))
{
UNEXIST;
return true;
}
if (refreshdirmenu & REFRESHDIR_ADDFILE)
{
char *message = NULL;
if (refreshdirmenu & REFRESHDIR_NOTLOADED)
{
S_StartSound(NULL, sfx_lose);
if (refreshdirmenu & REFRESHDIR_MAX)
message = va("%c%s\x80\nMaximum number of add-ons reached.\nA file could not be loaded.\nIf you want to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname);
else
message = va("%c%s\x80\nA file was not loaded.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname);
}
else if (refreshdirmenu & (REFRESHDIR_WARNING|REFRESHDIR_ERROR))
{
S_StartSound(NULL, sfx_skid);
message = va("%c%s\x80\nA file was loaded with %s.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings"));
}
if (message)
{
M_StartMessage(message,M_AddonsClearName,MM_EVENTHANDLER);
return true;
}
S_StartSound(NULL, sfx_strpst);
CLEARNAME;
}
return false;
}
static void M_DrawAddons(void)
{
INT32 x, y;
ssize_t i, m;
const UINT8 *flashcol = NULL;
UINT8 hilicol;
// hack - need to refresh at end of frame to handle addfile...
if (refreshdirmenu & M_AddonsRefresh())
{
M_DrawMessageMenu();
return;
}
if (Playing())
V_DrawCenteredString(BASEVIDWIDTH/2, 5, warningflags, "Adding files mid-game may cause problems.");
else
V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, LOCATIONSTRING1);
// (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)
if (numwadfiles <= mainwads+1)
y = 0;
else if (numwadfiles >= MAX_WADFILES)
y = FRACUNIT;
else
{
x = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))<<FRACBITS, ((ssize_t)MAX_WADFILES - (ssize_t)(mainwads+1))<<FRACBITS);
y = FixedDiv((((ssize_t)packetsizetally-(ssize_t)mainwadstally)<<FRACBITS), ((((ssize_t)MAXFILENEEDED*sizeof(UINT8)-(ssize_t)mainwadstally)-(5+22))<<FRACBITS)); // 5+22 = (a.ext + checksum length) is minimum addition to packet size tally
if (x > y)
y = x;
if (y > FRACUNIT) // happens because of how we're shrinkin' it a little
y = FRACUNIT;
}
M_DrawTemperature(BASEVIDWIDTH - 19 - 5, y);
// DRAW MENU
x = currentMenu->x;
y = currentMenu->y + 1;
hilicol = V_GetStringColormap(highlightflags)[120];
V_DrawString(x-21, (y - 16) + (lsheadingheight - 12), highlightflags|V_ALLOWLOWERCASE, M_AddonsHeaderPath());
V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), MAXSTRINGLENGTH*8+6, 1, hilicol);
V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), MAXSTRINGLENGTH*8+6, 1, 30);
m = (BASEVIDHEIGHT - currentMenu->y + 2) - (y - 1);
V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, m, 239);
// scrollbar!
if (sizedirmenu <= (2*numaddonsshown + 1))
i = 0;
else
{
ssize_t q = m;
m = ((2*numaddonsshown + 1) * m)/sizedirmenu;
if (dir_on[menudepthleft] <= numaddonsshown) // all the way up
i = 0;
else if (sizedirmenu <= (dir_on[menudepthleft] + numaddonsshown + 1)) // all the way down
i = q-m;
else
i = ((dir_on[menudepthleft] - numaddonsshown) * (q-m))/(sizedirmenu - (2*numaddonsshown + 1));
}
V_DrawFill(x + MAXSTRINGLENGTH*8+5 - 21, (y - 1) + i, 1, m, hilicol);
// get bottom...
m = dir_on[menudepthleft] + numaddonsshown + 1;
if (m > (ssize_t)sizedirmenu)
m = sizedirmenu;
// then compute top and adjust bottom if needed!
if (m < (2*numaddonsshown + 1))
{
m = min(sizedirmenu, 2*numaddonsshown + 1);
i = 0;
}
else
i = m - (2*numaddonsshown + 1);
if (i != 0)
V_DrawString(19, y+4 - (skullAnimCounter/5), highlightflags, "\x1A");
if (skullAnimCounter < 4)
flashcol = V_GetStringColormap(highlightflags);
for (; i < m; i++)
{
UINT32 flags = V_ALLOWLOWERCASE;
if (y > BASEVIDHEIGHT) break;
if (dirmenu[i])
#define type (UINT8)(dirmenu[i][DIR_TYPE])
{
if (type & EXT_LOADED)
{
flags |= V_TRANSLUCENT;
V_DrawSmallScaledPatch(x-(16+4), y, V_TRANSLUCENT, addonsp[(type & ~EXT_LOADED)]);
V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[NUM_EXT+2]);
}
else
V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[(type & ~EXT_LOADED)]);
if ((size_t)i == dir_on[menudepthleft])
{
V_DrawFixedPatch((x-(16+4))<<FRACBITS, (y)<<FRACBITS, FRACUNIT/2, 0, addonsp[NUM_EXT+1], flashcol);
flags = V_ALLOWLOWERCASE|highlightflags;
}
#define charsonside 14
if (dirmenu[i][DIR_LEN] > (charsonside*2 + 3))
V_DrawString(x, y+4, flags, va("%.*s...%s", charsonside, dirmenu[i]+DIR_STRING, dirmenu[i]+DIR_STRING+dirmenu[i][DIR_LEN]-(charsonside+1)));
#undef charsonside
else
V_DrawString(x, y+4, flags, dirmenu[i]+DIR_STRING);
}
#undef type
y += 16;
}
if (m != (ssize_t)sizedirmenu)
V_DrawString(19, y-12 + (skullAnimCounter/5), highlightflags, "\x1B");
y = BASEVIDHEIGHT - currentMenu->y + 1;
M_DrawTextBox(x - (21 + 5), y, MAXSTRINGLENGTH, 1);
if (menusearch[0])
V_DrawString(x - 18, y + 8, V_ALLOWLOWERCASE, menusearch+1);
else
V_DrawString(x - 18, y + 8, V_ALLOWLOWERCASE|V_TRANSLUCENT, "Type to search...");
if (skullAnimCounter < 4)
V_DrawCharacter(x - 18 + V_StringWidth(menusearch+1, 0), y + 8,
'_' | 0x80, false);
x -= (21 + 5 + 16);
V_DrawSmallScaledPatch(x, y + 4, (menusearch[0] ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+3]);
x = BASEVIDWIDTH - x - 16;
V_DrawSmallScaledPatch(x, y + 4, ((!modifiedgame || savemoddata) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]);
if (modifiedgame)
V_DrawSmallScaledPatch(x, y + 4, 0, addonsp[NUM_EXT+2]);
}
static void M_AddonExec(INT32 ch)
{
if (ch != 'y' && ch != KEY_ENTER)
return;
S_StartSound(NULL, sfx_zoom);
COM_BufAddText(va("exec \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING));
}
#define len menusearch[0]
static boolean M_ChangeStringAddons(INT32 choice)
{
if (shiftdown && choice >= 32 && choice <= 127)
choice = shiftxform[choice];
switch (choice)
{
case KEY_DEL:
if (len)
{
len = menusearch[1] = 0;
return true;
}
break;
case KEY_BACKSPACE:
if (len)
{
menusearch[1+--len] = 0;
return true;
}
break;
default:
if (choice >= 32 && choice <= 127)
{
if (len < MAXSTRINGLENGTH - 1)
{
menusearch[1+len++] = (char)choice;
menusearch[1+len] = 0;
return true;
}
}
break;
}
return false;
}
#undef len
static void M_HandleAddons(INT32 choice)
{
boolean exitmenu = false; // exit to previous menu
if (M_ChangeStringAddons(choice))
{
char *tempname = NULL;
if (dirmenu && dirmenu[dir_on[menudepthleft]])
tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL
#if 0 // much slower
if (!preparefilemenu(true))
{
UNEXIST;
return;
}
#else // streamlined
searchfilemenu(tempname);
#endif
}
switch (choice)
{
case KEY_DOWNARROW:
if (dir_on[menudepthleft] < sizedirmenu-1)
dir_on[menudepthleft]++;
S_StartSound(NULL, sfx_menu1);
break;
case KEY_UPARROW:
if (dir_on[menudepthleft])
dir_on[menudepthleft]--;
S_StartSound(NULL, sfx_menu1);
break;
case KEY_PGDN:
{
UINT8 i;
for (i = numaddonsshown; i && (dir_on[menudepthleft] < sizedirmenu-1); i--)
dir_on[menudepthleft]++;
}
S_StartSound(NULL, sfx_menu1);
break;
case KEY_PGUP:
{
UINT8 i;
for (i = numaddonsshown; i && (dir_on[menudepthleft]); i--)
dir_on[menudepthleft]--;
}
S_StartSound(NULL, sfx_menu1);
break;
case KEY_ENTER:
{
boolean refresh = true;
if (!dirmenu[dir_on[menudepthleft]])
S_StartSound(NULL, sfx_lose);
else
{
switch (dirmenu[dir_on[menudepthleft]][DIR_TYPE])
{
case EXT_FOLDER:
strcpy(&menupath[menupathindex[menudepthleft]],dirmenu[dir_on[menudepthleft]]+DIR_STRING);
if (menudepthleft)
{
menupathindex[--menudepthleft] = strlen(menupath);
menupath[menupathindex[menudepthleft]] = 0;
if (!preparefilemenu(false))
{
S_StartSound(NULL, sfx_skid);
M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING);
menupath[menupathindex[++menudepthleft]] = 0;
if (!preparefilemenu(true))
{
UNEXIST;
return;
}
}
else
{
S_StartSound(NULL, sfx_menu1);
dir_on[menudepthleft] = 1;
}
refresh = false;
}
else
{
S_StartSound(NULL, sfx_lose);
M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING);
menupath[menupathindex[menudepthleft]] = 0;
}
break;
case EXT_UP:
S_StartSound(NULL, sfx_menu1);
menupath[menupathindex[++menudepthleft]] = 0;
if (!preparefilemenu(false))
{
UNEXIST;
return;
}
break;
case EXT_TXT:
M_StartMessage(va("%c%s\x80\nThis file may not be a console script.\nAttempt to run anyways? \n\n(Press 'Y' to confirm)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),M_AddonExec,MM_YESNO);
break;
case EXT_CFG:
M_AddonExec(KEY_ENTER);
break;
case EXT_LUA:
#ifndef HAVE_BLUA
S_StartSound(NULL, sfx_lose);
M_StartMessage(va("%c%s\x80\nThis copy of SRB2 was compiled\nwithout support for .lua files.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),NULL,MM_NOTHING);
break;
#endif
// else intentional fallthrough
case EXT_SOC:
case EXT_WAD:
#ifdef USE_KART
case EXT_KART:
#endif
case EXT_PK3:
COM_BufAddText(va("addfile \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING));
break;
default:
S_StartSound(NULL, sfx_lose);
}
}
if (refresh)
refreshdirmenu |= REFRESHDIR_NORMAL;
}
break;
case KEY_ESCAPE:
exitmenu = true;
break;
default:
break;
}
if (exitmenu)
{
closefilemenu(true);
// Secret menu!
MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
if (currentMenu->prevMenu)
M_SetupNextMenu(currentMenu->prevMenu);
else
M_ClearMenus(true);
}
}
static void M_PandorasBox(INT32 choice) static void M_PandorasBox(INT32 choice)
{ {
(void)choice; (void)choice;

View file

@ -124,6 +124,8 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt);
#define IT_HEADER (IT_SPACE +IT_HEADERTEXT) #define IT_HEADER (IT_SPACE +IT_HEADERTEXT)
#define IT_SECRET (IT_SPACE +IT_QUESTIONMARKS) #define IT_SECRET (IT_SPACE +IT_QUESTIONMARKS)
#define MAXSTRINGLENGTH 32
typedef union typedef union
{ {
struct menu_s *submenu; // IT_SUBMENU struct menu_s *submenu; // IT_SUBMENU
@ -223,6 +225,9 @@ void M_CheatActivationResponder(INT32 ch);
void Moviemode_mode_Onchange(void); void Moviemode_mode_Onchange(void);
void Screenshot_option_Onchange(void); void Screenshot_option_Onchange(void);
// Addons menu updating
void Addons_option_Onchange(void);
// These defines make it a little easier to make menus // These defines make it a little easier to make menus
#define DEFAULTMENUSTYLE(header, source, prev, x, y)\ #define DEFAULTMENUSTYLE(header, source, prev, x, y)\
{\ {\

View file

@ -54,6 +54,8 @@
#include "v_video.h" #include "v_video.h"
#include "filesrch.h" // refreshdirmenu
// wipes // wipes
#include "f_finale.h" #include "f_finale.h"
@ -3197,6 +3199,7 @@ boolean P_AddWadFile(const char *wadfilename)
if ((numlumps = W_InitFile(wadfilename)) == INT16_MAX) if ((numlumps = W_InitFile(wadfilename)) == INT16_MAX)
{ {
refreshdirmenu |= REFRESHDIR_NOTLOADED;
CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename); CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename);
return false; return false;
} }

View file

@ -153,6 +153,8 @@ void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);
// draw a single character, but for the chat // draw a single character, but for the chat
void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UINT8 *colormap); void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UINT8 *colormap);
UINT8 *V_GetStringColormap(INT32 colorflags);
void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string); void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string);
// wordwrap a string using the hu_font // wordwrap a string using the hu_font

View file

@ -34,6 +34,8 @@
#include "z_zone.h" #include "z_zone.h"
#include "fastcmp.h" #include "fastcmp.h"
#include "filesrch.h"
#include "i_video.h" // rendermode #include "i_video.h" // rendermode
#include "d_netfil.h" #include "d_netfil.h"
#include "dehacked.h" #include "dehacked.h"
@ -647,12 +649,22 @@ UINT16 W_InitFile(const char *filename)
restype_t type; restype_t type;
UINT16 numlumps = 0; UINT16 numlumps = 0;
size_t i; size_t i;
size_t packetsize = 0; size_t packetsize;
serverinfo_pak *dummycheck = NULL;
UINT8 md5sum[16]; UINT8 md5sum[16];
boolean important;
// Shut the compiler up. if (!(refreshdirmenu & REFRESHDIR_ADDFILE))
(void)dummycheck; refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier
if (refreshdirname)
Z_Free(refreshdirname);
if (dirmenu)
{
refreshdirname = Z_StrDup(filename);
nameonly(refreshdirname);
}
else
refreshdirname = NULL;
//CONS_Debug(DBG_SETUP, "Loading %s\n", filename); //CONS_Debug(DBG_SETUP, "Loading %s\n", filename);
// //
@ -661,6 +673,7 @@ UINT16 W_InitFile(const char *filename)
if (numwadfiles >= MAX_WADFILES) if (numwadfiles >= MAX_WADFILES)
{ {
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
refreshdirmenu |= REFRESHDIR_MAX;
return INT16_MAX; return INT16_MAX;
} }
@ -670,21 +683,21 @@ UINT16 W_InitFile(const char *filename)
// Check if wad files will overflow fileneededbuffer. Only the filename part // Check if wad files will overflow fileneededbuffer. Only the filename part
// is send in the packet; cf. // is send in the packet; cf.
for (i = 0; i < numwadfiles; i++) // see PutFileNeeded in d_netfil.c
if ((important = !W_VerifyNMUSlumps(filename)))
{ {
packetsize += nameonlylength(wadfiles[i]->filename); packetsize = packetsizetally + nameonlylength(filename) + 22;
packetsize += 22; // MD5, etc.
}
packetsize += nameonlylength(filename); if (packetsize > MAXFILENEEDED*sizeof(UINT8))
packetsize += 22; {
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
refreshdirmenu |= REFRESHDIR_MAX;
if (handle)
fclose(handle);
return INT16_MAX;
}
if (packetsize > sizeof(dummycheck->fileneeded)) packetsizetally = packetsize;
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
if (handle)
fclose(handle);
return INT16_MAX;
} }
#ifndef NOMD5 #ifndef NOMD5
@ -741,6 +754,7 @@ UINT16 W_InitFile(const char *filename)
wadfile->handle = handle; wadfile->handle = handle;
wadfile->numlumps = (UINT16)numlumps; wadfile->numlumps = (UINT16)numlumps;
wadfile->lumpinfo = lumpinfo; wadfile->lumpinfo = lumpinfo;
wadfile->important = important;
fseek(handle, 0, SEEK_END); fseek(handle, 0, SEEK_END);
wadfile->filesize = (unsigned)ftell(handle); wadfile->filesize = (unsigned)ftell(handle);
wadfile->type = type; wadfile->type = type;

View file

@ -110,6 +110,7 @@ typedef struct wadfile_s
FILE *handle; FILE *handle;
UINT32 filesize; // for network UINT32 filesize; // for network
UINT8 md5sum[16]; UINT8 md5sum[16];
boolean important;
} wadfile_t; } wadfile_t;
#define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad flumpnum>>16) // wad file number in upper word #define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad flumpnum>>16) // wad file number in upper word