Merge remote-tracking branch 'refs/remotes/origin/master' into save-mode

This commit is contained in:
TehRealSalt 2017-08-06 01:19:33 -04:00
commit e24b8b917a
34 changed files with 1697 additions and 437 deletions

View File

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

View File

@ -315,6 +315,7 @@ typedef struct
} ATTRPACK clientconfig_pak;
#define MAXSERVERNAME 32
#define MAXFILENEEDED 915
// This packet is too large
typedef struct
{
@ -336,7 +337,7 @@ typedef struct
unsigned char mapmd5[16];
UINT8 actnum;
UINT8 iszone;
UINT8 fileneeded[915]; // is filled with writexxx (byteptr.h)
UINT8 fileneeded[MAXFILENEEDED]; // is filled with writexxx (byteptr.h)
} ATTRPACK serverinfo_pak;
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 "fastcmp.h"
#include "keys.h"
#include "filesrch.h" // refreshdirmenu, mainwadstally
#ifdef CMAKECONFIG
#include "config.h"
@ -584,6 +585,8 @@ void D_SRB2Loop(void)
realtics = entertic - oldentertics;
oldentertics = entertic;
refreshdirmenu = 0; // not sure where to put this, here as good as any?
#ifdef DEBUGFILE
if (!realtics)
if (debugload)
@ -871,7 +874,7 @@ static void IdentifyVersion(void)
}
#endif
#if 1 // This section can be deleted when music_new is merged with music.dta
#ifdef DEVELOP // This section can be deleted when music_new is merged with music.dta
{
const char *musicfile = "music_new.dta";
const char *musicpath = va(pandf,srb2waddir,musicfile);
@ -1163,6 +1166,11 @@ void D_SRB2Main(void)
#ifdef USE_PATCH_DTA
++mainwads; // patch.dta adds one more
#endif
#ifdef DEVELOP
++mainwads; // music_new, too
#endif
mainwadstally = packetsizetally;
cht_Init();

View File

@ -37,6 +37,7 @@
#include "d_main.h"
#include "m_random.h"
#include "f_finale.h"
#include "filesrch.h"
#include "mserv.h"
#include "md5.h"
#include "z_zone.h"
@ -714,6 +715,14 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_firenaxis);
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
// we need the mouse2port
CV_RegisterVar(&cv_mouse2port);

View File

@ -104,6 +104,7 @@ INT32 lastfilenum = -1;
/** Fills a serverinfo packet with information about wad files loaded.
*
* \todo Give this function a better name since it is in global scope.
* Used to have size limiting built in - now handled via W_LoadWadFile in w_wad.c
*
*/
UINT8 *PutFileNeeded(void)
@ -112,29 +113,22 @@ UINT8 *PutFileNeeded(void)
UINT8 *p = netbuffer->u.serverinfo.fileneeded;
char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus;
size_t bytesused = 0;
for (i = 0; i < numwadfiles; i++)
{
// If it has only music/sound lumps, mark it as unimportant
if (W_VerifyNMUSlumps(wadfiles[i]->filename))
filestatus = 0;
else
filestatus = 1; // Important
// If it has only music/sound lumps, don't put it in the list
if (!wadfiles[i]->important)
continue;
filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS
// Store in the upper four bits
if (!cv_downloading.value)
filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024))
filestatus += (0 << 4); // Won't send
else
else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
filestatus += (1 << 4); // Will send if requested
bytesused += (nameonlylength(wadfilename) + 22);
// 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);
// else
// filestatus += (0 << 4); -- Won't send, too big
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
filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].important = (UINT8)(filestatus & 3);
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
fileneeded[i].file = NULL; // The file isn't open yet
@ -197,7 +190,7 @@ boolean CL_CheckDownloadable(void)
UINT8 i,dlstatus = 0;
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)
continue;
@ -218,7 +211,7 @@ boolean CL_CheckDownloadable(void)
// not downloadable, put reason in console
CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n"));
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);
@ -271,7 +264,7 @@ boolean CL_SendRequestFile(void)
for (i = 0; i < fileneedednum; i++)
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");
}
@ -280,8 +273,7 @@ boolean CL_SendRequestFile(void)
netbuffer->packettype = PT_REQUESTFILE;
p = (char *)netbuffer->u.textcmd;
for (i = 0; i < fileneedednum; i++)
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)
&& fileneeded[i].important)
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD))
{
totalfreespaceneeded += fileneeded[i].totalsize;
nameonly(fileneeded[i].filename);
@ -360,15 +352,9 @@ INT32 CL_CheckFiles(void)
CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n");
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.
++j;
continue;
}
@ -411,7 +397,7 @@ INT32 CL_CheckFiles(void)
break;
}
}
if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important)
if (fileneeded[i].status != FS_NOTFOUND)
continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22;
@ -449,27 +435,8 @@ void CL_LoadServerFiles(void)
fileneeded[i].status = FS_OPEN;
}
else if (fileneeded[i].status == FS_MD5SUMBAD)
{
// If the file is marked important, don't even bother proceeding.
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, NULL);
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)
I_Error("Wrong version of file %s", fileneeded[i].filename);
else
{
const char *s;
switch(fileneeded[i].status)

View File

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

View File

@ -2239,12 +2239,12 @@ static void reademblemdata(MYFILE *f, INT32 num)
emblemlocations[num-1].type = ET_TIME;
else if (fastcmp(word2, "RINGS"))
emblemlocations[num-1].type = ET_RINGS;
else if (fastcmp(word2, "MAP"))
emblemlocations[num-1].type = ET_MAP;
else if (fastcmp(word2, "NGRADE"))
emblemlocations[num-1].type = ET_NGRADE;
else if (fastcmp(word2, "NTIME"))
emblemlocations[num-1].type = ET_NTIME;
else if (fastcmp(word2, "MAP"))
emblemlocations[num-1].type = ET_MAP;
else
emblemlocations[num-1].type = (UINT8)value;
}
@ -4693,6 +4693,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_WALLSPIKE5",
"S_WALLSPIKE6",
"S_WALLSPIKEBASE",
"S_WALLSPIKED1",
"S_WALLSPIKED2",
// Starpost
"S_STARPOST_IDLE",
@ -5946,16 +5948,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_NIGHTSWING_XMAS",
// NiGHTS Paraloop Powerups
"S_NIGHTSPOWERUP1",
"S_NIGHTSPOWERUP2",
"S_NIGHTSPOWERUP3",
"S_NIGHTSPOWERUP4",
"S_NIGHTSPOWERUP5",
"S_NIGHTSPOWERUP6",
"S_NIGHTSPOWERUP7",
"S_NIGHTSPOWERUP8",
"S_NIGHTSPOWERUP9",
"S_NIGHTSPOWERUP10",
"S_NIGHTSSUPERLOOP",
"S_NIGHTSDRILLREFILL",
"S_NIGHTSHELPER",
"S_NIGHTSEXTRATIME",
"S_NIGHTSLINKFREEZE",
"S_EGGCAPSULE",
// Orbiting Chaos Emeralds
@ -7190,7 +7187,11 @@ struct {
{"SF_X8AWAYSOUND",SF_X8AWAYSOUND},
{"SF_NOINTERRUPT",SF_NOINTERRUPT},
{"SF_X2AWAYSOUND",SF_X2AWAYSOUND},
// Global emblem var flags
{"GE_NIGHTSPULL",GE_NIGHTSPULL},
{"GE_NIGHTSITEM",GE_NIGHTSITEM},
// Map emblem var flags
{"ME_ALLEMERALDS",ME_ALLEMERALDS},
{"ME_ULTIMATE",ME_ULTIMATE},
@ -7872,11 +7873,14 @@ void FUNCMATH DEH_Check(void)
static inline int lib_freeslot(lua_State *L)
{
int n = lua_gettop(L);
int r = 0; // args returned
int r = 0; // args returned
char *s, *type,*word;
while (n-- > 0)
{
if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
while (n-- > 0)
{
s = Z_StrDup(luaL_checkstring(L,1));
type = strtok(s, "_");
if (type)

View File

@ -31,6 +31,8 @@
#include "filesrch.h"
#include "d_netfil.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)
@ -255,6 +257,28 @@ readdir (DIR * dirp)
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
*
@ -285,6 +309,35 @@ closedir (DIR * dirp)
return rc;
}
#endif
static CV_PossibleValue_t addons_cons_t[] = {{0, "SRB2 Folder"}, /*{1, "HOME"}, {2, "SRB2 Folder"},*/ {3, "CUSTOM"}, {0, NULL}};
consvar_t cv_addons_option = {"addons_option", "SRB2 Folder", 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;
size_t sizedirmenu;
size_t dir_on[menudepth];
UINT8 refreshdirmenu = 0;
size_t packetsizetally = 0;
size_t mainwadstally = 0;
#if defined (_XBOX) && defined (_MSC_VER)
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
boolean completepath, int maxsearchdepth)
@ -296,6 +349,13 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
completepath = false;
return FS_NOTFOUND;
}
boolean preparefilemenu(boolean samedepth)
{
(void)samedepth;
return false;
}
#elif defined (_WIN32_WCE)
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
boolean completepath, int maxsearchdepth)
@ -346,6 +406,12 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
#endif
return FS_NOTFOUND;
}
boolean preparefilemenu(boolean samedepth)
{
(void)samedepth;
return false;
}
#else
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth)
{
@ -387,25 +453,29 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
{
searchpath[searchpathindex[depthleft]]=0;
dent = readdir(dirhandle[depthleft]);
if (dent)
strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name);
if (!dent)
{
closedir(dirhandle[depthleft++]);
else if (dent->d_name[0]=='.' &&
continue;
}
if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
{
// 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
{
// was the file (re)moved? can't stat it
}
// okay, now we actually want searchpath to incorporate d_name
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)
{
strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name);
searchpathindex[--depthleft] = strlen(searchpath) + 1;
dirhandle[depthleft] = opendir(searchpath);
if (!dirhandle[depthleft])
@ -444,6 +514,255 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
free(searchname);
free(searchpathindex);
free(dirhandle);
return retval;
}
char exttable[NUM_EXT_TABLE][5] = {
".txt", ".cfg", // exec
".wad", ".soc", ".lua"}; // addfile
char filenamebuf[MAX_WADFILES][MAX_WADPATH];
static boolean filemenusearch(char *haystack, char *needle)
{
static char localhaystack[128];
strlcpy(localhaystack, haystack, 128);
if (!cv_addons_search_case.value)
strupr(localhaystack);
return ((cv_addons_search_type.value)
? (strstr(localhaystack, needle) != 0)
: (!strncmp(localhaystack, needle, menusearch[0])));
}
#define searchdir if (menusearch[0] && !filemenusearch(dent->d_name, localmenusearch))\
{\
rejected++;\
continue;\
}\
boolean preparefilemenu(boolean samedepth)
{
DIR *dirhandle;
struct dirent *dent;
struct stat fsstat;
size_t pos = 0, folderpos = 0, numfolders = 0, rejected = 0;
char *tempname = NULL;
boolean noresults = false;
char localmenusearch[MAXSTRINGLENGTH] = "";
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
for (; sizedirmenu > 0; sizedirmenu--) // clear out existing items
{
Z_Free(dirmenu[sizedirmenu-1]);
dirmenu[sizedirmenu-1] = NULL;
}
if (!(dirhandle = opendir(menupath))) // get directory
return false;
if (menusearch[0])
{
strcpy(localmenusearch, menusearch+1);
if (!cv_addons_search_case.value)
strupr(localmenusearch);
}
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], dent->d_name+len-5)) break; // extension comparison
if (ext == NUM_EXT_TABLE) continue; // not an addfile-able (or exec-able) file
}
searchdir;
}
else // directory
{
searchdir;
numfolders++;
}
sizedirmenu++;
}
}
if (!rejected && !sizedirmenu)
{
if (tempname)
Z_Free(tempname);
closedir(dirhandle);
return false;
}
if (((noresults = (menusearch[0] && !sizedirmenu)))
|| (!menusearch[0] && menudepthleft != menudepth-1)) // Make room for UP... or search entry
{
sizedirmenu++;
numfolders++;
folderpos++;
}
if (!(dirmenu = Z_Realloc(dirmenu, sizedirmenu*sizeof(char *), PU_STATIC, NULL)))
{
closedir(dirhandle); // just in case
I_Error("Ran out of memory whilst preparing add-ons menu");
}
rejected = 0;
rewinddir(dirhandle);
while ((pos+folderpos) < sizedirmenu)
{
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) < sizedirmenu)) continue; // crash prevention
for (; ext < NUM_EXT_TABLE; ext++)
if (!strcasecmp(exttable[ext], dent->d_name+len-5)) 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
searchdir;
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
{
searchdir;
len += (folder = 1);
}
if (len > 255)
len = 255;
if (!(temp = Z_Malloc((len+DIR_STRING+folder) * sizeof (char), PU_STATIC, NULL)))
I_Error("Ran out of memory whilst preparing add-ons menu");
temp[DIR_TYPE] = ext;
temp[DIR_LEN] = (UINT8)(len);
strlcpy(temp+DIR_STRING, dent->d_name, len);
if (folder)
{
strcpy(temp+len, "/");
dirmenu[folderpos++] = temp;
}
else
dirmenu[numfolders + pos++] = temp;
}
}
closedir(dirhandle);
if (noresults) // no results
dirmenu[0] = Z_StrDup(va("%c\13No results...", EXT_NORESULTS));
else if (!menusearch[0] &&menudepthleft != menudepth-1) // now for UP... entry
dirmenu[0] = Z_StrDup(va("%c\5UP...", EXT_UP));
menupath[menupathindex[menudepthleft]] = 0;
sizedirmenu = (numfolders+pos); // just in case things shrink between opening and rewind
if (tempname)
{
size_t i;
for (i = 0; i < sizedirmenu; i++)
{
if (!strcmp(dirmenu[i]+DIR_STRING, tempname))
{
dir_on[menudepthleft] = i;
break;
}
}
Z_Free(tempname);
}
if (!sizedirmenu)
{
dir_on[menudepthleft] = 0;
Z_Free(dirmenu);
return false;
}
else if (dir_on[menudepthleft] >= sizedirmenu)
dir_on[menudepthleft] = sizedirmenu-1;
return true;
}
#endif

View File

@ -6,6 +6,9 @@
#include "doomdef.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
@ -25,4 +28,64 @@
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
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 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,
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;
boolean preparefilemenu(boolean samedepth);
#endif // __FILESRCH_H__

View File

@ -641,13 +641,13 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is
{
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize;
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize;
angle = FOFsector->floorpic_angle>>ANGLETOFINESHIFT;
angle = FOFsector->floorpic_angle;
}
else // it's a ceiling
{
scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatsize;
scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatsize;
angle = FOFsector->ceilingpic_angle>>ANGLETOFINESHIFT;
angle = FOFsector->ceilingpic_angle;
}
}
else if (gr_frontsector)
@ -656,25 +656,19 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is
{
scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize;
scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize;
angle = gr_frontsector->floorpic_angle>>ANGLETOFINESHIFT;
angle = gr_frontsector->floorpic_angle;
}
else // it's a ceiling
{
scrollx = FIXED_TO_FLOAT(gr_frontsector->ceiling_xoffs)/fflatsize;
scrolly = FIXED_TO_FLOAT(gr_frontsector->ceiling_yoffs)/fflatsize;
angle = gr_frontsector->ceilingpic_angle>>ANGLETOFINESHIFT;
angle = gr_frontsector->ceilingpic_angle;
}
}
if (angle) // Only needs to be done if there's an altered angle
{
// This needs to be done so that it scrolls in a different direction after rotation like software
tempxsow = FLOAT_TO_FIXED(scrollx);
tempytow = FLOAT_TO_FIXED(scrolly);
scrollx = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
scrolly = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));
angle = InvAngle(angle)>>ANGLETOFINESHIFT;
// This needs to be done so everything aligns after rotation
// It would be done so that rotation is done, THEN the translation, but I couldn't get it to rotate AND scroll like software does
tempxsow = FLOAT_TO_FIXED(flatxref);
@ -687,7 +681,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is
{
// Hurdler: add scrolling texture on floor/ceiling
v3d->sow = (float)((pv->x / fflatsize) - flatxref + scrollx);
v3d->tow = (float)(flatyref - (pv->y / fflatsize) + scrolly);
v3d->tow = (float)(-(pv->y / fflatsize) + flatyref + scrolly);
//v3d->sow = (float)(pv->x / fflatsize);
//v3d->tow = (float)(pv->y / fflatsize);
@ -698,7 +692,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is
tempxsow = FLOAT_TO_FIXED(v3d->sow);
tempytow = FLOAT_TO_FIXED(v3d->tow);
v3d->sow = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
v3d->tow = (FIXED_TO_FLOAT(-FixedMul(tempxsow, FINESINE(angle)) - FixedMul(tempytow, FINECOSINE(angle))));
v3d->tow = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));
}
//v3d->sow = (float)(v3d->sow - flatxref + scrollx);

View File

@ -1563,13 +1563,13 @@ state_t states[NUMSTATES] =
// Floor Spike
{SPR_USPK, 0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2}, // S_SPIKE1 -- Fully extended
{SPR_USPK, 5, 2, {A_Pain}, 0, 0, S_SPIKE3}, // S_SPIKE2
{SPR_USPK, 4, 2, {NULL}, 0, 0, S_SPIKE4}, // S_SPIKE3
{SPR_USPK, 1, 2, {A_Pain}, 0, 0, S_SPIKE3}, // S_SPIKE2
{SPR_USPK, 2, 2, {NULL}, 0, 0, S_SPIKE4}, // S_SPIKE3
{SPR_USPK, 3,-1, {A_SpikeRetract}, 0, 0, S_SPIKE5}, // S_SPIKE4 -- Fully retracted
{SPR_USPK, 4, 2, {A_Pain}, 0, 0, S_SPIKE6}, // S_SPIKE5
{SPR_USPK, 5, 2, {NULL}, 0, 0, S_SPIKE1}, // S_SPIKE6
{SPR_USPK, 1,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED1 -- Busted spike particles
{SPR_USPK, 2,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED2
{SPR_USPK, 2, 2, {A_Pain}, 0, 0, S_SPIKE6}, // S_SPIKE5
{SPR_USPK, 1, 2, {NULL}, 0, 0, S_SPIKE1}, // S_SPIKE6
{SPR_USPK, 4,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED1 -- Busted spike particles
{SPR_USPK, 5,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED2
// Wall Spike
{SPR_WSPK, 0|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 1, 0, S_WALLSPIKE2}, // S_WALLSPIKE1 -- Fully extended
@ -1579,6 +1579,8 @@ state_t states[NUMSTATES] =
{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {A_Pain}, 0, 0, S_WALLSPIKE6}, // S_WALLSPIKE5
{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_WALLSPIKE1}, // S_WALLSPIKE6
{SPR_WSPB, 0|FF_PAPERSPRITE,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKEBASE -- Base
{SPR_WSPK, 4,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKED1 -- Busted spike particles
{SPR_WSPK, 5,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKED2
// Starpost
{SPR_STPT, 0 , -1, {NULL}, 0, 0, S_NULL}, // S_STARPOST_IDLE
@ -2894,16 +2896,11 @@ state_t states[NUMSTATES] =
{SPR_NWNG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSWING_XMAS
// NiGHTS Paraloop Powerups
{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSPOWERUP1
{SPR_NPRU, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSPOWERUP2
{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSPOWERUP3
{SPR_NPRU, 1, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSPOWERUP4
{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSPOWERUP5
{SPR_NPRU, 2, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSPOWERUP6
{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSPOWERUP7
{SPR_NPRU, 3, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSPOWERUP8
{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSPOWERUP9
{SPR_NPRU, 4, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSPOWERUP10
{SPR_NPRU, 0, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSSUPERLOOP
{SPR_NPRU, 1, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSDRILLREFILL
{SPR_NPRU, 2, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSHELPER
{SPR_NPRU, 3, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSEXTRATIME
{SPR_NPRU, 4, -1, {NULL}, 0, 0, S_NULL}, // S_NIGHTSLINKFREEZE
{SPR_CAPS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGCAPSULE
@ -5992,7 +5989,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_WALLSPIKE
522, // doomednum
S_WALLSPIKE1, // spawnstate
S_WALLSPIKE1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
@ -6003,11 +6000,11 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_s3k64, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
S_WALLSPIKED1, // deathstate
S_WALLSPIKED2, // xdeathstate
sfx_mspogo, // deathsound
2*TICRATE, // speed
32*FRACUNIT, // radius
16*FRACUNIT, // radius
14*FRACUNIT, // height
0, // display offset
4, // mass
@ -6019,7 +6016,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_WALLSPIKEBASE
-1, // doomednum
S_WALLSPIKEBASE, // spawnstate
S_WALLSPIKEBASE, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
@ -14294,9 +14291,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_NIGHTSSUPERLOOP
1707, // doomednum
S_NIGHTSPOWERUP1, // spawnstate
S_NIGHTSSUPERLOOP, // spawnstate
1000, // spawnhealth
S_NIGHTSPOWERUP2, // seestate
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
@ -14321,9 +14318,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_NIGHTSDRILLREFILL
1708, // doomednum
S_NIGHTSPOWERUP3, // spawnstate
S_NIGHTSDRILLREFILL, // spawnstate
1000, // spawnhealth
S_NIGHTSPOWERUP4, // seestate
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
@ -14348,9 +14345,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_NIGHTSHELPER
1709, // doomednum
S_NIGHTSPOWERUP5, // spawnstate
S_NIGHTSHELPER, // spawnstate
1000, // spawnhealth
S_NIGHTSPOWERUP6, // seestate
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
@ -14375,9 +14372,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_NIGHTSEXTRATIME
1711, // doomednum
S_NIGHTSPOWERUP7, // spawnstate
S_NIGHTSEXTRATIME, // spawnstate
1000, // spawnhealth
S_NIGHTSPOWERUP8, // seestate
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
@ -14402,9 +14399,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_NIGHTSLINKFREEZE
1712, // doomednum
S_NIGHTSPOWERUP9, // spawnstate
S_NIGHTSLINKFREEZE, // spawnstate
1000, // spawnhealth
S_NIGHTSPOWERUP10, // seestate
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound

View File

@ -1784,6 +1784,8 @@ typedef enum state
S_WALLSPIKE5,
S_WALLSPIKE6,
S_WALLSPIKEBASE,
S_WALLSPIKED1,
S_WALLSPIKED2,
// Starpost
S_STARPOST_IDLE,
@ -3039,16 +3041,11 @@ typedef enum state
S_NIGHTSWING_XMAS,
// NiGHTS Paraloop Powerups
S_NIGHTSPOWERUP1,
S_NIGHTSPOWERUP2,
S_NIGHTSPOWERUP3,
S_NIGHTSPOWERUP4,
S_NIGHTSPOWERUP5,
S_NIGHTSPOWERUP6,
S_NIGHTSPOWERUP7,
S_NIGHTSPOWERUP8,
S_NIGHTSPOWERUP9,
S_NIGHTSPOWERUP10,
S_NIGHTSSUPERLOOP,
S_NIGHTSDRILLREFILL,
S_NIGHTSHELPER,
S_NIGHTSEXTRATIME,
S_NIGHTSLINKFREEZE,
S_EGGCAPSULE,
// Orbiting Chaos Emeralds

View File

@ -22,8 +22,13 @@
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
// for functions not allowed in hud.add hooks
#define NOHUD if (hud_running)\
return luaL_error(L, "HUD rendering code should not call this function!");
// for functions not allowed in hooks or coroutines (supercedes above)
#define NOHOOK if (!lua_lumploading)\
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
// for functions only allowed within a level
#define INLEVEL if (gamestate != GS_LEVEL)\
return luaL_error(L, "This function can only be used in a level!");
@ -184,7 +189,7 @@ static int lib_comAddCommand(lua_State *L)
strlwr(name);
luaL_checktype(L, 2, LUA_TFUNCTION);
NOHUD
NOHOOK
if (lua_gettop(L) >= 3)
{ // For the third argument, only take a boolean or a number.
lua_settop(L, 3);
@ -296,7 +301,7 @@ static int lib_cvRegisterVar(lua_State *L)
consvar_t *cvar;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one.
NOHUD
NOHOOK
cvar = lua_newuserdata(L, sizeof(consvar_t));
luaL_getmetatable(L, META_CVAR);
lua_setmetatable(L, -2);

View File

@ -109,8 +109,8 @@ static int lib_addHook(lua_State *L)
luaL_checktype(L, 1, LUA_TFUNCTION);
if (hud_running)
return luaL_error(L, "HUD rendering code should not call this function!");
if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
switch(hook.type)
{

View File

@ -612,6 +612,9 @@ static int lib_hudadd(lua_State *L)
luaL_checktype(L, 1, LUA_TFUNCTION);
field = luaL_checkoption(L, 2, "game", hudhook_opt);
if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
lua_getfield(L, LUA_REGISTRYINDEX, "HUD");
I_Assert(lua_istable(L, -1));
lua_rawgeti(L, -1, field+2); // HUD[2+]

View File

@ -161,6 +161,11 @@ void LUA_ClearExtVars(void)
}
#endif
// Use this variable to prevent certain functions from running
// if they were not called on lump load
// (i.e. they were called in hooks or coroutines etc)
boolean lua_lumploading = false;
// Load a script from a MYFILE
static inline void LUA_LoadFile(MYFILE *f, char *name)
{
@ -198,7 +203,9 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump)
name[strlen(wadfiles[wad]->filename)+9] = '\0';
}
LUA_LoadFile(&f, name);
lua_lumploading = true; // turn on loading flag
LUA_LoadFile(&f, name); // actually load file!
lua_lumploading = false; // turn off again
free(name);
Z_Free(f.data);

View File

@ -38,6 +38,8 @@
void LUA_ClearExtVars(void);
#endif
extern boolean lua_lumploading; // is LUA_LoadLump being called?
void LUA_LoadLump(UINT16 wad, UINT16 lump);
#ifdef LUA_ALLOW_BYTECODE
void LUA_DumpFile(const char *filename);

View File

@ -66,14 +66,18 @@ typedef struct
} conditionset_t;
// Emblem information
#define ET_GLOBAL 0 // Global map emblem, var == color
#define ET_SKIN 1 // Skin specific emblem, var == skin
#define ET_SCORE 2
#define ET_TIME 3
#define ET_RINGS 4
#define ET_NGRADE 5
#define ET_NTIME 6
#define ET_MAP 7
#define ET_GLOBAL 0 // Emblem with a position in space
#define ET_SKIN 1 // Skin specific emblem with a position in space, var == skin
#define ET_MAP 2 // Beat the map
#define ET_SCORE 3 // Get the score
#define ET_TIME 4 // Get the time
#define ET_RINGS 5 // Get the rings
#define ET_NGRADE 6 // Get the grade
#define ET_NTIME 7 // Get the time (NiGHTS mode)
// Global emblem flags
#define GE_NIGHTSPULL 1 // sun off the nights track - loop it
#define GE_NIGHTSITEM 2 // moon on the nights track - find it
// Map emblem flags
#define ME_ALLEMERALDS 1

View File

@ -33,6 +33,9 @@
#include "s_sound.h"
#include "i_system.h"
// Addfile
#include "filesrch.h"
#include "v_video.h"
#include "i_video.h"
#include "keys.h"
@ -74,7 +77,6 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
#define SMALLLINEHEIGHT 8
#define SLIDER_RANGE 9
#define SLIDER_WIDTH 78
#define MAXSTRINGLENGTH 32
#define SERVERS_PER_PAGE 11
typedef enum
@ -211,14 +213,13 @@ menu_t SPauseDef;
// Level Select
static levelselect_t levelselect = {0, NULL};
static UINT8 levelselectselect[4];
static UINT8 levelselectselect[3];
static patch_t *levselp[2][3];
static INT32 lsoffs[2];
#define lsrow levelselectselect[0]
#define lscol levelselectselect[1]
#define lstic levelselectselect[2]
#define lshli levelselectselect[3]
#define lshli levelselectselect[2]
#define lshseperation 101
#define lsbasevseperation 62
@ -334,12 +335,20 @@ menu_t OP_MonitorToggleDef;
static void M_ScreenshotOptions(INT32 choice);
static void M_EraseData(INT32 choice);
static void M_DrawLevelPlatterHeader(INT32 y, const char *header, boolean headerhighlight);
static void M_Addons(INT32 choice);
static void M_AddonsOptions(INT32 choice);
static patch_t *addonsp[NUM_EXT+6];
static UINT8 addonsresponselimit = 0;
#define numaddonsshown 4
static void M_DrawLevelPlatterHeader(INT32 y, const char *header, boolean headerhighlight, boolean allowlowercase);
// Drawing functions
static void M_DrawGenericMenu(void);
static void M_DrawGenericScrollMenu(void);
static void M_DrawCenteredMenu(void);
static void M_DrawAddons(void);
static void M_DrawSkyRoom(void);
static void M_DrawChecklist(void);
static void M_DrawEmblemHints(void);
@ -379,6 +388,7 @@ static boolean M_CancelConnect(void);
#endif
static boolean M_ExitPandorasBox(void);
static boolean M_QuitMultiPlayerMenu(void);
static void M_HandleAddons(INT32 choice);
static void M_HandleLevelPlatter(INT32 choice);
static void M_HandleSoundTest(INT32 choice);
static void M_HandleImageDef(INT32 choice);
@ -487,10 +497,11 @@ static consvar_t cv_dummymares = {"dummymares", "Overall", CV_HIDEN|CV_CALL, dum
// ---------
static menuitem_t MainMenu[] =
{
{IT_CALL |IT_STRING, NULL, "Secrets", M_SecretsMenu, 84},
{IT_CALL |IT_STRING, NULL, "1 player", M_SinglePlayerMenu, 92},
{IT_SUBMENU|IT_STRING, NULL, "multiplayer", &MP_MainDef, 100},
{IT_CALL |IT_STRING, NULL, "options", M_Options, 108},
{IT_CALL |IT_STRING, NULL, "Secrets", M_SecretsMenu, 76},
{IT_CALL |IT_STRING, NULL, "1 player", M_SinglePlayerMenu, 84},
{IT_SUBMENU|IT_STRING, NULL, "multiplayer", &MP_MainDef, 92},
{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},
};
@ -500,9 +511,15 @@ typedef enum
singleplr,
multiplr,
options,
addons,
quitdoom
} 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
// ---------------------------------
@ -525,26 +542,28 @@ typedef enum
// ---------------------
static menuitem_t MPauseMenu[] =
{
{IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16},
{IT_STRING | IT_CALL, NULL, "Switch Gametype/Level...", M_GameTypeChange, 24},
{IT_STRING | IT_CALL, NULL, "Add-ons...", M_Addons, 8},
{IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16},
{IT_STRING | IT_CALL, NULL, "Switch Gametype/Level...", M_GameTypeChange, 24},
{IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,40},
{IT_CALL | IT_STRING, NULL, "Player 1 Setup", M_SetupMultiPlayer, 48}, // splitscreen
{IT_CALL | IT_STRING, NULL, "Player 2 Setup", M_SetupMultiPlayer2, 56}, // splitscreen
{IT_STRING | IT_CALL, NULL, "Continue", M_SelectableClearMenus,40},
{IT_STRING | IT_CALL, NULL, "Player 1 Setup", M_SetupMultiPlayer, 48}, // splitscreen
{IT_STRING | IT_CALL, NULL, "Player 2 Setup", M_SetupMultiPlayer2, 56}, // splitscreen
{IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 48},
{IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 48},
{IT_STRING | IT_SUBMENU, NULL, "Switch Team...", &MISC_ChangeTeamDef, 48},
{IT_CALL | IT_STRING, NULL, "Player Setup", M_SetupMultiPlayer, 56}, // alone
{IT_CALL | IT_STRING, NULL, "Options", M_Options, 64},
{IT_STRING | IT_CALL, NULL, "Player Setup", M_SetupMultiPlayer, 56}, // alone
{IT_STRING | IT_CALL, NULL, "Options", M_Options, 64},
{IT_CALL | IT_STRING, NULL, "Return to Title", M_EndGame, 80},
{IT_CALL | IT_STRING, NULL, "Quit Game", M_QuitSRB2, 88},
{IT_STRING | IT_CALL, NULL, "Return to Title", M_EndGame, 80},
{IT_STRING | IT_CALL, NULL, "Quit Game", M_QuitSRB2, 88},
};
typedef enum
{
mpause_scramble = 0,
mpause_addons = 0,
mpause_scramble,
mpause_switchmap,
mpause_continue,
@ -587,6 +606,7 @@ typedef enum
spause_continue,
spause_retry,
spause_options,
spause_title,
spause_quit
} spause_e;
@ -1318,9 +1338,10 @@ static menuitem_t OP_SoundOptionsMenu[] =
static menuitem_t OP_DataOptionsMenu[] =
{
{IT_STRING | IT_CALL, NULL, "Screenshot Options...", M_ScreenshotOptions, 10},
{IT_STRING | IT_CALL, NULL, "Add-on Options...", M_AddonsOptions, 10},
{IT_STRING | IT_CALL, NULL, "Screenshot Options...", M_ScreenshotOptions, 20},
{IT_STRING | IT_SUBMENU, NULL, "\x85" "Erase Data...", &OP_EraseDataDef, 20},
{IT_STRING | IT_SUBMENU, NULL, "\x85" "Erase Data...", &OP_EraseDataDef, 40},
};
static menuitem_t OP_ScreenshotOptionsMenu[] =
@ -1367,6 +1388,24 @@ static menuitem_t OP_EraseDataMenu[] =
{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, 12},
{IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_addons_folder, 22},
{IT_STRING|IT_CVAR, NULL, "Identify loaded files via", &cv_addons_md5, 50},
{IT_STRING|IT_CVAR, NULL, "Show unsupported file types", &cv_addons_showall, 60},
{IT_HEADER, NULL, "Search", NULL, 78},
{IT_STRING|IT_CVAR, NULL, "Matching", &cv_addons_search_type, 90},
{IT_STRING|IT_CVAR, NULL, "Case-sensitive", &cv_addons_search_case, 100},
};
enum
{
op_addons_folder = 2,
};
static menuitem_t OP_ServerOptionsMenu[] =
{
{IT_HEADER, NULL, "General", NULL, 0},
@ -1441,6 +1480,18 @@ static menuitem_t OP_MonitorToggleMenu[] =
// Main Menu and related
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 SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72);
menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72);
@ -1804,17 +1855,7 @@ menu_t OP_SoundOptionsDef =
NULL
};
menu_t OP_ServerOptionsDef =
{
"M_SERVER",
sizeof (OP_ServerOptionsMenu)/sizeof (menuitem_t),
&OP_MainDef,
OP_ServerOptionsMenu,
M_DrawGenericScrollMenu,
30, 30,
0,
NULL
};
menu_t OP_ServerOptionsDef = DEFAULTSCROLLMENUSTYLE("M_SERVER", OP_ServerOptionsMenu, &OP_MainDef, 30, 30);
menu_t OP_MonitorToggleDef =
{
@ -1856,7 +1897,7 @@ menu_t OP_OpenGLColorDef =
NULL
};
#endif
menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 30, 30);
menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30);
menu_t OP_ScreenshotOptionsDef =
{
@ -1870,6 +1911,8 @@ menu_t OP_ScreenshotOptionsDef =
NULL
};
menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30);
menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 60, 30);
// ==========================================================================
@ -2088,6 +2131,12 @@ void Moviemode_mode_Onchange(void)
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.
// ==========================================================================
@ -2150,9 +2199,12 @@ static void M_ChangeCvar(INT32 choice)
static boolean M_ChangeStringCvar(INT32 choice)
{
consvar_t *cv = (consvar_t *)currentMenu->menuitems[itemOn].itemaction;
char buf[255];
char buf[MAXSTRINGLENGTH];
size_t len;
if (shiftdown && choice >= 32 && choice <= 127)
choice = shiftxform[choice];
switch (choice)
{
case KEY_BACKSPACE:
@ -2463,8 +2515,6 @@ boolean M_Responder(event_t *ev)
{
if ((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_STRING)
{
if (shiftdown && ch >= 32 && ch <= 127)
ch = shiftxform[ch];
if (M_ChangeStringCvar(ch))
return true;
else
@ -2710,6 +2760,7 @@ void M_StartControlPanel(void)
else // multiplayer
{
MPauseMenu[mpause_switchmap].status = IT_DISABLED;
MPauseMenu[mpause_addons].status = IT_DISABLED;
MPauseMenu[mpause_scramble].status = IT_DISABLED;
MPauseMenu[mpause_psetupsplit].status = IT_DISABLED;
MPauseMenu[mpause_psetupsplit2].status = IT_DISABLED;
@ -2721,6 +2772,7 @@ void M_StartControlPanel(void)
if ((server || adminplayer == consoleplayer))
{
MPauseMenu[mpause_switchmap].status = IT_STRING | IT_CALL;
MPauseMenu[mpause_addons].status = IT_STRING | IT_CALL;
if (G_GametypeHasTeams())
MPauseMenu[mpause_scramble].status = IT_STRING | IT_SUBMENU;
}
@ -3262,7 +3314,7 @@ static void M_DrawGenericMenu(void)
y = currentMenu->y+currentMenu->menuitems[i].alphaKey;
//V_DrawString(x-16, y, V_YELLOWMAP, currentMenu->menuitems[i].text);
M_DrawLevelPlatterHeader(y - (lsheadingheight - 12), currentMenu->menuitems[i].text, true);
M_DrawLevelPlatterHeader(y - (lsheadingheight - 12), currentMenu->menuitems[i].text, true, false);
y += SMALLLINEHEIGHT;
break;
}
@ -3402,7 +3454,7 @@ static void M_DrawGenericScrollMenu(void)
break;
case IT_HEADERTEXT:
//V_DrawString(x-16, y, V_YELLOWMAP, currentMenu->menuitems[i].text);
M_DrawLevelPlatterHeader(y - (lsheadingheight - 12), currentMenu->menuitems[i].text, true);
M_DrawLevelPlatterHeader(y - (lsheadingheight - 12), currentMenu->menuitems[i].text, true, false);
break;
}
}
@ -3912,7 +3964,7 @@ static boolean M_PrepareLevelPlatter(INT32 gt)
I_Error("Insufficient memory to prepare level platter");
// done here so lsrow and lscol can be set if cv_nextmap is on the platter
lsrow = lscol = lstic = lshli = lsoffs[0] = lsoffs[1] = 0;
lsrow = lscol = lshli = lsoffs[0] = lsoffs[1] = 0;
while (mapnum < NUMMAPS)
{
@ -4171,10 +4223,10 @@ static void M_HandleLevelPlatter(INT32 choice)
}
}
void M_DrawLevelPlatterHeader(INT32 y, const char *header, boolean headerhighlight)
void M_DrawLevelPlatterHeader(INT32 y, const char *header, boolean headerhighlight, boolean allowlowercase)
{
y += lsheadingheight - 12;
V_DrawString(19, y, (headerhighlight ? V_YELLOWMAP : 0), header);
V_DrawString(19, y, (headerhighlight ? V_YELLOWMAP : 0)|(allowlowercase ? V_ALLOWLOWERCASE : 0), header);
y += 9;
if ((y >= 0) && (y < 200))
{
@ -4183,9 +4235,7 @@ void M_DrawLevelPlatterHeader(INT32 y, const char *header, boolean headerhighlig
}
y++;
if ((y >= 0) && (y < 200))
{
V_DrawFill(19, y, 282, 1, 26);
}
}
static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolean highlight)
@ -4279,7 +4329,7 @@ static void M_DrawLevelPlatterRow(UINT8 row, INT32 y)
const boolean rowhighlight = (row == lsrow);
if (levelselect.rows[row].header[0])
{
M_DrawLevelPlatterHeader(y, levelselect.rows[row].header, (rowhighlight || (row == lshli)));
M_DrawLevelPlatterHeader(y, levelselect.rows[row].header, (rowhighlight || (row == lshli)), false);
y += lsheadingheight;
}
@ -4298,9 +4348,6 @@ static void M_DrawLevelPlatterMenu(void)
INT32 y = lsbasey + lsoffs[0] - getheadingoffset(lsrow);
const INT32 cursorx = (sizeselect ? 0 : (lscol*lshseperation));
if (++lstic == 32)
lstic = 0;
if (gamestate == GS_TIMEATTACK)
V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE));
@ -4320,7 +4367,7 @@ static void M_DrawLevelPlatterMenu(void)
}
// draw cursor box
V_DrawSmallScaledPatch(lsbasex + cursorx + lsoffs[1], lsbasey, 0, ((lstic & 8) ? levselp[sizeselect][0] : levselp[sizeselect][1]));
V_DrawSmallScaledPatch(lsbasex + cursorx + lsoffs[1], lsbasey, 0, (levselp[sizeselect][((skullAnimCounter/4) ? 1 : 0)]));
if (levelselect.rows[lsrow].maplist[lscol])
V_DrawScaledPatch(lsbasex + cursorx-17, lsbasey+50+lsoffs[0], 0, W_CachePatchName("M_CURSOR", PU_CACHE));
@ -4620,6 +4667,511 @@ static void M_HandleImageDef(INT32 choice)
// MISC MAIN MENU OPTIONS
// ======================
static void M_AddonsOptions(INT32 choice)
{
(void)choice;
Addons_option_Onchange();
M_SetupNextMenu(&OP_AddonsOptionsDef);
}
#define LOCATIONSTRING "Visit \x83SRB2.ORG/MODS\x80 to get & make add-ons!"
static void M_Addons(INT32 choice)
{
const char *pathname = ".";
(void)choice;
/*if (cv_addons_option.value == 0)
pathname = srb2home; usehome ? srb2home : srb2path;
else if (cv_addons_option.value == 1)
pathname = srb2home;
else if (cv_addons_option.value == 2)
pathname = srb2path;
else*/
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] != '/')
{
menupath[menupathindex[menudepthleft]-1] = '/';
menupath[menupathindex[menudepthleft]] = 0;
}
else
--menupathindex[menudepthleft];
if (!preparefilemenu(false))
{
M_StartMessage(M_GetText("No files/folders found.\n\n"LOCATIONSTRING"\n\n(Press a key)\n"),NULL,MM_NOTHING);
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+6; 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);
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_FSEL1", PU_STATIC);
addonsp[NUM_EXT+2] = W_CachePatchName("M_FSEL2", PU_STATIC);
addonsp[NUM_EXT+3] = W_CachePatchName("M_FLOAD", PU_STATIC);
addonsp[NUM_EXT+4] = W_CachePatchName("M_FSRCH", PU_STATIC);
addonsp[NUM_EXT+5] = 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, 3);
V_DrawFill(x + width, vpadding, 1, h, 3);
V_DrawFill(x - 1, vpadding-1, width+2, 1, 3);
V_DrawFill(x - 1, vpadding+h, width+2, 1, 3);
// bar itself
y = h;
if (t)
for (t = h - t; y > 0; y--)
{
UINT8 colours[NUMCOLOURS] = {42, 40, 58, 222, 65, 90, 97, 98};
UINT8 c;
if (y <= t) break;
if (y+vpadding >= BASEVIDHEIGHT/2)
c = 113;
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, 27);
}
#undef width
#undef vpadding
#undef h
#undef NUMCOLOURS
static char *M_AddonsHeaderPath(void)
{
UINT32 len;
static char header[1024];
if (menupath[0] == '.')
strlcpy(header, va("SRB2 folder%s", menupath+1), 1024);
else
strcpy(header, menupath);
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)
// returns whether to do message draw
static boolean M_AddonsRefresh(void)
{
if ((refreshdirmenu & REFRESHDIR_NORMAL) && !preparefilemenu(true))
{
UNEXIST;
return true;
}
if (refreshdirmenu & REFRESHDIR_ADDFILE)
{
addonsresponselimit = 0;
if (refreshdirmenu & REFRESHDIR_NOTLOADED)
{
char *message = NULL;
S_StartSound(NULL, sfx_lose);
if (refreshdirmenu & REFRESHDIR_MAX)
message = va("\x82%s\x80\nMaximum number of add-ons reached.\nThis 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", dirmenu[dir_on[menudepthleft]]+DIR_STRING);
else
message = va("\x82%s\x80\nThe file was not loaded.\nCheck the console log for more information.\n\n(Press a key)\n", dirmenu[dir_on[menudepthleft]]+DIR_STRING);
M_StartMessage(message,NULL,MM_NOTHING);
return true;
}
if (refreshdirmenu & (REFRESHDIR_WARNING|REFRESHDIR_ERROR))
{
S_StartSound(NULL, sfx_skid);
M_StartMessage(va("\x82%s\x80\nThe file was loaded with %s.\nCheck the console log for more information.\n\n(Press a key)\n", dirmenu[dir_on[menudepthleft]]+DIR_STRING, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings")),NULL,MM_NOTHING);
return true;
}
S_StartSound(NULL, sfx_strpst);
}
return false;
}
#define offs 1
static void M_DrawAddons(void)
{
INT32 x, y;
ssize_t i, max;
// hack - need to refresh at end of frame to handle addfile...
if (refreshdirmenu & M_AddonsRefresh())
return M_DrawMessageMenu();
if (addonsresponselimit)
addonsresponselimit--;
V_DrawCenteredString(BASEVIDWIDTH/2, 4+offs, 0, (Playing()
? "\x85""Adding files mid-game may cause problems."
: LOCATIONSTRING));
if (numwadfiles <= mainwads+1)
y = 0;
else if (numwadfiles >= MAX_WADFILES)
y = FRACUNIT;
else
{
x = FixedDiv((numwadfiles - mainwads+1)<<FRACBITS, (MAX_WADFILES - mainwads+1)<<FRACBITS);
y = FixedDiv(((packetsizetally-mainwadstally)<<FRACBITS), (((MAXFILENEEDED*sizeof(UINT8)-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 + offs;
//M_DrawLevelPlatterHeader(y - 16, M_AddonsHeaderPath(), true, true); -- wanted different width
V_DrawString(x-21, (y - 16) + (lsheadingheight - 12), V_YELLOWMAP|V_ALLOWLOWERCASE, M_AddonsHeaderPath());
V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), (MAXSTRINGLENGTH*8+6 - 1), 1, yellowmap[3]);
V_DrawFill(x-21 + (MAXSTRINGLENGTH*8+6 - 1), (y - 16) + (lsheadingheight - 3), 1, 1, 26);
V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), MAXSTRINGLENGTH*8+6, 1, 26);
V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, (BASEVIDHEIGHT - currentMenu->y + 1 + offs) - (y - 1), 159);
// get bottom...
max = dir_on[menudepthleft] + numaddonsshown + 1;
if (max > (ssize_t)sizedirmenu)
max = sizedirmenu;
// then top...
i = max - (2*numaddonsshown + 1);
// then adjust!
if (i < 0)
{
if ((max -= i) > (ssize_t)sizedirmenu)
max = sizedirmenu;
i = 0;
}
if (i != 0)
V_DrawString(19, y+4, V_YELLOWMAP, "\x1A");
for (; i < max; 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, (flags & V_TRANSLUCENT), addonsp[((UINT8)(dirmenu[i][DIR_TYPE]) & ~EXT_LOADED)]);
if (type & EXT_LOADED)
V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[NUM_EXT+3]);
if ((size_t)i == dir_on[menudepthleft])
{
V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[NUM_EXT+1+((skullAnimCounter/4) ? 1 : 0)]);
flags = V_ALLOWLOWERCASE|V_YELLOWMAP;
}
#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 (max != (ssize_t)sizedirmenu)
V_DrawString(19, y-12, V_YELLOWMAP, "\x1B");
y = BASEVIDHEIGHT - currentMenu->y + offs;
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+4]);
#define CANSAVE (!modifiedgame || savemoddata)
x = BASEVIDWIDTH - x - 16;
V_DrawSmallScaledPatch(x, y + 4, (CANSAVE ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+5]);
if CANSAVE
V_DrawSmallScaledPatch(x, y + 4, 0, addonsp[NUM_EXT+3]);
#undef CANSAVE
}
#undef offs
static void M_AddonExec(INT32 ch)
{
if (ch != 'y' && ch != KEY_ENTER)
return;
S_StartSound(NULL, sfx_strpst);
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 (addonsresponselimit)
return;
if (M_ChangeStringAddons(choice))
{
if (!preparefilemenu(true))
{
UNEXIST;
return;
}
}
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("\x82%s\x80\nThis folder is empty.\n\n(Press a key)\n", 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("\x82%s\x80\nThis folder is too deep to navigate to!\n\n(Press a key)\n", 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("\x82%s\x80\nThis file may not be a console script.\nAttempt to run anyways? \n\n(Press 'Y' to confirm)\n", 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("\x82%s\x80\nThis copy of SRB2 was compiled\nwithout support for .lua files.\n\n(Press a key)\n", dirmenu[dir_on[menudepthleft]]+DIR_STRING),NULL,MM_NOTHING);
break;
#endif
// else intentional fallthrough
case EXT_SOC:
case EXT_WAD:
COM_BufAddText(va("addfile %s%s", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING));
addonsresponselimit = 5;
break;
default:
S_StartSound(NULL, sfx_lose);
}
}
if (refresh)
refreshdirmenu |= REFRESHDIR_NORMAL;
}
break;
case KEY_ESCAPE:
exitmenu = true;
break;
default:
break;
}
if (exitmenu)
{
for (; sizedirmenu > 0; sizedirmenu--)
{
Z_Free(dirmenu[sizedirmenu-1]);
dirmenu[sizedirmenu-1] = NULL;
}
Z_Free(dirmenu);
dirmenu = NULL;
// secrets disabled by addfile...
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)
{
(void)choice;
@ -4722,7 +5274,7 @@ static void M_Options(INT32 choice)
OP_MainMenu[5].status = (Playing() && !(server || adminplayer == consoleplayer)) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL);
// if the player is playing _at all_, disable the erase data options
OP_DataOptionsMenu[1].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU);
OP_DataOptionsMenu[2].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU);
OP_MainDef.prevMenu = currentMenu;
M_SetupNextMenu(&OP_MainDef);
@ -5136,9 +5688,7 @@ static void M_DrawChecklist(void)
finishchecklist:
if ((checklist_cangodown = ((y - currentMenu->y) > (scrollareaheight*2)))) // haaaaaaacks.
{
V_DrawString(10, currentMenu->y+(scrollareaheight*2), V_YELLOWMAP, "\x1B");
}
}
#define NUMHINTS 5
@ -6441,7 +6991,7 @@ void M_DrawTimeAttackMenu(void)
lumpnum_t lumpnum;
char beststr[40];
M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true);
M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true, false);
// A 160x100 image of the level as entry MAPxxP
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value)));
@ -6618,7 +7168,7 @@ void M_DrawNightsAttackMenu(void)
UINT32 bestscore = G_GetBestNightsScore(cv_nextmap.value, cv_dummymares.value);
tic_t besttime = G_GetBestNightsTime(cv_nextmap.value, cv_dummymares.value);
M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true);
M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true, false);
// A 160x100 image of the level as entry MAPxxP
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value)));
@ -7374,7 +7924,7 @@ static void M_DrawServerMenu(void)
// Room name
if (currentMenu == &MP_ServerDef)
{
M_DrawLevelPlatterHeader(currentMenu->y - lsheadingheight/2, "Server settings", true);
M_DrawLevelPlatterHeader(currentMenu->y - lsheadingheight/2, "Server settings", true, false);
if (ms_RoomId < 0)
V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey,
V_YELLOWMAP, (itemOn == mp_server_room) ? "<Select to change>" : "<Offline Mode>");
@ -7392,7 +7942,7 @@ static void M_DrawServerMenu(void)
sprintf(headerstr, "%s - %s", cv_newgametype.string, cv_nextmap.string);
M_DrawLevelPlatterHeader(currentMenu->y + MP_ServerMenu[mp_server_levelgt].alphaKey - 10 - lsheadingheight/2, (const char *)headerstr, true);
M_DrawLevelPlatterHeader(currentMenu->y + MP_ServerMenu[mp_server_levelgt].alphaKey - 10 - lsheadingheight/2, (const char *)headerstr, true, false);
// A 160x100 image of the level as entry MAPxxP
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value)));
@ -7422,7 +7972,7 @@ static void M_GameTypeChange(INT32 choice)
void M_DrawGameTypeMenu(void)
{
M_DrawGenericMenu();
M_DrawLevelPlatterHeader(currentMenu->y - lsheadingheight, "Select Gametype", true);
M_DrawLevelPlatterHeader(currentMenu->y - lsheadingheight, "Select Gametype", true, false);
if (!char_notes)
char_notes = V_WordWrap(0, (160 - 30) - 8, V_ALLOWLOWERCASE, gametypedesc[itemOn].notes);
@ -8174,7 +8724,7 @@ static void M_DrawControl(void)
/*else if (currentMenu->menuitems[i].status == IT_GRAYEDOUT2)
V_DrawString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text);*/
else if ((currentMenu->menuitems[i].status == IT_HEADER) && (i != max-1))
M_DrawLevelPlatterHeader(y, currentMenu->menuitems[i].text, true);
M_DrawLevelPlatterHeader(y, currentMenu->menuitems[i].text, true, false);
y += SMALLLINEHEIGHT;
}
@ -8749,7 +9299,7 @@ static void M_DrawColorMenu(void)
//V_DrawString(x-16, y, V_YELLOWMAP, currentMenu->menuitems[i].text);
V_DrawFill(19, y, 281, 9, currentMenu->menuitems[i+1].alphaKey);
V_DrawFill(300, y, 1, 9, 26);
M_DrawLevelPlatterHeader(y - (lsheadingheight - 12), currentMenu->menuitems[i].text, false);
M_DrawLevelPlatterHeader(y - (lsheadingheight - 12), currentMenu->menuitems[i].text, false, false);
break;
}
}

View File

@ -124,6 +124,8 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt);
#define IT_HEADER (IT_SPACE +IT_HEADERTEXT)
#define IT_SECRET (IT_SPACE +IT_QUESTIONMARKS)
#define MAXSTRINGLENGTH 32
typedef union
{
struct menu_s *submenu; // IT_SUBMENU
@ -249,6 +251,9 @@ void Nextmap_OnChange(void);
void Moviemode_mode_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
#define DEFAULTMENUSTYLE(header, source, prev, x, y)\
{\
@ -262,6 +267,18 @@ void Screenshot_option_Onchange(void);
NULL\
}
#define DEFAULTSCROLLMENUSTYLE(header, source, prev, x, y)\
{\
header,\
sizeof(source)/sizeof(menuitem_t),\
prev,\
source,\
M_DrawGenericScrollMenu,\
x, y,\
0,\
NULL\
}
#define PAUSEMENUSTYLE(source, x, y)\
{\
NULL,\

View File

@ -100,7 +100,7 @@ static CV_PossibleValue_t screenshot_cons_t[] = {{0, "Default"}, {1, "HOME"}, {2
consvar_t cv_screenshot_option = {"screenshot_option", "Default", CV_SAVE|CV_CALL, screenshot_cons_t, Screenshot_option_Onchange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_screenshot_folder = {"screenshot_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_screenshot_colorprofile = {"screenshot_colorprofile", "Yes", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_screenshot_colorprofile = {"screenshot_colorprofile", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t moviemode_cons_t[] = {{MM_GIF, "GIF"}, {MM_APNG, "aPNG"}, {MM_SCREENSHOT, "Screenshots"}, {0, NULL}};
consvar_t cv_moviemode = {"moviemode_mode", "GIF", CV_SAVE|CV_CALL, moviemode_cons_t, Moviemode_mode_Onchange, 0, NULL, NULL, 0, 0, NULL};

View File

@ -4110,15 +4110,18 @@ void A_SetSolidSteam(mobj_t *actor)
#endif
actor->flags &= ~MF_NOCLIP;
actor->flags |= MF_SOLID;
if (P_RandomChance(FRACUNIT/8))
if (!(actor->flags2 & MF2_AMBUSH))
{
if (actor->info->deathsound)
S_StartSound(actor, actor->info->deathsound); // Hiss!
}
else
{
if (actor->info->painsound)
S_StartSound(actor, actor->info->painsound);
if (P_RandomChance(FRACUNIT/8))
{
if (actor->info->deathsound)
S_StartSound(actor, actor->info->deathsound); // Hiss!
}
else
{
if (actor->info->painsound)
S_StartSound(actor, actor->info->painsound);
}
}
P_SetObjectMomZ (actor, 1, true);

View File

@ -878,7 +878,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (!(mo2->flags & MF_SPECIAL) && mo2->health)
{
P_SetMobjState(mo2, mo2->info->seestate);
mo2->flags2 &= ~MF2_DONTDRAW;
mo2->flags |= MF_SPECIAL;
mo2->flags &= ~MF_NIGHTSITEM;
S_StartSound(toucher, sfx_hidden);
@ -887,7 +887,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
if (!(mo2->type == MT_NIGHTSWING || mo2->type == MT_RING || mo2->type == MT_COIN
|| mo2->type == MT_BLUEBALL))
|| mo2->type == MT_BLUEBALL
|| ((mo2->type == MT_EMBLEM) && (mo2->reactiontime & GE_NIGHTSPULL))))
continue;
// Yay! The thing's in reach! Pull it in!
@ -1665,7 +1666,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
if (damagetype == DMG_NUKE) // SH_ARMAGEDDON, armageddon shield
str = M_GetText("%s%s's armageddon blast %s %s.\n");
else if ((inflictor->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL && (inflictor->player->pflags & PF_SHIELDABILITY))
str = M_GetText("%s%s's flame stomp %s %s.\n");
str = M_GetText("%s%s's elemental stomp %s %s.\n");
else if (inflictor->player->powers[pw_invulnerability])
str = M_GetText("%s%s's invincibility aura %s %s.\n");
else if (inflictor->player->powers[pw_super])
@ -1719,6 +1720,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
str = M_GetText("%s was %s by Eggman's nefarious TV magic.\n");
break;
case MT_SPIKE:
case MT_WALLSPIKE:
str = M_GetText("%s was %s by spikes.\n");
break;
default:
@ -2395,7 +2397,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
else
{
P_SetObjectMomZ(target, 14*FRACUNIT, false);
if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // Spikes
if (damagetype == DMG_SPIKE) // Spikes
S_StartSound(target, sfx_spkdth);
else
P_PlayDeathSound(target);
@ -2457,90 +2459,159 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
}
}
if (target->type == MT_SPIKE && inflictor && target->info->deathstate != S_NULL)
if (target->type == MT_SPIKE && target->info->deathstate != S_NULL)
{
const fixed_t x=target->x,y=target->y,z=target->z;
const fixed_t scale=target->scale;
const boolean flip=(target->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP;
S_StartSound(target,target->info->deathsound);
const angle_t ang = ((inflictor) ? inflictor->angle : 0) + ANGLE_90;
const fixed_t scale = target->scale;
const fixed_t xoffs = P_ReturnThrustX(target, ang, 8*scale), yoffs = P_ReturnThrustY(target, ang, 8*scale);
const UINT16 flip = (target->eflags & MFE_VERTICALFLIP);
mobj_t *chunk;
fixed_t momz;
P_SetMobjState(target, target->info->deathstate);
target->health = 0;
target->angle = inflictor->angle + ANGLE_90;
P_UnsetThingPosition(target);
target->flags = MF_NOCLIP;
target->x += P_ReturnThrustX(target, target->angle, FixedMul(8*FRACUNIT, target->scale));
target->y += P_ReturnThrustY(target, target->angle, FixedMul(8*FRACUNIT, target->scale));
if (flip)
target->z -= FixedMul(12*FRACUNIT, target->scale);
else
target->z += FixedMul(12*FRACUNIT, target->scale);
P_SetThingPosition(target);
P_InstaThrust(target,target->angle,FixedMul(2*FRACUNIT, target->scale));
target->momz = FixedMul(7*FRACUNIT, target->scale);
if (flip)
target->momz = -target->momz;
if (flip)
{
target = P_SpawnMobj(x,y,z-FixedMul(12*FRACUNIT, target->scale),MT_SPIKE);
target->eflags |= MFE_VERTICALFLIP;
}
else
target = P_SpawnMobj(x,y,z+FixedMul(12*FRACUNIT, target->scale),MT_SPIKE);
P_SetMobjState(target, target->info->deathstate);
target->health = 0;
target->angle = inflictor->angle - ANGLE_90;
target->destscale = scale;
P_SetScale(target, scale);
P_UnsetThingPosition(target);
target->flags = MF_NOCLIP;
target->x += P_ReturnThrustX(target, target->angle, FixedMul(8*FRACUNIT, target->scale));
target->y += P_ReturnThrustY(target, target->angle, FixedMul(8*FRACUNIT, target->scale));
P_SetThingPosition(target);
P_InstaThrust(target,target->angle,FixedMul(2*FRACUNIT, target->scale));
target->momz = FixedMul(7*FRACUNIT, target->scale);
if (flip)
target->momz = -target->momz;
S_StartSound(target, target->info->deathsound);
if (target->info->xdeathstate != S_NULL)
{
target = P_SpawnMobj(x,y,z,MT_SPIKE);
momz = 6*scale;
if (flip)
target->eflags |= MFE_VERTICALFLIP;
P_SetMobjState(target, target->info->xdeathstate);
target->health = 0;
target->angle = inflictor->angle + ANGLE_90;
target->destscale = scale;
P_SetScale(target, scale);
P_UnsetThingPosition(target);
target->flags = MF_NOCLIP;
target->x += P_ReturnThrustX(target, target->angle, FixedMul(8*FRACUNIT, target->scale));
target->y += P_ReturnThrustY(target, target->angle, FixedMul(8*FRACUNIT, target->scale));
P_SetThingPosition(target);
P_InstaThrust(target,target->angle,FixedMul(4*FRACUNIT, target->scale));
target->momz = FixedMul(6*FRACUNIT, target->scale);
if (flip)
target->momz = -target->momz;
momz *= -1;
#define makechunk(angtweak, xmov, ymov) \
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_SPIKE);\
chunk->eflags |= flip;\
P_SetMobjState(chunk, target->info->xdeathstate);\
chunk->health = 0;\
chunk->angle = angtweak;\
chunk->destscale = scale;\
P_SetScale(chunk, scale);\
P_UnsetThingPosition(chunk);\
chunk->flags = MF_NOCLIP;\
chunk->x += xmov;\
chunk->y += ymov;\
P_SetThingPosition(chunk);\
P_InstaThrust(chunk,chunk->angle, 4*scale);\
chunk->momz = momz
target = P_SpawnMobj(x,y,z,MT_SPIKE);
if (flip)
target->eflags |= MFE_VERTICALFLIP;
P_SetMobjState(target, target->info->xdeathstate);
target->health = 0;
target->angle = inflictor->angle - ANGLE_90;
target->destscale = scale;
P_SetScale(target, scale);
P_UnsetThingPosition(target);
target->flags = MF_NOCLIP;
target->x += P_ReturnThrustX(target, target->angle, FixedMul(8*FRACUNIT, target->scale));
target->y += P_ReturnThrustY(target, target->angle, FixedMul(8*FRACUNIT, target->scale));
P_SetThingPosition(target);
P_InstaThrust(target,target->angle,FixedMul(4*FRACUNIT, target->scale));
target->momz = FixedMul(6*FRACUNIT, target->scale);
if (flip)
target->momz = -target->momz;
makechunk(ang + ANGLE_180, -xoffs, -yoffs);
makechunk(ang, xoffs, yoffs);
#undef makechunk
}
momz = 7*scale;
if (flip)
momz *= -1;
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_SPIKE);
chunk->eflags |= flip;
P_SetMobjState(chunk, target->info->deathstate);
chunk->health = 0;
chunk->angle = ang + ANGLE_180;
chunk->destscale = scale;
P_SetScale(chunk, scale);
P_UnsetThingPosition(chunk);
chunk->flags = MF_NOCLIP;
chunk->x -= xoffs;
chunk->y -= yoffs;
if (flip)
chunk->z -= 12*scale;
else
chunk->z += 12*scale;
P_SetThingPosition(chunk);
P_InstaThrust(chunk, chunk->angle, 2*scale);
chunk->momz = momz;
P_SetMobjState(target, target->info->deathstate);
target->health = 0;
target->angle = ang;
P_UnsetThingPosition(target);
target->flags = MF_NOCLIP;
target->x += xoffs;
target->y += yoffs;
target->z = chunk->z;
P_SetThingPosition(target);
P_InstaThrust(target, target->angle, 2*scale);
target->momz = momz;
}
else if (target->type == MT_WALLSPIKE && target->info->deathstate != S_NULL)
{
const angle_t ang = (/*(inflictor) ? inflictor->angle : */target->angle) + ANGLE_90;
const fixed_t scale = target->scale;
const fixed_t xoffs = P_ReturnThrustX(target, ang, 8*scale), yoffs = P_ReturnThrustY(target, ang, 8*scale), forwardxoffs = P_ReturnThrustX(target, target->angle, 7*scale), forwardyoffs = P_ReturnThrustY(target, target->angle, 7*scale);
const UINT16 flip = (target->eflags & MFE_VERTICALFLIP);
mobj_t *chunk;
boolean sprflip;
S_StartSound(target, target->info->deathsound);
if (!P_MobjWasRemoved(target->tracer))
P_RemoveMobj(target->tracer);
if (target->info->xdeathstate != S_NULL)
{
sprflip = P_RandomChance(FRACUNIT/2);
#define makechunk(angtweak, xmov, ymov) \
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_WALLSPIKE);\
chunk->eflags |= flip;\
P_SetMobjState(chunk, target->info->xdeathstate);\
chunk->health = 0;\
chunk->angle = target->angle;\
chunk->destscale = scale;\
P_SetScale(chunk, scale);\
P_UnsetThingPosition(chunk);\
chunk->flags = MF_NOCLIP;\
chunk->x += xmov - forwardxoffs;\
chunk->y += ymov - forwardyoffs;\
P_SetThingPosition(chunk);\
P_InstaThrust(chunk, angtweak, 4*scale);\
chunk->momz = P_RandomRange(5, 7)*scale;\
if (flip)\
chunk->momz *= -1;\
if (sprflip)\
chunk->frame |= FF_VERTICALFLIP
makechunk(ang + ANGLE_180, -xoffs, -yoffs);
sprflip = !sprflip;
makechunk(ang, xoffs, yoffs);
#undef makechunk
}
sprflip = P_RandomChance(FRACUNIT/2);
chunk = P_SpawnMobj(target->x, target->y, target->z, MT_WALLSPIKE);
chunk->eflags |= flip;
P_SetMobjState(chunk, target->info->deathstate);
chunk->health = 0;
chunk->angle = target->angle;
chunk->destscale = scale;
P_SetScale(chunk, scale);
P_UnsetThingPosition(chunk);
chunk->flags = MF_NOCLIP;
chunk->x += forwardxoffs - xoffs;
chunk->y += forwardyoffs - yoffs;
P_SetThingPosition(chunk);
P_InstaThrust(chunk, ang + ANGLE_180, 2*scale);
chunk->momz = P_RandomRange(5, 7)*scale;
if (flip)
chunk->momz *= -1;
if (sprflip)
chunk->frame |= FF_VERTICALFLIP;
P_SetMobjState(target, target->info->deathstate);
target->health = 0;
P_UnsetThingPosition(target);
target->flags = MF_NOCLIP;
target->x += forwardxoffs + xoffs;
target->y += forwardyoffs + yoffs;
P_SetThingPosition(target);
P_InstaThrust(target, ang, 2*scale);
target->momz = P_RandomRange(5, 7)*scale;
if (flip)
target->momz *= -1;
if (!sprflip)
target->frame |= FF_VERTICALFLIP;
}
else if (target->player)
{
@ -2876,7 +2947,7 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source,
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // spikes
if (damagetype == DMG_SPIKE) // spikes
S_StartSound(player->mo, sfx_spkdth);
else
S_StartSound (player->mo, sfx_shldls); // Ba-Dum! Shield loss.
@ -2905,7 +2976,7 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // spikes
if (damagetype == DMG_SPIKE) // spikes
S_StartSound(player->mo, sfx_spkdth);
if (source && source->player && !player->powers[pw_super]) //don't score points against super players

View File

@ -439,7 +439,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
// Metal Sonic destroys tiny baby objects.
if (tmthing->type == MT_METALSONIC_RACE
&& (thing->flags & (MF_MISSILE|MF_ENEMY|MF_BOSS) || thing->type == MT_SPIKE))
&& (thing->flags & (MF_MISSILE|MF_ENEMY|MF_BOSS)
|| (thing->type == MT_SPIKE
|| thing->type == MT_WALLSPIKE)))
{
if ((thing->flags & (MF_ENEMY|MF_BOSS)) && (thing->health <= 0 || !(thing->flags & MF_SHOOTABLE)))
return true;
@ -451,12 +453,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (thing->type == MT_SPIKE)
if (thing->type == MT_SPIKE
|| thing->type == MT_WALLSPIKE)
{
mobjtype_t type = thing->type;
if (thing->flags & MF_SOLID)
S_StartSound(tmthing, thing->info->deathsound);
for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext)
if (thing->type == MT_SPIKE && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y) < FixedMul(56*FRACUNIT, thing->scale))
if (thing->type == type && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y), thing->z - tmthing->z) < 56*thing->scale)//FixedMul(56*FRACUNIT, thing->scale))
P_KillMobj(thing, tmthing, tmthing, 0);
}
else
@ -470,10 +474,13 @@ static boolean PIT_CheckThing(mobj_t *thing)
// SF_DASHMODE users destroy spikes and monitors, CA_TWINSPIN users and CA2_MELEE users destroy spikes.
if ((tmthing->player)
&& (((tmthing->player->charflags & SF_DASHMODE) && (tmthing->player->dashmode >= 3*TICRATE)
&& (thing->flags & (MF_MONITOR) || thing->type == MT_SPIKE))
&& (thing->flags & (MF_MONITOR)
|| (thing->type == MT_SPIKE
|| thing->type == MT_WALLSPIKE)))
|| ((((tmthing->player->charability == CA_TWINSPIN) && (tmthing->player->panim == PA_ABILITY))
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2))
&& (thing->type == MT_SPIKE))))
&& (thing->type == MT_SPIKE
|| thing->type == MT_WALLSPIKE))))
{
if ((thing->flags & (MF_MONITOR)) && (thing->health <= 0 || !(thing->flags & MF_SHOOTABLE)))
return true;
@ -485,12 +492,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (thing->type == MT_SPIKE)
if (thing->type == MT_SPIKE
|| thing->type == MT_WALLSPIKE)
{
mobjtype_t type = thing->type;
if (thing->flags & MF_SOLID)
S_StartSound(tmthing, thing->info->deathsound);
for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext)
if (thing->type == MT_SPIKE && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y) < FixedMul(56*FRACUNIT, thing->scale))
if (thing->type == type && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y), thing->z - tmthing->z) < 56*thing->scale)//FixedMul(56*FRACUNIT, thing->scale))
P_KillMobj(thing, tmthing, tmthing, 0);
}
else
@ -937,12 +946,12 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->z + thing->height <= tmthing->z + FixedMul(FRACUNIT, tmthing->scale)
&& thing->z + thing->height + thing->momz >= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz
&& !(thing->player->charability == CA_BOUNCE && thing->player->panim == PA_ABILITY && thing->eflags & MFE_VERTICALFLIP))
P_DamageMobj(thing, tmthing, tmthing, 1, 0);
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE);
}
else if (thing->z >= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale)
&& thing->z + thing->momz <= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz
&& !(thing->player->charability == CA_BOUNCE && thing->player->panim == PA_ABILITY && !(thing->eflags & MFE_VERTICALFLIP)))
P_DamageMobj(thing, tmthing, tmthing, 1, 0);
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE);
}
else if (thing->type == MT_SPIKE && thing->flags & MF_SOLID && tmthing->player) // unfortunate player falls into spike?!
{
@ -951,12 +960,12 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height <= thing->z - FixedMul(FRACUNIT, thing->scale)
&& tmthing->z + tmthing->height + tmthing->momz >= thing->z - FixedMul(FRACUNIT, thing->scale)
&& !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && tmthing->eflags & MFE_VERTICALFLIP))
P_DamageMobj(tmthing, thing, thing, 1, 0);
P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE);
}
else if (tmthing->z >= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)
&& tmthing->z + tmthing->momz <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)
&& !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && !(tmthing->eflags & MFE_VERTICALFLIP)))
P_DamageMobj(tmthing, thing, thing, 1, 0);
P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE);
}
if (tmthing->type == MT_WALLSPIKE && tmthing->flags & MF_SOLID && thing->player) // wall spike impales player
@ -971,15 +980,26 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->z + thing->height > bottomz // above bottom
&& thing->z < topz) // below top
{ // don't check angle, the player was clearly in the way in this case
// don't check angle, the player was clearly in the way in this case
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE);
}
}
else if (thing->type == MT_WALLSPIKE && thing->flags & MF_SOLID && tmthing->player)
{
fixed_t bottomz, topz;
angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y);
if (P_PlayerInPain(tmthing->player) && (tmthing->momx || tmthing->momy))
{
angle_t playerangle = R_PointToAngle2(0, 0, tmthing->momx, tmthing->momy) - touchangle;
if (playerangle > ANGLE_180)
playerangle = InvAngle(playerangle);
if (playerangle < ANGLE_90)
return true; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them.
}
bottomz = thing->z;
topz = thing->z + thing->height;
if (thing->eflags & MFE_VERTICALFLIP)
bottomz -= FixedMul(FRACUNIT, thing->scale);
else
@ -989,11 +1009,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
&& tmthing->z < topz // below top
&& !P_MobjWasRemoved(thing->tracer)) // this probably wouldn't work if we didn't have a tracer
{ // use base as a reference point to determine what angle you touched the spike at
angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y);
angle_t diffangle = thing->angle - touchangle;
if (diffangle > ANGLE_180)
diffangle = InvAngle(diffangle);
if (diffangle <= ANGLE_22h) // if you touched it at this close an angle, you get poked!
touchangle = thing->angle - touchangle;
if (touchangle > ANGLE_180)
touchangle = InvAngle(touchangle);
if (touchangle <= ANGLE_22h) // if you touched it at this close an angle, you get poked!
P_DamageMobj(tmthing, thing, thing, 1, DMG_SPIKE);
}
}
@ -1151,12 +1170,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
}
}
if (thing->flags & MF_SPRING && (tmthing->player || tmthing->flags & MF_PUSHABLE))
if (!(tmthing->player) && (thing->player))
; // no solid thing should ever be able to step up onto a player
else if (thing->flags & MF_SPRING && (tmthing->player || tmthing->flags & MF_PUSHABLE))
{
if (iwassprung) // this spring caused you to gain MFE_SPRUNG just now...
return false; // "cancel" P_TryMove via blocking so you keep your current position
}
else if (tmthing->flags & MF_SPRING && (thing->player || thing->flags & MF_PUSHABLE))
else if (tmthing->flags & MF_SPRING && (thing->flags & MF_PUSHABLE))
; // Fix a few nasty spring-jumping bugs that happen sometimes.
// Monitors are not treated as solid to players who are jumping, spinning or gliding,
// unless it's a CTF team monitor and you're on the wrong team
@ -3093,12 +3114,86 @@ void P_SlideMove(mobj_t *mo)
INT16 hitcount = 0;
boolean success = false;
boolean papercol = false;
vertex_t v1, v2; // fake vertexes
line_t junk; // fake linedef
if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height)
{
// Don't mess with your momentum if it's a pushable object. Pushables do their own crazy things already.
if (tmhitthing->flags & MF_PUSHABLE)
return;
if (tmhitthing->flags & MF_PAPERCOLLISION)
{
fixed_t cosradius, sinradius, num, den;
// trace along the three leading corners
if (mo->momx > 0)
{
leadx = mo->x + mo->radius;
trailx = mo->x - mo->radius;
}
else
{
leadx = mo->x - mo->radius;
trailx = mo->x + mo->radius;
}
if (mo->momy > 0)
{
leady = mo->y + mo->radius;
traily = mo->y - mo->radius;
}
else
{
leady = mo->y - mo->radius;
traily = mo->y + mo->radius;
}
papercol = true;
slidemo = mo;
bestslideline = &junk;
cosradius = FixedMul(tmhitthing->radius, FINECOSINE(tmhitthing->angle>>ANGLETOFINESHIFT));
sinradius = FixedMul(tmhitthing->radius, FINESINE(tmhitthing->angle>>ANGLETOFINESHIFT));
v1.x = tmhitthing->x - cosradius;
v1.y = tmhitthing->y - sinradius;
v2.x = tmhitthing->x + cosradius;
v2.y = tmhitthing->y + sinradius;
junk.v1 = &v1;
junk.v2 = &v2;
junk.dx = 2*cosradius; // v2.x - v1.x;
junk.dy = 2*sinradius; // v2.y - v1.y;
junk.slopetype = !cosradius ? ST_VERTICAL : !sinradius ? ST_HORIZONTAL :
((sinradius > 0) == (cosradius > 0)) ? ST_POSITIVE : ST_NEGATIVE;
bestslidefrac = FRACUNIT+1;
den = FixedMul(junk.dy>>8, mo->momx) - FixedMul(junk.dx>>8, mo->momy);
if (!den)
bestslidefrac = 0;
else
{
fixed_t frac;
#define P_PaperTraverse(startx, starty) \
num = FixedMul((v1.x - leadx)>>8, junk.dy) + FixedMul((leady - v1.y)>>8, junk.dx); \
frac = FixedDiv(num, den); \
if (frac < bestslidefrac) \
bestslidefrac = frac
P_PaperTraverse(leadx, leady);
P_PaperTraverse(trailx, leady);
P_PaperTraverse(leadx, traily);
#undef dowork
}
goto papercollision;
}
// Thankfully box collisions are a lot simpler than arbitrary lines. There's only four possible cases.
if (mo->y + mo->radius <= tmhitthing->y - tmhitthing->radius)
{
@ -3129,7 +3224,7 @@ void P_SlideMove(mobj_t *mo)
bestslideline = NULL;
retry:
if (++hitcount == 3)
if ((++hitcount == 3) || papercol)
goto stairstep; // don't loop forever
// trace along the three leading corners
@ -3171,6 +3266,7 @@ retry:
return;
}
papercollision:
// move up to the wall
if (bestslidefrac == FRACUNIT+1)
{

View File

@ -2739,8 +2739,9 @@ static boolean P_ZMovement(mobj_t *mo)
return true;
break;
case MT_SPIKE:
case MT_WALLSPIKE:
// Dead spike particles disappear upon ground contact
if ((mo->z <= mo->floorz || mo->z + mo->height >= mo->ceilingz) && mo->health <= 0)
if (!mo->health && (mo->z <= mo->floorz || mo->z + mo->height >= mo->ceilingz))
{
P_RemoveMobj(mo);
return false;
@ -7379,16 +7380,18 @@ void P_MobjThinker(mobj_t *mobj)
return;
}
mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|(mobj->target->frame & FF_FRAMEMASK);
#if 0
if (mobj->angle != mobj->target->angle + ANGLE_90) // reposition if not the correct angle
{
mobj_t *target = mobj->target; // shortcut
const fixed_t baseradius = target->radius/2 - FixedMul(FRACUNIT, target->scale);
const fixed_t baseradius = target->radius - (target->scale/2); //FixedMul(FRACUNIT/2, target->scale);
P_UnsetThingPosition(mobj);
mobj->x = target->x - P_ReturnThrustX(target, target->angle, baseradius);
mobj->y = target->y - P_ReturnThrustY(target, target->angle, baseradius);
P_SetThingPosition(mobj);
mobj->angle = target->angle + ANGLE_90;
}
#endif
break;
case MT_FALLINGROCK:
// Despawn rocks here in case zmovement code can't do so (blame slopes)
@ -7809,6 +7812,10 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->flags2 & MF2_NIGHTSPULL)
P_NightsItemChase(mobj);
break;
case MT_EMBLEM:
if (mobj->flags2 & MF2_NIGHTSPULL)
P_NightsItemChase(mobj);
break;
case MT_SHELL:
if (mobj->threshold && mobj->threshold != TICRATE)
mobj->threshold--;
@ -10117,8 +10124,8 @@ ML_NOCLIMB : Direction not controllable
mobj->flags &= ~MF_SCENERY;
mobj->fuse = mthing->angle + mobj->info->speed;
}
// Use per-thing collision for spikes if the deaf flag is checked.
if (mthing->options & MTF_AMBUSH && !metalrecording)
// Use per-thing collision for spikes if the deaf flag isn't checked.
if (!(mthing->options & MTF_AMBUSH) && !metalrecording)
{
P_UnsetThingPosition(mobj);
mobj->flags &= ~(MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT);
@ -10134,8 +10141,8 @@ ML_NOCLIMB : Direction not controllable
mobj->flags &= ~MF_SCENERY;
mobj->fuse = mobj->info->speed;
}
// Use per-thing collision for spikes if the deaf flag is checked.
if (mthing->options & MTF_AMBUSH && !metalrecording)
// Use per-thing collision for spikes if the deaf flag isn't checked.
if (!(mthing->options & MTF_AMBUSH) && !metalrecording)
{
P_UnsetThingPosition(mobj);
mobj->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIPHEIGHT);
@ -10146,7 +10153,7 @@ ML_NOCLIMB : Direction not controllable
// spawn base
{
const angle_t mobjangle = FixedAngle(mthing->angle*FRACUNIT); // the mobj's own angle hasn't been set quite yet so...
const fixed_t baseradius = mobj->radius/2 - FixedMul(FRACUNIT, mobj->scale);
const fixed_t baseradius = mobj->radius - mobj->scale;
mobj_t *base = P_SpawnMobj(
mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius),
mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius),
@ -10230,7 +10237,6 @@ ML_NOCLIMB : Direction not controllable
// Spawn already displayed
mobj->flags |= MF_SPECIAL;
mobj->flags &= ~MF_NIGHTSITEM;
P_SetMobjState(mobj, mobj->info->seestate);
}
if (mobj->flags & MF_PUSHABLE)
@ -10283,6 +10289,10 @@ ML_NOCLIMB : Direction not controllable
mobj->flags2 |= MF2_OBJECTFLIP;
}
// Final set of not being able to draw nightsitems.
if (mobj->flags & MF_NIGHTSITEM)
mobj->flags2 |= MF2_DONTDRAW;
mthing->mobj = mobj;
}

View File

@ -1237,7 +1237,7 @@ static void Polyobj_rotateLine(line_t *ld)
// determine slopetype
ld->slopetype = !ld->dx ? ST_VERTICAL : !ld->dy ? ST_HORIZONTAL :
FixedDiv(ld->dy, ld->dx) > 0 ? ST_POSITIVE : ST_NEGATIVE;
((ld->dy > 0) == (ld->dx > 0)) ? ST_POSITIVE : ST_NEGATIVE;
// update bounding box
if (v1->x < v2->x)

View File

@ -54,6 +54,8 @@
#include "v_video.h"
#include "filesrch.h" // refreshdirmenu
// wipes
#include "f_finale.h"
@ -1120,7 +1122,20 @@ static inline void P_SpawnEmblems(void)
P_SetThingPosition(emblemmobj);
}
else
{
emblemmobj->frame &= ~FF_TRANSMASK;
if (emblemlocations[i].type == ET_GLOBAL)
{
emblemmobj->reactiontime = emblemlocations[i].var;
if (emblemlocations[i].var & GE_NIGHTSITEM)
{
emblemmobj->flags |= MF_NIGHTSITEM;
emblemmobj->flags &= ~MF_SPECIAL;
emblemmobj->flags2 |= MF2_DONTDRAW;
}
}
}
}
}
@ -1214,7 +1229,7 @@ static void P_LoadLineDefs(lumpnum_t lumpnum)
ld->slopetype = ST_VERTICAL;
else if (!ld->dy)
ld->slopetype = ST_HORIZONTAL;
else if (FixedDiv(ld->dy, ld->dx) > 0)
else if ((ld->dy > 0) == (ld->dx > 0))
ld->slopetype = ST_POSITIVE;
else
ld->slopetype = ST_NEGATIVE;
@ -3082,6 +3097,7 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
if ((numlumps = W_LoadWadFile(wadfilename)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
CONS_Printf(M_GetText("Errors occured while loading %s; not added.\n"), wadfilename);
return false;
}

View File

@ -5879,10 +5879,8 @@ void P_SpawnSpecials(INT32 fromnetsave)
}
else // Otherwise, set calculated offsets such that line's v1 is the apparent origin
{
fixed_t cosinecomponent = FINECOSINE(flatangle>>ANGLETOFINESHIFT);
fixed_t sinecomponent = FINESINE(flatangle>>ANGLETOFINESHIFT);
xoffs = (-FixedMul(lines[i].v1->x, cosinecomponent) % MAXFLATSIZE) + (FixedMul(lines[i].v1->y, sinecomponent) % MAXFLATSIZE); // No danger of overflow thanks to the strategically placed modulo operations.
yoffs = (FixedMul(lines[i].v1->x, sinecomponent) % MAXFLATSIZE) + (FixedMul(lines[i].v1->y, cosinecomponent) % MAXFLATSIZE); // Ditto.
xoffs = -lines[i].v1->x;
yoffs = lines[i].v1->y;
}
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)

View File

@ -821,7 +821,10 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor)
if (inflictor)
{
ang = R_PointToAngle2(inflictor->x-inflictor->momx, inflictor->y - inflictor->momy, player->mo->x - player->mo->momx, player->mo->y - player->mo->momy);
if (inflictor->type == MT_WALLSPIKE)
ang = inflictor->angle;
else
ang = R_PointToAngle2(inflictor->x-inflictor->momx, inflictor->y - inflictor->momy, player->mo->x - player->mo->momx, player->mo->y - player->mo->momy);
// explosion and rail rings send you farther back, making it more difficult
// to recover

View File

@ -445,17 +445,18 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
#ifdef ESLOPE
if (slope); else // Don't mess with this right now if a slope is involved
#endif
if (plangle != 0)
{
// Add the view offset, rotated by the plane angle.
angle_t angle = plangle>>ANGLETOFINESHIFT;
xoff += FixedMul(viewx,FINECOSINE(angle))-FixedMul(viewy,FINESINE(angle));
yoff += -FixedMul(viewx,FINESINE(angle))-FixedMul(viewy,FINECOSINE(angle));
}
else
{
xoff += viewx;
yoff -= viewy;
if (plangle != 0)
{
// Add the view offset, rotated by the plane angle.
fixed_t cosinecomponent = FINECOSINE(plangle>>ANGLETOFINESHIFT);
fixed_t sinecomponent = FINESINE(plangle>>ANGLETOFINESHIFT);
fixed_t oldxoff = xoff;
xoff = FixedMul(xoff,cosinecomponent)+FixedMul(yoff,sinecomponent);
yoff = -FixedMul(oldxoff,sinecomponent)+FixedMul(yoff,cosinecomponent);
}
}
// This appears to fix the Nimbus Ruins sky bug.
@ -483,6 +484,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
&& !pfloor && !check->ffloor
&& check->viewx == viewx && check->viewy == viewy && check->viewz == viewz
&& check->viewangle == viewangle
&& check->plangle == plangle
#ifdef ESLOPE
&& check->slope == slope
#endif
@ -951,19 +953,57 @@ void R_DrawSinglePlane(visplane_t *pl)
floatv3_t p, m, n;
float ang;
float vx, vy, vz;
float fudge;
// compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly
// use this as a temp var to store P_GetZAt's return value each time
fixed_t temp;
xoffs &= ((1 << (32-nflatshiftup))-1);
yoffs &= ((1 << (32-nflatshiftup))-1);
xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1);
yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1);
// Okay, look, don't ask me why this works, but without this setup there's a disgusting-looking misalignment with the textures. -Red
fudge = ((1<<nflatshiftup)+1.0f)/(1<<nflatshiftup);
const float fudge = ((1<<nflatshiftup)+1.0f)/(1<<nflatshiftup);
angle_t hack = (pl->plangle & (ANGLE_90-1));
yoffs *= 1;
if (hack)
{
/*
Essentially: We can't & the components along the regular axes when the plane is rotated.
This is because the distance on each regular axis in order to loop is different.
We rotate them, & the components, add them together, & them again, and then rotate them back.
These three seperate & operations are done per axis in order to prevent overflows.
toast 10/04/17
*/
const fixed_t cosinecomponent = FINECOSINE(hack>>ANGLETOFINESHIFT);
const fixed_t sinecomponent = FINESINE(hack>>ANGLETOFINESHIFT);
const fixed_t modmask = ((1 << (32-nflatshiftup)) - 1);
fixed_t ox = (FixedMul(pl->slope->o.x,cosinecomponent) & modmask) - (FixedMul(pl->slope->o.y,sinecomponent) & modmask);
fixed_t oy = (-FixedMul(pl->slope->o.x,sinecomponent) & modmask) - (FixedMul(pl->slope->o.y,cosinecomponent) & modmask);
temp = ox & modmask;
oy &= modmask;
ox = FixedMul(temp,cosinecomponent)+FixedMul(oy,-sinecomponent); // negative sine for opposite direction
oy = -FixedMul(temp,-sinecomponent)+FixedMul(oy,cosinecomponent);
temp = xoffs;
xoffs = (FixedMul(temp,cosinecomponent) & modmask) + (FixedMul(yoffs,sinecomponent) & modmask);
yoffs = (-FixedMul(temp,sinecomponent) & modmask) + (FixedMul(yoffs,cosinecomponent) & modmask);
temp = xoffs & modmask;
yoffs &= modmask;
xoffs = FixedMul(temp,cosinecomponent)+FixedMul(yoffs,-sinecomponent); // ditto
yoffs = -FixedMul(temp,-sinecomponent)+FixedMul(yoffs,cosinecomponent);
xoffs -= (pl->slope->o.x - ox);
yoffs += (pl->slope->o.y + oy);
}
else
{
xoffs &= ((1 << (32-nflatshiftup))-1);
yoffs &= ((1 << (32-nflatshiftup))-1);
xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1);
yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1);
}
xoffs = (fixed_t)(xoffs*fudge);
yoffs = (fixed_t)(yoffs/fudge);

View File

@ -817,7 +817,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
colfunc = basecolfunc; // hack: this isn't resetting properly somewhere.
dc_colormap = vis->colormap;
if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"
if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"
{
// translate certain pixels to white
colfunc = transcolfunc;
@ -832,7 +832,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
{
colfunc = transtransfunc;
dc_transmap = vis->transmap;
if (vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_>
if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_>
{
size_t skinnum = (skin_t*)vis->mobj->skin-skins;
dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE);
@ -851,7 +851,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
colfunc = transcolfunc;
// New colormap stuff for skins Tails 06-07-2002
if (vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player!
if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player!
{
size_t skinnum = (skin_t*)vis->mobj->skin-skins;
dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE);
@ -881,18 +881,18 @@ static void R_DrawVisSprite(vissprite_t *vis)
frac = vis->startfrac;
windowtop = windowbottom = sprbotscreen = INT32_MAX;
if (vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES)
if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES)
this_scale = FixedMul(this_scale, ((skin_t *)vis->mobj->skin)->highresscale);
if (this_scale <= 0)
this_scale = 1;
if (this_scale != FRACUNIT)
{
if (!vis->isScaled)
if (!(vis->cut & SC_ISSCALED))
{
vis->scale = FixedMul(vis->scale, this_scale);
vis->scalestep = FixedMul(vis->scalestep, this_scale);
vis->xiscale = FixedDiv(vis->xiscale,this_scale);
vis->isScaled = true;
vis->cut |= SC_ISSCALED;
}
dc_texturemid = FixedDiv(dc_texturemid,this_scale);
}
@ -934,7 +934,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale));
dc_iscale = (0xffffffffu / (unsigned)spryscale);
}
if (vis->vflip)
if (vis->cut & SC_VFLIP)
R_DrawFlippedMaskedColumn(column, patch->height);
else
R_DrawMaskedColumn(column);
@ -1013,7 +1013,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
//
// R_SplitSprite
// runs through a sector's lightlist and
static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing)
static void R_SplitSprite(vissprite_t *sprite)
{
INT32 i, lightnum, lindex;
INT16 cutfrac;
@ -1049,6 +1049,8 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing)
// adjust the heights.
newsprite = M_Memcpy(R_NewVisSprite(), sprite, sizeof (vissprite_t));
newsprite->cut |= (sprite->cut & SC_FLAGMASK);
sprite->cut |= SC_BOTTOM;
sprite->gz = testheight;
@ -1081,15 +1083,7 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing)
newsprite->extra_colormap = sector->lightlist[i].extra_colormap;
/*
if (thing->frame & FF_TRANSMASK)
;
else if (thing->flags2 & MF2_SHADOW)
;
else
*/
if (!((thing->frame & (FF_FULLBRIGHT|FF_TRANSMASK) || thing->flags2 & MF2_SHADOW)
&& (!newsprite->extra_colormap || !newsprite->extra_colormap->fog)))
if (!((newsprite->cut & SC_FULLBRIGHT) && (!newsprite->extra_colormap || !newsprite->extra_colormap->fog)))
{
lindex = FixedMul(sprite->xscale, FixedDiv(640, vid.width))>>(LIGHTSCALESHIFT);
@ -1109,6 +1103,7 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing)
//
static void R_ProjectSprite(mobj_t *thing)
{
mobj_t *oldthing = thing;
fixed_t tr_x, tr_y;
fixed_t gxt, gyt;
fixed_t tx, tz;
@ -1128,6 +1123,8 @@ static void R_ProjectSprite(mobj_t *thing)
vissprite_t *vis;
spritecut_e cut = SC_NONE;
angle_t ang = 0; // compiler complaints
fixed_t iscale;
fixed_t scalestep;
@ -1326,24 +1323,14 @@ static void R_ProjectSprite(mobj_t *thing)
if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY)
{
fixed_t linkscale;
#if 0 // support for chains of linkdraw - probably not network safe to modify mobjs during rendering
mobj_t *link, *link2;
for (link = thing->tracer; (link->tracer && (link->flags2 & MF2_LINKDRAW)); link = link->tracer)
link->flags2 &= ~MF2_LINKDRAW; // to prevent infinite loops, otherwise would just be a ;
thing = thing->tracer;
for (link2 = thing->tracer; (link2->tracer && (link2 != link)); link2 = link2->tracer)
link->flags2 |= MF2_LINKDRAW; // only needed for correction of the above
if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)
return;
if (link->flags2 & MF2_LINKDRAW)
link->flags2 &= ~MF2_LINKDRAW; // let's try and make sure this doesn't happen again...
tr_x = link->x - viewx;
tr_y = link->y - viewy;
#else
tr_x = thing->tracer->x - viewx;
tr_y = thing->tracer->y - viewy;
#endif
tr_x = thing->x - viewx;
tr_y = thing->y - viewy;
gxt = FixedMul(tr_x, viewcos);
gyt = -FixedMul(tr_y, viewsin);
tz = gxt-gyt;
@ -1356,6 +1343,7 @@ static void R_ProjectSprite(mobj_t *thing)
dispoffset *= -1; // if it's physically behind, make sure it's ordered behind (if dispoffset > 0)
sortscale = linkscale; // now make sure it's linked
cut = SC_LINKDRAW;
}
// PORTAL SPRITE CLIPPING
@ -1374,12 +1362,12 @@ static void R_ProjectSprite(mobj_t *thing)
// When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned.
// sprite height - sprite topoffset is the proper inverse of the vertical offset, of course.
// remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes!
gz = thing->z + thing->height - FixedMul(spritecachedinfo[lump].topoffset, this_scale);
gz = oldthing->z + oldthing->height - FixedMul(spritecachedinfo[lump].topoffset, this_scale);
gzt = gz + FixedMul(spritecachedinfo[lump].height, this_scale);
}
else
{
gzt = thing->z + FixedMul(spritecachedinfo[lump].topoffset, this_scale);
gzt = oldthing->z + FixedMul(spritecachedinfo[lump].topoffset, this_scale);
gz = gzt - FixedMul(spritecachedinfo[lump].height, this_scale);
}
@ -1469,7 +1457,7 @@ static void R_ProjectSprite(mobj_t *thing)
vis->sector = thing->subsector->sector;
vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS);
vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS);
vis->cut = SC_NONE;
vis->cut = cut;
if (thing->subsector->sector->numlights)
vis->extra_colormap = thing->subsector->sector->lightlist[light].extra_colormap;
else
@ -1506,12 +1494,15 @@ static void R_ProjectSprite(mobj_t *thing)
// specific translucency
if (!cv_translucency.value)
; // no translucency
else if (thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility)
else if (oldthing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility)
vis->transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT); // because now the translucency is set through FF_TRANSMASK
else if (thing->frame & FF_TRANSMASK)
vis->transmap = transtables + (thing->frame & FF_TRANSMASK) - 0x10000;
else if (oldthing->frame & FF_TRANSMASK)
vis->transmap = transtables + (oldthing->frame & FF_TRANSMASK) - 0x10000;
if (((thing->frame & FF_FULLBRIGHT) || (thing->flags2 & MF2_SHADOW))
if ((oldthing->frame & FF_FULLBRIGHT) || (oldthing->flags2 & MF2_SHADOW))
vis->cut |= SC_FULLBRIGHT;
if (vis->cut & SC_FULLBRIGHT
&& (!vis->extra_colormap || !vis->extra_colormap->fog))
{
// full bright: goggles
@ -1528,14 +1519,11 @@ static void R_ProjectSprite(mobj_t *thing)
vis->colormap = spritelights[lindex];
}
vis->precip = false;
vis->vflip = vflip;
vis->isScaled = false;
if (vflip)
vis->cut |= SC_VFLIP;
if (thing->subsector->sector->numlights)
R_SplitSprite(vis, thing);
R_SplitSprite(vis);
// Debug
++objectsdrawn;
@ -1559,7 +1547,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
fixed_t iscale;
//SoM: 3/17/2000
fixed_t gz ,gzt;
fixed_t gz, gzt;
// transform the origin point
tr_x = thing->x - viewx;
@ -1695,16 +1683,14 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
else
vis->transmap = NULL;
vis->mobj = (mobj_t *)thing;
vis->mobjflags = 0;
vis->cut = SC_NONE;
vis->cut = SC_PRECIP;
vis->extra_colormap = thing->subsector->sector->extra_colormap;
vis->heightsec = thing->subsector->sector->heightsec;
// Fullbright
vis->colormap = colormaps;
vis->precip = true;
vis->vflip = false;
vis->isScaled = false;
}
// R_AddSprites
@ -1797,7 +1783,7 @@ static vissprite_t vsprsortedhead;
void R_SortVisSprites(void)
{
UINT32 i;
UINT32 i, linkedvissprites = 0;
vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
vissprite_t *best = NULL;
vissprite_t unsorted;
@ -1821,22 +1807,91 @@ void R_SortVisSprites(void)
ds->next = dsnext;
ds->prev = dsprev;
ds->linkdraw = NULL;
}
// Fix first and last. ds still points to the last one after the loop
dsfirst->prev = &unsorted;
unsorted.next = dsfirst;
if (ds)
{
ds->next = &unsorted;
ds->linkdraw = NULL;
}
unsorted.prev = ds;
// bundle linkdraw
for (ds = unsorted.prev; ds != &unsorted; ds = ds->prev)
{
if (!(ds->cut & SC_LINKDRAW))
continue;
// reuse dsfirst...
for (dsfirst = unsorted.prev; dsfirst != &unsorted; dsfirst = dsfirst->prev)
{
// don't connect if it's also a link
if (dsfirst->cut & SC_LINKDRAW)
continue;
// don't connect if it's not the tracer
if (dsfirst->mobj != ds->mobj)
continue;
// don't connect if the tracer's top is cut off, but lower than the link's top
if ((dsfirst->cut & SC_TOP)
&& dsfirst->szt > ds->szt)
continue;
// don't connect if the tracer's bottom is cut off, but higher than the link's bottom
if ((dsfirst->cut & SC_BOTTOM)
&& dsfirst->sz < ds->sz)
continue;
break;
}
// remove from chain
ds->next->prev = ds->prev;
ds->prev->next = ds->next;
linkedvissprites++;
if (dsfirst != &unsorted)
{
if (!(ds->cut & SC_FULLBRIGHT))
ds->colormap = dsfirst->colormap;
ds->extra_colormap = dsfirst->extra_colormap;
// reusing dsnext...
dsnext = dsfirst->linkdraw;
if (!dsnext || ds->dispoffset < dsnext->dispoffset)
{
ds->next = dsnext;
dsfirst->linkdraw = ds;
}
else
{
for (; dsnext->next != NULL; dsnext = dsnext->next)
if (ds->dispoffset < dsnext->next->dispoffset)
break;
ds->next = dsnext->next;
dsnext->next = ds;
}
}
}
// pull the vissprites out by scale
vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
for (i = 0; i < visspritecount; i++)
for (i = 0; i < visspritecount-linkedvissprites; i++)
{
bestscale = bestdispoffset = INT32_MAX;
for (ds = unsorted.next; ds != &unsorted; ds = ds->next)
{
#ifdef PARANOIA
if (ds->cut & SC_LINKDRAW)
I_Error("R_SortVisSprites: no link or discardal made for linkdraw!");
#endif
if (ds->sortscale < bestscale)
{
bestscale = ds->sortscale;
@ -2090,20 +2145,6 @@ static void R_CreateDrawNodes(void)
}
else if (r2->seg)
{
#if 0 //#ifdef POLYOBJECTS_PLANES
if (r2->seg->curline->polyseg && rover->mobj && P_MobjInsidePolyobj(r2->seg->curline->polyseg, rover->mobj)) {
// Determine if we need to sort in front of the polyobj, based on the planes. This fixes the issue where
// polyobject planes render above the object standing on them. (A bit hacky... but it works.) -Red
mobj_t *mo = rover->mobj;
sector_t *po = r2->seg->curline->backsector;
if (po->ceilingheight < viewz && mo->z+mo->height > po->ceilingheight)
continue;
if (po->floorheight > viewz && mo->z < po->floorheight)
continue;
}
#endif
if (rover->x1 > r2->seg->x2 || rover->x2 < r2->seg->x1)
continue;
@ -2230,7 +2271,7 @@ static void R_DrawPrecipitationSprite(vissprite_t *spr)
void R_ClipSprites(void)
{
vissprite_t *spr;
for (;clippedvissprites < visspritecount; clippedvissprites++)
for (; clippedvissprites < visspritecount; clippedvissprites++)
{
drawseg_t *ds;
INT32 x;
@ -2451,10 +2492,24 @@ void R_DrawMasked(void)
next = r2->prev;
// Tails 08-18-2002
if (r2->sprite->precip == true)
if (r2->sprite->cut & SC_PRECIP)
R_DrawPrecipitationSprite(r2->sprite);
else
else if (!r2->sprite->linkdraw)
R_DrawSprite(r2->sprite);
else // unbundle linkdraw
{
vissprite_t *ds = r2->sprite->linkdraw;
for (;
(ds != NULL && r2->sprite->dispoffset > ds->dispoffset);
ds = ds->next)
R_DrawSprite(ds);
R_DrawSprite(r2->sprite);
for (; ds != NULL; ds = ds->next)
R_DrawSprite(ds);
}
R_DoneWithNode(r2);
r2 = next;

View File

@ -127,9 +127,19 @@ typedef struct
// -----------
typedef enum
{
// actual cuts
SC_NONE = 0,
SC_TOP = 1,
SC_BOTTOM = 2
SC_BOTTOM = 1<<1,
// other flags
SC_PRECIP = 1<<2,
SC_LINKDRAW = 1<<3,
SC_FULLBRIGHT = 1<<4,
SC_VFLIP = 1<<5,
SC_ISSCALED = 1>>6,
// masks
SC_CUTMASK = SC_TOP|SC_BOTTOM,
SC_FLAGMASK = ~SC_CUTMASK
} spritecut_e;
// A vissprite_t is a thing that will be drawn during a refresh,
@ -140,6 +150,9 @@ typedef struct vissprite_s
struct vissprite_s *prev;
struct vissprite_s *next;
// Bonus linkdraw pointer.
struct vissprite_s *linkdraw;
mobj_t *mobj; // for easy access
INT32 x1, x2;
@ -178,9 +191,6 @@ typedef struct vissprite_s
INT16 clipbot[MAXVIDWIDTH], cliptop[MAXVIDWIDTH];
boolean precip;
boolean vflip; // Flip vertically
boolean isScaled;
INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing
} vissprite_t;

View File

@ -34,6 +34,8 @@
#include "z_zone.h"
#include "fastcmp.h"
#include "filesrch.h"
#include "i_video.h" // rendermode
#include "d_netfil.h"
#include "dehacked.h"
@ -294,12 +296,12 @@ UINT16 W_LoadWadFile(const char *filename)
UINT32 numlumps;
size_t i;
INT32 compressed = 0;
size_t packetsize = 0;
serverinfo_pak *dummycheck = NULL;
size_t packetsize;
UINT8 md5sum[16];
boolean important;
// Shut the compiler up.
(void)dummycheck;
if (!(refreshdirmenu & REFRESHDIR_ADDFILE))
refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier
//CONS_Debug(DBG_SETUP, "Loading %s\n", filename);
//
@ -308,6 +310,7 @@ UINT16 W_LoadWadFile(const char *filename)
if (numwadfiles >= MAX_WADFILES)
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
refreshdirmenu |= REFRESHDIR_MAX;
return INT16_MAX;
}
@ -317,21 +320,23 @@ UINT16 W_LoadWadFile(const char *filename)
// Check if wad files will overflow fileneededbuffer. Only the filename part
// 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 += 22; // MD5, etc.
}
packetsize = packetsizetally;
packetsize += nameonlylength(filename);
packetsize += 22;
packetsize += nameonlylength(filename) + 22;
if (packetsize > sizeof(dummycheck->fileneeded))
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
if (handle)
fclose(handle);
return INT16_MAX;
if (packetsize > MAXFILENEEDED*sizeof(UINT8))
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
refreshdirmenu |= REFRESHDIR_MAX;
if (handle)
fclose(handle);
return INT16_MAX;
}
packetsizetally = packetsize;
}
// detect dehacked file with the "soc" extension
@ -470,6 +475,7 @@ UINT16 W_LoadWadFile(const char *filename)
wadfile->handle = handle;
wadfile->numlumps = (UINT16)numlumps;
wadfile->lumpinfo = lumpinfo;
wadfile->important = important;
fseek(handle, 0, SEEK_END);
wadfile->filesize = (unsigned)ftell(handle);
@ -1239,6 +1245,7 @@ int W_VerifyNMUSlumps(const char *filename)
{"TNYFN", 5}, // Tiny console font changes
{"STT", 3}, // Acceptable HUD changes (Score Time Rings)
{"YB_", 3}, // Intermission graphics, goes with the above
{"M_", 2}, // As does menu stuff
{NULL, 0},
};

View File

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