diff --git a/appveyor.yml b/appveyor.yml index 0edc7ce28..6b80b4ec3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,7 +9,7 @@ environment: # c:\mingw-w64 i686 has gcc 6.3.0, so use c:\msys64 7.3.0 instead MINGW_SDK: c:\msys64\mingw32 # c:\msys64 x86_64 has gcc 8.2.0, so use c:\mingw-w64 7.3.0 instead - MINGW_SDK_64: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64 + MINGW_SDK_64: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64 CFLAGS: -Wall -W -Werror -Wno-error=implicit-fallthrough -Wimplicit-fallthrough=3 -Wno-tautological-compare -Wno-error=suggest-attribute=noreturn NASM_ZIP: nasm-2.12.01 NASM_URL: http://www.nasm.us/pub/nasm/releasebuilds/2.12.01/win64/nasm-2.12.01-win64.zip @@ -55,8 +55,6 @@ cache: install: - if [%CONFIGURATION%] == [SDL64] ( set "X86_64=1" ) - if [%CONFIGURATION%] == [SDL64] ( set "CONFIGURATION=SDL" ) -- if [%CONFIGURATION%] == [DD64] ( set "X86_64=1" ) -- if [%CONFIGURATION%] == [DD64] ( set "CONFIGURATION=DD" ) - if [%X86_64%] == [1] ( set "MINGW_SDK=%MINGW_SDK_64%" ) - if [%X86_64%] == [1] ( set "CCACHE_CC=%CCACHE_CC_64%" ) @@ -75,13 +73,6 @@ install: configuration: - SDL - SDL64 -- DD -- DD64 - -matrix: - allow_failures: - - configuration: DD - - configuration: DD64 before_build: - set "Path=%MINGW_SDK%\bin;%Path%" @@ -92,8 +83,8 @@ before_build: - ccache -V - ccache -s - if [%NOUPX%] == [1] ( set "NOUPX=NOUPX=1" ) else ( set "NOUPX=" ) -- set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 GCC73=1 NOOBJDUMP=1 %NOUPX%" -- if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" ) +- set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX%" +- if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1 GCC81=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" ) - set "SRB2_MFLAGS=%SRB2_MFLAGS% %MINGW_FLAGS% %CONFIGURATION%=1" build_script: diff --git a/src/android/i_system.c b/src/android/i_system.c index 58fca7c19..752e9f6c6 100644 --- a/src/android/i_system.c +++ b/src/android/i_system.c @@ -245,6 +245,8 @@ void I_GetJoystick2Events(void){} void I_GetMouseEvents(void){} +void I_UpdateMouseGrab(void){} + char *I_GetEnv(const char *name) { LOGW("I_GetEnv() called?!"); diff --git a/src/android/i_video.c b/src/android/i_video.c index 2d0151f5e..b8bb4fefb 100644 --- a/src/android/i_video.c +++ b/src/android/i_video.c @@ -19,6 +19,7 @@ boolean allow_fullscreen = false; consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; void I_StartupGraphics(void){} +void I_StartupHardwareGraphics(void){} void I_ShutdownGraphics(void){} @@ -51,6 +52,11 @@ INT32 VID_SetMode(INT32 modenum) return 0; } +void VID_CheckRenderer(void) +{ + // .............. +} + const char *VID_GetModeName(INT32 modenum) { return "A320x240"; diff --git a/src/b_bot.c b/src/b_bot.c index dfb5ee1cf..51dc4d2f2 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -335,27 +335,6 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) jump_last = jump; spin_last = spin; - // ******** - // Thinkfly overlay - if (thinkfly) - { - if (!tails->hnext) - { - P_SetTarget(&tails->hnext, P_SpawnMobjFromMobj(tails, 0, 0, 0, MT_OVERLAY)); - if (tails->hnext) - { - P_SetTarget(&tails->hnext->target, tails); - P_SetTarget(&tails->hnext->hprev, tails); - P_SetMobjState(tails->hnext, S_FLIGHTINDICATOR); - } - } - } - else if (tails->hnext && tails->hnext->type == MT_OVERLAY && tails->hnext->state == states+S_FLIGHTINDICATOR) - { - P_RemoveMobj(tails->hnext); - P_SetTarget(&tails->hnext, NULL); - } - // Turn the virtual keypresses into ticcmd_t. B_KeysToTiccmd(tails, cmd, forward, backward, left, right, false, false, jump, spin); @@ -565,3 +544,30 @@ void B_RespawnBot(INT32 playernum) P_SetScale(tails, sonic->scale); tails->destscale = sonic->destscale; } + +void B_HandleFlightIndicator(player_t *player) +{ + mobj_t *tails = player->mo; + + if (!tails) + return; + + if (thinkfly && player->bot == 1 && tails->health) + { + if (!tails->hnext) + { + P_SetTarget(&tails->hnext, P_SpawnMobjFromMobj(tails, 0, 0, 0, MT_OVERLAY)); + if (tails->hnext) + { + P_SetTarget(&tails->hnext->target, tails); + P_SetTarget(&tails->hnext->hprev, tails); + P_SetMobjState(tails->hnext, S_FLIGHTINDICATOR); + } + } + } + else if (tails->hnext && tails->hnext->type == MT_OVERLAY && tails->hnext->state == states+S_FLIGHTINDICATOR) + { + P_RemoveMobj(tails->hnext); + P_SetTarget(&tails->hnext, NULL); + } +} diff --git a/src/b_bot.h b/src/b_bot.h index b42577c5c..54ef300a3 100644 --- a/src/b_bot.h +++ b/src/b_bot.h @@ -15,3 +15,4 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward boolean B_CheckRespawn(player_t *player); void B_MoveBlocked(player_t *player); void B_RespawnBot(INT32 playernum); +void B_HandleFlightIndicator(player_t *player); diff --git a/src/command.c b/src/command.c index cf0fa5e7d..675490e43 100644 --- a/src/command.c +++ b/src/command.c @@ -54,13 +54,15 @@ static void COM_Add_f(void); static void CV_EnforceExecVersion(void); static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr); static boolean CV_Command(void); -static consvar_t *CV_FindVar(const char *name); +consvar_t *CV_FindVar(const char *name); static const char *CV_StringValue(const char *var_name); static consvar_t *consvar_vars; // list of registered console variables static char com_token[1024]; static char *COM_Parse(char *data); +static char * COM_Purge (char *text, int *lenp); + CV_PossibleValue_t CV_OnOff[] = {{0, "Off"}, {1, "On"}, {0, NULL}}; CV_PossibleValue_t CV_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}}; CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}}; @@ -100,31 +102,61 @@ static cmdalias_t *com_alias; // aliases list static vsbuf_t com_text; // variable sized buffer +/** Purges control characters out of some text. + * + * \param s The text. + * \param np Optionally a pointer to fill with the new string length. + * \return The text. + * \sa COM_ExecuteString + */ +static char * +COM_Purge (char *s, int *np) +{ + char *t; + char *p; + int n; + n = strlen(s); + t = s + n + 1; + p = s; + while (( p = strchr(p, '\033') )) + { + memmove(p, &p[1], t - p - 1); + n--; + } + if (np) + (*np) = n; + return s; +} + /** Adds text into the command buffer for later execution. * * \param ptext The text to add. - * \sa COM_BufInsertText + * \sa COM_BufInsertTextEx */ -void COM_BufAddText(const char *ptext) +void COM_BufAddTextEx(const char *ptext, int flags) { - size_t l; + int l; + char *text; - l = strlen(ptext); + text = COM_Purge(Z_StrDup(ptext), &l); - if (com_text.cursize + l >= com_text.maxsize) + if (com_text.cursize + 2 + l >= com_text.maxsize) { CONS_Alert(CONS_WARNING, M_GetText("Command buffer full!\n")); return; } - VS_Write(&com_text, ptext, l); + + VS_WriteEx(&com_text, text, l, flags); + + Z_Free(text); } /** Adds command text and executes it immediately. * * \param ptext The text to execute. A newline is automatically added. - * \sa COM_BufAddText + * \sa COM_BufAddTextEx */ -void COM_BufInsertText(const char *ptext) +void COM_BufInsertTextEx(const char *ptext, int flags) { char *temp = NULL; size_t templen; @@ -138,7 +170,7 @@ void COM_BufInsertText(const char *ptext) } // add the entire text of the file (or alias) - COM_BufAddText(ptext); + COM_BufAddTextEx(ptext, flags); COM_BufExecute(); // do it right away // add the copied off data @@ -272,6 +304,7 @@ static size_t com_argc; static char *com_argv[MAX_ARGS]; static const char *com_null_string = ""; static char *com_args = NULL; // current command args or NULL +static int com_flags; static void Got_NetVar(UINT8 **p, INT32 playernum); @@ -394,12 +427,21 @@ static void COM_TokenizeString(char *ptext) com_argc = 0; com_args = NULL; + com_flags = 0; while (com_argc < MAX_ARGS) { // Skip whitespace up to a newline. while (*ptext != '\0' && *ptext <= ' ' && *ptext != '\n') - ptext++; + { + if (ptext[0] == '\033') + { + com_flags = (unsigned)ptext[1]; + ptext += 2; + } + else + ptext++; + } // A newline means end of command in buffer, // thus end of this command's args too. @@ -1016,6 +1058,15 @@ void VS_Write(vsbuf_t *buf, const void *data, size_t length) M_Memcpy(VS_GetSpace(buf, length), data, length); } +void VS_WriteEx(vsbuf_t *buf, const void *data, size_t length, int flags) +{ + char *p; + p = VS_GetSpace(buf, 2 + length); + p[0] = '\033'; + p[1] = flags; + M_Memcpy(&p[2], data, length); +} + /** Prints text in a variable buffer. Like VS_Write() plus a * trailing NUL. * @@ -1055,7 +1106,7 @@ static const char *cv_null_string = ""; * \return Pointer to the variable if found, or NULL. * \sa CV_FindNetVar */ -static consvar_t *CV_FindVar(const char *name) +consvar_t *CV_FindVar(const char *name) { consvar_t *cvar; @@ -2015,6 +2066,9 @@ static boolean CV_Command(void) if (!v) return false; + if (( com_flags & COM_SAFE ) && ( v->flags & CV_NOLUA )) + return false; + // perform a variable print or set if (COM_Argc() == 1) { @@ -2116,8 +2170,13 @@ skipwhite: com_token[len] = 0; return data; } - com_token[len] = c; - len++; + if (c == '\033') + data++; + else + { + com_token[len] = c; + len++; + } } } @@ -2133,10 +2192,22 @@ skipwhite: // parse a regular word do { - com_token[len] = c; - data++; - len++; - c = *data; + if (c == '\033') + { + do + { + data += 2; + c = *data; + } + while (c == '\033') ; + } + else + { + com_token[len] = c; + data++; + len++; + c = *data; + } if (c == '{' || c == '}' || c == ')'|| c == '(' || c == '\'') break; } while (c > 32); diff --git a/src/command.h b/src/command.h index 51e161cd0..42bd6eb84 100644 --- a/src/command.h +++ b/src/command.h @@ -20,6 +20,11 @@ // Command buffer & command execution //=================================== +enum +{ + COM_SAFE = 1, +}; + typedef void (*com_func_t)(void); void COM_AddCommand(const char *name, com_func_t func); @@ -36,10 +41,12 @@ size_t COM_FirstOption(void); const char *COM_CompleteCommand(const char *partial, INT32 skips); // insert at queu (at end of other command) -void COM_BufAddText(const char *btext); +#define COM_BufAddText(s) COM_BufAddTextEx(s, 0) +void COM_BufAddTextEx(const char *btext, int flags); // insert in head (before other command) -void COM_BufInsertText(const char *btext); +#define COM_BufInsertText(s) COM_BufInsertTextEx(s, 0) +void COM_BufInsertTextEx(const char *btext, int flags); // don't bother inserting, just do immediately void COM_ImmedExecute(const char *ptext); @@ -71,6 +78,7 @@ void VS_Free(vsbuf_t *buf); void VS_Clear(vsbuf_t *buf); void *VS_GetSpace(vsbuf_t *buf, size_t length); void VS_Write(vsbuf_t *buf, const void *data, size_t length); +void VS_WriteEx(vsbuf_t *buf, const void *data, size_t length, int flags); void VS_Print(vsbuf_t *buf, const char *data); // strcats onto the sizebuf //================== @@ -100,7 +108,8 @@ typedef enum CV_HIDEN = 1024, // variable is not part of the cvar list so cannot be accessed by the console // can only be set when we have the pointer to it // used on menus - CV_CHEAT = 2048 // Don't let this be used in multiplayer unless cheats are on. + CV_CHEAT = 2048, // Don't let this be used in multiplayer unless cheats are on. + CV_NOLUA = 4096,/* don't let this be called from Lua */ } cvflags_t; typedef struct CV_PossibleValue_s @@ -140,6 +149,9 @@ void CV_ToggleExecVersion(boolean enable); // register a variable for use at the console void CV_RegisterVar(consvar_t *variable); +// returns a console variable by name +consvar_t *CV_FindVar(const char *name); + // sets changed to 0 for every console variable void CV_ClearChangedFlags(void); diff --git a/src/console.c b/src/console.c index 1fbca75b4..01d1ddaa2 100644 --- a/src/console.c +++ b/src/console.c @@ -20,6 +20,7 @@ #include "g_input.h" #include "hu_stuff.h" #include "keys.h" +#include "r_main.h" #include "r_defs.h" #include "sounds.h" #include "st_stuff.h" @@ -591,6 +592,8 @@ void CON_ToggleOff(void) CON_ClearHUD(); con_forcepic = 0; con_clipviewtop = -1; // remove console clipping of view + + I_UpdateMouseGrab(); } boolean CON_Ready(void) @@ -615,6 +618,7 @@ void CON_Ticker(void) consoletoggle = false; con_destlines = 0; CON_ClearHUD(); + I_UpdateMouseGrab(); } // console key was pushed @@ -627,6 +631,7 @@ void CON_Ticker(void) { con_destlines = 0; CON_ClearHUD(); + I_UpdateMouseGrab(); } else CON_ChangeHeight(); @@ -1285,10 +1290,10 @@ void CONS_Printf(const char *fmt, ...) con_scrollup = 0; // if not in display loop, force screen update - if (con_startup) + if (con_startup && (!setrenderneeded)) { #ifdef _WINDOWS - patch_t *con_backpic = W_CachePatchName("CONSBACK", PU_CACHE); + patch_t *con_backpic = W_CachePatchName("CONSBACK", PU_PATCH); // Jimita: CON_DrawBackpic just called V_DrawScaledPatch V_DrawScaledPatch(0, 0, 0, con_backpic); @@ -1545,7 +1550,7 @@ static void CON_DrawConsole(void) // draw console background if (cons_backpic.value || con_forcepic) { - patch_t *con_backpic = W_CachePatchName("CONSBACK", PU_CACHE); + patch_t *con_backpic = W_CachePatchName("CONSBACK", PU_PATCH); // Jimita: CON_DrawBackpic just called V_DrawScaledPatch V_DrawScaledPatch(0, 0, 0, con_backpic); @@ -1602,8 +1607,18 @@ void CON_Drawer(void) if (!con_started || !graphics_started) return; + if (needpatchrecache) + { + W_FlushCachedPatches(); + HU_LoadGraphics(); + } + if (con_recalc) + { CON_RecalcSize(); + if (con_curlines <= 0) + CON_ClearHUD(); + } if (con_curlines > 0) CON_DrawConsole(); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 4448aaae0..98ff3a6f8 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1265,8 +1265,12 @@ static boolean CL_SendJoin(void) if (splitscreen || botingame) localplayers++; netbuffer->u.clientcfg.localplayers = localplayers; + netbuffer->u.clientcfg._255 = 255; + netbuffer->u.clientcfg.packetversion = PACKETVERSION; netbuffer->u.clientcfg.version = VERSION; netbuffer->u.clientcfg.subversion = SUBVERSION; + strncpy(netbuffer->u.clientcfg.application, SRB2APPLICATION, + sizeof netbuffer->u.clientcfg.application); strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME); strncpy(netbuffer->u.clientcfg.names[1], cv_playername2.zstring, MAXPLAYERNAME); return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak)); @@ -1277,15 +1281,20 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) UINT8 *p; netbuffer->packettype = PT_SERVERINFO; + netbuffer->u.serverinfo._255 = 255; + netbuffer->u.serverinfo.packetversion = PACKETVERSION; netbuffer->u.serverinfo.version = VERSION; netbuffer->u.serverinfo.subversion = SUBVERSION; + strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION, + sizeof netbuffer->u.serverinfo.application); // return back the time value so client can compute their ping netbuffer->u.serverinfo.time = (tic_t)LONG(servertime); netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime); netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers(); netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value; - netbuffer->u.serverinfo.gametype = (UINT8)gametype; + strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], + sizeof netbuffer->u.serverinfo.gametypename); netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); netbuffer->u.serverinfo.isdedicated = (UINT8)dedicated; @@ -1712,12 +1721,21 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node) if (serverlistcount >= MAXSERVERLIST) return; // list full + if (info->_255 != 255) + return;/* old packet format */ + + if (info->packetversion != PACKETVERSION) + return;/* old new packet format */ + if (info->version != VERSION) return; // Not same version. if (info->subversion != SUBVERSION) return; // Close, but no cigar. + if (strcmp(info->application, SRB2APPLICATION)) + return;/* that's a different mod */ + i = serverlistcount++; } @@ -2105,13 +2123,10 @@ static void CL_ConnectToServer(boolean viams) if (i != -1) { - UINT16 num = serverlist[i].info.gametype; - const char *gametypestr = NULL; + char *gametypestr = serverlist[i].info.gametypename; CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername); - if (num < gametypecount) - gametypestr = Gametype_Names[num]; - if (gametypestr) - CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr); + gametypestr[sizeof serverlist[i].info.gametypename - 1] = '\0'; + CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr); CONS_Printf(M_GetText("Version: %d.%d.%u\n"), serverlist[i].info.version/100, serverlist[i].info.version%100, serverlist[i].info.subversion); } @@ -2987,8 +3002,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_RemovePlayer(pnum, kickreason); } -consvar_t cv_allownewplayer = {"allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; -consvar_t cv_joinnextround = {"joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done +consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; +consvar_t cv_joinnextround = {"joinnextround", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}}; @@ -3509,6 +3524,12 @@ static void HandleConnect(SINT8 node) if (bannednode && bannednode[node]) SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server")); + else if (netbuffer->u.clientcfg._255 != 255 || + netbuffer->u.clientcfg.packetversion != PACKETVERSION) + SV_SendRefuse(node, "Incompatible packet formats."); + else if (strncmp(netbuffer->u.clientcfg.application, SRB2APPLICATION, + sizeof netbuffer->u.clientcfg.application)) + SV_SendRefuse(node, "Different SRB2 modifications\nare not compatible."); else if (netbuffer->u.clientcfg.version != VERSION || netbuffer->u.clientcfg.subversion != SUBVERSION) SV_SendRefuse(node, va(M_GetText("Different SRB2 versions cannot\nplay a netgame!\n(server version %d.%d.%d)"), VERSION/100, VERSION%100, SUBVERSION)); @@ -3631,6 +3652,10 @@ static void HandleServerInfo(SINT8 node) const tic_t ticdiff = (ticnow - ticthen)*1000/NEWTICRATE; netbuffer->u.serverinfo.time = (tic_t)LONG(ticdiff); netbuffer->u.serverinfo.servername[MAXSERVERNAME-1] = 0; + netbuffer->u.serverinfo.application + [sizeof netbuffer->u.serverinfo.application - 1] = '\0'; + netbuffer->u.serverinfo.gametypename + [sizeof netbuffer->u.serverinfo.gametypename - 1] = '\0'; SL_InsertServer(&netbuffer->u.serverinfo, node); } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 4ba4ee0eb..c797e5ca8 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -19,6 +19,16 @@ #include "tables.h" #include "d_player.h" +/* +The 'packet version' may be used with packets whose +format is expected to change between versions. + +This version is independent of the mod name, and standard +version and subversion. It should only account for the +basic fields of the packet, and change infrequently. +*/ +#define PACKETVERSION 1 + // Network play related stuff. // There is a data struct that stores network // communication related stuff, and another @@ -320,8 +330,13 @@ typedef struct { #pragma warning(default : 4200) #endif +#define MAXAPPLICATION 16 + typedef struct { + UINT8 _255;/* see serverinfo_pak */ + UINT8 packetversion; + char application[MAXAPPLICATION]; UINT8 version; // Different versions don't work UINT8 subversion; // Contains build version UINT8 localplayers; @@ -334,11 +349,19 @@ typedef struct // This packet is too large typedef struct { + /* + In the old packet, 'version' is the first field. Now that field is set + to 255 always, so older versions won't be confused with the new + versions or vice-versa. + */ + UINT8 _255; + UINT8 packetversion; + char application[MAXAPPLICATION]; UINT8 version; UINT8 subversion; UINT8 numberofplayer; UINT8 maxplayer; - UINT8 gametype; + char gametypename[24]; UINT8 modifiedgame; UINT8 cheatsenabled; UINT8 isdedicated; diff --git a/src/d_main.c b/src/d_main.c index 0654e0927..432dfd34f 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -108,6 +108,8 @@ boolean devparm = false; // started game with -devparm boolean singletics = false; // timedemo boolean lastdraw = false; +static void D_CheckRendererState(void); + postimg_t postimgtype = postimg_none; INT32 postimgparam; postimg_t postimgtype2 = postimg_none; @@ -212,6 +214,7 @@ INT16 wipetypepost = -1; static void D_Display(void) { + INT32 setrenderstillneeded = 0; boolean forcerefresh = false; static boolean wipe = false; INT32 wipedefindex = 0; @@ -222,11 +225,38 @@ static void D_Display(void) if (nodrawers) return; // for comparative timing/profiling - // check for change of screen size (video mode) - if (setmodeneeded && !wipe) - SCR_SetMode(); // change video mode + // Lactozilla: Switching renderers works by checking + // if the game has to do it right when the frame + // needs to render. If so, five things will happen: + // 1. Interface functions will be called so + // that switching to OpenGL creates a + // GL context, and switching to Software + // allocates screen buffers. + // 2. Software will set drawer functions, + // and OpenGL will load textures and + // create plane polygons, if necessary. + // 3. Functions related to switching video + // modes (resolution) are called. + // 4. Patch data is freed from memory, + // and recached if necessary. + // 5. The frame is ready to be drawn! - if (vid.recalc) + // stop movie if needs to change renderer + if (setrenderneeded && (moviemode == MM_APNG)) + M_StopMovie(); + + // check for change of renderer or screen size (video mode) + if ((setrenderneeded || setmodeneeded) && !wipe) + { + if (setrenderneeded) + { + CONS_Debug(DBG_RENDER, "setrenderneeded set (%d)\n", setrenderneeded); + setrenderstillneeded = setrenderneeded; + } + SCR_SetMode(); // change video mode + } + + if (vid.recalc || setrenderstillneeded) { SCR_Recalc(); // NOTE! setsizeneeded is set by SCR_Recalc() #ifdef HWRENDER @@ -237,12 +267,15 @@ static void D_Display(void) } // change the view size if needed - if (setsizeneeded) + if (setsizeneeded || setrenderstillneeded) { R_ExecuteSetViewSize(); forcerefresh = true; // force background redraw } + // Lactozilla: Renderer switching + D_CheckRendererState(); + // draw buffered stuff to screen // Used only by linux GGI version I_UpdateNoBlit(); @@ -457,7 +490,7 @@ static void D_Display(void) py = 4; else py = viewwindowy + 4; - patch = W_CachePatchName("M_PAUSE", PU_CACHE); + patch = W_CachePatchName("M_PAUSE", PU_PATCH); V_DrawScaledPatch(viewwindowx + (BASEVIDWIDTH - SHORT(patch->width))/2, py, 0, patch); #else INT32 y = ((automapactive) ? (32) : (BASEVIDHEIGHT/2)); @@ -557,6 +590,25 @@ static void D_Display(void) I_FinishUpdate(); // page flip or blit buffer } + + needpatchflush = false; + needpatchrecache = false; +} + +// Lactozilla: Check the renderer's state +// after a possible renderer switch. +void D_CheckRendererState(void) +{ + // flush all patches from memory + // (also frees memory tagged with PU_CACHE) + // (which are not necessarily patches but I don't care) + if (needpatchflush) + Z_FlushCachedPatches(); + + // some patches have been freed, + // so cache them again + if (needpatchrecache) + R_ReloadHUDGraphics(); } // ========================================================================= @@ -600,8 +652,7 @@ void D_SRB2Loop(void) // hack to start on a nice clear console screen. COM_ImmedExecute("cls;version"); - if (rendermode == render_soft) - V_DrawScaledPatch(0, 0, 0, (patch_t *)W_CacheLumpNum(W_GetNumForName("CONSBACK"), PU_CACHE)); + V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(W_GetNumForName("CONSBACK"), PU_CACHE)); I_FinishUpdate(); // page flip or blit buffer for (;;) @@ -715,7 +766,7 @@ void D_StartTitle(void) if (netgame) { - if (gametype == GT_COOP) + if (gametyperules & GTR_CAMPAIGN) { G_SetGamestate(GS_WAITINGPLAYERS); // hack to prevent a command repeat @@ -1118,26 +1169,6 @@ void D_SRB2Main(void) if (M_CheckParm("-server") || dedicated) netgame = server = true; - if (M_CheckParm("-warp") && M_IsNextParm()) - { - const char *word = M_GetNextParm(); - char ch; // use this with sscanf to catch non-digits with - if (fastncmp(word, "MAP", 3)) // MAPxx name - pstartmap = M_MapNumber(word[3], word[4]); - else if (sscanf(word, "%d%c", &pstartmap, &ch) != 1) // a plain number - I_Error("Cannot warp to map %s (invalid map name)\n", word); - // Don't check if lump exists just yet because the wads haven't been loaded! - // Just do a basic range check here. - if (pstartmap < 1 || pstartmap > NUMMAPS) - I_Error("Cannot warp to map %d (out of range)\n", pstartmap); - else - { - if (!M_CheckParm("-server")) - G_SetGameModified(true); - autostart = true; - } - } - CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n"); Z_Init(); @@ -1194,6 +1225,20 @@ void D_SRB2Main(void) mainwadstally = packetsizetally; // technically not accurate atm, remember to port the two-stage -file process from kart in 2.2.x + if (M_CheckParm("-warp") && M_IsNextParm()) + { + const char *word = M_GetNextParm(); + pstartmap = G_FindMapByNameOrCode(word, 0); + if (! pstartmap) + I_Error("Cannot find a map remotely named '%s'\n", word); + else + { + if (!M_CheckParm("-server")) + G_SetGameModified(true); + autostart = true; + } + } + cht_Init(); //---------------------------------------------------- READY SCREEN @@ -1239,6 +1284,16 @@ void D_SRB2Main(void) // set user default mode or mode set at cmdline SCR_CheckDefaultMode(); + // Lactozilla: Does the render mode need to change? + if ((setrenderneeded != 0) && (setrenderneeded != rendermode)) + { + needpatchflush = true; + needpatchrecache = true; + VID_CheckRenderer(); + SCR_ChangeRendererCVars(setrenderneeded); + } + D_CheckRendererState(); + wipegamestate = gamestate; savedata.lives = 0; // flag this as not-used diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 4e14ca25f..19e1f1dad 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -848,6 +848,10 @@ void D_RegisterClientCommands(void) // screen.c CV_RegisterVar(&cv_fullscreen); CV_RegisterVar(&cv_renderview); + CV_RegisterVar(&cv_renderer); +#ifdef HWRENDER + CV_RegisterVar(&cv_newrenderer); +#endif CV_RegisterVar(&cv_scr_depth); CV_RegisterVar(&cv_scr_width); CV_RegisterVar(&cv_scr_height); @@ -1809,18 +1813,15 @@ static void Command_Map_f(void) boolean newresetplayers; boolean mustmodifygame; - boolean usemapcode = false; INT32 newmapnum; char * mapname; - size_t mapnamelen; char *realmapname = NULL; INT32 newgametype = gametype; INT32 d; - char *p; if (client && !IsPlayerAdmin(consoleplayer)) { @@ -1880,43 +1881,8 @@ static void Command_Map_f(void) } mapname = ConcatCommandArgv(1, first_option); - mapnamelen = strlen(mapname); - if (mapnamelen == 2)/* maybe two digit code */ - { - if (( newmapnum = M_MapNumber(mapname[0], mapname[1]) )) - usemapcode = true; - } - else if (mapnamelen == 5 && strnicmp(mapname, "MAP", 3) == 0) - { - if (( newmapnum = M_MapNumber(mapname[3], mapname[4]) ) == 0) - { - CONS_Alert(CONS_ERROR, M_GetText("Invalid map code '%s'.\n"), mapname); - Z_Free(mapname); - return; - } - usemapcode = true; - } - - if (!usemapcode) - { - /* Now detect map number in base 10, which no one asked for. */ - newmapnum = strtol(mapname, &p, 10); - if (*p == '\0')/* we got it */ - { - if (newmapnum < 1 || newmapnum > NUMMAPS) - { - CONS_Alert(CONS_ERROR, M_GetText("Invalid map number %d.\n"), newmapnum); - Z_Free(mapname); - return; - } - usemapcode = true; - } - else - { - newmapnum = G_FindMap(mapname, &realmapname, NULL, NULL); - } - } + newmapnum = G_FindMapByNameOrCode(mapname, &realmapname); if (newmapnum == 0) { @@ -1925,11 +1891,6 @@ static void Command_Map_f(void) return; } - if (usemapcode) - { - realmapname = G_BuildMapTitle(newmapnum); - } - if (mustmodifygame && option_force) { G_SetGameModified(false); @@ -2209,6 +2170,8 @@ static void Got_Pause(UINT8 **cp, INT32 playernum) else S_ResumeAudio(); } + + I_UpdateMouseGrab(); } // Command for stuck characters in netgames, griefing, etc. @@ -3745,7 +3708,7 @@ static void CoopStarposts_OnChange(void) { INT32 i; - if (!(netgame || multiplayer) || gametype != GT_COOP) + if (!(netgame || multiplayer) || !G_GametypeUsesCoopStarposts()) return; switch (cv_coopstarposts.value) @@ -3800,7 +3763,7 @@ static void CoopLives_OnChange(void) { INT32 i; - if (!(netgame || multiplayer) || gametype != GT_COOP) + if (!(netgame || multiplayer) || !G_GametypeUsesCoopLives()) return; switch (cv_cooplives.value) diff --git a/src/dehacked.c b/src/dehacked.c index b77939c2a..161a41c46 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4804,11 +4804,13 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) if (introchanged) { menuactive = false; + I_UpdateMouseGrab(); COM_BufAddText("playintro"); } else if (titlechanged) { menuactive = false; + I_UpdateMouseGrab(); COM_BufAddText("exitgame"); // Command_ExitGame_f() but delayed } } @@ -8824,9 +8826,11 @@ static const char *const MOBJEFLAG_LIST[] = { "JUSTSTEPPEDDOWN", // used for ramp sectors "VERTICALFLIP", // Vertically flip sprite/allow upside-down physics "GOOWATER", // Goo water + "TOUCHLAVA", // The mobj is touching a lava block "PUSHED", // Mobj was already pushed this tic "SPRUNG", // Mobj was already sprung this tic "APPLYPMOMZ", // Platform movement + "TRACERANGLE", // Compute and trigger on mobj angle relative to tracer NULL }; @@ -8902,32 +8906,35 @@ static const char *const GAMETYPERULE_LIST[] = { "CAMPAIGN", "RINGSLINGER", "SPECTATORS", - "FRIENDLYFIRE", "LIVES", "TEAMS", + "FIRSTPERSON", + "POWERSTONES", + "TEAMFLAGS", + "FRIENDLY", + "SPECIALSTAGES", + "EMERALDTOKENS", + "EMERALDHUNT", "RACE", "TAG", "POINTLIMIT", "TIMELIMIT", - "HIDETIME", + "OVERTIME", + "HURTMESSAGES", + "FRIENDLYFIRE", + "STARTCOUNTDOWN", "HIDEFROZEN", "BLINDFOLDED", - "FIRSTPERSON", - "MATCHEMERALDS", - "TEAMFLAGS", + "RESPAWNDELAY", "PITYSHIELD", "DEATHPENALTY", "NOSPECTATORSPAWN", "DEATHMATCHSTARTS", - "SPECIALSTAGES", - "EMERALDTOKENS", - "EMERALDHUNT", + "SPAWNINVUL", "SPAWNENEMIES", "ALLOWEXIT", "NOTITLECARD", - "OVERTIME", - "HURTMESSAGES", - "SPAWNINVUL", + "CUTSCENES", NULL }; @@ -9744,6 +9751,7 @@ struct { {"CV_HIDEN",CV_HIDEN}, {"CV_HIDDEN",CV_HIDEN}, {"CV_CHEAT",CV_CHEAT}, + {"CV_NOLUA",CV_NOLUA}, // v_video flags {"V_NOSCALEPATCH",V_NOSCALEPATCH}, diff --git a/src/djgppdos/i_video.c b/src/djgppdos/i_video.c index 56570b7bf..02c7a842b 100644 --- a/src/djgppdos/i_video.c +++ b/src/djgppdos/i_video.c @@ -338,3 +338,8 @@ void I_StartupGraphics(void) graphics_started = true; } + +void I_StartupHardwareGraphics(void) +{ + // oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo y +} diff --git a/src/djgppdos/vid_vesa.c b/src/djgppdos/vid_vesa.c index ec7b8b886..c8ce7dae5 100644 --- a/src/djgppdos/vid_vesa.c +++ b/src/djgppdos/vid_vesa.c @@ -378,6 +378,11 @@ INT32 VID_SetMode (INT32 modenum) //, UINT8 *palette) return 1; } +void VID_CheckRenderer(void) +{ + // .............. +} + // converts a segm:offs 32bit pair to a 32bit flat ptr diff --git a/src/doomdef.h b/src/doomdef.h index e6d3f1cee..51495eba3 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -130,6 +130,9 @@ extern FILE *logstream; extern char logfilename[1024]; #endif +/* A mod name to further distinguish versions. */ +#define SRB2APPLICATION "SRB2" + //#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3 #ifdef DEVELOP #define VERSION 0 // Game version @@ -461,6 +464,8 @@ extern void *(*M_Memcpy)(void* dest, const void* src, size_t n) FUNCNONNULL; char *va(const char *format, ...) FUNCPRINTF; char *M_GetToken(const char *inputString); void M_UnGetToken(void); +UINT32 M_GetTokenPos(void); +void M_SetTokenPos(UINT32 newPos); char *sizeu1(size_t num); char *sizeu2(size_t num); char *sizeu3(size_t num); @@ -623,6 +628,9 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// \note Required for proper collision with moving sloped surfaces that have sector specials on them. #define SECTORSPECIALSAFTERTHINK +/// Cache patches in Lua in a way that renderer switching will work flawlessly. +//#define LUA_PATCH_SAFETY + /// Sprite rotation #define ROTSPRITE #define ROTANGLES 72 // Needs to be a divisor of 360 (45, 60, 90, 120...) diff --git a/src/doomstat.h b/src/doomstat.h index b7bb7a362..6d1d6eb36 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -397,32 +397,35 @@ enum GameTypeRules GTR_CAMPAIGN = 1, // Linear Co-op map progression, don't allow random maps GTR_RINGSLINGER = 1<<1, // Outside of Co-op, Competition, and Race (overriden by cv_ringslinger) GTR_SPECTATORS = 1<<2, // Outside of Co-op, Competition, and Race - GTR_FRIENDLYFIRE = 1<<3, // Always allow friendly fire - GTR_LIVES = 1<<4, // Co-op and Competition - GTR_TEAMS = 1<<5, // Team Match, CTF - GTR_RACE = 1<<6, // Race and Competition - GTR_TAG = 1<<7, // Tag and Hide and Seek - GTR_POINTLIMIT = 1<<8, // Ringslinger point limit - GTR_TIMELIMIT = 1<<9, // Ringslinger time limit - GTR_HIDETIME = 1<<10, // Hide time (Tag and Hide and Seek) - GTR_HIDEFROZEN = 1<<11, // Frozen after hide time (Hide and Seek, but not Tag) - GTR_BLINDFOLDED = 1<<12, // Blindfolded view (Tag and Hide and Seek) - GTR_FIRSTPERSON = 1<<13, // First person camera - GTR_MATCHEMERALDS = 1<<14, // Ringslinger emeralds (Match and CTF) - GTR_TEAMFLAGS = 1<<15, // Gametype has team flags (CTF) - GTR_PITYSHIELD = 1<<16, // Award pity shield - GTR_DEATHPENALTY = 1<<17, // Death score penalty - GTR_NOSPECTATORSPAWN = 1<<18, // Use with GTR_SPECTATORS, spawn in the map instead of with the spectators - GTR_DEATHMATCHSTARTS = 1<<19, // Use deathmatch starts - GTR_SPECIALSTAGES = 1<<20, // Allow special stages - GTR_EMERALDTOKENS = 1<<21, // Spawn emerald tokens - GTR_EMERALDHUNT = 1<<22, // Emerald Hunt - GTR_SPAWNENEMIES = 1<<23, // Spawn enemies - GTR_ALLOWEXIT = 1<<24, // Allow exit sectors - GTR_NOTITLECARD = 1<<25, // Don't show the title card - GTR_OVERTIME = 1<<26, // Allow overtime - GTR_HURTMESSAGES = 1<<27, // Hit and death messages - GTR_SPAWNINVUL = 1<<28, // Babysitting deterrent + GTR_LIVES = 1<<3, // Co-op and Competition + GTR_TEAMS = 1<<4, // Team Match, CTF + GTR_FIRSTPERSON = 1<<5, // First person camera + GTR_POWERSTONES = 1<<6, // Power stones (Match and CTF) + GTR_TEAMFLAGS = 1<<7, // Gametype has team flags (CTF) + GTR_FRIENDLY = 1<<8, // Co-op + GTR_SPECIALSTAGES = 1<<9, // Allow special stages + GTR_EMERALDTOKENS = 1<<10, // Spawn emerald tokens + GTR_EMERALDHUNT = 1<<11, // Emerald Hunt + GTR_RACE = 1<<12, // Race and Competition + GTR_TAG = 1<<13, // Tag and Hide and Seek + GTR_POINTLIMIT = 1<<14, // Ringslinger point limit + GTR_TIMELIMIT = 1<<15, // Ringslinger time limit + GTR_OVERTIME = 1<<16, // Allow overtime + GTR_HURTMESSAGES = 1<<17, // Hit and death messages + GTR_FRIENDLYFIRE = 1<<18, // Always allow friendly fire + GTR_STARTCOUNTDOWN = 1<<19, // Hide time countdown (Tag and Hide and Seek) + GTR_HIDEFROZEN = 1<<20, // Frozen after hide time (Hide and Seek, but not Tag) + GTR_BLINDFOLDED = 1<<21, // Blindfolded view (Tag and Hide and Seek) + GTR_RESPAWNDELAY = 1<<22, // Respawn delay + GTR_PITYSHIELD = 1<<23, // Award pity shield + GTR_DEATHPENALTY = 1<<24, // Death score penalty + GTR_NOSPECTATORSPAWN = 1<<25, // Use with GTR_SPECTATORS, spawn in the map instead of with the spectators + GTR_DEATHMATCHSTARTS = 1<<26, // Use deathmatch starts + GTR_SPAWNINVUL = 1<<27, // Babysitting deterrent + GTR_SPAWNENEMIES = 1<<28, // Spawn enemies + GTR_ALLOWEXIT = 1<<29, // Allow exit sectors + GTR_NOTITLECARD = 1<<30, // Don't show the title card + GTR_CUTSCENES = 1<<31, // Play cutscenes, ending, credits, and evaluation }; // String names for gametypes diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c index a3fe3077c..5c0f7eb99 100644 --- a/src/dummy/i_system.c +++ b/src/dummy/i_system.c @@ -150,6 +150,8 @@ void I_GetJoystick2Events(void){} void I_GetMouseEvents(void){} +void I_UpdateMouseGrab(void){} + char *I_GetEnv(const char *name) { (void)name; diff --git a/src/dummy/i_video.c b/src/dummy/i_video.c index e167e833f..fafeee000 100644 --- a/src/dummy/i_video.c +++ b/src/dummy/i_video.c @@ -11,6 +11,7 @@ boolean allow_fullscreen = false; consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; void I_StartupGraphics(void){} +void I_StartupHardwareGraphics(void){} void I_ShutdownGraphics(void){} @@ -39,6 +40,11 @@ INT32 VID_SetMode(INT32 modenum) return 0; } +void VID_CheckRenderer(void) +{ + // .............. +} + const char *VID_GetModeName(INT32 modenum) { (void)modenum; diff --git a/src/f_finale.c b/src/f_finale.c index a004b470c..fee6161b7 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -530,78 +530,78 @@ static void F_IntroDrawScene(void) case 0: break; case 1: - background = W_CachePatchName("INTRO1", PU_CACHE); + background = W_CachePatchName("INTRO1", PU_PATCH); break; case 2: - background = W_CachePatchName("INTRO2", PU_CACHE); + background = W_CachePatchName("INTRO2", PU_PATCH); break; case 3: - background = W_CachePatchName("INTRO3", PU_CACHE); + background = W_CachePatchName("INTRO3", PU_PATCH); break; case 4: - background = W_CachePatchName("INTRO4", PU_CACHE); + background = W_CachePatchName("INTRO4", PU_PATCH); break; case 5: if (intro_curtime >= 5*TICRATE) - background = W_CachePatchName("RADAR", PU_CACHE); + background = W_CachePatchName("RADAR", PU_PATCH); else - background = W_CachePatchName("DRAT", PU_CACHE); + background = W_CachePatchName("DRAT", PU_PATCH); break; case 6: - background = W_CachePatchName("INTRO6", PU_CACHE); + background = W_CachePatchName("INTRO6", PU_PATCH); cx = 180; cy = 8; break; case 7: { if (intro_curtime >= 7*TICRATE + ((TICRATE/7)*2)) - background = W_CachePatchName("SGRASS5", PU_CACHE); + background = W_CachePatchName("SGRASS5", PU_PATCH); else if (intro_curtime >= 7*TICRATE + (TICRATE/7)) - background = W_CachePatchName("SGRASS4", PU_CACHE); + background = W_CachePatchName("SGRASS4", PU_PATCH); else if (intro_curtime >= 7*TICRATE) - background = W_CachePatchName("SGRASS3", PU_CACHE); + background = W_CachePatchName("SGRASS3", PU_PATCH); else if (intro_curtime >= 6*TICRATE) - background = W_CachePatchName("SGRASS2", PU_CACHE); + background = W_CachePatchName("SGRASS2", PU_PATCH); else - background = W_CachePatchName("SGRASS1", PU_CACHE); + background = W_CachePatchName("SGRASS1", PU_PATCH); break; } case 8: - background = W_CachePatchName("WATCHING", PU_CACHE); + background = W_CachePatchName("WATCHING", PU_PATCH); break; case 9: - background = W_CachePatchName("ZOOMING", PU_CACHE); + background = W_CachePatchName("ZOOMING", PU_PATCH); break; case 10: break; case 11: - background = W_CachePatchName("INTRO5", PU_CACHE); + background = W_CachePatchName("INTRO5", PU_PATCH); break; case 12: - background = W_CachePatchName("REVENGE", PU_CACHE); + background = W_CachePatchName("REVENGE", PU_PATCH); cx = 208; cy = 8; break; case 13: - background = W_CachePatchName("CONFRONT", PU_CACHE); + background = W_CachePatchName("CONFRONT", PU_PATCH); cy += 48; break; case 14: - background = W_CachePatchName("TAILSSAD", PU_CACHE); + background = W_CachePatchName("TAILSSAD", PU_PATCH); bgxoffs = 144; cx = 8; cy = 8; break; case 15: if (intro_curtime >= 7*TICRATE) - background = W_CachePatchName("SONICDO2", PU_CACHE); + background = W_CachePatchName("SONICDO2", PU_PATCH); else - background = W_CachePatchName("SONICDO1", PU_CACHE); + background = W_CachePatchName("SONICDO1", PU_PATCH); cx = 224; cy = 8; break; case 16: - background = W_CachePatchName("INTRO7", PU_CACHE); + background = W_CachePatchName("INTRO7", PU_PATCH); break; default: break; @@ -631,30 +631,30 @@ static void F_IntroDrawScene(void) S_ChangeMusicInternal("_stjr", false); x = (BASEVIDWIDTH< 6) { - V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH2", PU_CACHE)), aspect); + V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH2", PU_PATCH)), aspect); W_UnlockCachedPatch(patch); } if (finalecount > 10) { - V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH3", PU_CACHE)), aspect); + V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH3", PU_PATCH)), aspect); W_UnlockCachedPatch(patch); } if (finalecount > 14) { - V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH4", PU_CACHE)), aspect); + V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH4", PU_PATCH)), aspect); W_UnlockCachedPatch(patch); } } else if (finalecount-30 < 20) { // Big eggy - background = W_CachePatchName("FEEDIN", PU_CACHE); + background = W_CachePatchName("FEEDIN", PU_PATCH); x = (BASEVIDWIDTH< 4*TICRATE) { // Door is being raised! int ftime = (finalecount-TICRATE/2-4*TICRATE); y -= FixedDiv((ftime*ftime)< 5*TICRATE && timetonext < 6*TICRATE) { if (!(finalecount & 3)) - background = W_CachePatchName("BRITEGG1", PU_CACHE); + background = W_CachePatchName("BRITEGG1", PU_PATCH); else - background = W_CachePatchName("DARKEGG1", PU_CACHE); + background = W_CachePatchName("DARKEGG1", PU_PATCH); V_DrawSmallScaledPatch(0, 0, 0, background); } else if (timetonext > 3*TICRATE && timetonext < 4*TICRATE) { if (!(finalecount & 3)) - background = W_CachePatchName("BRITEGG2", PU_CACHE); + background = W_CachePatchName("BRITEGG2", PU_PATCH); else - background = W_CachePatchName("DARKEGG2", PU_CACHE); + background = W_CachePatchName("DARKEGG2", PU_PATCH); V_DrawSmallScaledPatch(0, 0, 0, background); } else if (timetonext > 1*TICRATE && timetonext < 2*TICRATE) { if (!(finalecount & 3)) - background = W_CachePatchName("BRITEGG3", PU_CACHE); + background = W_CachePatchName("BRITEGG3", PU_PATCH); else - background = W_CachePatchName("DARKEGG3", PU_CACHE); + background = W_CachePatchName("DARKEGG3", PU_PATCH); V_DrawSmallScaledPatch(0, 0, 0, background); } @@ -768,79 +768,79 @@ static void F_IntroDrawScene(void) knucklesx += sonicx; sonicx += P_ReturnThrustX(NULL, finalecount * ANG10, 3); - V_DrawSmallScaledPatch(skyx, 0, 0, (patch = W_CachePatchName("INTROSKY", PU_CACHE))); + V_DrawSmallScaledPatch(skyx, 0, 0, (patch = W_CachePatchName("INTROSKY", PU_PATCH))); V_DrawSmallScaledPatch(skyx - 320, 0, 0, patch); W_UnlockCachedPatch(patch); - V_DrawSmallScaledPatch(grassx, 0, 0, (patch = W_CachePatchName("INTROGRS", PU_CACHE))); + V_DrawSmallScaledPatch(grassx, 0, 0, (patch = W_CachePatchName("INTROGRS", PU_PATCH))); V_DrawSmallScaledPatch(grassx - 320, 0, 0, patch); W_UnlockCachedPatch(patch); if (finalecount & 1) { // Sonic - V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN2", PU_CACHE))); + V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN2", PU_PATCH))); W_UnlockCachedPatch(patch); // Appendages if (finalecount & 2) { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT4", PU_CACHE))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT4", PU_PATCH))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_CACHE))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH))); W_UnlockCachedPatch(patch); } else { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT2", PU_CACHE))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT2", PU_PATCH))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_CACHE))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH))); W_UnlockCachedPatch(patch); } // Tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY2", PU_CACHE))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY2", PU_PATCH))); W_UnlockCachedPatch(patch); // Knuckles - V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE2", PU_CACHE))); + V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE2", PU_PATCH))); W_UnlockCachedPatch(patch); } else { // Sonic - V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN1", PU_CACHE))); + V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN1", PU_PATCH))); W_UnlockCachedPatch(patch); // Appendages if (finalecount & 2) { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT3", PU_CACHE))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT3", PU_PATCH))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_CACHE))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH))); W_UnlockCachedPatch(patch); } else { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT1", PU_CACHE))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT1", PU_PATCH))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_CACHE))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH))); W_UnlockCachedPatch(patch); } // Tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY1", PU_CACHE))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY1", PU_PATCH))); W_UnlockCachedPatch(patch); // Knuckles - V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE1", PU_CACHE))); + V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE1", PU_PATCH))); W_UnlockCachedPatch(patch); } @@ -873,8 +873,8 @@ static void F_IntroDrawScene(void) y += (30*(FRACUNIT-scale)); } - rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (worktics % 35)), PU_LEVEL); - glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(worktics & 1)), PU_LEVEL); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (worktics % 35)), PU_PATCH); + glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(worktics & 1)), PU_PATCH); if (worktics >= 5) trans = (worktics-5)>>1; @@ -988,7 +988,7 @@ void F_IntroDrawer(void) { if (intro_scenenum == 5 && intro_curtime == 5*TICRATE) { - patch_t *radar = W_CachePatchName("RADAR", PU_CACHE); + patch_t *radar = W_CachePatchName("RADAR", PU_PATCH); F_WipeStartScreen(); F_WipeColorFill(31); @@ -1001,7 +1001,7 @@ void F_IntroDrawer(void) } else if (intro_scenenum == 7 && intro_curtime == 6*TICRATE) // Force a wipe here { - patch_t *grass = W_CachePatchName("SGRASS2", PU_CACHE); + patch_t *grass = W_CachePatchName("SGRASS2", PU_PATCH); F_WipeStartScreen(); F_WipeColorFill(31); @@ -1014,7 +1014,7 @@ void F_IntroDrawer(void) } /*else if (intro_scenenum == 12 && intro_curtime == 7*TICRATE) { - patch_t *confront = W_CachePatchName("CONFRONT", PU_CACHE); + patch_t *confront = W_CachePatchName("CONFRONT", PU_PATCH); F_WipeStartScreen(); F_WipeColorFill(31); @@ -1027,7 +1027,7 @@ void F_IntroDrawer(void) }*/ if (intro_scenenum == 15 && intro_curtime == 7*TICRATE) { - patch_t *sdo = W_CachePatchName("SONICDO2", PU_CACHE); + patch_t *sdo = W_CachePatchName("SONICDO2", PU_PATCH); F_WipeStartScreen(); F_WipeColorFill(31); @@ -1359,14 +1359,14 @@ void F_CreditDrawer(void) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Zig Zagz - V_DrawScaledPatch(-16, zagpos, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_CACHE)); - V_DrawScaledPatch(-16, zagpos - 320, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_CACHE)); - V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_CACHE)); - V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos - 320, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_CACHE)); + V_DrawScaledPatch(-16, zagpos, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH)); + V_DrawScaledPatch(-16, zagpos - 320, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH)); + V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH)); + V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos - 320, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH)); // Draw background pictures first for (i = 0; credits_pics[i].patch; i++) - V_DrawSciencePatch(credits_pics[i].x<>1); + V_DrawSciencePatch(credits_pics[i].x<>1); // Dim the background V_DrawFadeScreen(0xFF00, 16); @@ -1574,14 +1574,14 @@ void F_GameEvaluationDrawer(void) if (goodending) { - rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (finalecount % 35)), PU_LEVEL); - glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_LEVEL); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (finalecount % 35)), PU_PATCH); + glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_PATCH); x -= FRACUNIT; } else { rockpat = W_CachePatchName("ROID0000", PU_LEVEL); - glow = W_CachePatchName(va("ENDGLOW%.1d", (finalecount & 1)), PU_LEVEL); + glow = W_CachePatchName(va("ENDGLOW%.1d", (finalecount & 1)), PU_PATCH); } if (finalecount >= 5) @@ -1613,20 +1613,20 @@ void F_GameEvaluationDrawer(void) // if j == 0 - alternate between 0 and 1 // 1 - 1 and 2 // 2 - 2 and not rendered - V_DrawFixedPatch(x+sparkloffs[j-1][0], y+sparkloffs[j-1][1], FRACUNIT, 0, W_CachePatchName(va("ENDSPKL%.1d", (j - ((sparklloop & 1) ? 0 : 1))), PU_LEVEL), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_AQUA, GTC_CACHE)); + V_DrawFixedPatch(x+sparkloffs[j-1][0], y+sparkloffs[j-1][1], FRACUNIT, 0, W_CachePatchName(va("ENDSPKL%.1d", (j - ((sparklloop & 1) ? 0 : 1))), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_AQUA, GTC_CACHE)); } j--; } } else { - patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_LEVEL); + patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_PATCH); V_DrawFixedPatch(x, y, scale, 0, eggrock, colormap[0]); if (trans < 10) V_DrawFixedPatch(x, y, scale, trans< (XTRA_ENDING+2)) + { + sprdef = &skins[skinnum].sprites[SPR2_XTRA]; + // character head, skin specific + sprframe = &sprdef->spriteframes[XTRA_ENDING]; + endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); + sprframe = &sprdef->spriteframes[XTRA_ENDING+1]; + endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); + sprframe = &sprdef->spriteframes[XTRA_ENDING+2]; + endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); + } + else // Show a star if your character doesn't have an ending firework display. (Basically the MISSINGs for this) + { + endfwrk[0] = W_CachePatchName("ENDFWRK3", PU_PATCH); + endfwrk[1] = W_CachePatchName("ENDFWRK4", PU_PATCH); + endfwrk[2] = W_CachePatchName("ENDFWRK5", PU_PATCH); + } + + endbrdr[0] = W_CachePatchName("ENDBRDR2", PU_PATCH); + } + else + { + // eggman, skin nonspecific + endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_PATCH); + endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_PATCH); + endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_PATCH); + + endbrdr[0] = W_CachePatchName("ENDBRDR0", PU_LEVEL); + } +} + +static void F_CacheGoodEnding(void) +{ + endegrk[0] = W_CachePatchName("ENDEGRK2", PU_PATCH); + endegrk[1] = W_CachePatchName("ENDEGRK3", PU_PATCH); + + endglow[0] = W_CachePatchName("ENDGLOW2", PU_PATCH); + endglow[1] = W_CachePatchName("ENDGLOW3", PU_PATCH); + + endxpld[0] = W_CachePatchName("ENDEGRK4", PU_PATCH); +} + void F_StartEnding(void) { G_SetGamestate(GS_ENDING); @@ -1768,7 +1845,7 @@ void F_StartEnding(void) gameaction = ga_nothing; paused = false; CON_ToggleOff(); - S_StopMusic(); + S_StopMusic(); // todo: placeholder S_StopSounds(); finalecount = -10; // what? this totally isn't a hack. why are you asking? @@ -1776,68 +1853,7 @@ void F_StartEnding(void) memset(sparkloffs, 0, sizeof(INT32)*3*2); sparklloop = 0; - endbrdr[1] = W_CachePatchName("ENDBRDR1", PU_LEVEL); - - endegrk[0] = W_CachePatchName("ENDEGRK0", PU_LEVEL); - endegrk[1] = W_CachePatchName("ENDEGRK1", PU_LEVEL); - - endglow[0] = W_CachePatchName("ENDGLOW0", PU_LEVEL); - endglow[1] = W_CachePatchName("ENDGLOW1", PU_LEVEL); - - endbgsp[0] = W_CachePatchName("ENDBGSP0", PU_LEVEL); - endbgsp[1] = W_CachePatchName("ENDBGSP1", PU_LEVEL); - endbgsp[2] = W_CachePatchName("ENDBGSP2", PU_LEVEL); - - endspkl[0] = W_CachePatchName("ENDSPKL0", PU_LEVEL); - endspkl[1] = W_CachePatchName("ENDSPKL1", PU_LEVEL); - endspkl[2] = W_CachePatchName("ENDSPKL2", PU_LEVEL); - - endxpld[0] = W_CachePatchName("ENDXPLD0", PU_LEVEL); - endxpld[1] = W_CachePatchName("ENDXPLD1", PU_LEVEL); - endxpld[2] = W_CachePatchName("ENDXPLD2", PU_LEVEL); - endxpld[3] = W_CachePatchName("ENDXPLD3", PU_LEVEL); - - endescp[0] = W_CachePatchName("ENDESCP0", PU_LEVEL); - endescp[1] = W_CachePatchName("ENDESCP1", PU_LEVEL); - endescp[2] = W_CachePatchName("ENDESCP2", PU_LEVEL); - endescp[3] = W_CachePatchName("ENDESCP3", PU_LEVEL); - endescp[4] = W_CachePatchName("ENDESCP4", PU_LEVEL); - - // so we only need to check once - if ((goodending = ALL7EMERALDS(emeralds))) - { - UINT8 skinnum = players[consoleplayer].skin; - spritedef_t *sprdef; - spriteframe_t *sprframe; - if (skins[skinnum].sprites[SPR2_XTRA].numframes > (XTRA_ENDING+2)) - { - sprdef = &skins[skinnum].sprites[SPR2_XTRA]; - // character head, skin specific - sprframe = &sprdef->spriteframes[XTRA_ENDING]; - endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); - sprframe = &sprdef->spriteframes[XTRA_ENDING+1]; - endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); - sprframe = &sprdef->spriteframes[XTRA_ENDING+2]; - endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); - } - else // Show a star if your character doesn't have an ending firework display. (Basically the MISSINGs for this) - { - endfwrk[0] = W_CachePatchName("ENDFWRK3", PU_LEVEL); - endfwrk[1] = W_CachePatchName("ENDFWRK4", PU_LEVEL); - endfwrk[2] = W_CachePatchName("ENDFWRK5", PU_LEVEL); - } - - endbrdr[0] = W_CachePatchName("ENDBRDR2", PU_LEVEL); - } - else - { - // eggman, skin nonspecific - endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_LEVEL); - endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_LEVEL); - endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_LEVEL); - - endbrdr[0] = W_CachePatchName("ENDBRDR0", PU_LEVEL); - } + F_CacheEnding(); } void F_EndingTicker(void) @@ -1853,15 +1869,7 @@ void F_EndingTicker(void) S_ChangeMusicInternal((goodending ? "_endg" : "_endb"), false); if (goodending && finalecount == INFLECTIONPOINT) // time to swap some assets - { - endegrk[0] = W_CachePatchName("ENDEGRK2", PU_LEVEL); - endegrk[1] = W_CachePatchName("ENDEGRK3", PU_LEVEL); - - endglow[0] = W_CachePatchName("ENDGLOW2", PU_LEVEL); - endglow[1] = W_CachePatchName("ENDGLOW3", PU_LEVEL); - - endxpld[0] = W_CachePatchName("ENDEGRK4", PU_LEVEL); - } + F_CacheGoodEnding(); if (++sparklloop == SPARKLLOOPTIME) // time to roll the randomisation again { @@ -1880,10 +1888,17 @@ void F_EndingDrawer(void) INT32 x, y, i, j, parallaxticker; patch_t *rockpat; + if (needpatchrecache) + { + F_CacheEnding(); + if (goodending && finalecount >= INFLECTIONPOINT) // time to swap some assets + F_CacheGoodEnding(); + } + if (!goodending || finalecount < INFLECTIONPOINT) - rockpat = W_CachePatchName("ROID0000", PU_LEVEL); + rockpat = W_CachePatchName("ROID0000", PU_PATCH); else - rockpat = W_CachePatchName(va("ROID00%.2d", 34 - ((finalecount - INFLECTIONPOINT) % 35)), PU_LEVEL); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - ((finalecount - INFLECTIONPOINT) % 35)), PU_PATCH); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); @@ -2367,11 +2382,11 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) if (!scrollxspeed && !scrollyspeed) { - V_DrawPatchFill(W_CachePatchName(patchname, PU_CACHE)); + V_DrawPatchFill(W_CachePatchName(patchname, PU_PATCH)); return; } - pat = W_CachePatchName(patchname, PU_CACHE); + pat = W_CachePatchName(patchname, PU_PATCH); patwidth = SHORT(pat->width); patheight = SHORT(pat->height); @@ -2432,6 +2447,45 @@ else if (strlen(name) <= 6) \ else \ arr[0] = 0; +static void F_CacheTitleScreen(void) +{ + switch(curttmode) + { + case TTMODE_OLD: + case TTMODE_NONE: + ttbanner = W_CachePatchName("TTBANNER", PU_LEVEL); + ttwing = W_CachePatchName("TTWING", PU_LEVEL); + ttsonic = W_CachePatchName("TTSONIC", PU_LEVEL); + ttswave1 = W_CachePatchName("TTSWAVE1", PU_LEVEL); + ttswave2 = W_CachePatchName("TTSWAVE2", PU_LEVEL); + ttswip1 = W_CachePatchName("TTSWIP1", PU_LEVEL); + ttsprep1 = W_CachePatchName("TTSPREP1", PU_LEVEL); + ttsprep2 = W_CachePatchName("TTSPREP2", PU_LEVEL); + ttspop1 = W_CachePatchName("TTSPOP1", PU_LEVEL); + ttspop2 = W_CachePatchName("TTSPOP2", PU_LEVEL); + ttspop3 = W_CachePatchName("TTSPOP3", PU_LEVEL); + ttspop4 = W_CachePatchName("TTSPOP4", PU_LEVEL); + ttspop5 = W_CachePatchName("TTSPOP5", PU_LEVEL); + ttspop6 = W_CachePatchName("TTSPOP6", PU_LEVEL); + ttspop7 = W_CachePatchName("TTSPOP7", PU_LEVEL); + break; + + // don't load alacroix gfx yet; we do that upon first draw. + case TTMODE_ALACROIX: + break; + + case TTMODE_USER: + { + UINT16 i; + lumpnum_t lumpnum; + char lumpname[9]; + + LOADTTGFX(ttuser, curttname, TTMAX_USER) + break; + } + } +} + void F_StartTitleScreen(void) { if (menupres[MN_MAIN].musname[0]) @@ -2493,7 +2547,7 @@ void F_StartTitleScreen(void) camera.x = startpos->x << FRACBITS; camera.y = startpos->y << FRACBITS; camera.subsector = R_PointInSubsector(camera.x, camera.y); - camera.z = camera.subsector->sector->floorheight + ((startpos->options >> ZSHIFT) << FRACBITS); + camera.z = camera.subsector->sector->floorheight + (startpos->z << FRACBITS); camera.angle = (startpos->angle % 360)*ANG1; camera.aiming = 0; } @@ -2528,41 +2582,7 @@ void F_StartTitleScreen(void) demoDelayLeft = demoDelayTime; demoIdleLeft = demoIdleTime; - switch(curttmode) - { - case TTMODE_OLD: - case TTMODE_NONE: - ttbanner = W_CachePatchName("TTBANNER", PU_LEVEL); - ttwing = W_CachePatchName("TTWING", PU_LEVEL); - ttsonic = W_CachePatchName("TTSONIC", PU_LEVEL); - ttswave1 = W_CachePatchName("TTSWAVE1", PU_LEVEL); - ttswave2 = W_CachePatchName("TTSWAVE2", PU_LEVEL); - ttswip1 = W_CachePatchName("TTSWIP1", PU_LEVEL); - ttsprep1 = W_CachePatchName("TTSPREP1", PU_LEVEL); - ttsprep2 = W_CachePatchName("TTSPREP2", PU_LEVEL); - ttspop1 = W_CachePatchName("TTSPOP1", PU_LEVEL); - ttspop2 = W_CachePatchName("TTSPOP2", PU_LEVEL); - ttspop3 = W_CachePatchName("TTSPOP3", PU_LEVEL); - ttspop4 = W_CachePatchName("TTSPOP4", PU_LEVEL); - ttspop5 = W_CachePatchName("TTSPOP5", PU_LEVEL); - ttspop6 = W_CachePatchName("TTSPOP6", PU_LEVEL); - ttspop7 = W_CachePatchName("TTSPOP7", PU_LEVEL); - break; - - // don't load alacroix gfx yet; we do that upon first draw. - case TTMODE_ALACROIX: - break; - - case TTMODE_USER: - { - UINT16 i; - lumpnum_t lumpnum; - char lumpname[9]; - - LOADTTGFX(ttuser, curttname, TTMAX_USER) - break; - } - } + F_CacheTitleScreen(); } static void F_UnloadAlacroixGraphics(SINT8 oldttscale) @@ -2711,6 +2731,9 @@ void F_TitleScreenDrawer(void) if (modeattacking) return; // We likely came here from retrying. Don't do a damn thing. + if (needpatchrecache && (curttmode != TTMODE_ALACROIX)) + F_CacheTitleScreen(); + // Draw that sky! if (curbgcolor >= 0) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); @@ -2734,6 +2757,12 @@ void F_TitleScreenDrawer(void) return; #endif + if (needpatchrecache && (curttmode == TTMODE_ALACROIX)) + { + ttloaded[0] = ttloaded[1] = ttloaded[2] = ttloaded[3] = ttloaded[4] = ttloaded[5] = 0; + F_LoadAlacroixGraphics(activettscale); + } + switch(curttmode) { case TTMODE_OLD: @@ -3681,7 +3710,7 @@ void F_ContinueDrawer(void) V_DrawLevelTitle(x - (V_LevelNameWidth("Continue?")>>1), 16, 0, "Continue?"); // Two stars... - patch = W_CachePatchName("CONTSTAR", PU_CACHE); + patch = W_CachePatchName("CONTSTAR", PU_PATCH); V_DrawScaledPatch(x-32, 160, 0, patch); V_DrawScaledPatch(x+32, 160, 0, patch); @@ -3689,14 +3718,14 @@ void F_ContinueDrawer(void) if (timeleft > 9) { numbuf[7] = '1'; - V_DrawScaledPatch(x - 10, 160, 0, W_CachePatchName(numbuf, PU_CACHE)); + V_DrawScaledPatch(x - 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH)); numbuf[7] = '0'; - V_DrawScaledPatch(x + 10, 160, 0, W_CachePatchName(numbuf, PU_CACHE)); + V_DrawScaledPatch(x + 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH)); } else { numbuf[7] = '0'+timeleft; - V_DrawScaledPatch(x, 160, 0, W_CachePatchName(numbuf, PU_CACHE)); + V_DrawScaledPatch(x, 160, 0, W_CachePatchName(numbuf, PU_PATCH)); } // Draw the continue markers! Show continues. @@ -3723,7 +3752,7 @@ void F_ContinueDrawer(void) } // Spotlight - V_DrawScaledPatch(x, 140, 0, W_CachePatchName("CONTSPOT", PU_CACHE)); + V_DrawScaledPatch(x, 140, 0, W_CachePatchName("CONTSPOT", PU_PATCH)); // warping laser if (continuetime) @@ -3760,7 +3789,7 @@ void F_ContinueDrawer(void) #define drawchar(dx, dy, n) {\ sprdef = &contskins[n]->sprites[cont_spr2[n][0]];\ sprframe = &sprdef->spriteframes[cont_spr2[n][1]];\ - patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_CACHE);\ + patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH);\ V_DrawFixedPatch((dx), (dy), FRACUNIT, (sprframe->flip & (1<scene[scenenum].pichires[picnum]) V_DrawSmallScaledPatch(picxpos, picypos, 0, - W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_CACHE)); + W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH)); else V_DrawScaledPatch(picxpos,picypos, 0, - W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_CACHE)); + W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH)); } if (dofadenow && rendermode != render_none) @@ -4513,10 +4542,10 @@ void F_TextPromptDrawer(void) { if (textprompts[cutnum]->page[scenenum].pichires[picnum]) V_DrawSmallScaledPatch(picxpos, picypos, 0, - W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_CACHE)); + W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH)); else V_DrawScaledPatch(picxpos,picypos, 0, - W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_CACHE)); + W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH)); } // Draw background @@ -4526,7 +4555,7 @@ void F_TextPromptDrawer(void) if (iconlump != LUMPERROR) { INT32 iconx, icony, scale, scaledsize; - patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_CACHE); + patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_PATCH); // scale and center if (patch->width > patch->height) diff --git a/src/g_game.c b/src/g_game.c index e6a28aa41..b4f5d4c64 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1718,6 +1718,7 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver B_BuildTiccmd(player, cmd); } + B_HandleFlightIndicator(player); } if (cv_analog2.value) { @@ -1839,6 +1840,7 @@ void G_DoLoadLevel(boolean resetplayer) titlemapinaction = TITLEMAP_OFF; G_SetGamestate(GS_LEVEL); + I_UpdateMouseGrab(); for (i = 0; i < MAXPLAYERS; i++) { @@ -1854,8 +1856,7 @@ void G_DoLoadLevel(boolean resetplayer) return; } - if (!resetplayer) - P_FindEmerald(); + P_FindEmerald(); displayplayer = consoleplayer; // view the guy you are playing if (!splitscreen && !botingame) @@ -2689,8 +2690,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) // -- DM/Tag/CTF-spectator/etc -- // Order: DM->CTF->Coop - else if ((gametyperules & GTR_DEATHMATCHSTARTS) || gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF - || ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && !(players[playernum].pflags & PF_TAGIT))) + else if ((gametyperules & GTR_DEATHMATCHSTARTS) && !(players[playernum].pflags & PF_TAGIT)) { if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start && !(spawnpoint = G_FindCTFStart(playernum))) // find a CTF start @@ -2891,11 +2891,11 @@ void G_DoReborn(INT32 playernum) if (countdowntimeup || (!(netgame || multiplayer) && gametype == GT_COOP)) resetlevel = true; - else if (gametype == GT_COOP && (netgame || multiplayer) && !G_IsSpecialStage(gamemap)) + else if ((G_GametypeUsesCoopLives() || G_GametypeUsesCoopStarposts()) && (netgame || multiplayer) && !G_IsSpecialStage(gamemap)) { boolean notgameover = true; - if (cv_cooplives.value != 0 && player->lives <= 0) // consider game over first + if (G_GametypeUsesCoopLives() && (cv_cooplives.value != 0 && player->lives <= 0)) // consider game over first { for (i = 0; i < MAXPLAYERS; i++) { @@ -2930,7 +2930,7 @@ void G_DoReborn(INT32 playernum) } } - if (notgameover && cv_coopstarposts.value == 2) + if (G_GametypeUsesCoopStarposts() && (notgameover && cv_coopstarposts.value == 2)) { for (i = 0; i < MAXPLAYERS; i++) { @@ -2965,7 +2965,7 @@ void G_DoReborn(INT32 playernum) } if (!countdowntimeup && (mapheaderinfo[gamemap-1]->levelflags & LF_NORELOAD)) { - P_LoadThingsOnly(); + P_RespawnThings(); for (i = 0; i < MAXPLAYERS; i++) { @@ -3006,7 +3006,7 @@ void G_DoReborn(INT32 playernum) } // restore time in netgame (see also p_setup.c) - if ((netgame || multiplayer) && gametype == GT_COOP && cv_coopstarposts.value == 2) + if ((netgame || multiplayer) && G_GametypeUsesCoopStarposts() && cv_coopstarposts.value == 2) { // is this a hack? maybe tic_t maxstarposttime = 0; @@ -3077,7 +3077,7 @@ void G_AddPlayer(INT32 playernum) if (!players[i].exiting) notexiting++; - if (!(cv_coopstarposts.value && (gametype == GT_COOP) && (p->starpostnum < players[i].starpostnum))) + if (!(cv_coopstarposts.value && G_GametypeUsesCoopStarposts() && (p->starpostnum < players[i].starpostnum))) continue; p->starpostscale = players[i].starpostscale; @@ -3194,24 +3194,24 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Co-op - GTR_CAMPAIGN|GTR_LIVES|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, + GTR_CAMPAIGN|GTR_LIVES|GTR_FRIENDLY|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES|GTR_CUTSCENES, // Competition GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_SPAWNINVUL|GTR_ALLOWEXIT, // Race GTR_RACE|GTR_SPAWNENEMIES|GTR_SPAWNINVUL|GTR_ALLOWEXIT, // Match - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_SPAWNINVUL|GTR_PITYSHIELD|GTR_DEATHPENALTY, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_POWERSTONES|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD|GTR_DEATHPENALTY, // Team Match - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_SPAWNINVUL|GTR_PITYSHIELD, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD, // Tag - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_SPAWNINVUL, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_STARTCOUNTDOWN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY, // Hide and Seek - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_SPAWNINVUL, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_STARTCOUNTDOWN|GTR_BLINDFOLDED|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY, // CTF - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_TEAMFLAGS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_SPAWNINVUL|GTR_PITYSHIELD, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_TEAMFLAGS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_POWERSTONES|GTR_DEATHMATCHSTARTS|GTR_SPAWNINVUL|GTR_RESPAWNDELAY|GTR_PITYSHIELD, }; // @@ -3252,50 +3252,68 @@ INT16 G_AddGametype(UINT32 rules) // void G_AddGametypeConstant(INT16 gtype, const char *newgtconst) { - char *gtconst = Z_Malloc(strlen(newgtconst) + 3, PU_STATIC, NULL); - // Copy GT_ and the gametype name. - strcpy(gtconst, "GT_"); - strcat(gtconst, newgtconst); + size_t r = 0; // read + size_t w = 0; // write + char *gtconst = Z_Calloc(strlen(newgtconst) + 3, PU_STATIC, NULL); + char *tmpconst = Z_Calloc(strlen(newgtconst), PU_STATIC, NULL); + + // Copy the gametype name. + strcpy(tmpconst, newgtconst); + // Make uppercase. - strupr(gtconst); - // Remove characters. -#define REMOVECHAR(chr) \ - { \ - char *chrfind = strchr(gtconst, chr); \ - while (chrfind) \ - { \ - *chrfind = '_'; \ - chrfind = strchr(chrfind, chr); \ - } \ + strupr(tmpconst); + + // Prepare to write the new constant string now. + strcpy(gtconst, "GT_"); + + // Remove characters that will not be allowed in the constant string. + for (; r < strlen(tmpconst); r++) + { + boolean writechar = true; + char rc = tmpconst[r]; + switch (rc) + { + // Space, at sign and question mark + case ' ': + case '@': + case '?': + // Used for operations + case '+': + case '-': + case '*': + case '/': + case '%': + case '^': + case '&': + case '!': + // Part of Lua's syntax + case '#': + case '=': + case '~': + case '<': + case '>': + case '(': + case ')': + case '{': + case '}': + case '[': + case ']': + case ':': + case ';': + case ',': + case '.': + writechar = false; + break; + } + if (writechar) + { + gtconst[3 + w] = rc; + w++; + } } - // Space - REMOVECHAR(' ') - // Used for operations - REMOVECHAR('+') - REMOVECHAR('-') - REMOVECHAR('*') - REMOVECHAR('/') - REMOVECHAR('%') - REMOVECHAR('^') - // Part of Lua's syntax - REMOVECHAR('#') - REMOVECHAR('=') - REMOVECHAR('~') - REMOVECHAR('<') - REMOVECHAR('>') - REMOVECHAR('(') - REMOVECHAR(')') - REMOVECHAR('{') - REMOVECHAR('}') - REMOVECHAR('[') - REMOVECHAR(']') - REMOVECHAR(':') - REMOVECHAR(';') - REMOVECHAR(',') - REMOVECHAR('.') - -#undef REMOVECHAR + // Free the temporary string. + Z_Free(tmpconst); // Finally, set the constant string. Gametype_ConstantNames[gtype] = gtconst; @@ -3398,7 +3416,7 @@ INT32 G_GetGametypeByName(const char *gametypestr) { INT32 i; - for (i = 0; i < NUMGAMETYPES; i++) + for (i = 0; i < gametypecount; i++) if (!stricmp(gametypestr, Gametype_Names[i])) return i; @@ -3440,6 +3458,28 @@ boolean G_GametypeUsesLives(void) return false; } +// +// G_GametypeUsesCoopLives +// +// Returns true if the current gametype uses +// the cooplives CVAR. False otherwise. +// +boolean G_GametypeUsesCoopLives(void) +{ + return (gametyperules & (GTR_LIVES|GTR_FRIENDLY)) == (GTR_LIVES|GTR_FRIENDLY); +} + +// +// G_GametypeUsesCoopStarposts +// +// Returns true if the current gametype uses +// the coopstarposts CVAR. False otherwise. +// +boolean G_GametypeUsesCoopStarposts(void) +{ + return (gametyperules & GTR_FRIENDLY); +} + // // G_GametypeHasTeams // @@ -3493,6 +3533,16 @@ boolean G_TagGametype(void) return (gametyperules & GTR_TAG); } +// +// G_CompetitionGametype +// +// For gametypes that are race gametypes, and have lives. +// +boolean G_CompetitionGametype(void) +{ + return ((gametyperules & GTR_RACE) && (gametyperules & GTR_LIVES)); +} + /** Get the typeoflevel flag needed to indicate support of a gametype. * In single-player, this always returns TOL_SP. * \param gametype The gametype for which support is desired. @@ -3734,7 +3784,7 @@ void G_AfterIntermission(void) HU_ClearCEcho(); - if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1) // Start a custom cutscene. + if ((gametyperules & GTR_CUTSCENES) && mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1) // Start a custom cutscene. F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false); else { @@ -3844,7 +3894,7 @@ static void G_DoContinued(void) void G_EndGame(void) { // Only do evaluation and credits in coop games. - if (gametype == GT_COOP) + if (gametyperules & GTR_CUTSCENES) { if (nextmap == 1103-1) // end game with ending { @@ -4547,7 +4597,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean automapactive = false; imcontinuing = false; - if (!skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking) // Start a custom cutscene. + if ((gametyperules & GTR_CUTSCENES) && !skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking) // Start a custom cutscene. F_StartCustomCutscene(mapheaderinfo[gamemap-1]->precutscenenum-1, true, resetplayer); else G_DoLoadLevel(resetplayer); @@ -4780,6 +4830,61 @@ void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc) Z_Free(freq); } +INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) +{ + boolean usemapcode = false; + + INT32 newmapnum; + + size_t mapnamelen; + + char *p; + + mapnamelen = strlen(mapname); + + if (mapnamelen == 2)/* maybe two digit code */ + { + if (( newmapnum = M_MapNumber(mapname[0], mapname[1]) )) + usemapcode = true; + } + else if (mapnamelen == 5 && strnicmp(mapname, "MAP", 3) == 0) + { + if (( newmapnum = M_MapNumber(mapname[3], mapname[4]) )) + usemapcode = true; + } + + if (!usemapcode) + { + /* Now detect map number in base 10, which no one asked for. */ + newmapnum = strtol(mapname, &p, 10); + if (*p == '\0')/* we got it */ + { + if (newmapnum < 1 || newmapnum > NUMMAPS) + { + CONS_Alert(CONS_ERROR, M_GetText("Invalid map number %d.\n"), newmapnum); + return 0; + } + usemapcode = true; + } + else + { + newmapnum = G_FindMap(mapname, realmapnamep, NULL, NULL); + } + } + + if (usemapcode) + { + /* we can't check mapheaderinfo for this hahahaha */ + if (W_CheckNumForName(G_BuildMapName(newmapnum)) == LUMPERROR) + return 0; + + if (realmapnamep) + (*realmapnamep) = G_BuildMapTitle(newmapnum); + } + + return newmapnum; +} + // // DEMO RECORDING // @@ -6873,23 +6978,20 @@ void G_AddGhost(char *defdemoname) I_Assert(mthing); { // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling. fixed_t z,f,c; + fixed_t offset = mthing->z << FRACBITS; gh->mo = P_SpawnMobj(mthing->x << FRACBITS, mthing->y << FRACBITS, 0, MT_GHOST); - gh->mo->angle = FixedAngle(mthing->angle*FRACUNIT); + gh->mo->angle = FixedAngle(mthing->angle << FRACBITS); f = gh->mo->floorz; c = gh->mo->ceilingz - mobjinfo[MT_PLAYER].height; if (!!(mthing->options & MTF_AMBUSH) ^ !!(mthing->options & MTF_OBJECTFLIP)) { - z = c; - if (mthing->options >> ZSHIFT) - z -= ((mthing->options >> ZSHIFT) << FRACBITS); + z = c - offset; if (z < f) z = f; } else { - z = f; - if (mthing->options >> ZSHIFT) - z += ((mthing->options >> ZSHIFT) << FRACBITS); + z = f + offset; if (z > c) z = c; } diff --git a/src/g_game.h b/src/g_game.h index 238dd1964..cb51faaca 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -130,6 +130,9 @@ INT32 G_FindMap(const char *query, char **foundmapnamep, mapsearchfreq_t **freqp, INT32 *freqc); void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc); +/* Match map name by search + 2 digit map code or map number. */ +INT32 G_FindMapByNameOrCode(const char *query, char **foundmapnamep); + // XMOD spawning mapthing_t *G_FindCTFStart(INT32 playernum); mapthing_t *G_FindMatchStart(INT32 playernum); @@ -218,11 +221,14 @@ void G_SetGametypeDescription(INT16 gtype, char *descriptiontext, UINT8 leftcolo INT32 G_GetGametypeByName(const char *gametypestr); boolean G_IsSpecialStage(INT32 mapnum); boolean G_GametypeUsesLives(void); +boolean G_GametypeUsesCoopLives(void); +boolean G_GametypeUsesCoopStarposts(void); boolean G_GametypeHasTeams(void); boolean G_GametypeHasSpectators(void); boolean G_RingSlingerGametype(void); boolean G_PlatformGametype(void); boolean G_TagGametype(void); +boolean G_CompetitionGametype(void); boolean G_EnoughPlayersFinished(void); void G_ExitLevel(void); void G_NextLevel(void); diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 9e454bcd5..6f3dd9fbd 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -449,8 +449,12 @@ static poly_t *CutOutSubsecPoly(seg_t *lseg, INT32 count, poly_t *poly) // for each seg of the subsector for (; count--; lseg++) { - //x,y,dx,dy (like a divline) line_t *line = lseg->linedef; + + if (lseg->glseg) + continue; + + //x,y,dx,dy (like a divline) p1.x = FIXED_TO_FLOAT(lseg->side ? line->v2->x : line->v1->x); p1.y = FIXED_TO_FLOAT(lseg->side ? line->v2->y : line->v1->y); p2.x = FIXED_TO_FLOAT(lseg->side ? line->v1->x : line->v2->x); @@ -836,8 +840,10 @@ static INT32 SolveTProblem(void) return 0; CONS_Debug(DBG_RENDER, "Solving T-joins. This may take a while. Please wait...\n"); +#ifdef HWR_LOADING_SCREEN CON_Drawer(); //let the user know what we are doing I_FinishUpdate(); // page flip or blit buffer +#endif numsplitpoly = 0; @@ -964,9 +970,9 @@ void HWR_CreatePlanePolygons(INT32 bspnum) CONS_Debug(DBG_RENDER, "Creating polygons, please wait...\n"); #ifdef HWR_LOADING_SCREEN ls_count = ls_percent = 0; // reset the loading status -#endif CON_Drawer(); //let the user know what we are doing I_FinishUpdate(); // page flip or blit buffer +#endif HWR_ClearPolys(); diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index ea16fb6d7..c47833187 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -764,13 +764,12 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm // CACHING HANDLING // ================================================= -static size_t gr_numtextures; // Texture count +static size_t gr_numtextures = 0; // Texture count static GLTexture_t *gr_textures; // For all textures static GLTexture_t *gr_flats; // For all (texture) flats, as normal flats don't need to be cached void HWR_InitTextureCache(void) { - gr_numtextures = 0; gr_textures = NULL; gr_flats = NULL; } @@ -958,6 +957,9 @@ static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum) { UINT8 *flat; + if (needpatchflush) + W_FlushCachedPatches(); + // setup the texture info #ifdef GLIDE_API_COMPATIBILITY grMipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_64; @@ -983,6 +985,9 @@ void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum) if (flatlumpnum == LUMPERROR) return; + if (needpatchflush) + W_FlushCachedPatches(); + grmip = HWR_GetCachedGLPatch(flatlumpnum)->mipmap; if (!grmip->downloaded && !grmip->grInfo.data) HWR_CacheFlat(grmip, flatlumpnum); @@ -1061,6 +1066,9 @@ static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch) // -----------------+ void HWR_GetPatch(GLPatch_t *gpatch) { + if (needpatchflush) + W_FlushCachedPatches(); + // is it in hardware cache if (!gpatch->mipmap->downloaded && !gpatch->mipmap->grInfo.data) { @@ -1091,6 +1099,9 @@ void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap) { GLMipmap_t *grmip, *newmip; + if (needpatchflush) + W_FlushCachedPatches(); + if (colormap == colormaps || colormap == NULL) { // Load the default (green) color in doom cache (temporary?) AND hardware cache @@ -1216,6 +1227,9 @@ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum) { GLPatch_t *grpatch; + if (needpatchflush) + W_FlushCachedPatches(); + grpatch = HWR_GetCachedGLPatch(lumpnum); if (!grpatch->mipmap->downloaded && !grpatch->mipmap->grInfo.data) @@ -1419,6 +1433,9 @@ void HWR_GetFadeMask(lumpnum_t fademasklumpnum) { GLMipmap_t *grmip; + if (needpatchflush) + W_FlushCachedPatches(); + grmip = HWR_GetCachedGLPatch(fademasklumpnum)->mipmap; if (!grmip->downloaded && !grmip->grInfo.data) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index f93b52590..746f1c9ec 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -980,7 +980,7 @@ void HWR_DrawViewBorder(INT32 clearlines) // top edge if (clearlines > basewindowy - 8) { - patch = W_CachePatchNum(viewborderlump[BRDR_T], PU_CACHE); + patch = W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH); for (x = 0; x < baseviewwidth; x += 8) HWR_DrawPatch(patch, basewindowx + x, basewindowy - 8, 0); @@ -989,7 +989,7 @@ void HWR_DrawViewBorder(INT32 clearlines) // bottom edge if (clearlines > basewindowy + baseviewheight) { - patch = W_CachePatchNum(viewborderlump[BRDR_B], PU_CACHE); + patch = W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH); for (x = 0; x < baseviewwidth; x += 8) HWR_DrawPatch(patch, basewindowx + x, basewindowy + baseviewheight, 0); @@ -998,7 +998,7 @@ void HWR_DrawViewBorder(INT32 clearlines) // left edge if (clearlines > basewindowy) { - patch = W_CachePatchNum(viewborderlump[BRDR_L], PU_CACHE); + patch = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH); for (y = 0; y < baseviewheight && basewindowy + y < clearlines; y += 8) { @@ -1010,7 +1010,7 @@ void HWR_DrawViewBorder(INT32 clearlines) // right edge if (clearlines > basewindowy) { - patch = W_CachePatchNum(viewborderlump[BRDR_R], PU_CACHE); + patch = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH); for (y = 0; y < baseviewheight && basewindowy+y < clearlines; y += 8) { @@ -1022,22 +1022,22 @@ void HWR_DrawViewBorder(INT32 clearlines) // Draw beveled corners. if (clearlines > basewindowy - 8) HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TL], - PU_CACHE), + PU_PATCH), basewindowx - 8, basewindowy - 8, 0); if (clearlines > basewindowy - 8) HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_TR], - PU_CACHE), + PU_PATCH), basewindowx + baseviewwidth, basewindowy - 8, 0); if (clearlines > basewindowy+baseviewheight) HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BL], - PU_CACHE), + PU_PATCH), basewindowx - 8, basewindowy + baseviewheight, 0); if (clearlines > basewindowy + baseviewheight) HWR_DrawPatch(W_CachePatchNum(viewborderlump[BRDR_BR], - PU_CACHE), + PU_PATCH), basewindowx + baseviewwidth, basewindowy + baseviewheight, 0); } diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 3feb4d52e..99a45ee86 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -374,7 +374,6 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_ADST &lspr[NOLIGHT], // SPR_MCRT &lspr[NOLIGHT], // SPR_MCSP - &lspr[NOLIGHT], // SPR_NON2 &lspr[NOLIGHT], // SPR_SALD &lspr[NOLIGHT], // SPR_TRAE &lspr[NOLIGHT], // SPR_TRAI diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 1cfa1a2e8..2ce8c1364 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -556,7 +556,7 @@ static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) if (!M_PointInBox(segbbox,splat->v1.x,splat->v1.y) && !M_PointInBox(segbbox,splat->v2.x,splat->v2.y)) continue; - gpatch = W_CachePatchNum(splat->patch, PU_CACHE); + gpatch = W_CachePatchNum(splat->patch, PU_PATCH); HWR_GetPatch(gpatch); wallVerts[0].x = wallVerts[3].x = FIXED_TO_FLOAT(splat->v1.x); @@ -3404,11 +3404,16 @@ static void HWR_Subsector(size_t num) while (count--) { + + if (!line->glseg #ifdef POLYOBJECTS - if (!line->polyseg) // ignore segs that belong to polyobjects + && !line->polyseg // ignore segs that belong to polyobjects #endif + ) + { HWR_AddLine(line); - line++; + } + line++; } } @@ -6282,7 +6287,13 @@ void HWR_AddCommands(void) void HWR_AddSessionCommands(void) { + static boolean alreadycalled = false; + if (alreadycalled) + return; + CV_RegisterVar(&cv_granisotropicmode); + + alreadycalled = true; } // -------------------------------------------------------------------------- @@ -6315,6 +6326,17 @@ void HWR_Startup(void) HWD.pfnLoadShaders(); } +// -------------------------------------------------------------------------- +// Called after switching to the hardware renderer +// -------------------------------------------------------------------------- +void HWR_Switch(void) +{ + // Set special states from CVARs + HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, cv_grmodellighting.value); + HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, cv_grfogdensity.value); + HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_grfiltermode.value); + HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_granisotropicmode.value); +} // -------------------------------------------------------------------------- // Free resources allocated by the hardware renderer diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index ae2e3230e..844c517c5 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -29,6 +29,7 @@ // Startup & Shutdown the hardware mode renderer void HWR_Startup(void); +void HWR_Switch(void); void HWR_Shutdown(void); void HWR_drawAMline(const fline_t *fl, INT32 color); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index d9801793b..f558b8c0c 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1173,6 +1173,8 @@ void HU_clearChatChars(void) w_chat[i] = 0; // reset this. chat_on = false; c_input = 0; + + I_UpdateMouseGrab(); } #ifndef NONET @@ -1323,6 +1325,7 @@ boolean HU_Responder(event_t *ev) chat_on = false; c_input = 0; // reset input cursor chat_scrollmedown = true; // you hit enter, so you might wanna autoscroll to see what you just sent. :) + I_UpdateMouseGrab(); } else if (c == KEY_ESCAPE || ((c == gamecontrol[gc_talkkey][0] || c == gamecontrol[gc_talkkey][1] @@ -1331,6 +1334,7 @@ boolean HU_Responder(event_t *ev) { chat_on = false; c_input = 0; // reset input cursor + I_UpdateMouseGrab(); } else if ((c == KEY_UPARROW || c == KEY_MOUSEWHEELUP) && chat_scroll > 0 && !OLDCHAT) // CHAT SCROLLING YAYS! { @@ -2117,6 +2121,9 @@ static void HU_DrawDemoInfo(void) // void HU_Drawer(void) { + if (needpatchrecache) + R_ReloadHUDGraphics(); + #ifndef NONET // draw chat string plus cursor if (chat_on) @@ -2434,7 +2441,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I } } - if (G_GametypeUsesLives() && !(gametyperankings[gametype] == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives + if (G_GametypeUsesLives() && !(G_GametypeUsesCoopLives() && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|(greycheck ? V_60TRANS : 0), va("%dx", players[tab[i].num].lives)); else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT) { @@ -2743,7 +2750,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline | (greycheck ? V_TRANSLUCENT : 0) | V_ALLOWLOWERCASE, name); - if (G_GametypeUsesLives() && !(gametyperankings[gametype] == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives + if (G_GametypeUsesLives() && !(G_GametypeUsesCoopLives() && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE, va("%dx", players[tab[i].num].lives)); else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT) V_DrawSmallScaledPatch(x-28, y-4, 0, tagico); diff --git a/src/i_system.h b/src/i_system.h index 2532ba0ee..a60b56310 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -288,6 +288,10 @@ void I_GetJoystick2Events(void); */ void I_GetMouseEvents(void); +/** \brief Checks if the mouse needs to be grabbed +*/ +void I_UpdateMouseGrab(void); + char *I_GetEnv(const char *name); INT32 I_PutEnv(char *variable); diff --git a/src/i_video.h b/src/i_video.h index d8f11fb13..76b984d25 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -44,6 +44,7 @@ extern boolean highcolor; /** \brief setup video mode */ void I_StartupGraphics(void); +void I_StartupHardwareGraphics(void); /** \brief restore old video mode */ @@ -84,6 +85,7 @@ INT32 VID_GetModeForSize(INT32 w, INT32 h); \return currect video mode */ INT32 VID_SetMode(INT32 modenum); +void VID_CheckRenderer(void); /** \brief The VID_GetModeName function diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 695e9367e..2a82ec512 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2854,6 +2854,22 @@ static int lib_gGametypeUsesLives(lua_State *L) return 1; } +static int lib_gGametypeUsesCoopLives(lua_State *L) +{ + //HUDSAFE + INLEVEL + lua_pushboolean(L, G_GametypeUsesCoopLives()); + return 1; +} + +static int lib_gGametypeUsesCoopStarposts(lua_State *L) +{ + //HUDSAFE + INLEVEL + lua_pushboolean(L, G_GametypeUsesCoopStarposts()); + return 1; +} + static int lib_gGametypeHasTeams(lua_State *L) { //HUDSAFE @@ -2894,6 +2910,14 @@ static int lib_gTagGametype(lua_State *L) return 1; } +static int lib_gCompetitionGametype(lua_State *L) +{ + //HUDSAFE + INLEVEL + lua_pushboolean(L, G_CompetitionGametype()); + return 1; +} + static int lib_gTicsToHours(lua_State *L) { tic_t rtic = luaL_checkinteger(L, 1); @@ -3139,11 +3163,14 @@ static luaL_Reg lib[] = { {"G_ExitLevel",lib_gExitLevel}, {"G_IsSpecialStage",lib_gIsSpecialStage}, {"G_GametypeUsesLives",lib_gGametypeUsesLives}, + {"G_GametypeUsesCoopLives",lib_gGametypeUsesCoopLives}, + {"G_GametypeUsesCoopStarposts",lib_gGametypeUsesCoopStarposts}, {"G_GametypeHasTeams",lib_gGametypeHasTeams}, {"G_GametypeHasSpectators",lib_gGametypeHasSpectators}, {"G_RingSlingerGametype",lib_gRingSlingerGametype}, {"G_PlatformGametype",lib_gPlatformGametype}, {"G_TagGametype",lib_gTagGametype}, + {"G_CompetitionGametype",lib_gCompetitionGametype}, {"G_TicsToHours",lib_gTicsToHours}, {"G_TicsToMinutes",lib_gTicsToMinutes}, {"G_TicsToSeconds",lib_gTicsToSeconds}, diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 58e720c85..558540829 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -245,7 +245,7 @@ static int lib_comBufAddText(lua_State *L) return LUA_ErrInvalid(L, "player_t"); if (plr != &players[consoleplayer]) return 0; - COM_BufAddText(va("%s\n", luaL_checkstring(L, 2))); + COM_BufAddTextEx(va("%s\n", luaL_checkstring(L, 2)), COM_SAFE); return 0; } @@ -262,7 +262,7 @@ static int lib_comBufInsertText(lua_State *L) return LUA_ErrInvalid(L, "player_t"); if (plr != &players[consoleplayer]) return 0; - COM_BufInsertText(va("%s\n", luaL_checkstring(L, 2))); + COM_BufInsertTextEx(va("%s\n", luaL_checkstring(L, 2)), COM_SAFE); return 0; } @@ -427,6 +427,26 @@ static int lib_cvRegisterVar(lua_State *L) return 1; } +static int lib_cvFindVar(lua_State *L) +{ + consvar_t *cv; + if (( cv = CV_FindVar(luaL_checkstring(L,1)) )) + { + lua_settop(L,1);/* We only want one argument in the stack. */ + lua_pushlightuserdata(L, cv);/* Now the second value on stack. */ + luaL_getmetatable(L, META_CVAR); + /* + The metatable is the last value on the stack, so this + applies it to the second value, which is the cvar. + */ + lua_setmetatable(L,2); + lua_pushvalue(L,2); + return 1; + } + else + return 0; +} + // CONS_Printf for a single player // Use 'print' in baselib for a global message. static int lib_consPrintf(lua_State *L) @@ -466,6 +486,7 @@ static luaL_Reg lib[] = { {"COM_BufAddText", lib_comBufAddText}, {"COM_BufInsertText", lib_comBufInsertText}, {"CV_RegisterVar", lib_cvRegisterVar}, + {"CV_FindVar", lib_cvFindVar}, {"CONS_Printf", lib_consPrintf}, {NULL, NULL} }; diff --git a/src/lua_hook.h b/src/lua_hook.h index 68efbce93..61e945248 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -20,9 +20,12 @@ enum hook { hook_MapChange, hook_MapLoad, hook_PlayerJoin, + hook_PreThinkFrame, hook_ThinkFrame, + hook_PostThinkFrame, hook_MobjSpawn, hook_MobjCollide, + hook_MobjLineCollide, hook_MobjMoveCollide, hook_TouchSpecial, hook_MobjFuse, @@ -53,6 +56,7 @@ enum hook { hook_IntermissionThinker, hook_TeamSwitch, hook_ViewpointSwitch, + hook_SeenPlayer, hook_MAX // last hook }; @@ -61,12 +65,16 @@ extern const char *const hookNames[]; void LUAh_MapChange(INT16 mapnumber); // Hook for map change (before load) void LUAh_MapLoad(void); // Hook for map load void LUAh_PlayerJoin(int playernum); // Hook for Got_AddPlayer +void LUAh_PreThinkFrame(void); // Hook for frame (before mobj and player thinkers) void LUAh_ThinkFrame(void); // Hook for frame (after mobj and player thinkers) +void LUAh_PostThinkFrame(void); // Hook for frame (at end of tick, ie after overlays, precipitation, specials) boolean LUAh_MobjHook(mobj_t *mo, enum hook which); boolean LUAh_PlayerHook(player_t *plr, enum hook which); #define LUAh_MobjSpawn(mo) LUAh_MobjHook(mo, hook_MobjSpawn) // Hook for P_SpawnMobj by mobj type UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which); +UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which); #define LUAh_MobjCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjCollide) // Hook for PIT_CheckThing by (thing) mobj type +#define LUAh_MobjLineCollide(thing, line) LUAh_MobjLineCollideHook(thing, line, hook_MobjLineCollide) // Hook for PIT_CheckThing by (thing) mobj type #define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type #define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type @@ -97,5 +105,8 @@ void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting void LUAh_IntermissionThinker(void); // Hook for Y_Ticker boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); // Hook for team switching in... uh.... UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); // Hook for spy mode +#ifdef SEENAMES +boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend); // Hook for MT_NAMECHECK +#endif #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 91b4c6992..56a4fa3f7 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -31,9 +31,12 @@ const char *const hookNames[hook_MAX+1] = { "MapChange", "MapLoad", "PlayerJoin", + "PreThinkFrame", "ThinkFrame", + "PostThinkFrame", "MobjSpawn", "MobjCollide", + "MobjLineCollide", "MobjMoveCollide", "TouchSpecial", "MobjFuse", @@ -64,6 +67,7 @@ const char *const hookNames[hook_MAX+1] = { "IntermissionThinker", "TeamSwitch", "ViewpointSwitch", + "SeenPlayer", NULL }; @@ -123,6 +127,7 @@ static int lib_addHook(lua_State *L) // Take a mobjtype enum which this hook is specifically for. case hook_MobjSpawn: case hook_MobjCollide: + case hook_MobjLineCollide: case hook_MobjMoveCollide: case hook_TouchSpecial: case hook_MobjFuse: @@ -182,6 +187,7 @@ static int lib_addHook(lua_State *L) lastp = &mobjthinkerhooks[hook.s.mt]; break; case hook_MobjCollide: + case hook_MobjLineCollide: case hook_MobjMoveCollide: lastp = &mobjcollidehooks[hook.s.mt]; break; @@ -207,6 +213,7 @@ static int lib_addHook(lua_State *L) case hook_PlayerCanDamage: case hook_TeamSwitch: case hook_ViewpointSwitch: + case hook_SeenPlayer: case hook_ShieldSpawn: case hook_ShieldSpecial: lastp = &playerhooks; @@ -411,6 +418,29 @@ void LUAh_PlayerJoin(int playernum) lua_settop(gL, 0); } +// Hook for frame (before mobj and player thinkers) +void LUAh_PreThinkFrame(void) +{ + hook_p hookp; + if (!gL || !(hooksAvailable[hook_PreThinkFrame/8] & (1<<(hook_PreThinkFrame%8)))) + return; + + for (hookp = roothook; hookp; hookp = hookp->next) + { + if (hookp->type != hook_PreThinkFrame) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + if (lua_pcall(gL, 0, 0, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + } + } +} + // Hook for frame (after mobj and player thinkers) void LUAh_ThinkFrame(void) { @@ -434,6 +464,30 @@ void LUAh_ThinkFrame(void) } } + +// Hook for frame (at end of tick, ie after overlays, precipitation, specials) +void LUAh_PostThinkFrame(void) +{ + hook_p hookp; + if (!gL || !(hooksAvailable[hook_PostThinkFrame/8] & (1<<(hook_PostThinkFrame%8)))) + return; + + for (hookp = roothook; hookp; hookp = hookp->next) + { + if (hookp->type != hook_PostThinkFrame) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + if (lua_pcall(gL, 0, 0, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + } + } +} + // Hook for mobj collisions UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) { @@ -513,6 +567,84 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) return shouldCollide; } +UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which) +{ + hook_p hookp; + UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. + if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) + return 0; + + I_Assert(thing->type < NUMMOBJTYPES); + + lua_settop(gL, 0); + + // Look for all generic mobj collision hooks + for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next) + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, thing, META_MOBJ); + LUA_PushUserdata(gL, line, META_LINE); + } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } + lua_pop(gL, 1); + } + + for (hookp = mobjcollidehooks[thing->type]; hookp; hookp = hookp->next) + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, thing, META_MOBJ); + LUA_PushUserdata(gL, line, META_LINE); + } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + return shouldCollide; +} + // Hook for mobj thinkers boolean LUAh_MobjThinker(mobj_t *mo) { @@ -1412,7 +1544,7 @@ UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean return 0; lua_settop(gL, 0); - hud_running = true; + hud_running = true; // local hook for (hookp = playerhooks; hookp; hookp = hookp->next) { @@ -1453,4 +1585,49 @@ UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean return canSwitchView; } +// Hook for MT_NAMECHECK +#ifdef SEENAMES +boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend) +{ + hook_p hookp; + boolean hasSeenPlayer = true; + if (!gL || !(hooksAvailable[hook_SeenPlayer/8] & (1<<(hook_SeenPlayer%8)))) + return 0; + + lua_settop(gL, 0); + hud_running = true; // local hook + + for (hookp = playerhooks; hookp; hookp = hookp->next) + { + if (hookp->type != hook_SeenPlayer) + continue; + + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, seenfriend, META_PLAYER); + } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1) && !lua_toboolean(gL, -1)) + hasSeenPlayer = false; // Hasn't seen player + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + hud_running = false; + + return hasSeenPlayer; +} +#endif // SEENAMES + #endif diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 12ae1b5fc..58af64359 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -36,6 +36,11 @@ static UINT8 hud_enabled[(hud_MAX/8)+1]; static UINT8 hudAvailable; // hud hooks field +#ifdef LUA_PATCH_SAFETY +static patchinfo_t *patchinfo, *patchinfohead; +static int numluapatches; +#endif + // must match enum hud in lua_hud.h static const char *const hud_disable_options[] = { "stagetitle", @@ -256,12 +261,17 @@ static int colormap_get(lua_State *L) static int patch_get(lua_State *L) { +#ifdef LUA_PATCH_SAFETY patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); +#else + patchinfo_t *patch = *((patchinfo_t **)luaL_checkudata(L, 1, META_PATCH)); +#endif enum patch field = luaL_checkoption(L, 2, NULL, patch_opt); // patches are CURRENTLY always valid, expected to be cached with PU_STATIC // this may change in the future, so patch.valid still exists - I_Assert(patch != NULL); + if (!patch) + return LUA_ErrInvalid(L, "patch_t"); switch (field) { @@ -358,8 +368,59 @@ static int libd_patchExists(lua_State *L) static int libd_cachePatch(lua_State *L) { +#ifdef LUA_PATCH_SAFETY + int i; + lumpnum_t lumpnum; + patchinfo_t *luapat; + patch_t *realpatch; + HUDONLY - LUA_PushUserdata(L, W_CachePatchName(luaL_checkstring(L, 1), PU_STATIC), META_PATCH); + + luapat = patchinfohead; + lumpnum = W_CheckNumForName(luaL_checkstring(L, 1)); + if (lumpnum == LUMPERROR) + lumpnum = W_GetNumForName("MISSING"); + + for (i = 0; i < numluapatches; i++) + { + // check if already cached + if (luapat->wadnum == WADFILENUM(lumpnum) && luapat->lumpnum == LUMPNUM(lumpnum)) + { + LUA_PushUserdata(L, luapat, META_PATCH); + return 1; + } + luapat = luapat->next; + if (!luapat) + break; + } + + if (numluapatches > 0) + { + patchinfo->next = Z_Malloc(sizeof(patchinfo_t), PU_STATIC, NULL); + patchinfo = patchinfo->next; + } + else + { + patchinfo = Z_Malloc(sizeof(patchinfo_t), PU_STATIC, NULL); + patchinfohead = patchinfo; + } + + realpatch = W_CachePatchNum(lumpnum, PU_PATCH); + + patchinfo->width = realpatch->width; + patchinfo->height = realpatch->height; + patchinfo->leftoffset = realpatch->leftoffset; + patchinfo->topoffset = realpatch->topoffset; + + patchinfo->wadnum = WADFILENUM(lumpnum); + patchinfo->lumpnum = LUMPNUM(lumpnum); + + LUA_PushUserdata(L, patchinfo, META_PATCH); + numluapatches++; +#else + HUDONLY + LUA_PushUserdata(L, W_CachePatchName(luaL_checkstring(L, 1), PU_PATCH), META_PATCH); +#endif return 1; } @@ -415,7 +476,7 @@ static int libd_getSpritePatch(lua_State *L) return 0; // push both the patch and it's "flip" value - LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_STATIC), META_PATCH); + LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_PATCH), META_PATCH); lua_pushboolean(L, (sprframe->flip & (1<lumppat[angle], PU_STATIC), META_PATCH); + LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_PATCH), META_PATCH); lua_pushboolean(L, (sprframe->flip & (1<wadnum<<16)+luapat->lumpnum, PU_PATCH); +#else patch = *((patch_t **)luaL_checkudata(L, 3, META_PATCH)); + if (!patch) + return LUA_ErrInvalid(L, "patch_t"); +#endif flags = luaL_optinteger(L, 4, 0); if (!lua_isnoneornil(L, 5)) colormap = *((UINT8 **)luaL_checkudata(L, 5, META_COLORMAP)); @@ -540,6 +611,9 @@ static int libd_drawScaled(lua_State *L) fixed_t x, y, scale; INT32 flags; patch_t *patch; +#ifdef LUA_PATCH_SAFETY + patchinfo_t *luapat; +#endif const UINT8 *colormap = NULL; HUDONLY @@ -548,7 +622,14 @@ static int libd_drawScaled(lua_State *L) scale = luaL_checkinteger(L, 3); if (scale < 0) return luaL_error(L, "negative scale"); +#ifdef LUA_PATCH_SAFETY + luapat = *((patchinfo_t **)luaL_checkudata(L, 4, META_PATCH)); + patch = W_CachePatchNum((luapat->wadnum<<16)+luapat->lumpnum, PU_PATCH); +#else patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH)); + if (!patch) + return LUA_ErrInvalid(L, "patch_t"); +#endif flags = luaL_optinteger(L, 5, 0); if (!lua_isnoneornil(L, 6)) colormap = *((UINT8 **)luaL_checkudata(L, 6, META_COLORMAP)); @@ -1047,6 +1128,10 @@ int LUA_HudLib(lua_State *L) { memset(hud_enabled, 0xff, (hud_MAX/8)+1); +#ifdef LUA_PATCH_SAFETY + numluapatches = 0; +#endif + lua_newtable(L); // HUD registry table lua_newtable(L); luaL_register(L, NULL, lib_draw); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 8ad66d04f..309ba86a1 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -134,6 +134,7 @@ enum side_e { side_toptexture, side_bottomtexture, side_midtexture, + side_line, side_sector, side_special, side_repeatcnt, @@ -156,15 +157,13 @@ static const char *const side_opt[] = { enum vertex_e { vertex_valid = 0, vertex_x, - vertex_y, - vertex_z + vertex_y }; static const char *const vertex_opt[] = { "valid", "x", "y", - "z", NULL}; enum ffloor_e { @@ -869,6 +868,9 @@ static int side_get(lua_State *L) case side_midtexture: lua_pushinteger(L, side->midtexture); return 1; + case side_line: + LUA_PushUserdata(L, side->line, META_LINE); + return 1; case side_sector: LUA_PushUserdata(L, side->sector, META_SECTOR); return 1; @@ -902,6 +904,7 @@ static int side_set(lua_State *L) switch(field) { case side_valid: // valid + case side_line: case side_sector: case side_special: case side_text: @@ -965,9 +968,6 @@ static int vertex_get(lua_State *L) case vertex_y: lua_pushfixed(L, vertex->y); return 1; - case vertex_z: - lua_pushfixed(L, vertex->z); - return 1; } return 0; } diff --git a/src/lua_script.c b/src/lua_script.c index 18d9a87c2..eb1afaf09 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -299,9 +299,7 @@ int LUA_PushGlobals(lua_State *L, const char *word) // See the above. int LUA_CheckGlobals(lua_State *L, const char *word) { - if (fastcmp(word, "gametyperules")) - gametyperules = (UINT32)luaL_checkinteger(L, 2); - else if (fastcmp(word, "redscore")) + if (fastcmp(word, "redscore")) redscore = (UINT32)luaL_checkinteger(L, 2); else if (fastcmp(word, "bluescore")) bluescore = (UINT32)luaL_checkinteger(L, 2); diff --git a/src/m_cheat.c b/src/m_cheat.c index bd6eca73a..58bb2962c 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -517,6 +517,7 @@ void Command_Teleport_f(void) if (!starpostnum) // spawnpoints... { mapthing_t *mt; + fixed_t offset; if (starpostpath >= numcoopstarts) { @@ -527,6 +528,7 @@ void Command_Teleport_f(void) mt = playerstarts[starpostpath]; // Given above check, should never be NULL. intx = mt->x<y<z<sector->ceilingheight - ss->sector->floorheight < p->mo->height) @@ -538,17 +540,9 @@ void Command_Teleport_f(void) // Flagging a player's ambush will make them start on the ceiling // Objectflip inverts if (!!(mt->options & MTF_AMBUSH) ^ !!(mt->options & MTF_OBJECTFLIP)) - { - intz = ss->sector->ceilingheight - p->mo->height; - if (mt->options >> ZSHIFT) - intz -= ((mt->options >> ZSHIFT) << FRACBITS); - } + intz = ss->sector->ceilingheight - p->mo->height - offset; else - { - intz = ss->sector->floorheight; - if (mt->options >> ZSHIFT) - intz += ((mt->options >> ZSHIFT) << FRACBITS); - } + intz = ss->sector->floorheight + offset; if (mt->options & MTF_OBJECTFLIP) // flip the player! { @@ -1193,14 +1187,14 @@ void OP_NightsObjectplace(player_t *player) if (cmd->buttons & BT_TOSSFLAG) { UINT16 vertangle = (UINT16)(player->anotherflyangle % 360); - UINT16 newflags, newz; + UINT16 newflags; player->pflags |= PF_ATTACKDOWN; if (!OP_HeightOkay(player, false)) return; mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_NIGHTSBUMPER].doomednum, false); - newz = min((mt->options >> ZSHIFT) - (mobjinfo[MT_NIGHTSBUMPER].height/4), 0); + mt->z = min(mt->z - (mobjinfo[MT_NIGHTSBUMPER].height/4), 0); // height offset: from P_TouchSpecialThing case MT_NIGHTSBUMPER // clockwise @@ -1231,7 +1225,7 @@ void OP_NightsObjectplace(player_t *player) else // forward newflags = 0; - mt->options = (newz << ZSHIFT) | newflags; + mt->options = (mt->z << ZSHIFT) | newflags; // if NiGHTS is facing backwards, orient the Thing angle forwards so that the sprite angle // displays correctly. Backwards movement via the Thing flags is unaffected. @@ -1439,7 +1433,7 @@ void OP_ObjectplaceMovement(player_t *player) else P_SpawnMapThing(mt); - CONS_Printf(M_GetText("Placed object type %d at %d, %d, %d, %d\n"), mt->type, mt->x, mt->y, mt->options>>ZSHIFT, mt->angle); + CONS_Printf(M_GetText("Placed object type %d at %d, %d, %d, %d\n"), mt->type, mt->x, mt->y, mt->z, mt->angle); } } diff --git a/src/m_menu.c b/src/m_menu.c index b3ff8ce71..63ab21438 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -309,6 +309,7 @@ static void M_ChangeControl(INT32 choice); // Video & Sound menu_t OP_VideoOptionsDef, OP_VideoModeDef, OP_ColorOptionsDef; #ifdef HWRENDER +static void M_OpenGLOptionsMenu(void); menu_t OP_OpenGLOptionsDef, OP_OpenGLFogDef; #endif menu_t OP_SoundOptionsDef; @@ -388,6 +389,9 @@ static void M_ResetCvars(void); // Consvar onchange functions static void Newgametype_OnChange(void); +#ifdef HWRENDER +static void Newrenderer_OnChange(void); +#endif static void Dummymares_OnChange(void); // ========================================================================== @@ -412,6 +416,11 @@ CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1]; consvar_t cv_newgametype = {"newgametype", "Co-op", CV_HIDEN|CV_CALL, gametype_cons_t, Newgametype_OnChange, 0, NULL, NULL, 0, 0, NULL}; +#ifdef HWRENDER +consvar_t cv_newrenderer = {"newrenderer", "Software", CV_HIDEN|CV_CALL, cv_renderer_t, Newrenderer_OnChange, 0, NULL, NULL, 0, 0, NULL}; +static int newrenderer_set = 1;/* Software doesn't need confirmation! */ +#endif + static CV_PossibleValue_t serversort_cons_t[] = { {0,"Ping"}, {1,"Modified State"}, @@ -1211,9 +1220,10 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 11}, #endif {IT_STRING | IT_CVAR, NULL, "Vertical Sync", &cv_vidwait, 16}, - #ifdef HWRENDER - {IT_SUBMENU|IT_STRING, NULL, "OpenGL Options...", &OP_OpenGLOptionsDef, 21}, + {IT_STRING | IT_CVAR, NULL, "Renderer", &cv_newrenderer, 21}, +#else + {IT_TRANSTEXT | IT_PAIR, "Renderer", "Software", &cv_renderer, 21}, #endif {IT_HEADER, NULL, "Color Profile", NULL, 30}, @@ -1254,6 +1264,11 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 190}, {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 195}, {IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 200}, + +#ifdef HWRENDER + {IT_HEADER, NULL, "Renderer", NULL, 208}, + {IT_CALL | IT_STRING, NULL, "OpenGL Options...", M_OpenGLOptionsMenu, 214}, +#endif }; static menuitem_t OP_VideoModeMenu[] = @@ -2009,6 +2024,14 @@ menu_t OP_MonitorToggleDef = }; #ifdef HWRENDER +static void M_OpenGLOptionsMenu(void) +{ + if (rendermode == render_opengl) + M_SetupNextMenu(&OP_OpenGLOptionsDef); + else + M_StartMessage(M_GetText("You must be in OpenGL mode\nto access this menu.\n\n(Press a key)\n"), NULL, MM_NOTHING); +} + menu_t OP_OpenGLOptionsDef = DEFAULTMENUSTYLE( MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_OPENGL << 12), "M_VIDEO", OP_OpenGLOptionsMenu, &OP_VideoOptionsDef, 30, 30); @@ -2214,6 +2237,46 @@ static void Newgametype_OnChange(void) } } +#ifdef HWRENDER +static void Newrenderer_AREYOUSURE(INT32 c) +{ + int n; + switch (c) + { + case 'y': + case KEY_ENTER: + n = cv_newrenderer.value; + newrenderer_set |= n; + CV_SetValue(&cv_renderer, n); + break; + default: + CV_StealthSetValue(&cv_newrenderer, cv_renderer.value); + } +} + +static void Newrenderer_OnChange(void) +{ + /* Well this works for now because there's only two options. */ + int n; + n = cv_newrenderer.value; + newrenderer_set |= cv_renderer.value; + if (( newrenderer_set & n )) + CV_SetValue(&cv_renderer, n); + else + { + M_StartMessage( + "The OpenGL renderer is incomplete.\n" + "Some visuals may fail to appear, or\n" + "appear incorrectly.\n" + "Do you still want to switch to it?\n" + "\n" + "(Press 'y' or 'n')", + Newrenderer_AREYOUSURE, MM_YESNO + ); + } +} +#endif/*HWRENDER*/ + void Screenshot_option_Onchange(void) { OP_ScreenshotOptionsMenu[op_screenshot_folder].status = @@ -2814,6 +2877,7 @@ static void M_GoBack(INT32 choice) menuactive = false; wipetypepre = menupres[M_GetYoungestChildMenu()].exitwipe; + I_UpdateMouseGrab(); D_StartTitle(); } else @@ -2920,7 +2984,7 @@ static void M_NextOpt(void) itemOn = 0; else itemOn++; - } while (oldItemOn != itemOn && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_SPACE); + } while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE )); } static void M_PrevOpt(void) @@ -2932,7 +2996,7 @@ static void M_PrevOpt(void) itemOn = currentMenu->numitems - 1; else itemOn--; - } while (oldItemOn != itemOn && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_SPACE); + } while (oldItemOn != itemOn && ( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE )); } // lock out further input in a tic when important buttons are pressed @@ -3158,10 +3222,7 @@ boolean M_Responder(event_t *ev) case KEY_ESCAPE: // Pop up menu if (chat_on) - { HU_clearChatChars(); - chat_on = false; - } else M_StartControlPanel(); return true; @@ -3539,6 +3600,8 @@ void M_ClearMenus(boolean callexitmenufunc) currentMenu = &MainDef; // Not like it matters menuactive = false; hidetitlemap = false; + + I_UpdateMouseGrab(); } // @@ -3566,11 +3629,11 @@ void M_SetupNextMenu(menu_t *menudef) // the curent item can be disabled, // this code go up until an enabled item found - if ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_SPACE) + if (( (currentMenu->menuitems[itemOn].status & IT_TYPE) & IT_SPACE )) { for (i = 0; i < currentMenu->numitems; i++) { - if ((currentMenu->menuitems[i].status & IT_TYPE) != IT_SPACE) + if (!( (currentMenu->menuitems[i].status & IT_TYPE) & IT_SPACE )) { itemOn = i; break; @@ -3654,14 +3717,6 @@ void M_Init(void) quitmsg[QUIT3MSG5] = M_GetText("You'll be back to play soon, though...\n......right?\n\n(Press 'Y' to quit)"); quitmsg[QUIT3MSG6] = M_GetText("Aww, is Egg Rock Zone too\ndifficult for you?\n\n(Press 'Y' to quit)"); -#ifdef HWRENDER - // Permanently hide some options based on render mode - if (rendermode == render_soft) - OP_VideoOptionsMenu[4].status = IT_DISABLED; - else if (rendermode == render_opengl) - OP_ScreenshotOptionsMenu[op_screenshot_colorprofile].status = IT_GRAYEDOUT; -#endif - /* Well the menu sucks for forcing us to have an item set at all if every item just calls the same function, and @@ -3738,19 +3793,19 @@ static void M_DrawThermo(INT32 x, INT32 y, consvar_t *cv) centerlump[1] = W_GetNumForName("M_THERMM"); cursorlump = W_GetNumForName("M_THERMO"); - V_DrawScaledPatch(xx, y, 0, p = W_CachePatchNum(leftlump,PU_CACHE)); + V_DrawScaledPatch(xx, y, 0, p = W_CachePatchNum(leftlump,PU_PATCH)); xx += SHORT(p->width) - SHORT(p->leftoffset); for (i = 0; i < 16; i++) { - V_DrawScaledPatch(xx, y, V_WRAPX, W_CachePatchNum(centerlump[i & 1], PU_CACHE)); + V_DrawScaledPatch(xx, y, V_WRAPX, W_CachePatchNum(centerlump[i & 1], PU_PATCH)); xx += 8; } - V_DrawScaledPatch(xx, y, 0, W_CachePatchNum(rightlump, PU_CACHE)); + V_DrawScaledPatch(xx, y, 0, W_CachePatchNum(rightlump, PU_PATCH)); xx = (cv->value - cv->PossibleValue[0].value) * (15*8) / (cv->PossibleValue[1].value - cv->PossibleValue[0].value); - V_DrawScaledPatch((x + 8) + xx, y, 0, W_CachePatchNum(cursorlump, PU_CACHE)); + V_DrawScaledPatch((x + 8) + xx, y, 0, W_CachePatchNum(cursorlump, PU_PATCH)); } // A smaller 'Thermo', with range given as percents (0-100) @@ -3762,9 +3817,9 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) x = BASEVIDWIDTH - x - SLIDER_WIDTH; - V_DrawScaledPatch(x, y, 0, W_CachePatchName("M_SLIDEL", PU_CACHE)); + V_DrawScaledPatch(x, y, 0, W_CachePatchName("M_SLIDEL", PU_PATCH)); - p = W_CachePatchName("M_SLIDEM", PU_CACHE); + p = W_CachePatchName("M_SLIDEM", PU_PATCH); for (i = 1; i < SLIDER_RANGE; i++) V_DrawScaledPatch (x+i*8, y, 0,p); @@ -3776,11 +3831,11 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) '\x1D' | V_YELLOWMAP, false); } - p = W_CachePatchName("M_SLIDER", PU_CACHE); + p = W_CachePatchName("M_SLIDER", PU_PATCH); V_DrawScaledPatch(x+i*8, y, 0, p); // draw the slider cursor - p = W_CachePatchName("M_SLIDEC", PU_CACHE); + p = W_CachePatchName("M_SLIDEC", PU_PATCH); for (i = 0; cv->PossibleValue[i+1].strvalue; i++); @@ -3833,15 +3888,15 @@ void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines) // draw left side cx = x; cy = y; - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TL], PU_CACHE)); + V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TL], PU_PATCH)); cy += boff; - p = W_CachePatchNum(viewborderlump[BRDR_L], PU_CACHE); + p = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH); for (n = 0; n < boxlines; n++) { V_DrawScaledPatch(cx, cy, V_WRAPY, p); cy += step; } - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BL], PU_CACHE)); + V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BL], PU_PATCH)); // draw middle V_DrawFlatFill(x + boff, y + boff, width*step, boxlines*step, st_borderpatchnum); @@ -3850,23 +3905,23 @@ void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines) cy = y; while (width > 0) { - V_DrawScaledPatch(cx, cy, V_WRAPX, W_CachePatchNum(viewborderlump[BRDR_T], PU_CACHE)); - V_DrawScaledPatch(cx, y + boff + boxlines*step, V_WRAPX, W_CachePatchNum(viewborderlump[BRDR_B], PU_CACHE)); + V_DrawScaledPatch(cx, cy, V_WRAPX, W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH)); + V_DrawScaledPatch(cx, y + boff + boxlines*step, V_WRAPX, W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH)); width--; cx += step; } // draw right side cy = y; - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TR], PU_CACHE)); + V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_TR], PU_PATCH)); cy += boff; - p = W_CachePatchNum(viewborderlump[BRDR_R], PU_CACHE); + p = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH); for (n = 0; n < boxlines; n++) { V_DrawScaledPatch(cx, cy, V_WRAPY, p); cy += step; } - V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BR], PU_CACHE)); + V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BR], PU_PATCH)); */ } @@ -3877,7 +3932,7 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_ patch_t *patch; fixed_t sw, pw; - patch = W_CachePatchName("LSSTATIC", PU_CACHE); + patch = W_CachePatchName("LSSTATIC", PU_PATCH); pw = SHORT(patch->width) - (sw = w*2); //FixedDiv(w, scale); -- for scale FRACUNIT/2 /*if (pw > 0) -- model code for modders providing weird LSSTATIC @@ -3906,15 +3961,15 @@ static void M_DrawSaveLoadBorder(INT32 x,INT32 y) { INT32 i; - V_DrawScaledPatch (x-8,y+7,0,W_CachePatchName("M_LSLEFT",PU_CACHE)); + V_DrawScaledPatch (x-8,y+7,0,W_CachePatchName("M_LSLEFT",PU_PATCH)); for (i = 0;i < 24;i++) { - V_DrawScaledPatch (x,y+7,0,W_CachePatchName("M_LSCNTR",PU_CACHE)); + V_DrawScaledPatch (x,y+7,0,W_CachePatchName("M_LSCNTR",PU_PATCH)); x += 8; } - V_DrawScaledPatch (x,y+7,0,W_CachePatchName("M_LSRGHT",PU_CACHE)); + V_DrawScaledPatch (x,y+7,0,W_CachePatchName("M_LSRGHT",PU_PATCH)); } #endif @@ -3957,10 +4012,10 @@ static void M_DrawMapEmblems(INT32 mapnum, INT32 x, INT32 y) lasttype = curtype; if (emblem->collected) - V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE), + V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); else - V_DrawSmallScaledPatch(x, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); + V_DrawSmallScaledPatch(x, y, 0, W_CachePatchName("NEEDIT", PU_PATCH)); emblem = M_GetLevelEmblems(-1); x -= 12; @@ -3971,7 +4026,7 @@ static void M_DrawMenuTitle(void) { if (currentMenu->menutitlepic) { - patch_t *p = W_CachePatchName(currentMenu->menutitlepic, PU_CACHE); + patch_t *p = W_CachePatchName(currentMenu->menutitlepic, PU_PATCH); if (p->height > 24) // title is larger than normal { @@ -4023,13 +4078,13 @@ static void M_DrawGenericMenu(void) if (currentMenu->menuitems[i].status & IT_CENTER) { patch_t *p; - p = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); + p = W_CachePatchName(currentMenu->menuitems[i].patch, PU_PATCH); V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, y, 0, p); } else { V_DrawScaledPatch(x, y, 0, - W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE)); + W_CachePatchName(currentMenu->menuitems[i].patch, PU_PATCH)); } } /* FALLTHRU */ @@ -4098,7 +4153,7 @@ static void M_DrawGenericMenu(void) case IT_GRAYPATCH: if (currentMenu->menuitems[i].patch && currentMenu->menuitems[i].patch[0]) V_DrawMappedPatch(x, y, 0, - W_CachePatchName(currentMenu->menuitems[i].patch,PU_CACHE), graymap); + W_CachePatchName(currentMenu->menuitems[i].patch,PU_PATCH), graymap); y += LINEHEIGHT; break; case IT_TRANSTEXT: @@ -4132,12 +4187,12 @@ static void M_DrawGenericMenu(void) || ((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == IT_NOTHING)) { V_DrawScaledPatch(currentMenu->x + SKULLXOFF, cursory - 5, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + W_CachePatchName("M_CURSOR", PU_PATCH)); } else { V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + W_CachePatchName("M_CURSOR", PU_PATCH)); V_DrawString(currentMenu->x, cursory, V_YELLOWMAP, currentMenu->menuitems[itemOn].text); } } @@ -4261,7 +4316,18 @@ static void M_DrawGenericScrollMenu(void) } break; case IT_TRANSTEXT: - V_DrawString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text); + switch (currentMenu->menuitems[i].status & IT_TYPE) + { + case IT_PAIR: + V_DrawString(x, y, + V_TRANSLUCENT, currentMenu->menuitems[i].patch); + V_DrawRightAlignedString(BASEVIDWIDTH - x, y, + V_TRANSLUCENT, currentMenu->menuitems[i].text); + break; + default: + V_DrawString(x, y, + V_TRANSLUCENT, currentMenu->menuitems[i].text); + } break; case IT_QUESTIONMARKS: V_DrawString(x, y, V_TRANSLUCENT|V_OLDSPACING, M_CreateSecretMenuOption(currentMenu->menuitems[i].text)); @@ -4275,7 +4341,7 @@ static void M_DrawGenericScrollMenu(void) // DRAW THE SKULL CURSOR V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + W_CachePatchName("M_CURSOR", PU_PATCH)); } static void M_DrawPauseMenu(void) @@ -4396,10 +4462,10 @@ static void M_DrawPauseMenu(void) continue; if (emblem->collected) - V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE), + V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); else - V_DrawSmallScaledPatch(40, 44 + (i*8), 0, W_CachePatchName("NEEDIT", PU_CACHE)); + V_DrawSmallScaledPatch(40, 44 + (i*8), 0, W_CachePatchName("NEEDIT", PU_PATCH)); switch (emblem->type) { @@ -4445,13 +4511,13 @@ static void M_DrawCenteredMenu(void) if (currentMenu->menuitems[i].status & IT_CENTER) { patch_t *p; - p = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); + p = W_CachePatchName(currentMenu->menuitems[i].patch, PU_PATCH); V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, y, 0, p); } else { V_DrawScaledPatch(x, y, 0, - W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE)); + W_CachePatchName(currentMenu->menuitems[i].patch, PU_PATCH)); } } /* FALLTHRU */ @@ -4526,7 +4592,7 @@ static void M_DrawCenteredMenu(void) case IT_GRAYPATCH: if (currentMenu->menuitems[i].patch && currentMenu->menuitems[i].patch[0]) V_DrawMappedPatch(x, y, 0, - W_CachePatchName(currentMenu->menuitems[i].patch,PU_CACHE), graymap); + W_CachePatchName(currentMenu->menuitems[i].patch,PU_PATCH), graymap); y += LINEHEIGHT; break; } @@ -4537,12 +4603,12 @@ static void M_DrawCenteredMenu(void) || ((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == IT_NOTHING)) { V_DrawScaledPatch(x + SKULLXOFF, cursory - 5, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + W_CachePatchName("M_CURSOR", PU_PATCH)); } else { V_DrawScaledPatch(x - V_StringWidth(currentMenu->menuitems[itemOn].text, 0)/2 - 24, cursory, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + W_CachePatchName("M_CURSOR", PU_PATCH)); V_DrawCenteredString(x, cursory, V_YELLOWMAP, currentMenu->menuitems[itemOn].text); } } @@ -4690,7 +4756,7 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt) if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE)) return true; - if (gt > 0 && gt < gametypecount && (mapheaderinfo[mapnum]->typeoflevel & gametypetol[gt])) + if (gt >= 0 && gt < gametypecount && (mapheaderinfo[mapnum]->typeoflevel & gametypetol[gt])) return true; return false; @@ -4786,6 +4852,22 @@ static INT32 M_CountRowsToShowOnPlatter(INT32 gt) return rows; } +// +// M_CacheLevelPlatter +// +// Cache every patch used by the level platter. +// +static void M_CacheLevelPlatter(void) +{ + levselp[0][0] = W_CachePatchName("SLCT1LVL", PU_PATCH); + levselp[0][1] = W_CachePatchName("SLCT2LVL", PU_PATCH); + levselp[0][2] = W_CachePatchName("BLANKLVL", PU_PATCH); + + levselp[1][0] = W_CachePatchName("SLCT1LVW", PU_PATCH); + levselp[1][1] = W_CachePatchName("SLCT2LVW", PU_PATCH); + levselp[1][2] = W_CachePatchName("BLANKLVW", PU_PATCH); +} + // // M_PrepareLevelPlatter // @@ -4935,24 +5017,7 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) } #endif - if (levselp[0][0]) // never going to have some provided but not all, saves individually checking - { - W_UnlockCachedPatch(levselp[0][0]); - W_UnlockCachedPatch(levselp[0][1]); - W_UnlockCachedPatch(levselp[0][2]); - - W_UnlockCachedPatch(levselp[1][0]); - W_UnlockCachedPatch(levselp[1][1]); - W_UnlockCachedPatch(levselp[1][2]); - } - - levselp[0][0] = W_CachePatchName("SLCT1LVL", PU_STATIC); - levselp[0][1] = W_CachePatchName("SLCT2LVL", PU_STATIC); - levselp[0][2] = W_CachePatchName("BLANKLVL", PU_STATIC); - - levselp[1][0] = W_CachePatchName("SLCT1LVW", PU_STATIC); - levselp[1][1] = W_CachePatchName("SLCT2LVW", PU_STATIC); - levselp[1][2] = W_CachePatchName("BLANKLVW", PU_STATIC); + M_CacheLevelPlatter(); return true; } @@ -5173,6 +5238,9 @@ static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, bo if (map <= 0) return; + if (needpatchrecache) + M_CacheLevelPlatter(); + // A 564x100 image of the level as entry MAPxxW if (!(levelselect.rows[row].mapavailable[col])) { @@ -5182,7 +5250,7 @@ static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, bo else { if (W_CheckNumForName(va("%sW", G_BuildMapName(map))) != LUMPERROR) - patch = W_CachePatchName(va("%sW", G_BuildMapName(map)), PU_CACHE); + patch = W_CachePatchName(va("%sW", G_BuildMapName(map)), PU_PATCH); else patch = levselp[1][2]; // don't static to indicate that it's just a normal level @@ -5204,6 +5272,9 @@ static void M_DrawLevelPlatterMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolea if (map <= 0) return; + if (needpatchrecache) + M_CacheLevelPlatter(); + // A 160x100 image of the level as entry MAPxxP if (!(levelselect.rows[row].mapavailable[col])) { @@ -5213,7 +5284,7 @@ static void M_DrawLevelPlatterMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolea else { if (W_CheckNumForName(va("%sP", G_BuildMapName(map))) != LUMPERROR) - patch = W_CachePatchName(va("%sP", G_BuildMapName(map)), PU_CACHE); + patch = W_CachePatchName(va("%sP", G_BuildMapName(map)), PU_PATCH); else patch = levselp[0][2]; // don't static to indicate that it's just a normal level @@ -5273,8 +5344,8 @@ static void M_DrawLevelPlatterRow(UINT8 row, INT32 y) // new menus static void M_DrawRecordAttackForeground(void) { - patch_t *fg = W_CachePatchName("RECATKFG", PU_CACHE); - patch_t *clock = W_CachePatchName("RECCLOCK", PU_CACHE); + patch_t *fg = W_CachePatchName("RECATKFG", PU_PATCH); + patch_t *clock = W_CachePatchName("RECCLOCK", PU_PATCH); angle_t fa; INT32 i; @@ -5312,7 +5383,7 @@ static void M_DrawNightsAttackMountains(void) { static INT32 bgscrollx; INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - patch_t *background = W_CachePatchName(curbgname, PU_CACHE); + patch_t *background = W_CachePatchName(curbgname, PU_PATCH); INT32 x = FixedInt(bgscrollx) % SHORT(background->width); INT32 y = BASEVIDHEIGHT - SHORT(background->height)*2; @@ -5335,16 +5406,16 @@ static void M_DrawNightsAttackBackground(void) INT32 i; // top - patch_t *backtopfg = W_CachePatchName("NTSATKT1", PU_CACHE); - patch_t *fronttopfg = W_CachePatchName("NTSATKT2", PU_CACHE); + patch_t *backtopfg = W_CachePatchName("NTSATKT1", PU_PATCH); + patch_t *fronttopfg = W_CachePatchName("NTSATKT2", PU_PATCH); INT32 backtopwidth = SHORT(backtopfg->width); //INT32 backtopheight = SHORT(backtopfg->height); INT32 fronttopwidth = SHORT(fronttopfg->width); //INT32 fronttopheight = SHORT(fronttopfg->height); // bottom - patch_t *backbottomfg = W_CachePatchName("NTSATKB1", PU_CACHE); - patch_t *frontbottomfg = W_CachePatchName("NTSATKB2", PU_CACHE); + patch_t *backbottomfg = W_CachePatchName("NTSATKB1", PU_PATCH); + patch_t *frontbottomfg = W_CachePatchName("NTSATKB2", PU_PATCH); INT32 backbottomwidth = SHORT(backbottomfg->width); INT32 backbottomheight = SHORT(backbottomfg->height); INT32 frontbottomwidth = SHORT(frontbottomfg->width); @@ -5488,7 +5559,7 @@ static void M_DrawLevelPlatterMenu(void) #if 0 if (levelselect.rows[lsrow].maplist[lscol] > 0) - V_DrawScaledPatch(lsbasex + cursorx-17, lsbasey+50+lsoffs[0], 0, W_CachePatchName("M_CURSOR", PU_CACHE)); + V_DrawScaledPatch(lsbasex + cursorx-17, lsbasey+50+lsoffs[0], 0, W_CachePatchName("M_CURSOR", PU_PATCH)); #endif // handle movement of cursor box @@ -5758,7 +5829,7 @@ static void M_DrawImageDef(void) V_DrawScaledPic(0,0,0,W_GetNumForName(currentMenu->menuitems[itemOn].text)); else { - patch_t *patch = W_CachePatchName(currentMenu->menuitems[itemOn].text,PU_CACHE); + patch_t *patch = W_CachePatchName(currentMenu->menuitems[itemOn].text,PU_PATCH); if (patch->width <= BASEVIDWIDTH) V_DrawScaledPatch(0,0,0,patch); else @@ -5817,6 +5888,27 @@ static void M_AddonsOptions(INT32 choice) #define LOCATIONSTRING1 "Visit \x83SRB2.ORG/MODS\x80 to get & make add-ons!" //#define LOCATIONSTRING2 "Visit \x88SRB2.ORG/MODS\x80 to get & make add-ons!" +static void M_LoadAddonsPatches(void) +{ + addonsp[EXT_FOLDER] = W_CachePatchName("M_FFLDR", PU_PATCH); + addonsp[EXT_UP] = W_CachePatchName("M_FBACK", PU_PATCH); + addonsp[EXT_NORESULTS] = W_CachePatchName("M_FNOPE", PU_PATCH); + addonsp[EXT_TXT] = W_CachePatchName("M_FTXT", PU_PATCH); + addonsp[EXT_CFG] = W_CachePatchName("M_FCFG", PU_PATCH); + addonsp[EXT_WAD] = W_CachePatchName("M_FWAD", PU_PATCH); +#ifdef USE_KART + addonsp[EXT_KART] = W_CachePatchName("M_FKART", PU_PATCH); +#endif + addonsp[EXT_PK3] = W_CachePatchName("M_FPK3", PU_PATCH); + addonsp[EXT_SOC] = W_CachePatchName("M_FSOC", PU_PATCH); + addonsp[EXT_LUA] = W_CachePatchName("M_FLUA", PU_PATCH); + addonsp[NUM_EXT] = W_CachePatchName("M_FUNKN", PU_PATCH); + addonsp[NUM_EXT+1] = W_CachePatchName("M_FSEL", PU_PATCH); + addonsp[NUM_EXT+2] = W_CachePatchName("M_FLOAD", PU_PATCH); + addonsp[NUM_EXT+3] = W_CachePatchName("M_FSRCH", PU_PATCH); + addonsp[NUM_EXT+4] = W_CachePatchName("M_FSAVE", PU_PATCH); +} + static void M_Addons(INT32 choice) { const char *pathname = "."; @@ -5860,30 +5952,7 @@ static void M_Addons(INT32 choice) else dir_on[menudepthleft] = 0; - if (addonsp[0]) // never going to have some provided but not all, saves individually checking - { - size_t i; - for (i = 0; i < NUM_EXT+5; i++) - W_UnlockCachedPatch(addonsp[i]); - } - - addonsp[EXT_FOLDER] = W_CachePatchName("M_FFLDR", PU_STATIC); - addonsp[EXT_UP] = W_CachePatchName("M_FBACK", PU_STATIC); - addonsp[EXT_NORESULTS] = W_CachePatchName("M_FNOPE", PU_STATIC); - addonsp[EXT_TXT] = W_CachePatchName("M_FTXT", PU_STATIC); - addonsp[EXT_CFG] = W_CachePatchName("M_FCFG", PU_STATIC); - addonsp[EXT_WAD] = W_CachePatchName("M_FWAD", PU_STATIC); -#ifdef USE_KART - addonsp[EXT_KART] = W_CachePatchName("M_FKART", PU_STATIC); -#endif - addonsp[EXT_PK3] = W_CachePatchName("M_FPK3", PU_STATIC); - addonsp[EXT_SOC] = W_CachePatchName("M_FSOC", PU_STATIC); - addonsp[EXT_LUA] = W_CachePatchName("M_FLUA", PU_STATIC); - addonsp[NUM_EXT] = W_CachePatchName("M_FUNKN", PU_STATIC); - addonsp[NUM_EXT+1] = W_CachePatchName("M_FSEL", PU_STATIC); - addonsp[NUM_EXT+2] = W_CachePatchName("M_FLOAD", PU_STATIC); - addonsp[NUM_EXT+3] = W_CachePatchName("M_FSRCH", PU_STATIC); - addonsp[NUM_EXT+4] = W_CachePatchName("M_FSAVE", PU_STATIC); + M_LoadAddonsPatches(); MISC_AddonsDef.prevMenu = currentMenu; M_SetupNextMenu(&MISC_AddonsDef); @@ -6023,6 +6092,10 @@ static void M_DrawAddons(void) return; } + // Lactozilla: Load addons menu patches. + if (needpatchrecache) + M_LoadAddonsPatches(); + if (Playing()) V_DrawCenteredString(BASEVIDWIDTH/2, 5, warningflags, "Adding files mid-game may cause problems."); else @@ -6958,13 +7031,13 @@ static void M_DrawEmblemHints(void) if (emblem->collected) { collected = V_GREENMAP; - V_DrawMappedPatch(12, 12+(28*j), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE), + V_DrawMappedPatch(12, 12+(28*j), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); } else { collected = 0; - V_DrawScaledPatch(12, 12+(28*j), 0, W_CachePatchName("NEEDIT", PU_CACHE)); + V_DrawScaledPatch(12, 12+(28*j), 0, W_CachePatchName("NEEDIT", PU_PATCH)); } if (emblem->hint[0]) @@ -7018,11 +7091,29 @@ static tic_t st_time = 0; static patch_t* st_radio[9]; static patch_t* st_launchpad[4]; +static void M_CacheSoundTest(void) +{ + UINT8 i; + char buf[8]; + + STRBUFCPY(buf, "M_RADIOn"); + for (i = 0; i < 9; i++) + { + buf[7] = (char)('0'+i); + st_radio[i] = W_CachePatchName(buf, PU_PATCH); + } + + STRBUFCPY(buf, "M_LPADn"); + for (i = 0; i < 4; i++) + { + buf[6] = (char)('0'+i); + st_launchpad[i] = W_CachePatchName(buf, PU_PATCH); + } +} + static void M_SoundTest(INT32 choice) { INT32 ul = skyRoomMenuTranslations[choice-1]; - UINT8 i; - char buf[8]; soundtestpage = (UINT8)(unlockables[ul].variable); if (!soundtestpage) @@ -7034,23 +7125,7 @@ static void M_SoundTest(INT32 choice) return; } - STRBUFCPY(buf, "M_RADIOn"); - for (i = 0; i < 9; i++) - { - if (st_radio[i]) - W_UnlockCachedPatch(st_radio[i]); - buf[7] = (char)('0'+i); - st_radio[i] = W_CachePatchName(buf, PU_STATIC); - } - - STRBUFCPY(buf, "M_LPADn"); - for (i = 0; i < 4; i++) - { - if (st_launchpad[i]) - W_UnlockCachedPatch(st_launchpad[i]); - buf[6] = (char)('0'+i); - st_launchpad[i] = W_CachePatchName(buf, PU_STATIC); - } + M_CacheSoundTest(); curplaying = NULL; st_time = 0; @@ -7069,6 +7144,9 @@ static void M_DrawSoundTest(void) fixed_t hscale = FRACUNIT/2, vscale = FRACUNIT/2, bounce = 0; UINT8 frame[4] = {0, 0, -1, SKINCOLOR_RUBY}; + if (needpatchrecache) + M_CacheSoundTest(); + // let's handle the ticker first. ideally we'd tick this somewhere else, BUT... if (curplaying) { @@ -7641,6 +7719,17 @@ static INT32 saveSlotSelected = 1; static INT32 loadgamescroll = 0; static UINT8 loadgameoffset = 0; +static void M_CacheLoadGameData(void) +{ + savselp[0] = W_CachePatchName("SAVEBACK", PU_PATCH); + savselp[1] = W_CachePatchName("SAVENONE", PU_PATCH); + savselp[2] = W_CachePatchName("ULTIMATE", PU_PATCH); + + savselp[3] = W_CachePatchName("GAMEDONE", PU_PATCH); + savselp[4] = W_CachePatchName("BLACXLVL", PU_PATCH); + savselp[5] = W_CachePatchName("BLANKLVL", PU_PATCH); +} + static void M_DrawLoadGameData(void) { INT32 i, savetodraw, x, y, hsep = 90; @@ -7649,6 +7738,9 @@ static void M_DrawLoadGameData(void) if (vid.width != BASEVIDWIDTH*vid.dupx) hsep = (hsep*vid.width)/(BASEVIDWIDTH*vid.dupx); + if (needpatchrecache) + M_CacheLoadGameData(); + for (i = -2; i <= 2; i++) { savetodraw = (saveSlotSelected + i + numsaves)%numsaves; @@ -7757,7 +7849,7 @@ static void M_DrawLoadGameData(void) { lumpnum_t lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName((savegameinfo[savetodraw].gamemap) & 8191))); if (lumpnum != LUMPERROR) - patch = W_CachePatchNum(lumpnum, PU_CACHE); + patch = W_CachePatchNum(lumpnum, PU_PATCH); else patch = savselp[5]; } @@ -7813,7 +7905,7 @@ static void M_DrawLoadGameData(void) goto skipbot; colormap = R_GetTranslationColormap(savegameinfo[savetodraw].botskin, charbotskin->prefcolor, 0); sprframe = &sprdef->spriteframes[0]; - patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); V_DrawFixedPatch( tempx + (18<numframes) goto skipsign; sprframe = &sprdef->spriteframes[0]; - patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); V_DrawFixedPatch( tempx, @@ -7859,7 +7951,7 @@ skipsign: if (!sprdef->numframes) goto skiplife; sprframe = &sprdef->spriteframes[0]; - patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); V_DrawFixedPatch( (tempx + 4)< 0) { - V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTSAVE", PU_CACHE)); + V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTSAVE", PU_PATCH)); V_DrawScaledPatch(tempx + 9, y + 2, 0, patch); V_DrawString(tempx + 16, y, 0, va("%d", savegameinfo[savetodraw].continues)); } else { - V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTNONE", PU_CACHE)); - V_DrawScaledPatch(tempx + 9, y + 2, 0, W_CachePatchName("STNONEX", PU_CACHE)); + V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTNONE", PU_PATCH)); + V_DrawScaledPatch(tempx + 9, y + 2, 0, W_CachePatchName("STNONEX", PU_PATCH)); V_DrawString(tempx + 16, y, V_GRAYMAP, "0"); } } @@ -8125,24 +8217,7 @@ static void M_ReadSaveStrings(void) M_ReadSavegameInfo(i); } - if (savselp[0]) // never going to have some provided but not all, saves individually checking - { - W_UnlockCachedPatch(savselp[0]); - W_UnlockCachedPatch(savselp[1]); - W_UnlockCachedPatch(savselp[2]); - - W_UnlockCachedPatch(savselp[3]); - W_UnlockCachedPatch(savselp[4]); - W_UnlockCachedPatch(savselp[5]); - } - - savselp[0] = W_CachePatchName("SAVEBACK", PU_STATIC); - savselp[1] = W_CachePatchName("SAVENONE", PU_STATIC); - savselp[2] = W_CachePatchName("ULTIMATE", PU_STATIC); - - savselp[3] = W_CachePatchName("GAMEDONE", PU_STATIC); - savselp[4] = W_CachePatchName("BLACXLVL", PU_STATIC); - savselp[5] = W_CachePatchName("BLANKLVL", PU_STATIC); + M_CacheLoadGameData(); } // @@ -8322,6 +8397,43 @@ void M_ForceSaveSlotSelected(INT32 sslot) // CHARACTER SELECT // ================ +// lactozilla: sometimes the renderer changes and these patches don't exist anymore +static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum) +{ + if (!(description[i].picname[0])) + { + if (skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CHARSEL) + { + spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; + spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; + description[i].charpic = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); + } + else + description[i].charpic = W_CachePatchName("MISSING", PU_PATCH); + } + else + description[i].charpic = W_CachePatchName(description[i].picname, PU_PATCH); + + if (description[i].nametag[0]) + description[i].namepic = W_CachePatchName(description[i].nametag, PU_PATCH); +} + +static void M_CacheCharacterSelect(void) +{ + INT32 i, skinnum; + + for (i = 0; i < 32; i++) + { + if (!description[i].used) + continue; + + // Already set in M_SetupChoosePlayer + skinnum = description[i].skinnum[0]; + if ((skinnum != -1) && (R_SkinUsable(-1, skinnum))) + M_CacheCharacterSelectEntry(i, skinnum); + } +} + static void M_SetupChoosePlayer(INT32 choice) { INT32 skinnum; @@ -8369,27 +8481,7 @@ static void M_SetupChoosePlayer(INT32 choice) if (i == char_on) allowed = true; - if (!(description[i].picname[0])) - { - if (skins[skinnum].sprites[SPR2_XTRA].numframes > XTRA_CHARSEL) - { - spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; - spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; - description[i].charpic = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); - } - else - description[i].charpic = W_CachePatchName("MISSING", PU_CACHE); - } - else - description[i].charpic = W_CachePatchName(description[i].picname, PU_CACHE); - - if (description[i].nametag[0]) - { - const char *nametag = description[i].nametag; - description[i].namepic = NULL; - if (W_LumpExists(nametag)) - description[i].namepic = W_CachePatchName(nametag, PU_CACHE); - } + M_CacheCharacterSelectEntry(i, skinnum); } // else -- Technically, character select icons without corresponding skins get bundled away behind this too. Sucks to be them. } @@ -8528,8 +8620,8 @@ static void M_DrawSetupChoosePlayerMenu(void) UINT8 *colormap = NULL; INT32 prev = -1, next = -1; - patch_t *charbg = W_CachePatchName("CHARBG", PU_CACHE); - patch_t *charfg = W_CachePatchName("CHARFG", PU_CACHE); + patch_t *charbg = W_CachePatchName("CHARBG", PU_PATCH); + patch_t *charfg = W_CachePatchName("CHARFG", PU_PATCH); INT16 bgheight = SHORT(charbg->height); INT16 fgheight = SHORT(charfg->height); INT16 bgwidth = SHORT(charbg->width); @@ -8537,6 +8629,10 @@ static void M_DrawSetupChoosePlayerMenu(void) INT32 x, y; INT32 w = (vid.width/vid.dupx); + // lactozilla: the renderer changed so recache patches + if (needpatchrecache) + M_CacheCharacterSelect(); + if (abs(char_scroll) > FRACUNIT) char_scroll -= (char_scroll>>2); else // close enough. @@ -8715,7 +8811,7 @@ static void M_DrawSetupChoosePlayerMenu(void) // Alternative menu header #ifdef CHOOSEPLAYER_DRAWHEADER { - patch_t *header = W_CachePatchName("M_PICKP", PU_CACHE); + patch_t *header = W_CachePatchName("M_PICKP", PU_PATCH); INT32 xtitle = 146; INT32 ytitle = (35 - SHORT(header->height))/2; V_DrawFixedPatch(xtitle<collected) - V_DrawSmallMappedPatch(292, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem, false), PU_CACHE), + V_DrawSmallMappedPatch(292, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem, false), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, M_GetExtraEmblemColor(exemblem), GTC_CACHE)); else - V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); + V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_PATCH)); V_DrawString(20, y, V_YELLOWMAP|V_ALLOWLOWERCASE, va("%s", exemblem->description)); } @@ -8964,7 +9060,7 @@ static void M_DrawLevelStats(void) V_DrawString(20, 56, V_GREENMAP, "(complete)"); V_DrawString(36, 64, 0, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems)); - V_DrawSmallScaledPatch(20, 64, 0, W_CachePatchName("EMBLICON", PU_STATIC)); + V_DrawSmallScaledPatch(20, 64, 0, W_CachePatchName("EMBLICON", PU_PATCH)); sprintf(beststr, "%u", bestscore); V_DrawString(BASEVIDWIDTH/2, 48, V_YELLOWMAP, "SCORE:"); @@ -9096,7 +9192,7 @@ void M_DrawTimeAttackMenu(void) } // DRAW THE SKULL CURSOR - V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); + V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, W_CachePatchName("M_CURSOR", PU_PATCH)); V_DrawString(currentMenu->x, cursory, V_YELLOWMAP, currentMenu->menuitems[itemOn].text); // Character face! @@ -9105,10 +9201,10 @@ void M_DrawTimeAttackMenu(void) { spritedef_t *sprdef = &skins[cv_chooseskin.value-1].sprites[SPR2_XTRA]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; - PictureOfUrFace = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + PictureOfUrFace = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); } else - PictureOfUrFace = W_CachePatchName("MISSING", PU_CACHE); + PictureOfUrFace = W_CachePatchName("MISSING", PU_PATCH); if (PictureOfUrFace->width >= 256) V_DrawTinyScaledPatch(224, 120, 0, PictureOfUrFace); @@ -9136,9 +9232,9 @@ void M_DrawTimeAttackMenu(void) lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchName(va("%sP", G_BuildMapName(cv_nextmap.value)), PU_CACHE); + PictureOfLevel = W_CachePatchName(va("%sP", G_BuildMapName(cv_nextmap.value)), PU_PATCH); else - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = W_CachePatchName("BLANKLVL", PU_PATCH); y = 32+lsheadingheight; V_DrawSmallScaledPatch(216, y, 0, PictureOfLevel); @@ -9183,7 +9279,7 @@ void M_DrawTimeAttackMenu(void) goto skipThisOne; } - empatch = W_CachePatchName(M_GetEmblemPatch(em, true), PU_CACHE); + empatch = W_CachePatchName(M_GetEmblemPatch(em, true), PU_PATCH); empatx = SHORT(empatch->leftoffset)/2; empaty = SHORT(empatch->topoffset)/2; @@ -9192,7 +9288,7 @@ void M_DrawTimeAttackMenu(void) V_DrawSmallMappedPatch(104+76+empatx, yHeight+lsheadingheight/2+empaty, 0, empatch, R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); else - V_DrawSmallScaledPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDITL", PU_CACHE)); + V_DrawSmallScaledPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDITL", PU_PATCH)); skipThisOne: em = M_GetLevelEmblems(-1); @@ -9372,7 +9468,7 @@ void M_DrawNightsAttackMenu(void) } // DRAW THE SKULL CURSOR - V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); + V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, W_CachePatchName("M_CURSOR", PU_PATCH)); V_DrawString(currentMenu->x, cursory, V_YELLOWMAP, currentMenu->menuitems[itemOn].text); // Level record list @@ -9396,9 +9492,9 @@ void M_DrawNightsAttackMenu(void) lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchName(va("%sP", G_BuildMapName(cv_nextmap.value)), PU_CACHE); + PictureOfLevel = W_CachePatchName(va("%sP", G_BuildMapName(cv_nextmap.value)), PU_PATCH); else - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = W_CachePatchName("BLANKLVL", PU_PATCH); y = 32+lsheadingheight; V_DrawSmallScaledPatch(208, y, 0, PictureOfLevel); @@ -9470,10 +9566,10 @@ void M_DrawNightsAttackMenu(void) } if (em->collected) - V_DrawSmallMappedPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_CACHE), + V_DrawSmallMappedPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); else - V_DrawSmallScaledPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE)); + V_DrawSmallScaledPatch(xpos, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_PATCH)); skipThisOne: em = M_GetLevelEmblems(-1); @@ -9509,8 +9605,8 @@ static void M_NightsAttack(INT32 choice) // This is really just to make sure Sonic is the played character, just in case M_PatchSkinNameTable(); - ntssupersonic[0] = W_CachePatchName("NTSSONC1", PU_CACHE); - ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_CACHE); + ntssupersonic[0] = W_CachePatchName("NTSSONC1", PU_PATCH); + ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_PATCH); G_SetGamestate(GS_TIMEATTACK); // do this before M_SetupNextMenu so that menu meta state knows that we're switching titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please @@ -9896,7 +9992,7 @@ static void M_DrawRoomMenu(void) static void M_DrawConnectMenu(void) { UINT16 i; - const char *gt = "Unknown"; + char *gt; INT32 numPages = (serverlistcount+(SERVERS_PER_PAGE-1))/SERVERS_PER_PAGE; for (i = FIRSTSERVERLINE; i < min(localservercount, SERVERS_PER_PAGE)+FIRSTSERVERLINE; i++) @@ -9940,14 +10036,17 @@ static void M_DrawConnectMenu(void) V_DrawSmallString(currentMenu->x, S_LINEY(i)+8, globalflags, va("Ping: %u", (UINT32)LONG(serverlist[slindex].info.time))); - gt = "Unknown"; - if (serverlist[slindex].info.gametype < gametypecount) - gt = Gametype_Names[serverlist[slindex].info.gametype]; + gt = serverlist[slindex].info.gametypename; V_DrawSmallString(currentMenu->x+46,S_LINEY(i)+8, globalflags, va("Players: %02d/%02d", serverlist[slindex].info.numberofplayer, serverlist[slindex].info.maxplayer)); - V_DrawSmallString(currentMenu->x+112, S_LINEY(i)+8, globalflags, va("Gametype: %s", gt)); + if (strlen(gt) > 11) + gt = va("Gametype: %.11s...", gt); + else + gt = va("Gametype: %s", gt); + + V_DrawSmallString(currentMenu->x+112, S_LINEY(i)+8, globalflags, gt); MP_ConnectMenu[i+FIRSTSERVERLINE].status = IT_STRING | IT_CALL; } @@ -9988,7 +10087,15 @@ SERVER_LIST_ENTRY_COMPARATOR(time) SERVER_LIST_ENTRY_COMPARATOR(numberofplayer) SERVER_LIST_ENTRY_COMPARATOR_REVERSE(numberofplayer) SERVER_LIST_ENTRY_COMPARATOR_REVERSE(maxplayer) -SERVER_LIST_ENTRY_COMPARATOR(gametype) + +static int ServerListEntryComparator_gametypename(const void *entry1, const void *entry2) +{ + const serverelem_t *sa = (const serverelem_t*)entry1, *sb = (const serverelem_t*)entry2; + int c; + if (( c = strcasecmp(sa->info.gametypename, sb->info.gametypename) )) + return c; + return strcmp(sa->info.servername, sb->info.servername); \ +} // Special one for modified state. static int ServerListEntryComparator_modified(const void *entry1, const void *entry2) @@ -10028,7 +10135,7 @@ void M_SortServerList(void) qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_maxplayer_reverse); break; case 5: // Gametype. - qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametype); + qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename); break; } #endif @@ -10232,9 +10339,9 @@ static void M_DrawServerMenu(void) lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchName(va("%sP", G_BuildMapName(cv_nextmap.value)), PU_CACHE); + PictureOfLevel = W_CachePatchName(va("%sP", G_BuildMapName(cv_nextmap.value)), PU_PATCH); else - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = W_CachePatchName("BLANKLVL", PU_PATCH); V_DrawSmallScaledPatch(319 - (currentMenu->x + (SHORT(PictureOfLevel->width)/2)), currentMenu->y + imgheight, 0, PictureOfLevel); } @@ -10413,15 +10520,78 @@ static void M_HandleConnectIP(INT32 choice) break; case KEY_DEL: - if (setupm_ip[0]) + if (setupm_ip[0] && !shiftdown) // Shift+Delete is used for something else. { S_StartSound(NULL,sfx_menu1); // Tails setupm_ip[0] = 0; } - break; + if (!shiftdown) // Shift+Delete is used for something else. + break; + /* FALLTHRU */ default: l = strlen(setupm_ip); + + if ( ctrldown ) { + switch (choice) { + case 'v': + case 'V': // ctrl+v, pasting + { + const char *paste = I_ClipboardPaste(); + + if (paste != NULL) { + strncat(setupm_ip, paste, 28-1 - l); // Concat the ip field with clipboard + if (strlen(paste) != 0) // Don't play sound if nothing was pasted + S_StartSound(NULL,sfx_menu1); // Tails + } + + break; + } + case KEY_INS: + case 'c': + case 'C': // ctrl+c, ctrl+insert, copying + I_ClipboardCopy(setupm_ip, l); + S_StartSound(NULL,sfx_menu1); // Tails + break; + + case 'x': + case 'X': // ctrl+x, cutting + I_ClipboardCopy(setupm_ip, l); + S_StartSound(NULL,sfx_menu1); // Tails + setupm_ip[0] = 0; + break; + + default: // otherwise do nothing + break; + } + break; // don't check for typed keys + } + + if ( shiftdown ) { + switch (choice) { + case KEY_INS: // shift+insert, pasting + { + const char *paste = I_ClipboardPaste(); + + if (paste != NULL) { + strncat(setupm_ip, paste, 28-1 - l); // Concat the ip field with clipboard + if (strlen(paste) != 0) // Don't play sound if nothing was pasted + S_StartSound(NULL,sfx_menu1); // Tails + } + + break; + } + case KEY_DEL: // shift+delete, cutting + I_ClipboardCopy(setupm_ip, l); + S_StartSound(NULL,sfx_menu1); // Tails + setupm_ip[0] = 0; + break; + default: // otherwise do nothing. + break; + } + break; // don't check for typed keys + } + if (l >= 28-1) break; @@ -10551,7 +10721,7 @@ static void M_DrawSetupMultiPlayerMenu(void) multi_frame = 0; sprframe = &sprdef->spriteframes[multi_frame]; - patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); if (sprframe->flip & 1) // Only for first sprite flags |= V_FLIP; // This sprite is left/right flipped! @@ -10572,7 +10742,7 @@ faildraw: return; // Can't render! sprframe = &sprdef->spriteframes[0]; - patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); if (sprframe->flip & 1) // Only for first sprite flags |= V_FLIP; // This sprite is left/right flipped! @@ -10643,7 +10813,7 @@ colordraw: cursory = y; V_DrawScaledPatch(x - 17, cursory, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + W_CachePatchName("M_CURSOR", PU_PATCH)); } // Handle 1P/2P MP Setup @@ -10969,7 +11139,7 @@ static void M_DrawJoystick(void) if (i == itemOn) { V_DrawScaledPatch(currentMenu->x - 24, OP_JoystickSetDef.y+LINEHEIGHT*i-4, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + W_CachePatchName("M_CURSOR", PU_PATCH)); } } } @@ -11287,7 +11457,7 @@ static void M_DrawControl(void) } V_DrawScaledPatch(currentMenu->x - 20, cursory, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + W_CachePatchName("M_CURSOR", PU_PATCH)); } #undef controlbuffer @@ -11579,7 +11749,7 @@ static void M_DrawVideoMode(void) j = OP_VideoModeDef.y + 14 + ((vidm_selected % vidm_column_size)*8); V_DrawScaledPatch(i - 8, j, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + W_CachePatchName("M_CURSOR", PU_PATCH)); } // Just M_DrawGenericScrollMenu but showing a backing behind the headers. @@ -11707,7 +11877,7 @@ static void M_DrawColorMenu(void) // DRAW THE SKULL CURSOR V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + W_CachePatchName("M_CURSOR", PU_PATCH)); } // special menuitem key handler for video mode list @@ -11785,17 +11955,7 @@ static void M_HandleVideoMode(INT32 ch) static void M_DrawScreenshotMenu(void) { - M_DrawGenericScrollMenu(); -#ifdef HWRENDER - if ((rendermode == render_opengl) && (itemOn < 7)) // where it starts to go offscreen; change this number if you change the layout of the screenshot menu - { - INT32 y = currentMenu->y+currentMenu->menuitems[op_screenshot_colorprofile].alphaKey*2; - if (itemOn == 6) - y -= 10; - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, y, V_REDMAP, "ON"); - } -#endif } // =============== @@ -11880,7 +12040,7 @@ void M_QuitResponse(INT32 ch) ptime = I_GetTime() + NEWTICRATE*2; // Shortened the quit time, used to be 2 seconds Tails 03-26-2001 while (ptime > I_GetTime()) { - V_DrawScaledPatch(0, 0, 0, W_CachePatchName("GAMEQUIT", PU_CACHE)); // Demo 3 Quit Screen Tails 06-16-2001 + V_DrawScaledPatch(0, 0, 0, W_CachePatchName("GAMEQUIT", PU_PATCH)); // Demo 3 Quit Screen Tails 06-16-2001 I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001 I_Sleep(); } diff --git a/src/m_menu.h b/src/m_menu.h index 19858e2fc..48a4ba6f0 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -222,13 +222,14 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); // flags for items in the menu // menu handle (what we do when key is pressed -#define IT_TYPE 14 // (2+4+8) +#define IT_TYPE 15 // (1+2+4+8) #define IT_CALL 0 // call the function +#define IT_SPACE 1 // no handling #define IT_ARROWS 2 // call function with 0 for left arrow and 1 for right arrow in param #define IT_KEYHANDLER 4 // call with the key in param #define IT_SUBMENU 6 // go to sub menu #define IT_CVAR 8 // handle as a cvar -#define IT_SPACE 10 // no handling +#define IT_PAIR 11 // no handling, define both sides of text #define IT_MSGHANDLER 12 // same as key but with event and sometime can handle y/n key (special for message) #define IT_DISPLAY (48+64+128) // 16+32+64+128 diff --git a/src/m_misc.c b/src/m_misc.c index b0a1fb8c5..edb24ab1e 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -1908,6 +1908,20 @@ void M_UnGetToken(void) endPos = oldendPos; } +/** Returns the current token's position. + */ +UINT32 M_GetTokenPos(void) +{ + return endPos; +} + +/** Sets the current token's position. + */ +void M_SetTokenPos(UINT32 newPos) +{ + endPos = newPos; +} + /** Count bits in a number. */ UINT8 M_CountBits(UINT32 num, UINT8 size) diff --git a/src/p_enemy.c b/src/p_enemy.c index 637bc775c..61ab6d3c1 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -14225,7 +14225,7 @@ void A_SaloonDoorSpawn(mobj_t *actor) fixed_t c = FINECOSINE(fa)*locvar2; fixed_t s = FINESINE(fa)*locvar2; mobj_t *door; - mobjflag2_t ambush = (actor->flags & MF2_AMBUSH); + mobjflag2_t ambush = (actor->flags2 & MF2_AMBUSH); #ifdef HAVE_BLUA if (LUA_CallAction("A_SaloonDoorSpawn", actor)) diff --git a/src/p_inter.c b/src/p_inter.c index e8095ebfc..4c4ba4f24 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1451,7 +1451,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->starpostnum >= special->health) return; // Already hit this post - if (cv_coopstarposts.value && gametype == GT_COOP && (netgame || multiplayer)) + if (cv_coopstarposts.value && G_GametypeUsesCoopStarposts() && (netgame || multiplayer)) { for (i = 0; i < MAXPLAYERS; i++) { @@ -1807,7 +1807,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; case MT_MINECARTSPAWNER: - if (!player->bot && (special->fuse < TICRATE || player->powers[pw_carry] != CR_MINECART)) + if (!player->bot && special->fuse <= TICRATE && player->powers[pw_carry] != CR_MINECART) { mobj_t *mcart = P_SpawnMobj(special->x, special->y, special->z, MT_MINECART); P_SetTarget(&mcart->target, toucher); @@ -2481,9 +2481,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget P_SetMobjState(scoremobj, scorestate); - // On ground? No chain starts. - if (source->player->powers[pw_invulnerability] || !P_IsObjectOnGround(source)) - source->player->scoreadd = locscoreadd; + source->player->scoreadd = locscoreadd; } } @@ -2523,7 +2521,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->colorized = false; G_GhostAddColor(GHC_NORMAL); - if ((target->player->lives <= 1) && (netgame || multiplayer) && (gametype == GT_COOP) && (cv_cooplives.value == 0)) + if ((target->player->lives <= 1) && (netgame || multiplayer) && G_GametypeUsesCoopLives() && (cv_cooplives.value == 0)) ; else if (!target->player->bot && !target->player->spectator && (target->player->lives != INFLIVES) && G_GametypeUsesLives()) @@ -2533,7 +2531,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (target->player->lives <= 0) // Tails 03-14-2000 { boolean gameovermus = false; - if ((netgame || multiplayer) && (gametype == GT_COOP) && (cv_cooplives.value != 1)) + if ((netgame || multiplayer) && G_GametypeUsesCoopLives() && (cv_cooplives.value != 1)) { INT32 i; for (i = 0; i < MAXPLAYERS; i++) @@ -3201,10 +3199,12 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) player->powers[pw_carry] = CR_NONE; // Burst weapons and emeralds in Match/CTF only - if (source && (gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF)) + if (source) { - P_PlayerRingBurst(player, player->rings); - P_PlayerEmeraldBurst(player, false); + if ((gametyperules & GTR_RINGSLINGER) && !(gametyperules & GTR_TAG)) + P_PlayerRingBurst(player, player->rings); + if (gametyperules & GTR_POWERSTONES) + P_PlayerEmeraldBurst(player, false); } // Get rid of shield diff --git a/src/p_map.c b/src/p_map.c index 1b6f23cde..a522418f7 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -745,9 +745,8 @@ static boolean PIT_CheckThing(mobj_t *thing) // So that NOTHING ELSE can see MT_NAMECHECK because it is client-side. if (tmthing->type == MT_NAMECHECK) { - // Ignore things that aren't players, ignore spectators, ignore yourself. - // (also don't bother to check that tmthing->target->player is non-NULL because we're not actually using it here.) - if (!thing->player || thing->player->spectator || (tmthing->target && thing->player == tmthing->target->player)) + // Ignore things that aren't players, ignore spectators, ignore yourself. + if (!thing->player || !(tmthing->target && tmthing->target->player) || thing->player->spectator || (tmthing->target && thing->player == tmthing->target->player)) return true; // Now check that you actually hit them. @@ -760,6 +759,12 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath +#ifdef HAVE_BLUA + // REX HAS SEEN YOU + if (!LUAh_SeenPlayer(tmthing->target->player, thing->player)) + return false; +#endif + seenplayer = thing->player; return false; } @@ -829,13 +834,13 @@ static boolean PIT_CheckThing(mobj_t *thing) for (iter = thing->subsector->sector->thinglist; iter; iter = iter->snext) if (iter->type == thing->type && iter->health > 0 && iter->flags & MF_SOLID && (iter == thing || P_AproxDistance(P_AproxDistance(thing->x - iter->x, thing->y - iter->y), thing->z - iter->z) < 56*thing->scale))//FixedMul(56*FRACUNIT, thing->scale)) P_KillMobj(iter, tmthing, tmthing, 0); + return true; } else { - thing->health = 0; - P_KillMobj(thing, tmthing, tmthing, 0); + if (P_DamageMobj(thing, tmthing, tmthing, 1, 0)) + return true; } - return true; } // vectorise metal - done in a special case as at this point neither has the right flags for touching @@ -995,7 +1000,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_SALOONDOOR && tmthing->player) { mobj_t *ref = (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer)) ? tmthing->tracer : tmthing; - if ((thing->flags & MF2_AMBUSH) || ref != tmthing) + if ((thing->flags2 & MF2_AMBUSH) || ref != tmthing) { fixed_t dm = min(FixedHypot(ref->momx, ref->momy), 16*FRACUNIT); angle_t ang = R_PointToAngle2(0, 0, ref->momx, ref->momy) - thing->angle; @@ -1008,7 +1013,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_SALOONDOORCENTER && tmthing->player) { - if ((thing->flags & MF2_AMBUSH) || (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer))) + if ((thing->flags2 & MF2_AMBUSH) || (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer))) return true; } @@ -1943,6 +1948,19 @@ static boolean PIT_CheckLine(line_t *ld) // this line is out of the if so upper and lower textures can be hit by a splat blockingline = ld; + +#ifdef HAVE_BLUA + { + UINT8 shouldCollide = LUAh_MobjLineCollide(tmthing, blockingline); // checks hook for thing's type + if (P_MobjWasRemoved(tmthing)) + return true; // one of them was removed??? + if (shouldCollide == 1) + return false; // force collide + else if (shouldCollide == 2) + return true; // force no collide + } +#endif + if (!ld->backsector) // one sided line { if (P_PointOnLineSide(tmthing->x, tmthing->y, ld)) @@ -1987,7 +2005,7 @@ static boolean PIT_CheckLine(line_t *ld) if (lowfloor < tmdropoffz) tmdropoffz = lowfloor; - + return true; } diff --git a/src/p_maputl.c b/src/p_maputl.c index f598595e2..afa020504 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -78,68 +78,37 @@ void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result) return; } -// -// P_ClosestPointOnLine3D -// Finds the closest point on a given line to the supplied point IN 3D!!! -// -void P_ClosestPointOnLine3D(fixed_t x, fixed_t y, fixed_t z, line_t *line, vertex_t *result) +/// Similar to FV3_ClosestPointOnLine() except it actually works. +void P_ClosestPointOnLine3D(const vector3_t *p, const vector3_t *Line, vector3_t *result) { - fixed_t startx = line->v1->x; - fixed_t starty = line->v1->y; - fixed_t startz = line->v1->z; - fixed_t dx = line->dx; - fixed_t dy = line->dy; - fixed_t dz = line->v2->z - line->v1->z; + const vector3_t* v1 = &Line[0]; + const vector3_t* v2 = &Line[1]; + vector3_t c, V, n; + fixed_t t, d; + FV3_SubEx(v2, v1, &V); + FV3_SubEx(p, v1, &c); - // Determine t (the length of the vector from �Line[0]� to �p�) - fixed_t cx, cy, cz; - fixed_t vx, vy, vz; - fixed_t magnitude; - fixed_t t; + d = R_PointToDist2(0, v2->z, R_PointToDist2(v2->x, v2->y, v1->x, v1->y), v1->z); + FV3_Copy(&n, &V); + FV3_Divide(&n, d); - //Sub (p, &Line[0], &c); - cx = x - startx; - cy = y - starty; - cz = z - startz; - - //Sub (&Line[1], &Line[0], &V); - vx = dx; - vy = dy; - vz = dz; - - //Normalize (&V, &V); - magnitude = R_PointToDist2(0, line->v2->z, R_PointToDist2(line->v2->x, line->v2->y, startx, starty), startz); - vx = FixedDiv(vx, magnitude); - vy = FixedDiv(vy, magnitude); - vz = FixedDiv(vz, magnitude); - - t = (FixedMul(vx, cx) + FixedMul(vy, cy) + FixedMul(vz, cz)); + t = FV3_Dot(&n, &c); // Set closest point to the end if it extends past -Red if (t <= 0) { - result->x = line->v1->x; - result->y = line->v1->y; - result->z = line->v1->z; + FV3_Copy(result, v1); return; } - else if (t >= magnitude) + else if (t >= d) { - result->x = line->v2->x; - result->y = line->v2->y; - result->z = line->v2->z; + FV3_Copy(result, v2); return; } - // Return the point between �Line[0]� and �Line[1]� - vx = FixedMul(vx, t); - vy = FixedMul(vy, t); - vz = FixedMul(vz, t); + FV3_Mul(&n, t); - //Add (&Line[0], &V, out); - result->x = startx + vx; - result->y = starty + vy; - result->z = startz + vz; + FV3_AddEx(v1, &n, result); return; } diff --git a/src/p_maputl.h b/src/p_maputl.h index 2ca718779..16cfc834e 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -43,7 +43,7 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2, FUNCMATH fixed_t P_AproxDistance(fixed_t dx, fixed_t dy); void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result); -void P_ClosestPointOnLine3D(fixed_t x, fixed_t y, fixed_t z, line_t *line, vertex_t *result); +void P_ClosestPointOnLine3D(const vector3_t *p, const vector3_t *line, vector3_t *result); INT32 P_PointOnLineSide(fixed_t x, fixed_t y, line_t *line); void P_MakeDivline(line_t *li, divline_t *dl); void P_CameraLineOpening(line_t *plinedef); diff --git a/src/p_mobj.c b/src/p_mobj.c index 9e91f88ae..9ea5d0941 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7977,15 +7977,19 @@ static void P_MobjSceneryThink(mobj_t *mobj) mobj->x = mobj->extravalue1 + P_ReturnThrustX(mobj, mobj->movedir, mobj->cvmem*mobj->scale); mobj->y = mobj->extravalue2 + P_ReturnThrustY(mobj, mobj->movedir, mobj->cvmem*mobj->scale); P_SetThingPosition(mobj); - if ((--mobj->fuse) < 6) + + if (!mobj->fuse) { - if (!mobj->fuse) - { +#ifdef HAVE_BLUA + if (!LUAh_MobjFuse(mobj)) +#endif P_RemoveMobj(mobj); - return; - } - mobj->frame = (mobj->frame & ~FF_TRANSMASK) | ((10 - (mobj->fuse*2)) << (FF_TRANSSHIFT)); + return; } + if (mobj->fuse < 0) + return; + if ((--mobj->fuse) < 6) + mobj->frame = (mobj->frame & ~FF_TRANSMASK) | ((10 - (mobj->fuse*2)) << (FF_TRANSSHIFT)); } break; case MT_VWREF: @@ -9903,19 +9907,12 @@ static void P_FlagFuseThink(mobj_t *mobj) x = mobj->spawnpoint->x << FRACBITS; y = mobj->spawnpoint->y << FRACBITS; + z = mobj->spawnpoint->z << FRACBITS; ss = R_PointInSubsector(x, y); if (mobj->spawnpoint->options & MTF_OBJECTFLIP) - { - z = ss->sector->ceilingheight - mobjinfo[mobj->type].height; - if (mobj->spawnpoint->options >> ZSHIFT) - z -= (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; - } + z = ss->sector->ceilingheight - mobjinfo[mobj->type].height - z; else - { - z = ss->sector->floorheight; - if (mobj->spawnpoint->options >> ZSHIFT) - z += (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; - } + z = ss->sector->floorheight + z; flagmo = P_SpawnMobj(x, y, z, mobj->type); flagmo->spawnpoint = mobj->spawnpoint; if (mobj->spawnpoint->options & MTF_OBJECTFLIP) @@ -11289,9 +11286,6 @@ static mobjtype_t P_GetMobjtype(UINT16 mthingtype) // void P_RespawnSpecials(void) { - fixed_t x, y, z; - subsector_t *ss; - mobj_t *mo = NULL; mapthing_t *mthing = NULL; // only respawn items when cv_itemrespawn is on @@ -11321,63 +11315,8 @@ void P_RespawnSpecials(void) #endif if (mthing) - { - mobjtype_t i = P_GetMobjtype(mthing->type); - x = mthing->x << FRACBITS; - y = mthing->y << FRACBITS; - ss = R_PointInSubsector(x, y); + P_SpawnMapThing(mthing); - if (i == MT_UNKNOWN) // prevent creation of objects with this type -- Monster Iestyn 17/12/17 - { - // 3D Mode start Thing is unlikely to be added to the que, - // so don't bother checking for that specific type - CONS_Alert(CONS_WARNING, M_GetText("P_RespawnSpecials: Unknown thing type %d attempted to respawn at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); - // pull it from the que - iquetail = (iquetail+1)&(ITEMQUESIZE-1); - return; - } - - //CTF rings should continue to respawn as normal rings outside of CTF. - if (!(gametyperules & GTR_TEAMFLAGS)) - { - if (i == MT_REDTEAMRING || i == MT_BLUETEAMRING) - i = MT_RING; - } - - if (mthing->options & MTF_OBJECTFLIP) - { - z = ( -#ifdef ESLOPE - ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : -#endif - ss->sector->ceilingheight) - (mthing->options >> ZSHIFT) * FRACUNIT; - if (mthing->options & MTF_AMBUSH - && (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || i == MT_NIGHTSSTAR || P_WeaponOrPanel(i))) - z -= 24*FRACUNIT; - z -= mobjinfo[i].height; // Don't forget the height! - } - else - { - z = ( -#ifdef ESLOPE - ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : -#endif - ss->sector->floorheight) + (mthing->options >> ZSHIFT) * FRACUNIT; - if (mthing->options & MTF_AMBUSH - && (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || i == MT_NIGHTSSTAR || P_WeaponOrPanel(i))) - z += 24*FRACUNIT; - } - - mo = P_SpawnMobj(x, y, z, i); - mo->spawnpoint = mthing; - mo->angle = ANGLE_45 * (mthing->angle/45); - - if (mthing->options & MTF_OBJECTFLIP) - { - mo->eflags |= MFE_VERTICALFLIP; - mo->flags2 |= MF2_OBJECTFLIP; - } - } // pull it from the que iquetail = (iquetail+1)&(ITEMQUESIZE-1); } @@ -11563,7 +11502,7 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing) fixed_t z; sector_t *sector; - fixed_t floor, ceiling; + fixed_t floor, ceiling, ceilingspawn; player_t *p = &players[playernum]; mobj_t *mobj = p->mo; @@ -11590,23 +11529,18 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing) sector->c_slope ? P_GetZAt(sector->c_slope, x, y) : #endif sector->ceilingheight; + ceilingspawn = ceiling - mobjinfo[MT_PLAYER].height; if (mthing) { + fixed_t offset = mthing->z << FRACBITS; + // Flagging a player's ambush will make them start on the ceiling // Objectflip inverts if (!!(mthing->options & MTF_AMBUSH) ^ !!(mthing->options & MTF_OBJECTFLIP)) - { - z = ceiling - mobjinfo[MT_PLAYER].height; - if (mthing->options >> ZSHIFT) - z -= ((mthing->options >> ZSHIFT) << FRACBITS); - } + z = ceilingspawn - offset; else - { - z = floor; - if (mthing->options >> ZSHIFT) - z += ((mthing->options >> ZSHIFT) << FRACBITS); - } + z = floor + offset; if (mthing->options & MTF_OBJECTFLIP) // flip the player! { @@ -11623,8 +11557,8 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing) if (z < floor) z = floor; - else if (z > ceiling - mobjinfo[MT_PLAYER].height) - z = ceiling - mobjinfo[MT_PLAYER].height; + else if (z > ceilingspawn) + z = ceilingspawn; mobj->floorz = floor; mobj->ceilingz = ceiling; @@ -11893,7 +11827,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) if (!cv_powerstones.value) return false; - if (!(gametyperules & GTR_MATCHEMERALDS)) + if (!(gametyperules & GTR_POWERSTONES)) return false; runemeraldmanager = true; @@ -12465,7 +12399,7 @@ static boolean P_SetupParticleGen(mapthing_t *mthing, mobj_t *mobj) || (ticcount = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS)) < 1) ticcount = 3; - numdivisions = (mthing->options >> ZSHIFT); + numdivisions = mthing->z; if (numdivisions) { diff --git a/src/p_polyobj.c b/src/p_polyobj.c index c37926adf..36a9ba613 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -400,6 +400,8 @@ static void Polyobj_findSegs(polyobj_t *po, seg_t *seg) // Find backfacings for (s = 0; s < numsegs; s++) { + if (segs[s].glseg) + continue; if (segs[s].linedef == seg->linedef && segs[s].side == 1) { @@ -436,6 +438,8 @@ newseg: // seg's ending vertex. for (i = 0; i < numsegs; ++i) { + if (segs[i].glseg) + continue; if (segs[i].side != 0) // needs to be frontfacing continue; if (segs[i].v1->x == seg->v2->x && segs[i].v1->y == seg->v2->y) @@ -460,6 +464,9 @@ newseg: // Find backfacings for (q = 0; q < numsegs; q++) { + if (segs[q].glseg) + continue; + if (segs[q].linedef == segs[i].linedef && segs[q].side == 1) { @@ -606,6 +613,9 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id) INT32 poflags = POF_SOLID|POF_TESTHEIGHT|POF_RENDERSIDES; INT32 parentID = 0, potrans = 0; + if (seg->glseg) + continue; + if (seg->side != 0) // needs to be frontfacing continue; @@ -1815,6 +1825,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th) if (po->thinker == NULL) po->thinker = &th->thinker; +/* // Find out target first. // We redo this each tic to make savegame compatibility easier. for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next) @@ -1833,6 +1844,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th) break; } } +*/ + + target = th->target; if (!target) { @@ -2015,6 +2029,8 @@ void T_PolyObjWaypoint(polywaypoint_t *th) target = waypoint; th->pointnum = target->health; + // Set the mobj as your target! -- Monster Iestyn 27/12/19 + P_SetTarget(&th->target, target); // calculate MOMX/MOMY/MOMZ for next waypoint // change slope @@ -2641,6 +2657,9 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) // Set pointnum th->pointnum = target->health; + th->target = NULL; // set to NULL first so the below doesn't go wrong + // Set the mobj as your target! -- Monster Iestyn 27/12/19 + P_SetTarget(&th->target, target); // We don't deal with the mirror crap here, we'll // handle that in the T_Thinker function. diff --git a/src/p_polyobj.h b/src/p_polyobj.h index ffacf628b..339390c0a 100644 --- a/src/p_polyobj.h +++ b/src/p_polyobj.h @@ -161,6 +161,8 @@ typedef struct polywaypoint_s fixed_t diffx; fixed_t diffy; fixed_t diffz; + + mobj_t *target; // next waypoint mobj } polywaypoint_t; typedef struct polyslidedoor_s diff --git a/src/p_saveg.c b/src/p_saveg.c index 4cfeab6f8..2b6a474bf 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2055,6 +2055,7 @@ static void SavePolywaypointThinker(const thinker_t *th, UINT8 type) WRITEFIXED(save_p, ht->diffx); WRITEFIXED(save_p, ht->diffy); WRITEFIXED(save_p, ht->diffz); + WRITEUINT32(save_p, SaveMobjnum(ht->target)); } // @@ -3244,6 +3245,7 @@ static inline thinker_t* LoadPolywaypointThinker(actionf_p1 thinker) ht->diffx = READFIXED(save_p); ht->diffy = READFIXED(save_p); ht->diffz = READFIXED(save_p); + ht->target = LoadMobj(READUINT32(save_p)); return &ht->thinker; } @@ -3538,6 +3540,7 @@ static void P_NetUnArchiveThinkers(void) case tc_polywaypoint: th = LoadPolywaypointThinker((actionf_p1)T_PolyObjWaypoint); + restoreNum = true; break; case tc_polyslidedoor: @@ -3599,9 +3602,9 @@ static void P_NetUnArchiveThinkers(void) if (restoreNum) { executor_t *delay = NULL; + polywaypoint_t *polywp = NULL; UINT32 mobjnum; - for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN]; - currentthinker = currentthinker->next) + for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN]; currentthinker = currentthinker->next) { if (currentthinker->function.acp1 != (actionf_p1)T_ExecutorDelay) continue; @@ -3610,6 +3613,15 @@ static void P_NetUnArchiveThinkers(void) continue; delay->caller = P_FindNewPosition(mobjnum); } + for (currentthinker = thlist[THINK_POLYOBJ].next; currentthinker != &thlist[THINK_POLYOBJ]; currentthinker = currentthinker->next) + { + if (currentthinker->function.acp1 != (actionf_p1)T_PolyObjWaypoint) + continue; + polywp = (void *)currentthinker; + if (!(mobjnum = (UINT32)(size_t)polywp->target)) + continue; + polywp->target = P_FindNewPosition(mobjnum); + } } } diff --git a/src/p_setup.c b/src/p_setup.c index ff7eecef5..a4e083f18 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -83,6 +83,8 @@ #include "p_slopes.h" #endif +#include "fastcmp.h" // textmap parsing + // // Map MD5, calculated on level load. // Sent to clients in PT_SERVERINFO. @@ -373,114 +375,6 @@ UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade) return mapheaderinfo[map-1]->grades[mare].grade[grade-1]; } -// Loads the vertexes for a level. -static inline void P_LoadRawVertexes(UINT8 *data) -{ - mapvertex_t *ml = (mapvertex_t *)data; - vertex_t *li = vertexes; - size_t i; - - // Copy and convert vertex coordinates, internal representation as fixed. - for (i = 0; i < numvertexes; i++, li++, ml++) - { - li->x = SHORT(ml->x)<y = SHORT(ml->y)<v2->x - seg->v1->x)>>1; - INT64 dy = (seg->v2->y - seg->v1->y)>>1; - return FixedHypot(dx, dy)<<1; -} - -#ifdef HWRENDER -/** Computes the length of a seg as a float. - * This is needed for OpenGL. - * - * \param seg Seg to compute length for. - * \return Length as a float. - */ -static inline float P_SegLengthFloat(seg_t *seg) -{ - float dx, dy; - - // make a vector (start at origin) - dx = FIXED_TO_FLOAT(seg->v2->x - seg->v1->x); - dy = FIXED_TO_FLOAT(seg->v2->y - seg->v1->y); - - return (float)hypot(dx, dy); -} -#endif - -// Loads the SEGS resource from a level. -static void P_LoadRawSegs(UINT8 *data) -{ - INT32 linedef, side; - mapseg_t *ml = (mapseg_t*)data; - seg_t *li = segs; - line_t *ldef; - size_t i; - - for (i = 0; i < numsegs; i++, li++, ml++) - { - li->v1 = &vertexes[SHORT(ml->v1)]; - li->v2 = &vertexes[SHORT(ml->v2)]; - - li->length = P_SegLength(li); -#ifdef HWRENDER - if (rendermode == render_opengl) - { - li->flength = P_SegLengthFloat(li); - //Hurdler: 04/12/2000: for now, only used in hardware mode - li->lightmaps = NULL; // list of static lightmap for this seg - } - li->pv1 = li->pv2 = NULL; -#endif - - li->angle = (SHORT(ml->angle))<offset = (SHORT(ml->offset))<linedef); - ldef = &lines[linedef]; - li->linedef = ldef; - li->side = side = SHORT(ml->side); - li->sidedef = &sides[ldef->sidenum[side]]; - li->frontsector = sides[ldef->sidenum[side]].sector; - if (ldef->flags & ML_TWOSIDED) - li->backsector = sides[ldef->sidenum[side^1]].sector; - else - li->backsector = 0; - - li->numlights = 0; - li->rlights = NULL; - } -} - -// Loads the SSECTORS resource from a level. -static inline void P_LoadRawSubsectors(void *data) -{ - mapsubsector_t *ms = (mapsubsector_t*)data; - subsector_t *ss = subsectors; - size_t i; - - for (i = 0; i < numsubsectors; i++, ss++, ms++) - { - ss->sector = NULL; - ss->numlines = SHORT(ms->numsegs); - ss->firstline = SHORT(ms->firstseg); -#ifdef FLOORSPLATS - ss->splats = NULL; -#endif - ss->validcount = 0; - } -} - // // levelflats // @@ -647,107 +541,6 @@ INT32 P_CheckLevelFlat(const char *flatname) return (INT32)i; } -// Sets up the ingame sectors structures. -static void P_LoadRawSectors(UINT8 *data) -{ - mapsector_t *ms = (mapsector_t *)data; - sector_t *ss = sectors; - size_t i; - - // For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss. - for (i = 0; i < numsectors; i++, ss++, ms++) - { - ss->floorheight = SHORT(ms->floorheight)<ceilingheight = SHORT(ms->ceilingheight)<floorpic = P_AddLevelFlat(ms->floorpic, foundflats); - ss->ceilingpic = P_AddLevelFlat(ms->ceilingpic, foundflats); - - ss->lightlevel = SHORT(ms->lightlevel); - ss->spawn_lightlevel = ss->lightlevel; - ss->special = SHORT(ms->special); - ss->tag = SHORT(ms->tag); - ss->nexttag = ss->firsttag = -1; - - memset(&ss->soundorg, 0, sizeof(ss->soundorg)); - ss->validcount = 0; - - ss->thinglist = NULL; - ss->touching_thinglist = NULL; - ss->preciplist = NULL; - ss->touching_preciplist = NULL; - - ss->floordata = NULL; - ss->ceilingdata = NULL; - ss->lightingdata = NULL; - - ss->linecount = 0; - ss->lines = NULL; - - ss->heightsec = -1; - ss->camsec = -1; - ss->floorlightsec = -1; - ss->ceilinglightsec = -1; - ss->crumblestate = 0; - ss->ffloors = NULL; - ss->lightlist = NULL; - ss->numlights = 0; - ss->attached = NULL; - ss->attachedsolid = NULL; - ss->numattached = 0; - ss->maxattached = 1; - ss->moved = true; - - ss->extra_colormap = NULL; - ss->spawn_extra_colormap = NULL; - - ss->floor_xoffs = ss->ceiling_xoffs = ss->floor_yoffs = ss->ceiling_yoffs = 0; - ss->floorpic_angle = ss->ceilingpic_angle = 0; - ss->gravity = NULL; - ss->cullheight = NULL; - ss->verticalflip = false; - ss->flags = 0; - ss->flags |= SF_FLIPSPECIAL_FLOOR; - - ss->floorspeed = 0; - ss->ceilspeed = 0; - -#ifdef HWRENDER // ----- for special tricks with HW renderer ----- - ss->pseudoSector = false; - ss->virtualFloor = false; - ss->virtualCeiling = false; - ss->sectorLines = NULL; - ss->stackList = NULL; - ss->lineoutLength = -1.0l; -#endif // ----- end special tricks ----- - } -} - -// -// P_LoadNodes -// -static void P_LoadRawNodes(UINT8 *data) -{ - UINT8 j, k; - mapnode_t *mn = (mapnode_t*)data; - node_t *no = nodes; - size_t i; - - for (i = 0; i < numnodes; i++, no++, mn++) - { - no->x = SHORT(mn->x)<y = SHORT(mn->y)<dx = SHORT(mn->dx)<dy = SHORT(mn->dy)<children[j] = SHORT(mn->children[j]); - for (k = 0; k < 4; k++) - no->bbox[j][k] = SHORT(mn->bbox[j][k])<x = READINT16(data); - mt->y = READINT16(data); - - mt->angle = READINT16(data); - mt->type = READUINT16(data); - mt->options = READUINT16(data); - mt->extrainfo = (UINT8)(mt->type >> 12); - - mt->type &= 4095; - - if (mt->type == 1705 || (mt->type == 750 && mt->extrainfo)) - mt->z = mt->options; // NiGHTS Hoops use the full flags bits to set the height. - else - mt->z = mt->options >> ZSHIFT; - } -} - static void P_SpawnEmeraldHunt(void) { INT32 emer1, emer2, emer3; @@ -1062,7 +831,217 @@ void P_WriteThings(lumpnum_t lumpnum) CONS_Printf(M_GetText("newthings%d.lmp saved.\n"), gamemap); } -static void P_LoadRawLineDefs(UINT8 *data) +// +// MAP LOADING FUNCTIONS +// + +static void P_LoadVertices(UINT8 *data) +{ + mapvertex_t *mv = (mapvertex_t *)data; + vertex_t *v = vertexes; + size_t i; + + // Copy and convert vertex coordinates, internal representation as fixed. + for (i = 0; i < numvertexes; i++, v++, mv++) + { + v->x = SHORT(mv->x)<y = SHORT(mv->y)<nexttag = ss->firsttag = -1; + + memset(&ss->soundorg, 0, sizeof(ss->soundorg)); + + ss->validcount = 0; + + ss->thinglist = NULL; + + ss->floordata = NULL; + ss->ceilingdata = NULL; + ss->lightingdata = NULL; + ss->fadecolormapdata = NULL; + + ss->heightsec = -1; + ss->camsec = -1; + + ss->floorlightsec = ss->ceilinglightsec = -1; + ss->crumblestate = 0; + + ss->touching_thinglist = NULL; + + ss->linecount = 0; + ss->lines = NULL; + ss->tagline = NULL; + + ss->ffloors = NULL; + ss->attached = NULL; + ss->attachedsolid = NULL; + ss->numattached = 0; + ss->maxattached = 1; + ss->lightlist = NULL; + ss->numlights = 0; + ss->moved = true; + + ss->extra_colormap = NULL; + +#ifdef HWRENDER // ----- for special tricks with HW renderer ----- + ss->pseudoSector = false; + ss->virtualFloor = false; + ss->virtualFloorheight = 0; + ss->virtualCeiling = false; + ss->virtualCeilingheight = 0; + ss->sectorLines = NULL; + ss->stackList = NULL; + ss->lineoutLength = -1.0l; +#endif // ----- end special tricks ----- + + ss->gravity = NULL; + ss->verticalflip = false; + ss->flags = SF_FLIPSPECIAL_FLOOR; + + ss->cullheight = NULL; + + ss->floorspeed = ss->ceilspeed = 0; + + ss->preciplist = NULL; + ss->touching_preciplist = NULL; + +#ifdef ESLOPE + ss->f_slope = NULL; + ss->c_slope = NULL; + ss->hasslope = false; +#endif + + ss->spawn_lightlevel = ss->lightlevel; + + ss->spawn_extra_colormap = NULL; +} + +static void P_LoadSectors(UINT8 *data) +{ + mapsector_t *ms = (mapsector_t *)data; + sector_t *ss = sectors; + size_t i; + + // For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss. + for (i = 0; i < numsectors; i++, ss++, ms++) + { + ss->floorheight = SHORT(ms->floorheight)<ceilingheight = SHORT(ms->ceilingheight)<floorpic = P_AddLevelFlat(ms->floorpic, foundflats); + ss->ceilingpic = P_AddLevelFlat(ms->ceilingpic, foundflats); + + ss->lightlevel = SHORT(ms->lightlevel); + ss->special = SHORT(ms->special); + ss->tag = SHORT(ms->tag); + + ss->floor_xoffs = ss->floor_yoffs = 0; + ss->ceiling_xoffs = ss->ceiling_yoffs = 0; + + ss->floorpic_angle = ss->ceilingpic_angle = 0; + + P_InitializeSector(ss); + } +} + +static void P_InitializeLinedef(line_t *ld) +{ + vertex_t *v1 = ld->v1; + vertex_t *v2 = ld->v2; + UINT8 j; + + ld->dx = v2->x - v1->x; + ld->dy = v2->y - v1->y; + + ld->bbox[BOXLEFT] = min(v1->x, v2->x); + ld->bbox[BOXRIGHT] = max(v1->x, v2->x); + ld->bbox[BOXBOTTOM] = min(v1->y, v2->y); + ld->bbox[BOXTOP] = max(v1->y, v2->y); + + if (!ld->dx) + ld->slopetype = ST_VERTICAL; + else if (!ld->dy) + ld->slopetype = ST_HORIZONTAL; + else if ((ld->dy > 0) == (ld->dx > 0)) + ld->slopetype = ST_POSITIVE; + else + ld->slopetype = ST_NEGATIVE; + + ld->frontsector = ld->backsector = NULL; + + ld->validcount = 0; +#ifdef WALLSPLATS + ld->splats = NULL; +#endif + ld->firsttag = ld->nexttag = -1; +#ifdef POLYOBJECTS + ld->polyobj = NULL; +#endif + + ld->text = NULL; + ld->callcount = 0; + + // cph 2006/09/30 - fix sidedef errors right away. + // cph 2002/07/20 - these errors are fatal if not fixed, so apply them + for (j = 0; j < 2; j++) + if (ld->sidenum[j] != 0xffff && ld->sidenum[j] >= (UINT16)numsides) + { + ld->sidenum[j] = 0xffff; + CONS_Debug(DBG_SETUP, "P_InitializeLinedef: Linedef %s has out-of-range sidedef number\n", sizeu1((size_t)(ld - lines))); + } + + // killough 11/98: fix common wad errors (missing sidedefs): + if (ld->sidenum[0] == 0xffff) + { + ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side + // cph - print a warning about the bug + CONS_Debug(DBG_SETUP, "P_InitializeLinedef: Linedef %s missing first sidedef\n", sizeu1((size_t)(ld - lines))); + } + + if ((ld->sidenum[1] == 0xffff) && (ld->flags & ML_TWOSIDED)) + { + ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side + // cph - print a warning about the bug + CONS_Debug(DBG_SETUP, "P_InitializeLinedef: Linedef %s has two-sided flag set, but no second sidedef\n", sizeu1((size_t)(ld - lines))); + } + + if (ld->sidenum[0] != 0xffff) + { + sides[ld->sidenum[0]].special = ld->special; + sides[ld->sidenum[0]].line = ld; + } + if (ld->sidenum[1] != 0xffff) + { + sides[ld->sidenum[1]].special = ld->special; + sides[ld->sidenum[1]].line = ld; + } +} + +static void P_SetLinedefV1(size_t i, UINT16 vertex_num) +{ + if (vertex_num >= numvertexes) + { + CONS_Debug(DBG_SETUP, "P_SetLinedefV1: linedef %s has out-of-range v1 num %u\n", sizeu1(i), vertex_num); + vertex_num = 0; + } + lines[i].v1 = &vertexes[vertex_num]; +} + +static void P_SetLinedefV2(size_t i, UINT16 vertex_num) +{ + if (vertex_num >= numvertexes) + { + CONS_Debug(DBG_SETUP, "P_SetLinedefV2: linedef %s has out-of-range v2 num %u\n", sizeu1(i), vertex_num); + vertex_num = 0; + } + lines[i].v2 = &vertexes[vertex_num]; +} + +static void P_LoadLinedefs(UINT8 *data) { maplinedef_t *mld = (maplinedef_t *)data; line_t *ld = lines; @@ -1073,240 +1052,75 @@ static void P_LoadRawLineDefs(UINT8 *data) ld->flags = SHORT(mld->flags); ld->special = SHORT(mld->special); ld->tag = SHORT(mld->tag); - ld->v1 = &vertexes[SHORT(mld->v1)]; - ld->v2 = &vertexes[SHORT(mld->v2)]; + P_SetLinedefV1(i, SHORT(mld->v1)); + P_SetLinedefV2(i, SHORT(mld->v2)); ld->sidenum[0] = SHORT(mld->sidenum[0]); ld->sidenum[1] = SHORT(mld->sidenum[1]); + + P_InitializeLinedef(ld); } } -static void P_SetupLines(void) +static void P_SetSidedefSector(size_t i, UINT16 sector_num) { - line_t *ld = lines; + // cph 2006/09/30 - catch out-of-range sector numbers; use sector 0 instead + if (sector_num >= numsectors) + { + CONS_Debug(DBG_SETUP, "P_SetSidedefSector: sidedef %s has out-of-range sector num %u\n", sizeu1(i), sector_num); + sector_num = 0; + } + sides[i].sector = §ors[sector_num]; +} + +static void P_InitializeSidedef(side_t *sd) +{ + if (!sd->line) + { + CONS_Debug(DBG_SETUP, "P_LoadSidedefs: Sidedef %s is not used by any linedef\n", sizeu1((size_t)(sd - sides))); + sd->line = &lines[0]; + sd->special = sd->line->special; + } + + sd->text = NULL; + sd->colormap_data = NULL; +} + +static void P_LoadSidedefs(UINT8 *data) +{ + mapsidedef_t *msd = (mapsidedef_t*)data; + side_t *sd = sides; size_t i; - for (i = 0; i < numlines; i++, ld++) + for (i = 0; i < numsides; i++, sd++, msd++) { - vertex_t *v1 = ld->v1; - vertex_t *v2 = ld->v2; + INT16 textureoffset = SHORT(msd->textureoffset); + boolean isfrontside; -#ifdef WALLSPLATS - ld->splats = NULL; -#endif + P_InitializeSidedef(sd); -#ifdef POLYOBJECTS - ld->polyobj = NULL; -#endif - - ld->dx = v2->x - v1->x; - ld->dy = v2->y - v1->y; - - if (!ld->dx) - ld->slopetype = ST_VERTICAL; - else if (!ld->dy) - ld->slopetype = ST_HORIZONTAL; - else if ((ld->dy > 0) == (ld->dx > 0)) - ld->slopetype = ST_POSITIVE; - else - ld->slopetype = ST_NEGATIVE; - - if (v1->x < v2->x) - { - ld->bbox[BOXLEFT] = v1->x; - ld->bbox[BOXRIGHT] = v2->x; - } - else - { - ld->bbox[BOXLEFT] = v2->x; - ld->bbox[BOXRIGHT] = v1->x; - } - - if (v1->y < v2->y) - { - ld->bbox[BOXBOTTOM] = v1->y; - ld->bbox[BOXTOP] = v2->y; - } - else - { - ld->bbox[BOXBOTTOM] = v2->y; - ld->bbox[BOXTOP] = v1->y; - } - - { - // cph 2006/09/30 - fix sidedef errors right away. - // cph 2002/07/20 - these errors are fatal if not fixed, so apply them - UINT8 j; - - for (j=0; j < 2; j++) - if (ld->sidenum[j] != 0xffff && ld->sidenum[j] >= (UINT16)numsides) - { - ld->sidenum[j] = 0xffff; - CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has out-of-range sidedef number\n", sizeu1(numlines-i-1)); - } - } - - ld->frontsector = ld->backsector = NULL; - ld->validcount = 0; - ld->firsttag = ld->nexttag = -1; - ld->callcount = 0; - - // killough 11/98: fix common wad errors (missing sidedefs): - if (ld->sidenum[0] == 0xffff) - { - ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side - // cph - print a warning about the bug - CONS_Debug(DBG_SETUP, "Linedef %s missing first sidedef\n", sizeu1(numlines-i-1)); - } - - if ((ld->sidenum[1] == 0xffff) && (ld->flags & ML_TWOSIDED)) - { - ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side - // cph - print a warning about the bug - CONS_Debug(DBG_SETUP, "Linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1)); - } - - if (ld->sidenum[0] != 0xffff && ld->special) - sides[ld->sidenum[0]].special = ld->special; - if (ld->sidenum[1] != 0xffff && ld->special) - sides[ld->sidenum[1]].special = ld->special; - } -} - -static void P_LoadLineDefs2(void) -{ - size_t i = numlines; - register line_t *ld = lines; - for (;i--;ld++) - { - ld->frontsector = sides[ld->sidenum[0]].sector; //e6y: Can't be -1 here - ld->backsector = ld->sidenum[1] != 0xffff ? sides[ld->sidenum[1]].sector : 0; + isfrontside = sd->line->sidenum[0] == i; // Repeat count for midtexture - if ((ld->flags & ML_EFFECT5) && (ld->sidenum[1] != 0xffff) - && !(ld->special >= 300 && ld->special < 500)) // exempt linedef exec specials + if (((sd->line->flags & (ML_TWOSIDED|ML_EFFECT5)) == (ML_TWOSIDED|ML_EFFECT5)) + && !(sd->special >= 300 && sd->special < 500)) // exempt linedef exec specials { - sides[ld->sidenum[0]].repeatcnt = (INT16)(((unsigned)sides[ld->sidenum[0]].textureoffset >> FRACBITS) >> 12); - sides[ld->sidenum[0]].textureoffset = (((unsigned)sides[ld->sidenum[0]].textureoffset >> FRACBITS) & 2047) << FRACBITS; - sides[ld->sidenum[1]].repeatcnt = (INT16)(((unsigned)sides[ld->sidenum[1]].textureoffset >> FRACBITS) >> 12); - sides[ld->sidenum[1]].textureoffset = (((unsigned)sides[ld->sidenum[1]].textureoffset >> FRACBITS) & 2047) << FRACBITS; + sd->repeatcnt = (INT16)(((unsigned)textureoffset) >> 12); + sd->textureoffset = (((unsigned)textureoffset) & 2047) << FRACBITS; } - - // Compile linedef 'text' from both sidedefs 'text' for appropriate specials. - switch(ld->special) + else { - case 331: // Trigger linedef executor: Skin - Continuous - case 332: // Trigger linedef executor: Skin - Each time - case 333: // Trigger linedef executor: Skin - Once - case 443: // Calls a named Lua function - if (sides[ld->sidenum[0]].text) - { - size_t len = strlen(sides[ld->sidenum[0]].text)+1; - if (ld->sidenum[1] != 0xffff && sides[ld->sidenum[1]].text) - len += strlen(sides[ld->sidenum[1]].text); - ld->text = Z_Malloc(len, PU_LEVEL, NULL); - M_Memcpy(ld->text, sides[ld->sidenum[0]].text, strlen(sides[ld->sidenum[0]].text)+1); - if (ld->sidenum[1] != 0xffff && sides[ld->sidenum[1]].text) - M_Memcpy(ld->text+strlen(ld->text)+1, sides[ld->sidenum[1]].text, strlen(sides[ld->sidenum[1]].text)+1); - } - break; + sd->repeatcnt = 0; + sd->textureoffset = textureoffset << FRACBITS; } - } - - // Optimize sidedefs - if (M_CheckParm("-compress")) - { - side_t *newsides; - size_t numnewsides = 0; - size_t z; - - for (i = 0; i < numsides; i++) - { - size_t j, k; - if (sides[i].sector == NULL) - continue; - - for (k = numlines, ld = lines; k--; ld++) - { - if (ld->sidenum[0] == i) - ld->sidenum[0] = (UINT16)numnewsides; - - if (ld->sidenum[1] == i) - ld->sidenum[1] = (UINT16)numnewsides; - } - - for (j = i+1; j < numsides; j++) - { - if (sides[j].sector == NULL) - continue; - - if (!memcmp(&sides[i], &sides[j], sizeof(side_t))) - { - // Find the linedefs that belong to this one - for (k = numlines, ld = lines; k--; ld++) - { - if (ld->sidenum[0] == j) - ld->sidenum[0] = (UINT16)numnewsides; - - if (ld->sidenum[1] == j) - ld->sidenum[1] = (UINT16)numnewsides; - } - sides[j].sector = NULL; // Flag for deletion - } - } - numnewsides++; - } - - // We're loading crap into this block anyhow, so no point in zeroing it out. - newsides = Z_Malloc(numnewsides * sizeof(*newsides), PU_LEVEL, NULL); - - // Copy the sides to their new block of memory. - for (i = 0, z = 0; i < numsides; i++) - { - if (sides[i].sector != NULL) - M_Memcpy(&newsides[z++], &sides[i], sizeof(side_t)); - } - - CONS_Debug(DBG_SETUP, "Old sides is %s, new sides is %s\n", sizeu1(numsides), sizeu1(numnewsides)); - - Z_Free(sides); - sides = newsides; - numsides = numnewsides; - } -} - -static void P_LoadRawSideDefs2(void *data) -{ - UINT16 i; - - for (i = 0; i < numsides; i++) - { - register mapsidedef_t *msd = (mapsidedef_t *)data + i; - register side_t *sd = sides + i; - register sector_t *sec; - - sd->textureoffset = SHORT(msd->textureoffset)<rowoffset = SHORT(msd->rowoffset)<sector); + P_SetSidedefSector(i, SHORT(msd->sector)); - if (sector_num >= numsectors) - { - CONS_Debug(DBG_SETUP, "P_LoadRawSideDefs2: sidedef %u has out-of-range sector num %u\n", i, sector_num); - sector_num = 0; - } - sd->sector = sec = §ors[sector_num]; - } - - sd->sector = sec = §ors[SHORT(msd->sector)]; - - sd->colormap_data = NULL; - - // Colormaps! + // Special info stored in texture fields! switch (sd->special) { - case 63: // variable colormap via 242 linedef + case 63: // Fake floor/ceiling planes case 606: //SoM: 4/4/2000: Just colormap transfer case 447: // Change colormap of tagged sectors! -- Monster Iestyn 14/06/18 case 455: // Fade colormaps! mazmazz 9/12/2018 (:flag_us:) @@ -1336,9 +1150,8 @@ static void P_LoadRawSideDefs2(void *data) sd->midtexture = get_number(process); } - // always process if back sidedef, because we need that - symbol sd->text = Z_Malloc(7, PU_LEVEL, NULL); - if (i == 1 || msd->toptexture[0] != '-' || msd->toptexture[1] != '\0') + if (isfrontside && !(msd->toptexture[0] == '-' && msd->toptexture[1] == '\0')) { M_Memcpy(process,msd->toptexture,8); process[8] = '\0'; @@ -1415,6 +1228,20 @@ static void P_LoadRawSideDefs2(void *data) break; } + case 259: // Custom FOF + if (!isfrontside) + { + if ((msd->toptexture[0] >= '0' && msd->toptexture[0] <= '9') + || (msd->toptexture[0] >= 'A' && msd->toptexture[0] <= 'F')) + sd->toptexture = axtoi(msd->toptexture); + else + I_Error("Custom FOF (tag %d) needs a value in the linedef's back side upper texture field.", sd->line->tag); + + sd->midtexture = R_TextureNumForName(msd->midtexture); + sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); + break; + } + // FALLTHRU default: // normal cases if (msd->toptexture[0] == '#') { @@ -1434,6 +1261,998 @@ static void P_LoadRawSideDefs2(void *data) } } +static void P_LoadThings(UINT8 *data) +{ + mapthing_t *mt; + size_t i; + + for (i = 0, mt = mapthings; i < nummapthings; i++, mt++) + { + mt->x = READINT16(data); + mt->y = READINT16(data); + + mt->angle = READINT16(data); + mt->type = READUINT16(data); + mt->options = READUINT16(data); + mt->extrainfo = (UINT8)(mt->type >> 12); + + mt->type &= 4095; + + if (mt->type == 1705 || (mt->type == 750 && mt->extrainfo)) + mt->z = mt->options; // NiGHTS Hoops use the full flags bits to set the height. + else + mt->z = mt->options >> ZSHIFT; + + mt->mobj = NULL; + } +} + +// Stores positions for relevant map data spread through a TEXTMAP. +UINT32 mapthingsPos[UINT16_MAX]; +UINT32 linesPos[UINT16_MAX]; +UINT32 sidesPos[UINT16_MAX]; +UINT32 vertexesPos[UINT16_MAX]; +UINT32 sectorsPos[UINT16_MAX]; + +// Determine total amount of map data in TEXTMAP. +static boolean TextmapCount(UINT8 *data, size_t size) +{ + char *tkn = M_GetToken((char *)data); + UINT8 brackets = 0; + + nummapthings = 0; + numlines = 0; + numsides = 0; + numvertexes = 0; + numsectors = 0; + + // Look for namespace at the beginning. + if (!fastcmp(tkn, "namespace")) + { + Z_Free(tkn); + CONS_Alert(CONS_ERROR, "No namespace at beginning of lump!\n"); + return false; + } + Z_Free(tkn); + + // Check if namespace is valid. + tkn = M_GetToken(NULL); + if (!fastcmp(tkn, "srb2")) + CONS_Alert(CONS_WARNING, "Invalid namespace '%s', only 'srb2' is supported.\n", tkn); + Z_Free(tkn); + + tkn = M_GetToken(NULL); + while (tkn && M_GetTokenPos() < size) + { + // Avoid anything inside bracketed stuff, only look for external keywords. + if (brackets) + { + if (fastcmp(tkn, "}")) + brackets--; + } + else if (fastcmp(tkn, "{")) + brackets++; + // Check for valid fields. + else if (fastcmp(tkn, "thing")) + mapthingsPos[nummapthings++] = M_GetTokenPos(); + else if (fastcmp(tkn, "linedef")) + linesPos[numlines++] = M_GetTokenPos(); + else if (fastcmp(tkn, "sidedef")) + sidesPos[numsides++] = M_GetTokenPos(); + else if (fastcmp(tkn, "vertex")) + vertexesPos[numvertexes++] = M_GetTokenPos(); + else if (fastcmp(tkn, "sector")) + sectorsPos[numsectors++] = M_GetTokenPos(); + else + CONS_Alert(CONS_NOTICE, "Unknown field '%s'.\n", tkn); + + Z_Free(tkn); + tkn = M_GetToken(NULL); + } + + Z_Free(tkn); + + if (brackets) + { + CONS_Alert(CONS_ERROR, "Unclosed brackets detected in textmap lump.\n"); + return false; + } + + return true; +} + +static void ParseTextmapVertexParameter(UINT32 i, char *param, char *val) +{ + if (fastcmp(param, "x")) + vertexes[i].x = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "y")) + vertexes[i].y = FLOAT_TO_FIXED(atof(val)); +} + +static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val) +{ + if (fastcmp(param, "heightfloor")) + sectors[i].floorheight = atol(val) << FRACBITS; + else if (fastcmp(param, "heightceiling")) + sectors[i].ceilingheight = atol(val) << FRACBITS; + if (fastcmp(param, "texturefloor")) + sectors[i].floorpic = P_AddLevelFlat(val, foundflats); + else if (fastcmp(param, "textureceiling")) + sectors[i].ceilingpic = P_AddLevelFlat(val, foundflats); + else if (fastcmp(param, "lightlevel")) + sectors[i].lightlevel = atol(val); + else if (fastcmp(param, "special")) + sectors[i].special = atol(val); + else if (fastcmp(param, "id")) + sectors[i].tag = atol(val); + else if (fastcmp(param, "xpanningfloor")) + sectors[i].floor_xoffs = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "ypanningfloor")) + sectors[i].floor_yoffs = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "xpanningceiling")) + sectors[i].ceiling_xoffs = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "ypanningceiling")) + sectors[i].ceiling_yoffs = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "rotationfloor")) + sectors[i].floorpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val))); + else if (fastcmp(param, "rotationceiling")) + sectors[i].ceilingpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val))); +} + +static void ParseTextmapSidedefParameter(UINT32 i, char *param, char *val) +{ + if (fastcmp(param, "offsetx")) + sides[i].textureoffset = atol(val)<floorpic_angle) + { + fixed_t pc = FINECOSINE(sec->floorpic_angle>>ANGLETOFINESHIFT); + fixed_t ps = FINESINE (sec->floorpic_angle>>ANGLETOFINESHIFT); + fixed_t xoffs = sec->floor_xoffs; + fixed_t yoffs = sec->floor_yoffs; + sec->floor_xoffs = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); + sec->floor_yoffs = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); + } + + if (sec->ceilingpic_angle) + { + fixed_t pc = FINECOSINE(sec->ceilingpic_angle>>ANGLETOFINESHIFT); + fixed_t ps = FINESINE (sec->ceilingpic_angle>>ANGLETOFINESHIFT); + fixed_t xoffs = sec->ceiling_xoffs; + fixed_t yoffs = sec->ceiling_yoffs; + sec->ceiling_xoffs = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); + sec->ceiling_yoffs = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); + } +} + +/** Loads the textmap data, after obtaining the elements count and allocating their respective space. + */ +static void P_LoadTextmap(void) +{ + UINT32 i; + + vertex_t *vt; + sector_t *sc; + line_t *ld; + side_t *sd; + mapthing_t *mt; + + CONS_Alert(CONS_NOTICE, "UDMF support is still a work-in-progress; its specs and features are prone to change until it is fully implemented.\n"); + + /// Given the UDMF specs, some fields are given a default value. + /// If an element's field has a default value set, it is omitted + /// from the textmap, and therefore we have to account for it by + /// preemptively setting that value beforehand. + + for (i = 0, vt = vertexes; i < numvertexes; i++, vt++) + { + // Defaults. + vt->x = vt->y = INT32_MAX; + + TextmapParse(vertexesPos[i], i, ParseTextmapVertexParameter); + + if (vt->x == INT32_MAX) + I_Error("P_LoadTextmap: vertex %s has no x value set!\n", sizeu1(i)); + if (vt->y == INT32_MAX) + I_Error("P_LoadTextmap: vertex %s has no y value set!\n", sizeu1(i)); + } + + for (i = 0, sc = sectors; i < numsectors; i++, sc++) + { + // Defaults. + sc->floorheight = 0; + sc->ceilingheight = 0; + + sc->floorpic = 0; + sc->ceilingpic = 0; + + sc->lightlevel = 255; + + sc->special = 0; + sc->tag = 0; + + sc->floor_xoffs = sc->floor_yoffs = 0; + sc->ceiling_xoffs = sc->ceiling_yoffs = 0; + + sc->floorpic_angle = sc->ceilingpic_angle = 0; + + TextmapParse(sectorsPos[i], i, ParseTextmapSectorParameter); + P_InitializeSector(sc); + TextmapFixFlatOffsets(sc); + } + + for (i = 0, ld = lines; i < numlines; i++, ld++) + { + // Defaults. + ld->v1 = ld->v2 = NULL; + ld->flags = 0; + ld->special = 0; + ld->tag = 0; + ld->sidenum[0] = 0xffff; + ld->sidenum[1] = 0xffff; + + TextmapParse(linesPos[i], i, ParseTextmapLinedefParameter); + + if (!ld->v1) + I_Error("P_LoadTextmap: linedef %s has no v1 value set!\n", sizeu1(i)); + if (!ld->v2) + I_Error("P_LoadTextmap: linedef %s has no v2 value set!\n", sizeu1(i)); + if (ld->sidenum[0] == 0xffff) + I_Error("P_LoadTextmap: linedef %s has no sidefront value set!\n", sizeu1(i)); + + P_InitializeLinedef(ld); + } + + for (i = 0, sd = sides; i < numsides; i++, sd++) + { + // Defaults. + sd->textureoffset = 0; + sd->rowoffset = 0; + sd->toptexture = R_TextureNumForName("-"); + sd->midtexture = R_TextureNumForName("-"); + sd->bottomtexture = R_TextureNumForName("-"); + sd->sector = NULL; + sd->repeatcnt = 0; + + TextmapParse(sidesPos[i], i, ParseTextmapSidedefParameter); + + if (!sd->sector) + I_Error("P_LoadTextmap: sidedef %s has no sector value set!\n", sizeu1(i)); + + P_InitializeSidedef(sd); + } + + for (i = 0, mt = mapthings; i < nummapthings; i++, mt++) + { + // Defaults. + mt->x = mt->y = 0; + mt->angle = 0; + mt->type = 0; + mt->options = 0; + mt->z = 0; + mt->extrainfo = 0; + mt->mobj = NULL; + + TextmapParse(mapthingsPos[i], i, ParseTextmapThingParameter); + } +} + +static void P_ProcessLinedefsAfterSidedefs(void) +{ + size_t i = numlines; + register line_t *ld = lines; + for (; i--; ld++) + { + ld->frontsector = sides[ld->sidenum[0]].sector; //e6y: Can't be -1 here + ld->backsector = ld->sidenum[1] != 0xffff ? sides[ld->sidenum[1]].sector : 0; + + // Compile linedef 'text' from both sidedefs 'text' for appropriate specials. + switch (ld->special) + { + case 331: // Trigger linedef executor: Skin - Continuous + case 332: // Trigger linedef executor: Skin - Each time + case 333: // Trigger linedef executor: Skin - Once + case 443: // Calls a named Lua function + if (sides[ld->sidenum[0]].text) + { + size_t len = strlen(sides[ld->sidenum[0]].text) + 1; + if (ld->sidenum[1] != 0xffff && sides[ld->sidenum[1]].text) + len += strlen(sides[ld->sidenum[1]].text); + ld->text = Z_Malloc(len, PU_LEVEL, NULL); + M_Memcpy(ld->text, sides[ld->sidenum[0]].text, strlen(sides[ld->sidenum[0]].text) + 1); + if (ld->sidenum[1] != 0xffff && sides[ld->sidenum[1]].text) + M_Memcpy(ld->text + strlen(ld->text) + 1, sides[ld->sidenum[1]].text, strlen(sides[ld->sidenum[1]].text) + 1); + } + break; + } + } +} + +static boolean P_LoadMapData(const virtres_t *virt) +{ + virtlump_t *virtvertexes = NULL, *virtsectors = NULL, *virtsidedefs = NULL, *virtlinedefs = NULL, *virtthings = NULL; + virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); + + // Count map data. + if (textmap) // Count how many entries for each type we got in textmap. + { + if (!TextmapCount(textmap->data, textmap->size)) + return false; + } + else + { + virtthings = vres_Find(virt, "THINGS"); + virtvertexes = vres_Find(virt, "VERTEXES"); + virtsectors = vres_Find(virt, "SECTORS"); + virtsidedefs = vres_Find(virt, "SIDEDEFS"); + virtlinedefs = vres_Find(virt, "LINEDEFS"); + + if (!virtthings) + I_Error("THINGS lump not found"); + if (!virtvertexes) + I_Error("VERTEXES lump not found"); + if (!virtsectors) + I_Error("SECTORS lump not found"); + if (!virtsidedefs) + I_Error("SIDEDEFS lump not found"); + if (!virtlinedefs) + I_Error("LINEDEFS lump not found"); + + // Traditional doom map format just assumes the number of elements from the lump sizes. + numvertexes = virtvertexes->size / sizeof (mapvertex_t); + numsectors = virtsectors->size / sizeof (mapsector_t); + numsides = virtsidedefs->size / sizeof (mapsidedef_t); + numlines = virtlinedefs->size / sizeof (maplinedef_t); + nummapthings = virtthings->size / (5 * sizeof (INT16)); + } + + if (numvertexes <= 0) + I_Error("Level has no vertices"); + if (numsectors <= 0) + I_Error("Level has no sectors"); + if (numsides <= 0) + I_Error("Level has no sidedefs"); + if (numlines <= 0) + I_Error("Level has no linedefs"); + + vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); + sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); + sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); + lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); + mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); + + // Allocate a big chunk of memory as big as our MAXLEVELFLATS limit. + //Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty + foundflats = calloc(MAXLEVELFLATS, sizeof (*foundflats)); + if (foundflats == NULL) + I_Error("Ran out of memory while loading sectors\n"); + + numlevelflats = 0; + + // Load map data. + if (textmap) + P_LoadTextmap(); + else + { + P_LoadVertices(virtvertexes->data); + P_LoadSectors(virtsectors->data); + P_LoadLinedefs(virtlinedefs->data); + P_LoadSidedefs(virtsidedefs->data); + P_LoadThings(virtthings->data); + } + + P_ProcessLinedefsAfterSidedefs(); + + R_ClearTextureNumCache(true); + + // set the sky flat num + skyflatnum = P_AddLevelFlat(SKYFLATNAME, foundflats); + + // copy table for global usage + levelflats = M_Memcpy(Z_Calloc(numlevelflats * sizeof (*levelflats), PU_LEVEL, NULL), foundflats, numlevelflats * sizeof (levelflat_t)); + free(foundflats); + + // search for animated flats and set up + P_SetupLevelFlatAnims(); + + return true; +} + +static void P_InitializeSubsector(subsector_t *ss) +{ + ss->sector = NULL; +#ifdef FLOORSPLATS + ss->splats = NULL; +#endif + ss->validcount = 0; +} + +static inline void P_LoadSubsectors(UINT8 *data) +{ + mapsubsector_t *ms = (mapsubsector_t*)data; + subsector_t *ss = subsectors; + size_t i; + + for (i = 0; i < numsubsectors; i++, ss++, ms++) + { + ss->numlines = SHORT(ms->numsegs); + ss->firstline = SHORT(ms->firstseg); + P_InitializeSubsector(ss); + } +} + +static void P_LoadNodes(UINT8 *data) +{ + UINT8 j, k; + mapnode_t *mn = (mapnode_t*)data; + node_t *no = nodes; + size_t i; + + for (i = 0; i < numnodes; i++, no++, mn++) + { + no->x = SHORT(mn->x)<y = SHORT(mn->y)<dx = SHORT(mn->dx)<dy = SHORT(mn->dy)<children[j] = SHORT(mn->children[j]); + for (k = 0; k < 4; k++) + no->bbox[j][k] = SHORT(mn->bbox[j][k])<v2->x - seg->v1->x)>>1; + INT64 dy = (seg->v2->y - seg->v1->y)>>1; + return FixedHypot(dx, dy)<<1; +} + +#ifdef HWRENDER +/** Computes the length of a seg as a float. + * This is needed for OpenGL. + * + * \param seg Seg to compute length for. + * \return Length as a float. + */ +static inline float P_SegLengthFloat(seg_t *seg) +{ + float dx, dy; + + // make a vector (start at origin) + dx = FIXED_TO_FLOAT(seg->v2->x - seg->v1->x); + dy = FIXED_TO_FLOAT(seg->v2->y - seg->v1->y); + + return (float)hypot(dx, dy); +} +#endif + +static void P_InitializeSeg(seg_t *seg) +{ + if (seg->linedef) + { + seg->sidedef = &sides[seg->linedef->sidenum[seg->side]]; + + seg->frontsector = seg->sidedef->sector; + seg->backsector = (seg->linedef->flags & ML_TWOSIDED) ? sides[seg->linedef->sidenum[seg->side ^ 1]].sector : NULL; + } + +#ifdef HWRENDER + seg->pv1 = seg->pv2 = NULL; + + //Hurdler: 04/12/2000: for now, only used in hardware mode + seg->lightmaps = NULL; // list of static lightmap for this seg +#endif + + seg->numlights = 0; + seg->rlights = NULL; +#ifdef POLYOBJECTS + seg->polyseg = NULL; + seg->dontrenderme = false; +#endif +} + +static void P_LoadSegs(UINT8 *data) +{ + mapseg_t *ms = (mapseg_t*)data; + seg_t *seg = segs; + size_t i; + + for (i = 0; i < numsegs; i++, seg++, ms++) + { + seg->v1 = &vertexes[SHORT(ms->v1)]; + seg->v2 = &vertexes[SHORT(ms->v2)]; + + seg->side = SHORT(ms->side); + + seg->offset = (SHORT(ms->offset)) << FRACBITS; + + seg->angle = (SHORT(ms->angle)) << FRACBITS; + + seg->linedef = &lines[SHORT(ms->linedef)]; + + seg->length = P_SegLength(seg); +#ifdef HWRENDER + seg->flength = (rendermode == render_opengl) ? P_SegLengthFloat(seg) : 0; +#endif + + seg->glseg = false; + P_InitializeSeg(seg); + } +} + +typedef enum { + NT_DOOM, + NT_XNOD, + NT_ZNOD, + NT_XGLN, + NT_ZGLN, + NT_XGL2, + NT_ZGL2, + NT_XGL3, + NT_ZGL3, + NT_UNSUPPORTED, + NUMNODETYPES +} nodetype_t; + +// Find out the BSP format. +static nodetype_t P_GetNodetype(const virtres_t *virt, UINT8 **nodedata) +{ + boolean supported[NUMNODETYPES] = {0}; + nodetype_t nodetype = NT_UNSUPPORTED; + char signature[4 + 1]; + + if (vres_Find(virt, "TEXTMAP")) + { + *nodedata = vres_Find(virt, "ZNODES")->data; + supported[NT_XGLN] = supported[NT_XGL3] = true; + } + else + { + virtlump_t *virtsegs = vres_Find(virt, "SEGS"); + virtlump_t *virtssectors; + + if (virtsegs && virtsegs->size) + { + *nodedata = vres_Find(virt, "NODES")->data; + return NT_DOOM; // Traditional map format BSP tree. + } + + virtssectors = vres_Find(virt, "SSECTORS"); + + if (virtssectors && virtssectors->size) + { // Possibly GL nodes: NODES ignored, SSECTORS takes precedence as nodes lump, (It is confusing yeah) and has a signature. + *nodedata = virtssectors->data; + supported[NT_XGLN] = supported[NT_ZGLN] = supported[NT_XGL3] = true; + } + else + { // Possibly ZDoom extended nodes: SSECTORS is empty, NODES has a signature. + *nodedata = vres_Find(virt, "NODES")->data; + supported[NT_XNOD] = supported[NT_ZNOD] = true; + } + } + + M_Memcpy(signature, *nodedata, 4); + signature[4] = '\0'; + (*nodedata) += 4; + + if (!strcmp(signature, "XNOD")) + nodetype = NT_XNOD; + else if (!strcmp(signature, "ZNOD")) + nodetype = NT_ZNOD; + else if (!strcmp(signature, "XGLN")) + nodetype = NT_XGLN; + else if (!strcmp(signature, "ZGLN")) + nodetype = NT_ZGLN; + else if (!strcmp(signature, "XGL3")) + nodetype = NT_XGL3; + + return supported[nodetype] ? nodetype : NT_UNSUPPORTED; +} + +// Extended node formats feature additional vertices; useful for OpenGL, but totally useless in gamelogic. +static boolean P_LoadExtraVertices(UINT8 **data) +{ + UINT32 origvrtx = READUINT32((*data)); + UINT32 xtrvrtx = READUINT32((*data)); + line_t* ld = lines; + vertex_t *oldpos = vertexes; + ssize_t offset; + size_t i; + + if (numvertexes != origvrtx) // If native vertex count doesn't match node original vertex count, bail out (broken data?). + { + CONS_Alert(CONS_WARNING, "Vertex count in map data and nodes differ!\n"); + return false; + } + + if (!xtrvrtx) + return true; + + // If extra vertexes were generated, reallocate the vertex array and fix the pointers. + numvertexes += xtrvrtx; + vertexes = Z_Realloc(vertexes, numvertexes*sizeof(*vertexes), PU_LEVEL, NULL); + offset = (size_t)(vertexes - oldpos); + + for (i = 0, ld = lines; i < numlines; i++, ld++) + { + ld->v1 += offset; + ld->v2 += offset; + } + + // Read extra vertex data. + for (i = origvrtx; i < numvertexes; i++) + { + vertexes[i].x = READFIXED((*data)); + vertexes[i].y = READFIXED((*data)); + } + + return true; +} + +static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype) +{ + size_t i, k; + INT16 m; + seg_t *seg; + + // Subsectors + numsubsectors = READUINT32((*data)); + subsectors = Z_Calloc(numsubsectors*sizeof(*subsectors), PU_LEVEL, NULL); + + for (i = 0; i < numsubsectors; i++) + subsectors[i].numlines = READUINT32((*data)); + + // Segs + numsegs = READUINT32((*data)); + segs = Z_Calloc(numsegs*sizeof(*segs), PU_LEVEL, NULL); + + for (i = 0, k = 0; i < numsubsectors; i++) + { + subsectors[i].firstline = k; + P_InitializeSubsector(&subsectors[i]); + + switch (nodetype) + { + case NT_XGLN: + case NT_XGL3: + for (m = 0; m < subsectors[i].numlines; m++, k++) + { + UINT32 vertexnum = READUINT32((*data)); + UINT16 linenum; + + if (vertexnum >= numvertexes) + I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid vertex %d!\n", sizeu1(k), m, vertexnum); + + segs[k - 1 + ((m == 0) ? subsectors[i].numlines : 0)].v2 = segs[k].v1 = &vertexes[vertexnum]; + + READUINT32((*data)); // partner, can be ignored by software renderer + if (nodetype == NT_XGL3) + READUINT16((*data)); // Line number is 32-bit in XGL3, but we're limited to 16 bits. + + linenum = READUINT16((*data)); + if (linenum != 0xFFFF && linenum >= numlines) + I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid linedef %d!\n", sizeu1(k), m, linenum); + segs[k].glseg = (linenum == 0xFFFF); + segs[k].linedef = (linenum == 0xFFFF) ? NULL : &lines[linenum]; + segs[k].side = READUINT8((*data)); + } + break; + + case NT_XNOD: + for (m = 0; m < subsectors[i].numlines; m++, k++) + { + UINT32 v1num = READUINT32((*data)); + UINT32 v2num = READUINT32((*data)); + UINT16 linenum = READUINT16((*data)); + + if (v1num >= numvertexes) + I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid v1 %d!\n", sizeu1(k), m, v1num); + if (v2num >= numvertexes) + I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid v2 %d!\n", sizeu1(k), m, v2num); + if (linenum >= numlines) + I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid linedef %d!\n", sizeu1(k), m, linenum); + + segs[k].v1 = &vertexes[v1num]; + segs[k].v2 = &vertexes[v2num]; + segs[k].linedef = &lines[linenum]; + segs[k].side = READUINT8((*data)); + segs[k].glseg = false; + } + break; + + default: + return false; + } + } + + for (i = 0, seg = segs; i < numsegs; i++, seg++) + { + vertex_t *v1 = seg->v1; + vertex_t *v2 = seg->v2; + P_InitializeSeg(seg); + seg->angle = R_PointToAngle2(v1->x, v1->y, v2->x, v2->y); + if (seg->linedef) + segs[i].offset = FixedHypot(v1->x - seg->linedef->v1->x, v1->y - seg->linedef->v1->y); + } + + return true; +} + +// Auxiliary function: Shrink node ID from 32-bit to 16-bit. +static UINT16 ShrinkNodeID(UINT32 x) { + UINT16 mask = (x >> 16) & 0xC000; + UINT16 result = x; + return result | mask; +} + +static void P_LoadExtendedNodes(UINT8 **data, nodetype_t nodetype) +{ + node_t *mn; + size_t i, j, k; + boolean xgl3 = (nodetype == NT_XGL3); + + numnodes = READINT32((*data)); + nodes = Z_Calloc(numnodes*sizeof(*nodes), PU_LEVEL, NULL); + + for (i = 0, mn = nodes; i < numnodes; i++, mn++) + { + // Splitter + mn->x = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS); + mn->y = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS); + mn->dx = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS); + mn->dy = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS); + + // Bounding boxes + for (j = 0; j < 2; j++) + for (k = 0; k < 4; k++) + mn->bbox[j][k] = READINT16((*data)) << FRACBITS; + + //Children + mn->children[0] = ShrinkNodeID(READUINT32((*data))); /// \todo Use UINT32 for node children in a future, instead? + mn->children[1] = ShrinkNodeID(READUINT32((*data))); + } +} + +static void P_LoadMapBSP(const virtres_t *virt) +{ + UINT8 *nodedata = NULL; + nodetype_t nodetype = P_GetNodetype(virt, &nodedata); + + switch (nodetype) + { + case NT_DOOM: + { + virtlump_t *virtssectors = vres_Find(virt, "SSECTORS"); + virtlump_t* virtnodes = vres_Find(virt, "NODES"); + virtlump_t *virtsegs = vres_Find(virt, "SEGS"); + + numsubsectors = virtssectors->size / sizeof(mapsubsector_t); + numnodes = virtnodes->size / sizeof(mapnode_t); + numsegs = virtsegs->size / sizeof(mapseg_t); + + if (numsubsectors <= 0) + I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)"); + if (numnodes <= 0) + I_Error("Level has no nodes"); + if (numsegs <= 0) + I_Error("Level has no segs"); + + subsectors = Z_Calloc(numsubsectors * sizeof(*subsectors), PU_LEVEL, NULL); + nodes = Z_Calloc(numnodes * sizeof(*nodes), PU_LEVEL, NULL); + segs = Z_Calloc(numsegs * sizeof(*segs), PU_LEVEL, NULL); + + P_LoadSubsectors(virtssectors->data); + P_LoadNodes(virtnodes->data); + P_LoadSegs(virtsegs->data); + break; + } + case NT_XNOD: + case NT_XGLN: + case NT_XGL3: + if (!P_LoadExtraVertices(&nodedata)) + return; + if (!P_LoadExtendedSubsectorsAndSegs(&nodedata, nodetype)) + return; + P_LoadExtendedNodes(&nodedata, nodetype); + break; + default: + CONS_Alert(CONS_WARNING, "Unsupported BSP format detected.\n"); + return; + } + return; +} + +// Split from P_LoadBlockMap for convenience +// -- Monster Iestyn 08/01/18 +static void P_ReadBlockMapLump(INT16 *wadblockmaplump, size_t count) +{ + size_t i; + blockmaplump = Z_Calloc(sizeof (*blockmaplump) * count, PU_LEVEL, NULL); + + // killough 3/1/98: Expand wad blockmap into larger internal one, + // by treating all offsets except -1 as unsigned and zero-extending + // them. This potentially doubles the size of blockmaps allowed, + // because Doom originally considered the offsets as always signed. + + blockmaplump[0] = SHORT(wadblockmaplump[0]); + blockmaplump[1] = SHORT(wadblockmaplump[1]); + blockmaplump[2] = (INT32)(SHORT(wadblockmaplump[2])) & 0xffff; + blockmaplump[3] = (INT32)(SHORT(wadblockmaplump[3])) & 0xffff; + + for (i = 4; i < count; i++) + { + INT16 t = SHORT(wadblockmaplump[i]); // killough 3/1/98 + blockmaplump[i] = t == -1 ? (INT32)-1 : (INT32) t & 0xffff; + } +} + +// This needs to be a separate function +// because making both the WAD and PK3 loading code use +// the same functions is trickier than it looks for blockmap +// -- Monster Iestyn 09/01/18 +static boolean P_LoadBlockMap(UINT8 *data, size_t count) +{ + if (!count || count >= 0x20000) + return false; + + //CONS_Printf("Reading blockmap lump for pk3...\n"); + + // no need to malloc anything, assume the data is uncompressed for now + count /= 2; + P_ReadBlockMapLump((INT16 *)data, count); + + bmaporgx = blockmaplump[0]<= 0x20000) - return false; + // Lookup tables + if (virtreject) + P_LoadReject(virtreject->data, virtreject->size); + else + rejectmatrix = NULL; - //CONS_Printf("Reading blockmap lump for pk3...\n"); - - // no need to malloc anything, assume the data is uncompressed for now - count /= 2; - P_ReadBlockMapLump((INT16 *)data, count); - - bmaporgx = blockmaplump[0]<data, virtblockmap->size))) + P_CreateBlockMap(); } // -// P_GroupLines +// P_LinkMapData // Builds sector line lists and subsector sector numbers. // Finds block bounding boxes for sectors. // -static void P_GroupLines(void) +static void P_LinkMapData(void) { size_t i, j; line_t *li; @@ -1773,20 +2558,20 @@ static void P_GroupLines(void) for (i = 0; i < numsubsectors; i++, ss++) { if (ss->firstline >= numsegs) - CorruptMapError(va("P_GroupLines: ss->firstline invalid " + CorruptMapError(va("P_LinkMapData: ss->firstline invalid " "(subsector %s, firstline refers to %d of %s)", sizeu1(i), ss->firstline, sizeu2(numsegs))); seg = &segs[ss->firstline]; sidei = (size_t)(seg->sidedef - sides); if (!seg->sidedef) - CorruptMapError(va("P_GroupLines: seg->sidedef is NULL " + CorruptMapError(va("P_LinkMapData: seg->sidedef is NULL " "(subsector %s, firstline is %d)", sizeu1(i), ss->firstline)); if (seg->sidedef - sides < 0 || seg->sidedef - sides > (UINT16)numsides) - CorruptMapError(va("P_GroupLines: seg->sidedef refers to sidedef %s of %s " + CorruptMapError(va("P_LinkMapData: seg->sidedef refers to sidedef %s of %s " "(subsector %s, firstline is %d)", sizeu1(sidei), sizeu2(numsides), sizeu3(i), ss->firstline)); if (!seg->sidedef->sector) - CorruptMapError(va("P_GroupLines: seg->sidedef->sector is NULL " + CorruptMapError(va("P_LinkMapData: seg->sidedef->sector is NULL " "(subsector %s, firstline is %d, sidedef is %s)", sizeu1(i), ss->firstline, sizeu1(sidei))); ss->sector = seg->sidedef->sector; @@ -1807,7 +2592,7 @@ static void P_GroupLines(void) if (sector->linecount == 0) // no lines found? { sector->lines = NULL; - CONS_Debug(DBG_SETUP, "P_GroupLines: sector %s has no lines\n", sizeu1(i)); + CONS_Debug(DBG_SETUP, "P_LinkMapData: sector %s has no lines\n", sizeu1(i)); } else { @@ -1850,172 +2635,6 @@ static void P_GroupLines(void) } } -// PK3 version -// -- Monster Iestyn 09/01/18 -static void P_LoadRawReject(UINT8 *data, size_t count) -{ - if (!count) // zero length, someone probably used ZDBSP - { - rejectmatrix = NULL; - CONS_Debug(DBG_SETUP, "P_LoadRawReject: REJECT lump has size 0, will not be loaded\n"); - } - else - { - rejectmatrix = Z_Malloc(count, PU_LEVEL, NULL); // allocate memory for the reject matrix - M_Memcpy(rejectmatrix, data, count); // copy the data into it - } -} - -static void P_LoadMapBSP(const virtres_t* virt) -{ - virtlump_t* virtssectors = vres_Find(virt, "SSECTORS"); - virtlump_t* virtsegs = vres_Find(virt, "SEGS"); - virtlump_t* virtnodes = vres_Find(virt, "NODES"); - - numsubsectors = virtssectors->size / sizeof(mapsubsector_t); - numnodes = virtnodes->size / sizeof(mapnode_t); - numsegs = virtsegs->size / sizeof(mapseg_t); - - if (numsubsectors <= 0) - I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)"); - if (numnodes <= 0) - I_Error("Level has no nodes"); - if (numsegs <= 0) - I_Error("Level has no segs"); - - subsectors = Z_Calloc(numsubsectors * sizeof(*subsectors), PU_LEVEL, NULL); - nodes = Z_Calloc(numnodes * sizeof(*nodes), PU_LEVEL, NULL); - segs = Z_Calloc(numsegs * sizeof(*segs), PU_LEVEL, NULL); - - // Nodes - P_LoadRawSubsectors(virtssectors->data); - P_LoadRawNodes(virtnodes->data); - P_LoadRawSegs(virtsegs->data); -} - -static void P_LoadMapLUT(const virtres_t* virt) -{ - virtlump_t* virtblockmap = vres_Find(virt, "BLOCKMAP"); - virtlump_t* virtreject = vres_Find(virt, "REJECT"); - - // Lookup tables - if (virtreject) - P_LoadRawReject(virtreject->data, virtreject->size); - else - rejectmatrix = NULL; - - if (!(virtblockmap && P_LoadRawBlockMap(virtblockmap->data, virtblockmap->size))) - P_CreateBlockMap(); -} - -static void P_LoadMapData(const virtres_t* virt) -{ - virtlump_t* virtvertexes = NULL, * virtsectors = NULL, * virtsidedefs = NULL, * virtlinedefs = NULL, * virtthings = NULL; -#ifdef UDMF - virtlump_t* textmap = vres_Find(virt, "TEXTMAP"); - - // Count map data. - if (textmap) - { - nummapthings = 0; - numlines = 0; - numsides = 0; - numvertexes = 0; - numsectors = 0; - - // Count how many entries for each type we got in textmap. - //TextmapCount(vtextmap->data, vtextmap->size); - } - else -#endif - { - virtthings = vres_Find(virt, "THINGS"); - virtvertexes = vres_Find(virt, "VERTEXES"); - virtsectors = vres_Find(virt, "SECTORS"); - virtsidedefs = vres_Find(virt, "SIDEDEFS"); - virtlinedefs = vres_Find(virt, "LINEDEFS"); - - if (!virtthings) - I_Error("THINGS lump not found"); - if (!virtvertexes) - I_Error("VERTEXES lump not found"); - if (!virtsectors) - I_Error("SECTORS lump not found"); - if (!virtsidedefs) - I_Error("SIDEDEFS lump not found"); - if (!virtlinedefs) - I_Error("LINEDEFS lump not found"); - - // Traditional doom map format just assumes the number of elements from the lump sizes. - numvertexes = virtvertexes->size / sizeof (mapvertex_t); - numsectors = virtsectors->size / sizeof (mapsector_t); - numsides = virtsidedefs->size / sizeof (mapsidedef_t); - numlines = virtlinedefs->size / sizeof (maplinedef_t); - nummapthings = virtthings->size / (5 * sizeof (INT16)); - } - - if (numvertexes <= 0) - I_Error("Level has no vertices"); - if (numsectors <= 0) - I_Error("Level has no sectors"); - if (numsides <= 0) - I_Error("Level has no sidedefs"); - if (numlines <= 0) - I_Error("Level has no linedefs"); - - vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); - sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); - sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); - lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); - mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); - - // Allocate a big chunk of memory as big as our MAXLEVELFLATS limit. - //Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty - foundflats = calloc(MAXLEVELFLATS, sizeof (*foundflats)); - if (foundflats == NULL) - I_Error("Ran out of memory while loading sectors\n"); - - numlevelflats = 0; - -#ifdef UDMF - if (textmap) - { - - } - else -#endif - { - // Strict map data - P_LoadRawVertexes(virtvertexes->data); - P_LoadRawSectors(virtsectors->data); - P_LoadRawLineDefs(virtlinedefs->data); - P_SetupLines(); - P_LoadRawSideDefs2(virtsidedefs->data); - P_PrepareRawThings(virtthings->data); - } - - R_ClearTextureNumCache(true); - - // set the sky flat num - skyflatnum = P_AddLevelFlat(SKYFLATNAME, foundflats); - - // copy table for global usage - levelflats = M_Memcpy(Z_Calloc(numlevelflats * sizeof (*levelflats), PU_LEVEL, NULL), foundflats, numlevelflats * sizeof (levelflat_t)); - free(foundflats); - - // search for animated flats and set up - P_SetupLevelFlatAnims(); - - // Copy relevant map data for NetArchive purposes. - spawnsectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); - spawnlines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); - spawnsides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); - - memcpy(spawnsectors, sectors, numsectors * sizeof (*sectors)); - memcpy(spawnlines, lines, numlines * sizeof (*lines)); - memcpy(spawnsides, sides, numsides * sizeof (*sides)); -} - /** Compute MD5 message digest for bytes read from memory source * * The resulting message digest number will be written into the 16 bytes @@ -2025,7 +2644,7 @@ static void P_LoadMapData(const virtres_t* virt) * \param resblock resulting MD5 checksum * \return 0 if MD5 checksum was made, and is at resblock, 1 if error was found */ -static INT32 P_MakeBufferMD5(const char* buffer, size_t len, void* resblock) +static INT32 P_MakeBufferMD5(const char *buffer, size_t len, void *resblock) { #ifdef NOMD5 (void)buffer; @@ -2042,85 +2661,69 @@ static INT32 P_MakeBufferMD5(const char* buffer, size_t len, void* resblock) #endif } -static void P_MakeMapMD5(virtres_t* virt, void* dest) +static void P_MakeMapMD5(virtres_t *virt, void *dest) { - unsigned char linemd5[16]; - unsigned char sectormd5[16]; - unsigned char thingmd5[16]; - unsigned char sidedefmd5[16]; + virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); unsigned char resmd5[16]; - UINT8 i; - // Create a hash for the current map - // get the actual lumps! - virtlump_t *virtlines = vres_Find(virt, "LINEDEFS"); - virtlump_t *virtsectors = vres_Find(virt, "SECTORS"); - virtlump_t *virtmthings = vres_Find(virt, "THINGS"); - virtlump_t *virtsides = vres_Find(virt, "SIDEDEFS"); + if (textmap) + P_MakeBufferMD5((char*)textmap->data, textmap->size, resmd5); + else + { + unsigned char linemd5[16]; + unsigned char sectormd5[16]; + unsigned char thingmd5[16]; + unsigned char sidedefmd5[16]; + UINT8 i; - P_MakeBufferMD5((char*)virtlines->data, virtlines->size, linemd5); - P_MakeBufferMD5((char*)virtsectors->data, virtsectors->size, sectormd5); - P_MakeBufferMD5((char*)virtmthings->data, virtmthings->size, thingmd5); - P_MakeBufferMD5((char*)virtsides->data, virtsides->size, sidedefmd5); + // Create a hash for the current map + // get the actual lumps! + virtlump_t* virtlines = vres_Find(virt, "LINEDEFS"); + virtlump_t* virtsectors = vres_Find(virt, "SECTORS"); + virtlump_t* virtmthings = vres_Find(virt, "THINGS"); + virtlump_t* virtsides = vres_Find(virt, "SIDEDEFS"); - for (i = 0; i < 16; i++) - resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF; + P_MakeBufferMD5((char*)virtlines->data, virtlines->size, linemd5); + P_MakeBufferMD5((char*)virtsectors->data, virtsectors->size, sectormd5); + P_MakeBufferMD5((char*)virtmthings->data, virtmthings->size, thingmd5); + P_MakeBufferMD5((char*)virtsides->data, virtsides->size, sidedefmd5); + + for (i = 0; i < 16; i++) + resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF; + } M_Memcpy(dest, &resmd5, 16); } -static void P_LoadMapFromFile(void) +static boolean P_LoadMapFromFile(void) { virtres_t *virt = vres_GetMap(lastloadedmaplumpnum); - P_LoadMapData(virt); + if (!P_LoadMapData(virt)) + return false; P_LoadMapBSP(virt); P_LoadMapLUT(virt); - P_LoadLineDefs2(); - P_GroupLines(); + P_LinkMapData(); + + // Copy relevant map data for NetArchive purposes. + spawnsectors = Z_Calloc(numsectors * sizeof(*sectors), PU_LEVEL, NULL); + spawnlines = Z_Calloc(numlines * sizeof(*lines), PU_LEVEL, NULL); + spawnsides = Z_Calloc(numsides * sizeof(*sides), PU_LEVEL, NULL); + + memcpy(spawnsectors, sectors, numsectors * sizeof(*sectors)); + memcpy(spawnlines, lines, numlines * sizeof(*lines)); + memcpy(spawnsides, sides, numsides * sizeof(*sides)); P_MakeMapMD5(virt, &mapmd5); vres_Free(virt); + return true; } -#if 0 -static char *levellumps[] = -{ - "label", // ML_LABEL, A separator, name, MAPxx - "THINGS", // ML_THINGS, Enemies, items.. - "LINEDEFS", // ML_LINEDEFS, Linedefs, from editing - "SIDEDEFS", // ML_SIDEDEFS, Sidedefs, from editing - "VERTEXES", // ML_VERTEXES, Vertices, edited and BSP splits generated - "SEGS", // ML_SEGS, Linesegs, from linedefs split by BSP - "SSECTORS", // ML_SSECTORS, Subsectors, list of linesegs - "NODES", // ML_NODES, BSP nodes - "SECTORS", // ML_SECTORS, Sectors, from editing - "REJECT", // ML_REJECT, LUT, sector-sector visibility -}; - -/** Checks a lump and returns whether it is a valid start-of-level marker. - * - * \param lumpnum Lump number to check. - * \return True if the lump is a valid level marker, false if not. - */ -static inline boolean P_CheckLevel(lumpnum_t lumpnum) -{ - UINT16 file, lump; - size_t i; - - for (i = ML_THINGS; i <= ML_REJECT; i++) - { - file = WADFILENUM(lumpnum); - lump = LUMPNUM(lumpnum+1); - if (file > numwadfiles || lump < LUMPNUM(lumpnum) || lump > wadfiles[file]->numlumps || - memcmp(wadfiles[file]->lumpinfo[lump].name, levellumps[i], 8) != 0) - return false; - } - return true; // all right -} -#endif +// +// LEVEL INITIALIZATION FUNCTIONS +// /** Sets up a sky texture to use for the level. * The sky texture is used instead of F_SKY1. @@ -2211,7 +2814,7 @@ static void P_InitLevelSettings(void) // earthquake camera memset(&quake,0,sizeof(struct quake)); - if ((netgame || multiplayer) && gametype == GT_COOP && cv_coopstarposts.value == 2) + if ((netgame || multiplayer) && G_GametypeUsesCoopStarposts() && cv_coopstarposts.value == 2) { for (i = 0; i < MAXPLAYERS; i++) { @@ -2229,7 +2832,7 @@ static void P_InitLevelSettings(void) { G_PlayerReborn(i, true); - if (canresetlives && (netgame || multiplayer) && playeringame[i] && (gametype == GT_COMPETITION || players[i].lives <= 0)) + if (canresetlives && (netgame || multiplayer) && playeringame[i] && (G_CompetitionGametype() || players[i].lives <= 0)) { // In Co-Op, replenish a user's lives if they are depleted. players[i].lives = cv_startinglives.value; @@ -2250,12 +2853,8 @@ static void P_InitLevelSettings(void) CV_SetValue(&cv_analog2, true); } -// -// P_LoadThingsOnly -// -// "Reloads" a level, but only reloads all of the mobjs. -// -void P_LoadThingsOnly(void) +// Respawns all the mapthings and mobjs in the map from the already loaded map data. +void P_RespawnThings(void) { // Search through all the thinkers. thinker_t *think; @@ -2523,17 +3122,10 @@ static void P_SetupCamera(void) { mapthing_t *thing; - switch (gametype) - { - case GT_MATCH: - case GT_TAG: + if (gametyperules & GTR_DEATHMATCHSTARTS) thing = deathmatchstarts[0]; - break; - - default: + else thing = playerstarts[0]; - break; - } if (thing) { @@ -2748,7 +3340,7 @@ static void P_InitGametype(void) P_InitPlayers(); // restore time in netgame (see also g_game.c) - if ((netgame || multiplayer) && gametype == GT_COOP && cv_coopstarposts.value == 2) + if ((netgame || multiplayer) && G_GametypeUsesCoopStarposts() && cv_coopstarposts.value == 2) { // is this a hack? maybe tic_t maxstarposttime = 0; @@ -2792,6 +3384,7 @@ boolean P_LoadLevel(boolean fromnetsave) // This is needed. Don't touch. maptol = mapheaderinfo[gamemap-1]->typeoflevel; + gametyperules = gametypedefaultrules[gametype]; CON_Drawer(); // let the user know what we are going to do I_FinishUpdate(); // page flip or blit buffer @@ -2955,7 +3548,7 @@ boolean P_LoadLevel(boolean fromnetsave) // internal game map maplumpname = G_BuildMapName(gamemap); lastloadedmaplumpnum = W_CheckNumForName(maplumpname); - if (lastloadedmaplumpnum == INT16_MAX) + if (lastloadedmaplumpnum == LUMPERROR) I_Error("Map %s not found.\n", maplumpname); R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette); @@ -2968,8 +3561,8 @@ boolean P_LoadLevel(boolean fromnetsave) P_MapStart(); - if (lastloadedmaplumpnum) - P_LoadMapFromFile(); + if (!P_LoadMapFromFile()) + return false; // init gravity, tag lists, // anything that P_ResetDynamicSlopes/P_LoadThings needs to know @@ -2994,23 +3587,14 @@ boolean P_LoadLevel(boolean fromnetsave) P_SpawnPrecipitation(); #ifdef HWRENDER // not win32 only 19990829 by Kin + // Lactozilla: Free extrasubsectors regardless of renderer. + // Maybe we're not in OpenGL anymore. + if (extrasubsectors) + free(extrasubsectors); + extrasubsectors = NULL; + // stuff like HWR_CreatePlanePolygons is called there if (rendermode == render_opengl) - { - // Lactozilla (December 8, 2019) - // Level setup used to free EVERY mipmap from memory. - // Even mipmaps that aren't related to level textures. - // Presumably, the hardware render code used to store textures as level data. - // Meaning, they had memory allocated and marked with the PU_LEVEL tag. - // Level textures are only reloaded after R_LoadTextures, which is - // when the texture list is loaded. -#ifdef ALAM_LIGHTING - // BP: reset light between levels (we draw preview frame lights on current frame) - HWR_ResetLights(); -#endif - // Correct missing sidedefs & deep water trick - HWR_CorrectSWTricks(); - HWR_CreatePlanePolygons((INT32)numnodes - 1); - } + HWR_SetupLevel(); #endif // oh god I hope this helps @@ -3090,6 +3674,26 @@ boolean P_LoadLevel(boolean fromnetsave) return true; } +#ifdef HWRENDER +void HWR_SetupLevel(void) +{ + // Lactozilla (December 8, 2019) + // Level setup used to free EVERY mipmap from memory. + // Even mipmaps that aren't related to level textures. + // Presumably, the hardware render code used to store textures as level data. + // Meaning, they had memory allocated and marked with the PU_LEVEL tag. + // Level textures are only reloaded after R_LoadTextures, which is + // when the texture list is loaded. +#ifdef ALAM_LIGHTING + // BP: reset light between levels (we draw preview frame lights on current frame) + HWR_ResetLights(); +#endif + // Correct missing sidedefs & deep water trick + HWR_CorrectSWTricks(); + HWR_CreatePlanePolygons((INT32)numnodes - 1); +} +#endif + // // P_RunSOC // diff --git a/src/p_setup.h b/src/p_setup.h index de791677c..d7e2d8861 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -96,8 +96,11 @@ void P_SetupLevelSky(INT32 skynum, boolean global); #ifdef SCANTHINGS void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); #endif -void P_LoadThingsOnly(void); +void P_RespawnThings(void); boolean P_LoadLevel(boolean fromnetsave); +#ifdef HWRENDER +void HWR_SetupLevel(void); +#endif boolean P_AddWadFile(const char *wadfilename); boolean P_RunSOC(const char *socfilename); void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); diff --git a/src/p_sight.c b/src/p_sight.c index 499d4a095..07dfabbc1 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -222,6 +222,9 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) fixed_t fracx, fracy; #endif + if (seg->glseg) + continue; + // already checked other side? if (line->validcount == validcount) continue; diff --git a/src/p_slopes.c b/src/p_slopes.c index f35e7d732..2cf2c74ba 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -50,10 +50,10 @@ static void ReconfigureViaVertexes (pslope_t *slope, const vector3_t v1, const v // Set some defaults for a non-sloped "slope" if (vec1.z == 0 && vec2.z == 0) { - /// \todo Fix fully flat cases. - slope->zangle = slope->xydirection = 0; slope->zdelta = slope->d.x = slope->d.y = 0; + slope->normal.x = slope->normal.y = 0; + slope->normal.z = FRACUNIT; } else { @@ -445,10 +445,9 @@ static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag I_Error("MakeViaMapthings: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1); vx[i].x = mt->x << FRACBITS; vx[i].y = mt->y << FRACBITS; - if (mt->extrainfo) - vx[i].z = mt->options << FRACBITS; - else - vx[i].z = (R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector->floorheight) + ((mt->options >> ZSHIFT) << FRACBITS); + vx[i].z = mt->z << FRACBITS; + if (!mt->extrainfo) + vx[i].z += R_PointInSubsector(vx[i].x, vx[i].y)->sector->floorheight; } ReconfigureViaVertexes(ret, vx[0], vx[1], vx[2]); @@ -654,7 +653,9 @@ void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope) // Handles slope ejection for objects void P_SlopeLaunch(mobj_t *mo) { - if (!(mo->standingslope->flags & SL_NOPHYSICS)) // If there's physics, time for launching. + if (!(mo->standingslope->flags & SL_NOPHYSICS) // If there's physics, time for launching. + && (mo->standingslope->normal.x != 0 + || mo->standingslope->normal.y != 0)) { // Double the pre-rotation Z, then halve the post-rotation Z. This reduces the // vertical launch given from slopes while increasing the horizontal launch @@ -711,8 +712,7 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope) void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) { vector3_t mom; // Ditto. - - if (slope->flags & SL_NOPHYSICS) { // No physics, no need to make anything complicated. + if (slope->flags & SL_NOPHYSICS || (slope->normal.x == 0 && slope->normal.y == 0)) { // No physics, no need to make anything complicated. if (P_MobjFlip(thing)*(thing->momz) < 0) // falling, land on slope { thing->standingslope = slope; diff --git a/src/p_spec.c b/src/p_spec.c index 20c312bb3..32a05969f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -52,9 +52,6 @@ mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs // Amount (dx, dy) vector linedef is shifted right to get scroll amount #define SCROLL_SHIFT 5 -// This must be updated whenever we up the max flat size - quicker to assume rather than figuring out the sqrt of the specific flat's filesize. -#define MAXFLATSIZE (2048<mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ROPEHANG) @@ -5189,38 +5185,34 @@ DoneSection2: // Next, we need to find the closest point on the line between each set, and determine which one we're // closest to. + p.x = player->mo->x; + p.y = player->mo->y; + p.z = player->mo->z; + // Waypointmid and Waypointlow: if (waypointlow) { - v1.x = waypointmid->x; - v1.y = waypointmid->y; - v1.z = waypointmid->z; - v2.x = waypointlow->x; - v2.y = waypointlow->y; - v2.z = waypointlow->z; - junk.v1 = &v1; - junk.v2 = &v2; - junk.dx = v2.x - v1.x; - junk.dy = v2.y - v1.y; + line[0].x = waypointmid->x; + line[0].y = waypointmid->y; + line[0].z = waypointmid->z; + line[1].x = waypointlow->x; + line[1].y = waypointlow->y; + line[1].z = waypointlow->z; - P_ClosestPointOnLine3D(player->mo->x, player->mo->y, player->mo->z, &junk, &resultlow); + P_ClosestPointOnLine3D(&p, line, &resultlow); } // Waypointmid and Waypointhigh: if (waypointhigh) { - v1.x = waypointmid->x; - v1.y = waypointmid->y; - v1.z = waypointmid->z; - v2.x = waypointhigh->x; - v2.y = waypointhigh->y; - v2.z = waypointhigh->z; - junk.v1 = &v1; - junk.v2 = &v2; - junk.dx = v2.x - v1.x; - junk.dy = v2.y - v1.y; + line[0].x = waypointmid->x; + line[0].y = waypointmid->y; + line[0].z = waypointmid->z; + line[1].x = waypointhigh->x; + line[1].y = waypointhigh->y; + line[1].z = waypointhigh->z; - P_ClosestPointOnLine3D(player->mo->x, player->mo->y, player->mo->z, &junk, &resulthigh); + P_ClosestPointOnLine3D(&p, line, &resulthigh); } // 3D support now available. Disregard the previous notice here. -Red @@ -6433,7 +6425,6 @@ void P_SpawnSpecials(boolean fromnetsave) INT32 j; thinkerlist_t *secthinkers; thinker_t *th; - virtres_t* virt = NULL; // This used to be used, and *should* be used in the future, // but currently isn't. (void)fromnetsave; @@ -7179,38 +7170,14 @@ void P_SpawnSpecials(boolean fromnetsave) EV_AddLaserThinker(§ors[s], §ors[sec], lines + i, secthinkers); break; - case 259: // Make-Your-Own FOF! + case 259: // Custom FOF if (lines[i].sidenum[1] != 0xffff) { - UINT8 *data; - UINT16 b; - - if (!virt) - virt = vres_GetMap(lastloadedmaplumpnum); - - data = (UINT8*) vres_Find(virt, "SIDEDEFS")->data; - - for (b = 0; b < (INT16)numsides; b++) - { - register mapsidedef_t *msd = (mapsidedef_t *)data + b; - - if (b == lines[i].sidenum[1]) - { - if ((msd->toptexture[0] >= '0' && msd->toptexture[0] <= '9') - || (msd->toptexture[0] >= 'A' && msd->toptexture[0] <= 'F')) - { - ffloortype_e FOF_Flags = axtoi(msd->toptexture); - - P_AddFakeFloorsByLine(i, FOF_Flags, secthinkers); - break; - } - else - I_Error("Make-Your-Own-FOF (tag %d) needs a value in the linedef's second side upper texture field.", lines[i].tag); - } - } + ffloortype_e fofflags = sides[lines[i].sidenum[1]].toptexture; + P_AddFakeFloorsByLine(i, fofflags, secthinkers); } else - I_Error("Make-Your-Own FOF (tag %d) found without a 2nd linedef side!", lines[i].tag); + I_Error("Custom FOF (tag %d) found without a linedef back side!", lines[i].tag); break; case 300: // Linedef executor (combines with sector special 974/975) and commands @@ -7433,9 +7400,6 @@ void P_SpawnSpecials(boolean fromnetsave) } } - if (virt) - vres_Free(virt); - // Allocate each list for (i = 0; i < numsectors; i++) if(secthinkers[i].thinkers) diff --git a/src/p_spec.h b/src/p_spec.h index 630bcb3de..4b64fe05d 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -27,6 +27,9 @@ extern mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs // #define GETSECSPECIAL(i,j) ((i >> ((j-1)*4))&15) +// This must be updated whenever we up the max flat size - quicker to assume rather than figuring out the sqrt of the specific flat's filesize. +#define MAXFLATSIZE (2048<target, players[i].mo); P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); + + // Make sure we're not being carried before our tracer is changed + if (players[i].powers[pw_carry] != CR_NIGHTSMODE) + players[i].powers[pw_carry] = CR_NONE; + P_SetTarget(&players[i].mo->tracer, emmo); if (pnum == 255) @@ -1230,13 +1235,13 @@ void P_GivePlayerLives(player_t *player, INT32 numlives) if (gamestate == GS_LEVEL) { - if (player->lives == INFLIVES || (gametype != GT_COOP && gametype != GT_COMPETITION)) + if (player->lives == INFLIVES || !(gametyperules & GTR_LIVES)) { P_GivePlayerRings(player, 100*numlives); return; } - if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) + if ((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 0) { P_GivePlayerRings(player, 100*numlives); if (player->lives - prevlives >= numlives) @@ -1267,7 +1272,7 @@ docooprespawn: void P_GiveCoopLives(player_t *player, INT32 numlives, boolean sound) { - if (!((netgame || multiplayer) && gametype == GT_COOP)) + if (!((netgame || multiplayer) && G_GametypeUsesCoopLives())) { P_GivePlayerLives(player, numlives); if (sound) @@ -1395,7 +1400,7 @@ void P_AddPlayerScore(player_t *player, UINT32 amount) player->score = MAXSCORE; // check for extra lives every 50000 pts - if (!ultimatemode && !modeattacking && player->score > oldscore && player->score % 50000 < amount && (gametype == GT_COMPETITION || gametype == GT_COOP)) + if (!ultimatemode && !modeattacking && player->score > oldscore && player->score % 50000 < amount && (gametyperules & GTR_LIVES)) { P_GivePlayerLives(player, (player->score/50000) - (oldscore/50000)); P_PlayLivesJingle(player); @@ -4631,6 +4636,12 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) S_StartSound(player->mo, sfx_spin); break; } + if (player->dashspeed < player->mindash) + player->dashspeed = player->mindash; + + if (player->dashspeed > player->maxdash) + player->dashspeed = player->maxdash; + if (player->dashspeed < player->maxdash && player->mindash != player->maxdash) { #define chargecalculation (6*(player->dashspeed - player->mindash))/(player->maxdash - player->mindash) @@ -7780,6 +7791,7 @@ void P_ElementalFire(player_t *player, boolean cropcircle) flame->fuse = TICRATE*7; // takes about an extra second to hit the ground flame->destscale = player->mo->scale; P_SetScale(flame, player->mo->scale); + flame->flags2 = (flame->flags2 & ~MF2_OBJECTFLIP)|(player->mo->flags2 & MF2_OBJECTFLIP); flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); P_InstaThrust(flame, flame->angle, FixedMul(3*FRACUNIT, flame->scale)); P_SetObjectMomZ(flame, 3*FRACUNIT, false); @@ -9298,7 +9310,7 @@ boolean P_GetLives(player_t *player) { INT32 i, maxlivesplayer = -1, livescheck = 1; if (!(netgame || multiplayer) - || (gametype != GT_COOP) + || !G_GametypeUsesCoopLives() || (player->lives == INFLIVES)) return true; @@ -9447,7 +9459,7 @@ static void P_DeathThink(player_t *player) player->playerstate = PST_REBORN; else if ((player->lives > 0 || j != MAXPLAYERS) && !(!(netgame || multiplayer) && G_IsSpecialStage(gamemap))) // Don't allow "click to respawn" in special stages! { - if (gametype == GT_COOP && (netgame || multiplayer) && cv_coopstarposts.value == 2) + if (G_GametypeUsesCoopStarposts() && (netgame || multiplayer) && cv_coopstarposts.value == 2) { P_ConsiderAllGone(); if ((player->deadtimer > TICRATE<<1) || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE))) @@ -9462,19 +9474,22 @@ static void P_DeathThink(player_t *player) // Respawn with jump button, force respawn time (3 second default, cheat protected) in shooter modes. if (cmd->buttons & BT_JUMP) { - if (gametype != GT_COOP && player->spectator) + // You're a spectator, so respawn right away. + if ((gametyperules & GTR_SPECTATORS) && player->spectator) player->playerstate = PST_REBORN; - else switch(gametype) { - case GT_COOP: - case GT_COMPETITION: - case GT_RACE: - if (player->deadtimer > TICRATE) - player->playerstate = PST_REBORN; - break; - default: - if (player->deadtimer > cv_respawntime.value*TICRATE) - player->playerstate = PST_REBORN; - break; + else + { + // Give me one second. + INT32 respawndelay = TICRATE; + + // Non-platform gametypes + if (gametyperules & GTR_RESPAWNDELAY) + respawndelay = (cv_respawntime.value*TICRATE); + + // You've been dead for enough time. + // You may now respawn. + if (player->deadtimer > respawndelay) + player->playerstate = PST_REBORN; } } @@ -9488,7 +9503,7 @@ static void P_DeathThink(player_t *player) INT32 i, deadtimercheck = INT32_MAX; // In a net/multiplayer game, and out of lives - if (gametype == GT_COMPETITION) + if (G_CompetitionGametype()) { for (i = 0; i < MAXPLAYERS; i++) { @@ -11244,7 +11259,10 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) if (panim == PA_WALK) { if (stat != fume->info->spawnstate) + { + fume->threshold = 0; P_SetMobjState(fume, fume->info->spawnstate); + } return; } } @@ -11275,6 +11293,12 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) if (underwater) { fume->frame = (fume->frame & FF_FRAMEMASK) | FF_ANIMATE | (P_RandomRange(0, 9) * FF_TRANS10); + fume->threshold = 1; + } + else if (fume->threshold) + { + fume->frame = (fume->frame & FF_FRAMEMASK) | fume->state->frame; + fume->threshold = 0; } } @@ -11534,7 +11558,7 @@ void P_PlayerThink(player_t *player) #else if (player->spectator && #endif - gametype == GT_COOP && (netgame || multiplayer) && cv_coopstarposts.value == 2) + G_GametypeUsesCoopStarposts() && (netgame || multiplayer) && cv_coopstarposts.value == 2) P_ConsiderAllGone(); if (player->playerstate == PST_DEAD) diff --git a/src/r_bsp.c b/src/r_bsp.c index 51d9bd3fd..6b4667aee 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -1169,9 +1169,11 @@ static void R_Subsector(size_t num) while (count--) { // CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime); + if (!line->glseg #ifdef POLYOBJECTS - if (!line->polyseg) // ignore segs that belong to polyobjects + && !line->polyseg // ignore segs that belong to polyobjects #endif + ) R_AddLine(line); line++; curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */ diff --git a/src/r_data.c b/src/r_data.c index cecd4840c..986b65dea 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -324,8 +324,8 @@ UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 al else if (style != AST_TRANSLUCENT) { RGBA_t texel; - RGBA_t bg = V_GetColor(background); - RGBA_t fg = V_GetColor(foreground); + RGBA_t bg = V_GetMasterColor(background); + RGBA_t fg = V_GetMasterColor(foreground); texel.rgba = ASTBlendPixel(bg, fg, style, alpha); return NearestColor(texel.s.red, texel.s.green, texel.s.blue); } @@ -1664,7 +1664,7 @@ static void R_CreateFadeColormaps(void) #define GETCOLOR \ px = colormaps[i%256]; \ fade = (i/256) * (256 / FADECOLORMAPROWS); \ - rgba = V_GetColor(px); + rgba = V_GetMasterColor(px); // to black makeblack: @@ -2095,7 +2095,6 @@ lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap) ///////////////////// // This code creates the colormap array used by software renderer ///////////////////// - if (rendermode == render_soft) { double r, g, b, cbrightness; int p; @@ -2717,7 +2716,7 @@ void R_PrecacheLevel(void) lump = sf->lumppat[k]; if (devparm) spritememory += W_LumpLength(lump); - W_CachePatchNum(lump, PU_CACHE); + W_CachePatchNum(lump, PU_PATCH); } } } diff --git a/src/r_defs.h b/src/r_defs.h index 353dc572b..c7c198d66 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -83,7 +83,7 @@ typedef struct extracolormap_s */ typedef struct { - fixed_t x, y, z; + fixed_t x, y; } vertex_t; // Forward of linedefs, for sectors. @@ -436,14 +436,10 @@ typedef struct line_s polyobj_t *polyobj; // Belongs to a polyobject? #endif - char *text; // a concatination of all front and back texture names, for linedef specials that require a string. + char *text; // a concatenation of all front and back texture names, for linedef specials that require a string. INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0 } line_t; -// -// The SideDef. -// - typedef struct { // add this to the calculated texture column @@ -456,13 +452,16 @@ typedef struct // We do not maintain names here. INT32 toptexture, bottomtexture, midtexture; - // Sector the SideDef is facing. + // Linedef the sidedef belongs to + line_t *line; + + // Sector the sidedef is facing. sector_t *sector; INT16 special; // the special of the linedef this side belongs to INT16 repeatcnt; // # of times to repeat midtexture - char *text; // a concatination of all top, bottom, and mid texture names, for linedef specials that require a string. + char *text; // a concatenation of all top, bottom, and mid texture names, for linedef specials that require a string. extracolormap_t *colormap_data; // storage for colormaps; not applied to sectors. } side_t; @@ -587,6 +586,7 @@ typedef struct seg_s polyobj_t *polyseg; boolean dontrenderme; #endif + boolean glseg; } seg_t; // @@ -731,9 +731,9 @@ typedef struct boolean cached[8]; #ifdef HWRENDER aatree_t *hardware_patch[8]; -#endif +#endif/*HWRENDER*/ } rotsprite_t; -#endif +#endif/*ROTSPRITE*/ typedef enum { @@ -745,6 +745,24 @@ typedef enum SRF_NONE = 0xff // Initial value } spriterotateflags_t; // SRF's up! +// Same as a patch_t, except just the header +// and the wadnum/lumpnum combination that points +// to wherever the patch is in memory. +struct patchinfo_s +{ + INT16 width; // bounding box size + INT16 height; + INT16 leftoffset; // pixels to the left of origin + INT16 topoffset; // pixels below the origin + + UINT16 wadnum; // the software patch lump num for when the patch + UINT16 lumpnum; // was flushed, and we need to re-create it + + // next patchinfo_t in memory + struct patchinfo_s *next; +}; +typedef struct patchinfo_s patchinfo_t; + // // Sprites are patches with a special naming convention so they can be // recognized by R_InitSprites. diff --git a/src/r_main.c b/src/r_main.c index 09bbf6aa1..eba9942ea 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -19,6 +19,7 @@ #include "r_local.h" #include "r_splats.h" // faB(21jan): testing #include "r_sky.h" +#include "hu_stuff.h" #include "st_stuff.h" #include "p_local.h" #include "keys.h" @@ -28,6 +29,7 @@ #include "d_main.h" #include "v_video.h" #include "p_spec.h" // skyboxmo +#include "p_setup.h" #include "z_zone.h" #include "m_random.h" // quake camera shake #include "r_portal.h" @@ -691,6 +693,7 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) INT32 side, i; size_t nodenum; subsector_t *ret; + seg_t *seg; // single subsector is a special case if (numnodes == 0) @@ -706,10 +709,15 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) } ret = &subsectors[nodenum & ~NF_SUBSECTOR]; - for (i = 0; i < ret->numlines; i++) - //if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) -- breaks in ogl because polyvertex_t cast over vertex pointers - if (P_PointOnLineSide(x, y, segs[ret->firstline + i].linedef) != segs[ret->firstline + i].side) + for (i = 0, seg = &segs[ret->firstline]; i < ret->numlines; i++, seg++) + { + if (seg->glseg) + continue; + + //if (R_PointOnSegSide(x, y, seg)) -- breaks in ogl because polyvertex_t cast over vertex pointers + if (P_PointOnLineSide(x, y, seg->linedef) != seg->side) return 0; + } return ret; } @@ -1154,6 +1162,26 @@ void R_RenderPlayerView(player_t *player) free(masks); } +// Lactozilla: Renderer switching +#ifdef HWRENDER +void R_InitHardwareMode(void) +{ + HWR_AddSessionCommands(); + HWR_Switch(); + HWR_LoadTextures(numtextures); + if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)) + HWR_SetupLevel(); +} +#endif + +void R_ReloadHUDGraphics(void) +{ + CONS_Debug(DBG_RENDER, "R_ReloadHUDGraphics()...\n"); + ST_LoadGraphics(); + HU_LoadGraphics(); + ST_ReloadSkinFaceGraphics(); +} + // ========================================================================= // ENGINE COMMANDS & VARS // ========================================================================= diff --git a/src/r_main.h b/src/r_main.h index 58c23cd81..143cc1de0 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -89,6 +89,10 @@ extern consvar_t cv_tailspickup; // Called by startup code. void R_Init(void); +#ifdef HWRENDER +void R_InitHardwareMode(void); +#endif +void R_ReloadHUDGraphics(void); // just sets setsizeneeded true extern boolean setsizeneeded; diff --git a/src/r_patch.c b/src/r_patch.c index 0519d6dc9..fbb64e362 100644 --- a/src/r_patch.c +++ b/src/r_patch.c @@ -1396,4 +1396,19 @@ void R_FreeSkinRotSprite(size_t skinnum) skinsprites++; } } + +// +// R_FreeAllRotSprite +// +// Free ALL sprite rotation data from memory. +// +void R_FreeAllRotSprite(void) +{ + INT32 i; + size_t s; + for (s = 0; s < numsprites; s++) + R_FreeSingleRotSprite(&sprites[s]); + for (i = 0; i < numskins; ++i) + R_FreeSkinRotSprite(i); +} #endif diff --git a/src/r_patch.h b/src/r_patch.h index 72371f253..2961448a0 100644 --- a/src/r_patch.h +++ b/src/r_patch.h @@ -68,6 +68,7 @@ void R_FreeSingleRotSprite(spritedef_t *spritedef); void R_FreeSkinRotSprite(size_t skinnum); extern fixed_t rollcosang[ROTANGLES]; extern fixed_t rollsinang[ROTANGLES]; +void R_FreeAllRotSprite(void); #endif #endif // __R_PATCH__ diff --git a/src/r_segs.c b/src/r_segs.c index 29120ebb8..dcb5fc160 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -165,7 +165,7 @@ static void R_DrawWallSplats(void) mfloorclip = floorclip; mceilingclip = ceilingclip; - patch = W_CachePatchNum(splat->patch, PU_CACHE); + patch = W_CachePatchNum(splat->patch, PU_PATCH); dc_texturemid = splat->top + (SHORT(patch->height)<<(FRACBITS-1)) - viewz; if (splat->yoffset) @@ -308,6 +308,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) // for horizontal / vertical / diagonal. Diagonal? // OPTIMIZE: get rid of LIGHTSEGSHIFT globally curline = ds->curline; + frontsector = curline->frontsector; backsector = curline->backsector; texnum = R_GetTextureNum(curline->sidedef->midtexture); diff --git a/src/r_splats.c b/src/r_splats.c index 414e93eb6..f690dfa94 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -147,7 +147,7 @@ void R_AddWallSplat(line_t *wallline, INT16 sectorside, const char *patchname, f splat->flags = flags; // bad.. but will be needed for drawing anyway.. - patch = W_CachePatchNum(splat->patch, PU_CACHE); + patch = W_CachePatchNum(splat->patch, PU_PATCH); // offset needed by draw code for texture mapping linelength = P_SegLength((seg_t *)wallline); diff --git a/src/r_things.c b/src/r_things.c index cd7e40064..927d199a5 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -126,11 +126,10 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch for (ang = 0; ang < ROTANGLES; ang++) sprtemp[frame].rotsprite.patch[r][ang] = NULL; #ifdef HWRENDER - if (rendermode == render_opengl) - sprtemp[frame].rotsprite.hardware_patch[r] = M_AATreeAlloc(AATREE_ZUSER); -#endif // HWRENDER + sprtemp[frame].rotsprite.hardware_patch[r] = M_AATreeAlloc(AATREE_ZUSER); +#endif/*HWRENDER*/ } -#endif +#endif/*ROTSPRITE*/ if (rotation == 0) { @@ -988,7 +987,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) // // R_SplitSprite -// runs through a sector's lightlist and +// runs through a sector's lightlist and Knuckles static void R_SplitSprite(vissprite_t *sprite) { INT32 i, lightnum, lindex; diff --git a/src/s_sound.c b/src/s_sound.c index b2caeb1fd..4c6e27537 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -61,7 +61,9 @@ static void GameMIDIMusic_OnChange(void); static void GameSounds_OnChange(void); static void GameDigiMusic_OnChange(void); +#ifdef HAVE_OPENMPT static void ModFilter_OnChange(void); +#endif static lumpnum_t S_GetMusicLumpNum(const char *mname); diff --git a/src/screen.c b/src/screen.c index 507067705..5bb304c08 100644 --- a/src/screen.c +++ b/src/screen.c @@ -53,6 +53,7 @@ void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void); // ------------------ viddef_t vid; INT32 setmodeneeded; //video mode change needed if > 0 (the mode number to set + 1) +UINT8 setrenderneeded = 0; static CV_PossibleValue_t scr_depth_cons_t[] = {{8, "8 bits"}, {16, "16 bits"}, {24, "24 bits"}, {32, "32 bits"}, {0, NULL}}; @@ -62,7 +63,17 @@ consvar_t cv_scr_height = {"scr_height", "800", CV_SAVE, CV_Unsigned, NULL, 0, N consvar_t cv_scr_depth = {"scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_renderview = {"renderview", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -static void SCR_ChangeFullscreen (void); +static void SCR_ActuallyChangeRenderer(void); +CV_PossibleValue_t cv_renderer_t[] = { + {1, "Software"}, +#ifdef HWRENDER + {2, "OpenGL"}, +#endif + {0, NULL} +}; +consvar_t cv_renderer = {"renderer", "Software", CV_SAVE|CV_NOLUA|CV_CALL, cv_renderer_t, SCR_ChangeRenderer, 0, NULL, NULL, 0, 0, NULL}; + +static void SCR_ChangeFullscreen(void); consvar_t cv_fullscreen = {"fullscreen", "Yes", CV_SAVE|CV_CALL, CV_YesNo, SCR_ChangeFullscreen, 0, NULL, NULL, 0, 0, NULL}; @@ -87,19 +98,8 @@ boolean R_3DNow = false; boolean R_MMXExt = false; boolean R_SSE2 = false; - -void SCR_SetMode(void) +void SCR_SetDrawFuncs(void) { - if (dedicated) - return; - - if (!setmodeneeded || WipeInAction) - return; // should never happen and don't change it during a wipe, BAD! - - VID_SetMode(--setmodeneeded); - - V_SetPalette(0); - // // setup the right draw routines for either 8bpp or 16bpp // @@ -193,9 +193,37 @@ void SCR_SetMode(void) if (SCR_IsAspectCorrect(vid.width, vid.height)) CONS_Alert(CONS_WARNING, M_GetText("Resolution is not aspect-correct!\nUse a multiple of %dx%d\n"), BASEVIDWIDTH, BASEVIDHEIGHT); */ +} + +void SCR_SetMode(void) +{ + if (dedicated) + return; + + if (!(setmodeneeded || setrenderneeded) || WipeInAction) + return; // should never happen and don't change it during a wipe, BAD! + + // Lactozilla: Renderer switching + if (setrenderneeded) + { + Z_PreparePatchFlush(); + needpatchflush = true; + needpatchrecache = true; + VID_CheckRenderer(); + if (!setmodeneeded) + VID_SetMode(vid.modenum); + } + + if (setmodeneeded) + VID_SetMode(--setmodeneeded); + + V_SetPalette(0); + + SCR_SetDrawFuncs(); // set the apprpriate drawer for the sky (tall or INT16) setmodeneeded = 0; + setrenderneeded = 0; } // do some initial settings for the game loading screen @@ -383,6 +411,8 @@ void SCR_CheckDefaultMode(void) // see note above setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1; } + + SCR_ActuallyChangeRenderer(); } // sets the modenum as the new default video mode to be saved in the config file @@ -412,6 +442,55 @@ void SCR_ChangeFullscreen(void) #endif } +static int target_renderer = 0; + +void SCR_ActuallyChangeRenderer(void) +{ + setrenderneeded = target_renderer; + // setting the same renderer twice WILL crash your game, so let's not, please + if (rendermode == setrenderneeded) + setrenderneeded = 0; +} + +// Lactozilla: Renderer switching +void SCR_ChangeRenderer(void) +{ + setrenderneeded = 0; + + if (con_startup) + { + target_renderer = cv_renderer.value; +#ifdef HWRENDER + if (M_CheckParm("-opengl")) + target_renderer = rendermode = render_opengl; + else +#endif + if (M_CheckParm("-software")) + target_renderer = rendermode = render_soft; + // set cv_renderer back + SCR_ChangeRendererCVars(rendermode); + return; + } + + if (cv_renderer.value == 1) + target_renderer = render_soft; + else if (cv_renderer.value == 2) + target_renderer = render_opengl; + SCR_ActuallyChangeRenderer(); +} + +void SCR_ChangeRendererCVars(INT32 mode) +{ + // set cv_renderer back + if (mode == render_soft) + CV_StealthSetValue(&cv_renderer, 1); + else if (mode == render_opengl) + CV_StealthSetValue(&cv_renderer, 2); +#ifdef HWRENDER + CV_StealthSetValue(&cv_newrenderer, cv_renderer.value); +#endif +} + boolean SCR_IsAspectCorrect(INT32 width, INT32 height) { return diff --git a/src/screen.h b/src/screen.h index 470acb4b9..02b336f75 100644 --- a/src/screen.h +++ b/src/screen.h @@ -170,18 +170,29 @@ extern boolean R_SSE2; // ---------------- // screen variables // ---------------- + extern viddef_t vid; extern INT32 setmodeneeded; // mode number to set if needed, or 0 +void SCR_ChangeRenderer(void); +void SCR_ChangeRendererCVars(INT32 mode); +extern UINT8 setrenderneeded; + extern INT32 scr_bpp; extern UINT8 *scr_borderpatch; // patch used to fill the view borders -extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_fullscreen; +extern CV_PossibleValue_t cv_renderer_t[]; + +extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_renderer, cv_fullscreen; +#ifdef HWRENDER +extern consvar_t cv_newrenderer; +#endif // wait for page flipping to end or not extern consvar_t cv_vidwait; // Change video mode, only at the start of a refresh. void SCR_SetMode(void); +void SCR_SetDrawFuncs(void); // Recalc screen size dependent stuff void SCR_Recalc(void); // Check parms once at startup diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 2dd168b93..5fa631c97 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -67,10 +67,12 @@ #include "../s_sound.h" #include "../i_joy.h" #include "../st_stuff.h" +#include "../hu_stuff.h" #include "../g_game.h" #include "../i_video.h" #include "../console.h" #include "../command.h" +#include "../r_main.h" #include "sdlmain.h" #ifdef HWRENDER #include "../hardware/hw_main.h" @@ -98,6 +100,7 @@ boolean highcolor = false; // synchronize page flipping with screen refresh consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_stretch = {"stretch", "Off", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +static consvar_t cv_alwaysgrabmouse = {"alwaysgrabmouse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; UINT8 graphics_started = 0; // Is used in console.c and screen.c @@ -107,6 +110,7 @@ static SDL_bool disable_fullscreen = SDL_FALSE; #define USE_FULLSCREEN (disable_fullscreen||!allow_fullscreen)?0:cv_fullscreen.value static SDL_bool disable_mouse = SDL_FALSE; #define USE_MOUSEINPUT (!disable_mouse && cv_usemouse.value && havefocus) +#define IGNORE_MOUSE (!cv_alwaysgrabmouse.value && (menuactive || paused || con_destlines || chat_on || gamestate != GS_LEVEL)) #define MOUSE_MENU false //(!disable_mouse && cv_usemouse.value && menuactive && !USE_FULLSCREEN) #define MOUSEBUTTONS_MAX MOUSEBUTTONS @@ -373,12 +377,15 @@ static void SDLdoUngrabMouse(void) void SDLforceUngrabMouse(void) { if (SDL_WasInit(SDL_INIT_VIDEO)==SDL_INIT_VIDEO && window != NULL) - { - SDL_ShowCursor(SDL_ENABLE); - SDL_SetWindowGrab(window, SDL_FALSE); - wrapmouseok = SDL_FALSE; - SDL_SetRelativeMouseMode(SDL_FALSE); - } + SDLdoUngrabMouse(); +} + +void I_UpdateMouseGrab(void) +{ + if (SDL_WasInit(SDL_INIT_VIDEO) == SDL_INIT_VIDEO && window != NULL + && SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window + && USE_MOUSEINPUT && !IGNORE_MOUSE) + SDLdoGrabMouse(); } static void VID_Command_NumModes_f (void) @@ -585,7 +592,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) } //else firsttimeonmouse = SDL_FALSE; - if (USE_MOUSEINPUT) + if (USE_MOUSEINPUT && !IGNORE_MOUSE) SDLdoGrabMouse(); } else if (!mousefocus && !kbfocus) @@ -632,11 +639,14 @@ static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type) static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt) { + static boolean firstmove = true; + if (USE_MOUSEINPUT) { - if ((SDL_GetMouseFocus() != window && SDL_GetKeyboardFocus() != window)) + if ((SDL_GetMouseFocus() != window && SDL_GetKeyboardFocus() != window) || (IGNORE_MOUSE && !firstmove)) { SDLdoUngrabMouse(); + firstmove = false; return; } @@ -650,6 +660,7 @@ static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt) mousemovey += -evt.yrel; SDL_SetWindowGrab(window, SDL_TRUE); } + firstmove = false; return; } @@ -657,6 +668,7 @@ static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt) // of the screen then ignore it. if ((evt.x == realwidth/2) && (evt.y == realheight/2)) { + firstmove = false; return; } @@ -669,6 +681,8 @@ static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt) SDLdoGrabMouse(); } } + + firstmove = false; } static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type) @@ -682,7 +696,7 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type) // this apparently makes a mouse button down event but not a mouse button up event, // resulting in whatever key was pressed down getting "stuck" if we don't ignore it. // -- Monster Iestyn (28/05/18) - if (SDL_GetMouseFocus() != window) + if (SDL_GetMouseFocus() != window || IGNORE_MOUSE) return; /// \todo inputEvent.button.which @@ -1064,7 +1078,7 @@ void I_StartupMouse(void) } else firsttimeonmouse = SDL_FALSE; - if (cv_usemouse.value) + if (cv_usemouse.value && !IGNORE_MOUSE) SDLdoGrabMouse(); else SDLdoUngrabMouse(); @@ -1204,7 +1218,6 @@ void I_FinishUpdate(void) SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); } - #ifdef HWRENDER else if (rendermode == render_opengl) { @@ -1404,37 +1417,53 @@ void VID_PrepareModeList(void) #endif } -INT32 VID_SetMode(INT32 modeNum) +static SDL_bool Impl_CreateContext(void) { - SDLdoUngrabMouse(); - - vid.recalc = 1; - vid.bpp = 1; - - if (modeNum >= 0 && modeNum < MAXWINMODES) + // Renderer-specific stuff +#ifdef HWRENDER + if (rendermode == render_opengl) { - vid.width = windowedModes[modeNum][0]; - vid.height = windowedModes[modeNum][1]; - vid.modenum = modeNum; + if (!sdlglcontext) + sdlglcontext = SDL_GL_CreateContext(window); + if (sdlglcontext == NULL) + { + SDL_DestroyWindow(window); + I_Error("Failed to create a GL context: %s\n", SDL_GetError()); + } + SDL_GL_MakeCurrent(window, sdlglcontext); } else +#endif + if (rendermode == render_soft) { - // just set the desktop resolution as a fallback - SDL_DisplayMode mode; - SDL_GetWindowDisplayMode(window, &mode); - if (mode.w >= 2048) + int flags = 0; // Use this to set SDL_RENDERER_* flags now + if (usesdl2soft) + flags |= SDL_RENDERER_SOFTWARE; + else if (cv_vidwait.value) + flags |= SDL_RENDERER_PRESENTVSYNC; + + if (!renderer) + renderer = SDL_CreateRenderer(window, -1, flags); + if (renderer == NULL) { - vid.width = 1920; - vid.height = 1200; + CONS_Printf(M_GetText("Couldn't create rendering context: %s\n"), SDL_GetError()); + return SDL_FALSE; } - else - { - vid.width = mode.w; - vid.height = mode.h; - } - vid.modenum = -1; + SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT); + } + return SDL_TRUE; +} + +void VID_CheckRenderer(void) +{ + if (dedicated) + return; + + if (setrenderneeded) + { + rendermode = setrenderneeded; + Impl_CreateContext(); } - //Impl_SetWindowName("SRB2 "VERSIONSTRING); SDLSetMode(vid.width, vid.height, USE_FULLSCREEN); Impl_VideoSetupBuffer(); @@ -1446,8 +1475,39 @@ INT32 VID_SetMode(INT32 modeNum) SDL_FreeSurface(bufSurface); bufSurface = NULL; } +#ifdef HWRENDER + HWR_FreeTextureCache(); +#endif + SCR_SetDrawFuncs(); } +#ifdef HWRENDER + else if (rendermode == render_opengl) + { + I_StartupHardwareGraphics(); + R_InitHardwareMode(); + HWR_Switch(); + } +#endif +} +INT32 VID_SetMode(INT32 modeNum) +{ + SDLdoUngrabMouse(); + + vid.recalc = 1; + vid.bpp = 1; + + if (modeNum < 0) + modeNum = 0; + if (modeNum >= MAXWINMODES) + modeNum = MAXWINMODES-1; + + vid.width = windowedModes[modeNum][0]; + vid.height = windowedModes[modeNum][1]; + vid.modenum = modeNum; + + //Impl_SetWindowName("SRB2 "VERSIONSTRING); + VID_CheckRenderer(); return SDL_TRUE; } @@ -1468,8 +1528,7 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) flags |= SDL_WINDOW_BORDERLESS; #ifdef HWRENDER - if (rendermode == render_opengl) - flags |= SDL_WINDOW_OPENGL; + flags |= SDL_WINDOW_OPENGL; #endif // Create a window @@ -1482,38 +1541,7 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) return SDL_FALSE; } - // Renderer-specific stuff -#ifdef HWRENDER - if (rendermode == render_opengl) - { - sdlglcontext = SDL_GL_CreateContext(window); - if (sdlglcontext == NULL) - { - SDL_DestroyWindow(window); - I_Error("Failed to create a GL context: %s\n", SDL_GetError()); - } - SDL_GL_MakeCurrent(window, sdlglcontext); - } - else -#endif - if (rendermode == render_soft) - { - flags = 0; // Use this to set SDL_RENDERER_* flags now - if (usesdl2soft) - flags |= SDL_RENDERER_SOFTWARE; - else if (cv_vidwait.value) - flags |= SDL_RENDERER_PRESENTVSYNC; - - renderer = SDL_CreateRenderer(window, -1, flags); - if (renderer == NULL) - { - CONS_Printf(M_GetText("Couldn't create rendering context: %s\n"), SDL_GetError()); - return SDL_FALSE; - } - SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT); - } - - return SDL_TRUE; + return Impl_CreateContext(); } /* @@ -1568,17 +1596,14 @@ static void Impl_VideoSetupSDLBuffer(void) static void Impl_VideoSetupBuffer(void) { // Set up game's software render buffer - //if (rendermode == render_soft) + vid.rowbytes = vid.width * vid.bpp; + vid.direct = NULL; + if (vid.buffer) + free(vid.buffer); + vid.buffer = calloc(vid.rowbytes*vid.height, NUMSCREENS); + if (!vid.buffer) { - vid.rowbytes = vid.width * vid.bpp; - vid.direct = NULL; - if (vid.buffer) - free(vid.buffer); - vid.buffer = calloc(vid.rowbytes*vid.height, NUMSCREENS); - if (!vid.buffer) - { - I_Error("%s", M_GetText("Not enough memory for video buffer\n")); - } + I_Error("%s", M_GetText("Not enough memory for video buffer\n")); } } @@ -1598,6 +1623,7 @@ void I_StartupGraphics(void) COM_AddCommand ("vid_mode", VID_Command_Mode_f); CV_RegisterVar (&cv_vidwait); CV_RegisterVar (&cv_stretch); + CV_RegisterVar (&cv_alwaysgrabmouse); disable_mouse = M_CheckParm("-nomouse"); disable_fullscreen = M_CheckParm("-win") ? 1 : 0; @@ -1623,16 +1649,12 @@ void I_StartupGraphics(void) framebuffer = SDL_TRUE; } - if (M_CheckParm("-software")) - { - rendermode = render_soft; - } #ifdef HWRENDER - else if (M_CheckParm("-opengl")) - { + if (M_CheckParm("-opengl")) rendermode = render_opengl; - } + else if (M_CheckParm("-software")) #endif + rendermode = render_soft; usesdl2soft = M_CheckParm("-softblit"); borderlesswindow = M_CheckParm("-borderless"); @@ -1640,48 +1662,7 @@ void I_StartupGraphics(void) //SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY>>1,SDL_DEFAULT_REPEAT_INTERVAL<<2); VID_Command_ModeList_f(); #ifdef HWRENDER - if (rendermode == render_opengl) - { - HWD.pfnInit = hwSym("Init",NULL); - HWD.pfnFinishUpdate = NULL; - HWD.pfnDraw2DLine = hwSym("Draw2DLine",NULL); - HWD.pfnDrawPolygon = hwSym("DrawPolygon",NULL); - HWD.pfnRenderSkyDome = hwSym("RenderSkyDome",NULL); - HWD.pfnSetBlend = hwSym("SetBlend",NULL); - HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); - HWD.pfnSetTexture = hwSym("SetTexture",NULL); - HWD.pfnReadRect = hwSym("ReadRect",NULL); - HWD.pfnGClipRect = hwSym("GClipRect",NULL); - HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); - HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); - HWD.pfnSetPalette = hwSym("SetPalette",NULL); - HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); - HWD.pfnDrawModel = hwSym("DrawModel",NULL); - HWD.pfnCreateModelVBOs = hwSym("CreateModelVBOs",NULL); - HWD.pfnSetTransform = hwSym("SetTransform",NULL); - HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); - HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL); - HWD.pfnStartScreenWipe = hwSym("StartScreenWipe",NULL); - HWD.pfnEndScreenWipe = hwSym("EndScreenWipe",NULL); - HWD.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL); - HWD.pfnDrawIntermissionBG=hwSym("DrawIntermissionBG",NULL); - HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL); - HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); - HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); - - HWD.pfnLoadShaders = hwSym("LoadShaders",NULL); - HWD.pfnKillShaders = hwSym("KillShaders",NULL); - HWD.pfnSetShader = hwSym("SetShader",NULL); - HWD.pfnUnSetShader = hwSym("UnSetShader",NULL); - - HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL); - HWD.pfnInitCustomShaders = hwSym("InitCustomShaders",NULL); - - if (!HWD.pfnInit()) // load the OpenGL library - { - rendermode = render_soft; - } - } + I_StartupHardwareGraphics(); #endif // Fury: we do window initialization after GL setup to allow @@ -1731,16 +1712,65 @@ void I_StartupGraphics(void) SDL_RaiseWindow(window); if (mousegrabok && !disable_mouse) - { - SDL_ShowCursor(SDL_DISABLE); - SDL_SetRelativeMouseMode(SDL_TRUE); - wrapmouseok = SDL_TRUE; - SDL_SetWindowGrab(window, SDL_TRUE); - } + SDLdoGrabMouse(); graphics_started = true; } +void I_StartupHardwareGraphics(void) +{ +#ifdef HWRENDER + static boolean glstartup = false; + if (!glstartup) + { + if (rendermode == render_opengl) + { + HWD.pfnInit = hwSym("Init",NULL); + HWD.pfnFinishUpdate = NULL; + HWD.pfnDraw2DLine = hwSym("Draw2DLine",NULL); + HWD.pfnDrawPolygon = hwSym("DrawPolygon",NULL); + HWD.pfnRenderSkyDome = hwSym("RenderSkyDome",NULL); + HWD.pfnSetBlend = hwSym("SetBlend",NULL); + HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); + HWD.pfnSetTexture = hwSym("SetTexture",NULL); + HWD.pfnReadRect = hwSym("ReadRect",NULL); + HWD.pfnGClipRect = hwSym("GClipRect",NULL); + HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); + HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); + HWD.pfnSetPalette = hwSym("SetPalette",NULL); + HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); + HWD.pfnDrawModel = hwSym("DrawModel",NULL); + HWD.pfnCreateModelVBOs = hwSym("CreateModelVBOs",NULL); + HWD.pfnSetTransform = hwSym("SetTransform",NULL); + HWD.pfnPostImgRedraw = hwSym("PostImgRedraw",NULL); + HWD.pfnFlushScreenTextures=hwSym("FlushScreenTextures",NULL); + HWD.pfnStartScreenWipe = hwSym("StartScreenWipe",NULL); + HWD.pfnEndScreenWipe = hwSym("EndScreenWipe",NULL); + HWD.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL); + HWD.pfnDrawIntermissionBG=hwSym("DrawIntermissionBG",NULL); + HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL); + HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); + HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); + + HWD.pfnLoadShaders = hwSym("LoadShaders",NULL); + HWD.pfnKillShaders = hwSym("KillShaders",NULL); + HWD.pfnSetShader = hwSym("SetShader",NULL); + HWD.pfnUnSetShader = hwSym("UnSetShader",NULL); + + HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL); + HWD.pfnInitCustomShaders = hwSym("InitCustomShaders",NULL); + + // check gl renderer lib + if (HWD.pfnGetRenderVersion() != VERSION) + I_Error("%s", M_GetText("The version of the renderer doesn't match the version of the executable\nBe sure you have installed SRB2 properly.\n")); + if (!HWD.pfnInit(I_Error)) // let load the OpenGL library + rendermode = render_soft; + else + glstartup = true; + } +#endif +} + void I_ShutdownGraphics(void) { const rendermode_t oldrendermode = rendermode; diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c index 33b366bf6..b8991293c 100644 --- a/src/sdl/sdl_sound.c +++ b/src/sdl/sdl_sound.c @@ -1432,6 +1432,8 @@ static void I_ResumeGME(void) boolean I_LoadSong(char *data, size_t len) { + (void)data; + (void)len; return false; } @@ -1493,6 +1495,7 @@ boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms (void)target_volume; (void)source_volume; (void)ms; + (void)callback; return false; } @@ -1500,6 +1503,7 @@ boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)) { (void)target_volume; (void)ms; + (void)callback; return false; } diff --git a/src/sounds.c b/src/sounds.c index 6b0a11ed7..e2351a430 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -187,6 +187,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"shield", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pity Shield"}, // generic GET! {"wirlsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Whirlwind Shield"}, // Whirlwind GET! {"forcsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Force Shield"}, // Force GET! + {"frcssg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Weak Force Shield"}, // Force GET...? (consider making a custom shield with this instead of a single-hit force shield!) {"elemsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Elemental Shield"}, // Elemental GET! {"armasg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon Shield"}, // Armaggeddon GET! {"attrsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction Shield"}, // Attract GET! @@ -220,6 +221,9 @@ sfxinfo_t S_sfx[NUMSFX] = {"sprong", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power spring"}, {"lvfal1", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rumble"}, {"pscree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "SCREE!"}, + {"iceb", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ice crack"}, + {"shattr", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Shattering"}, + {"antiri", true, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Depletion"}, // Menu, interface {"chchng", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Score"}, @@ -233,6 +237,9 @@ sfxinfo_t S_sfx[NUMSFX] = {"wepchg", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Weapon change"}, // Weapon switch is identical to menu for now {"wtrdng", true, 212, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aquaphobia"}, // make sure you can hear the DING DING! Tails 03-08-2000 {"zelda", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Discovery"}, + {"adderr", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Error"}, + {"notadd", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Reject"}, + {"addfil", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Accept"}, // NiGHTS {"ideya", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Success"}, @@ -427,24 +434,9 @@ sfxinfo_t S_sfx[NUMSFX] = {"s25e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s25f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s260", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s261", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s262", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s263", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s264", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s265", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s266", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s267", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s268", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s269", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s26a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s26b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s26c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s26d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s26e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s26f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s270", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // S3&K sounds + {"s3k2b", true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Emerald"}, // Got Emerald! {"s3k33", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sparkle"}, // stereo in original game, identical to latter {"s3k34", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sparkle"}, // mono in original game, identical to previous {"s3k35", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hurt"}, @@ -566,6 +558,21 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3ka9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aquaphobia"}, {"s3kaa", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bumper"}, {"s3kab", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kab1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kab2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kab3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kab4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kab5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kab6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kab7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kab8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kab9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kaba", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kabb", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kabc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kabd", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kabe", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, + {"s3kabf", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spindash"}, {"s3kac", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Continue"}, {"s3kad", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "GO!"}, {"s3kae", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pinball flipper"}, @@ -604,7 +611,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kc5l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Revving up"}, // ditto {"s3kc6s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Orbiting"}, {"s3kc6l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Orbiting"}, // ditto - {"s3kc7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"}, + {"s3kc7s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"}, + {"s3kc7l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"}, // ditto {"s3kc8s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sliding"}, {"s3kc8l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sliding"}, // ditto {"s3kc9s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Swinging"}, diff --git a/src/sounds.h b/src/sounds.h index dfd3fb731..6880e44bb 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -236,6 +236,7 @@ typedef enum sfx_shield, sfx_wirlsg, sfx_forcsg, + sfx_frcssg, sfx_elemsg, sfx_armasg, sfx_attrsg, @@ -269,6 +270,9 @@ typedef enum sfx_sprong, sfx_lvfal1, sfx_pscree, + sfx_iceb, + sfx_shattr, + sfx_antiri, // Menu, interface sfx_chchng, @@ -282,6 +286,9 @@ typedef enum sfx_wepchg, sfx_wtrdng, sfx_zelda, + sfx_adderr, + sfx_notadd, + sfx_addfil, // NiGHTS sfx_ideya, @@ -476,24 +483,9 @@ typedef enum sfx_s25e, sfx_s25f, sfx_s260, - sfx_s261, - sfx_s262, - sfx_s263, - sfx_s264, - sfx_s265, - sfx_s266, - sfx_s267, - sfx_s268, - sfx_s269, - sfx_s26a, - sfx_s26b, - sfx_s26c, - sfx_s26d, - sfx_s26e, - sfx_s26f, - sfx_s270, // S3&K sounds + sfx_s3k2b, sfx_s3k33, sfx_s3k34, sfx_s3k35, @@ -615,6 +607,21 @@ typedef enum sfx_s3ka9, sfx_s3kaa, sfx_s3kab, + sfx_s3kab1, + sfx_s3kab2, + sfx_s3kab3, + sfx_s3kab4, + sfx_s3kab5, + sfx_s3kab6, + sfx_s3kab7, + sfx_s3kab8, + sfx_s3kab9, + sfx_s3kaba, + sfx_s3kabb, + sfx_s3kabc, + sfx_s3kabd, + sfx_s3kabe, + sfx_s3kabf, sfx_s3kac, sfx_s3kad, sfx_s3kae, @@ -653,7 +660,8 @@ typedef enum sfx_s3kc5l, sfx_s3kc6s, sfx_s3kc6l, - sfx_s3kc7, + sfx_s3kc7s, + sfx_s3kc7l, sfx_s3kc8s, sfx_s3kc8l, sfx_s3kc9s, diff --git a/src/st_stuff.c b/src/st_stuff.c index 5e05030c3..9a1505ce3 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -694,7 +694,7 @@ static void ST_drawTime(void) else { // Counting down the hidetime? - if ((gametyperules & GTR_HIDETIME) && (stplyr->realtime <= (hidetime*TICRATE))) + if ((gametyperules & GTR_STARTCOUNTDOWN) && (stplyr->realtime <= (hidetime*TICRATE))) { tics = (hidetime*TICRATE - stplyr->realtime); if (tics < 3*TICRATE) @@ -705,7 +705,7 @@ static void ST_drawTime(void) else { // Hidetime finish! - if ((gametyperules & GTR_HIDETIME) && (stplyr->realtime < ((hidetime+1)*TICRATE))) + if ((gametyperules & GTR_STARTCOUNTDOWN) && (stplyr->realtime < ((hidetime+1)*TICRATE))) ST_drawRaceNum(hidetime*TICRATE - stplyr->realtime); // Time limit? @@ -723,7 +723,7 @@ static void ST_drawTime(void) downwards = true; } // Post-hidetime normal. - else if (gametyperules & GTR_TAG) + else if (gametyperules & GTR_STARTCOUNTDOWN) tics = stplyr->realtime - hidetime*TICRATE; // "Shadow! What are you doing? Hurry and get back here // right now before the island blows up with you on it!" @@ -845,69 +845,13 @@ static void ST_drawLivesArea(void) hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, faceprefix[stplyr->skin], colormap); } - // Lives number + // Metal Sonic recording if (metalrecording) { if (((2*leveltime)/TICRATE) & 1) V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, hudinfo[HUD_LIVES].f|V_PERPLAYER|V_REDMAP|V_HUDTRANS, "REC"); } - else if (G_GametypeUsesLives() || gametype == GT_RACE) - { - // x - V_DrawScaledPatch(hudinfo[HUD_LIVES].x+22, hudinfo[HUD_LIVES].y+10, - hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, stlivex); - - // lives number - if (gametype == GT_RACE) - { - livescount = INFLIVES; - notgreyedout = true; - } - else if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3) - { - INT32 i; - livescount = 0; - notgreyedout = (stplyr->lives > 0); - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - if (players[i].lives < 1) - continue; - - if (players[i].lives > 1) - notgreyedout = true; - - if (players[i].lives == INFLIVES) - { - livescount = INFLIVES; - break; - } - else if (livescount < 99) - livescount += (players[i].lives); - } - } - else - { - livescount = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? INFLIVES : stplyr->lives); - notgreyedout = true; - } - - if (livescount == INFLIVES) - V_DrawCharacter(hudinfo[HUD_LIVES].x+50, hudinfo[HUD_LIVES].y+8, - '\x16' | 0x80 | hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, false); - else - { - if (stplyr->playerstate == PST_DEAD && !(stplyr->spectator) && (livescount || stplyr->deadtimer < (TICRATE<<1))) - livescount++; - if (livescount > 99) - livescount = 99; - V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, - hudinfo[HUD_LIVES].f|V_PERPLAYER|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF), va("%d",livescount)); - } - } // Spectator else if (stplyr->spectator) v_colmap = V_GRAYMAP; @@ -934,11 +878,89 @@ static void ST_drawLivesArea(void) v_colmap = V_BLUEMAP; } } + // Lives number + else + { + boolean candrawlives = true; + + // Co-op and Competition, normal life counter + if (G_GametypeUsesLives()) + { + // Handle cooplives here + if ((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 3) + { + INT32 i; + livescount = 0; + notgreyedout = (stplyr->lives > 0); + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (players[i].lives < 1) + continue; + + if (players[i].lives > 1) + notgreyedout = true; + + if (players[i].lives == INFLIVES) + { + livescount = INFLIVES; + break; + } + else if (livescount < 99) + livescount += (players[i].lives); + } + } + else + { + livescount = (((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 0) ? INFLIVES : stplyr->lives); + notgreyedout = true; + } + } + // Infinity symbol (Race) + else if (G_PlatformGametype() && !(gametyperules & GTR_LIVES)) + { + livescount = INFLIVES; + notgreyedout = true; + } + // Otherwise nothing, sorry. + // Special Stages keep not showing lives, + // as G_GametypeUsesLives() returns false in + // Special Stages, and the infinity symbol + // cannot show up because Special Stages + // still have the GTR_LIVES gametype rule + // by default. + else + candrawlives = false; + + // Draw the lives counter here. + if (candrawlives) + { + // x + V_DrawScaledPatch(hudinfo[HUD_LIVES].x+22, hudinfo[HUD_LIVES].y+10, hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, stlivex); + if (livescount == INFLIVES) + V_DrawCharacter(hudinfo[HUD_LIVES].x+50, hudinfo[HUD_LIVES].y+8, + '\x16' | 0x80 | hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, false); + else + { + if (stplyr->playerstate == PST_DEAD && !(stplyr->spectator) && (livescount || stplyr->deadtimer < (TICRATE<<1))) + livescount++; + if (livescount > 99) + livescount = 99; + V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, + hudinfo[HUD_LIVES].f|V_PERPLAYER|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF), va("%d",livescount)); + } + } +#undef ST_drawLivesX + } // name v_colmap |= (V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER); if (strlen(skins[stplyr->skin].hudname) <= 5) V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); + else if (V_StringWidth(skins[stplyr->skin].hudname, v_colmap) <= 48) + V_DrawString(hudinfo[HUD_LIVES].x+18, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); else if (V_ThinStringWidth(skins[stplyr->skin].hudname, v_colmap) <= 40) V_DrawRightAlignedThinString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y, v_colmap, skins[stplyr->skin].hudname); else @@ -2202,7 +2224,7 @@ static void ST_drawTextHUD(void) donef12 = true; } } - else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) // Death overrides spectator text. + else if ((gametyperules & GTR_RESPAWNDELAY) && stplyr->playerstate == PST_DEAD && stplyr->lives) // Death overrides spectator text. { INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE; @@ -2226,7 +2248,7 @@ static void ST_drawTextHUD(void) textHUDdraw(M_GetText("\x82""Wait for the stage to end...")) else if (G_PlatformGametype()) { - if (gametype == GT_COOP) + if (G_GametypeUsesCoopLives()) { if (stplyr->lives <= 0 && cv_cooplives.value == 2 @@ -2637,7 +2659,7 @@ static void ST_overlayDrawer(void) INT32 i = MAXPLAYERS; INT32 deadtimer = stplyr->spectator ? TICRATE : (stplyr->deadtimer-(TICRATE<<1)); - if ((gametype == GT_COOP) + if (G_GametypeUsesCoopLives() && (netgame || multiplayer) && (cv_cooplives.value != 1)) { @@ -2766,6 +2788,9 @@ static void ST_overlayDrawer(void) void ST_Drawer(void) { + if (needpatchrecache) + R_ReloadHUDGraphics(); + #ifdef SEENAMES if (cv_seenames.value && cv_allowseenames.value && displayplayer == consoleplayer && seenplayer && seenplayer->mo) { diff --git a/src/v_video.c b/src/v_video.c index d78614b13..94f76fa58 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1045,13 +1045,13 @@ void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skin { spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CONTINUE]; - patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); + patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); const UINT8 *colormap = R_GetTranslationColormap(skinnum, skincolor, GTC_CACHE); V_DrawMappedPatch(x, y, flags, patch, colormap); } else - V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE)); + V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_PATCH)); } // diff --git a/src/v_video.h b/src/v_video.h index 36d1914af..eb75a414f 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -64,6 +64,7 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue); // Retrieve the ARGB value from a palette color index #define V_GetColor(color) (pLocalPalette[color&0xFF]) +#define V_GetMasterColor(color) (pMasterPalette[color&0xFF]) // Bottom 8 bits are used for parameter (screen or character) #define V_PARAMMASK 0x000000FF diff --git a/src/w_wad.c b/src/w_wad.c index 15196c6eb..4a5378e27 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -55,6 +55,7 @@ #include "dehacked.h" #include "d_clisrv.h" #include "r_defs.h" +#include "r_data.h" #include "i_system.h" #include "md5.h" #include "lua_script.h" @@ -1380,7 +1381,6 @@ void *W_CacheLumpNumPwad(UINT16 wad, UINT16 lump, INT32 tag) void *W_CacheLumpNum(lumpnum_t lumpnum, INT32 tag) { - return W_CacheLumpNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),tag); } @@ -1493,12 +1493,31 @@ void *W_CacheLumpName(const char *name, INT32 tag) // Cache a patch into heap memory, convert the patch format as necessary // +void W_FlushCachedPatches(void) +{ + if (needpatchflush) + { + Z_FreeTag(PU_CACHE); + Z_FreeTag(PU_PATCH); + Z_FreeTag(PU_HUDGFX); + Z_FreeTag(PU_HWRPATCHINFO); + Z_FreeTag(PU_HWRMODELTEXTURE); + Z_FreeTag(PU_HWRCACHE); + Z_FreeTags(PU_HWRCACHE_UNLOCKED, PU_HWRPATCHINFO_UNLOCKED); + } + needpatchflush = false; +} + +// Software-only compile cache the data without conversion void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) { #ifdef HWRENDER GLPatch_t *grPatch; #endif + if (needpatchflush) + W_FlushCachedPatches(); + if (!TestValidLump(wad, lump)) return NULL; diff --git a/src/w_wad.h b/src/w_wad.h index 8008a577c..aca67c00f 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -196,6 +196,7 @@ void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag); // return a patch void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag); // return a patch_t void W_UnlockCachedPatch(void *patch); +void W_FlushCachedPatches(void); void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5); diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index c9fdb1c97..42733c309 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -1354,6 +1354,8 @@ getBufferedData: } } +void I_UpdateMouseGrab(void) {} + // =========================================================================================== // DIRECT INPUT JOYSTICK // =========================================================================================== diff --git a/src/win32/win_vid.c b/src/win32/win_vid.c index 39a60cd93..d0aab92b3 100644 --- a/src/win32/win_vid.c +++ b/src/win32/win_vid.c @@ -239,6 +239,11 @@ void I_StartupGraphics(void) if (!dedicated) graphics_started = true; } +void I_StartupHardwareGraphics(void) +{ + // oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo y +} + // ------------------ // I_ShutdownGraphics // Close the screen, restore previous video mode. @@ -946,6 +951,11 @@ INT32 VID_SetMode(INT32 modenum) return 1; } +void VID_CheckRenderer(void) +{ + // .............. +} + // ======================================================================== // Free the video buffer of the last video mode, // allocate a new buffer for the video mode to set. diff --git a/src/y_inter.c b/src/y_inter.c index b26c0797e..214dee92e 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -161,6 +161,7 @@ typedef struct boolean usebuffer = false; static boolean useinterpic; +static boolean safetorender = true; static y_buffer_t *y_buffer; static INT32 intertic; @@ -177,6 +178,7 @@ static void Y_CalculateCompetitionWinners(void); static void Y_CalculateTimeRaceWinners(void); static void Y_CalculateMatchWinners(void); static void Y_UnloadData(void); +static void Y_CleanupData(void); // Stuff copy+pasted from st_stuff.c #define ST_DrawNumFromHud(h,n) V_DrawTallNum(hudinfo[h].x, hudinfo[h].y, hudinfo[h].f, n) @@ -335,8 +337,19 @@ void Y_IntermissionDrawer(void) } if (!usebuffer) + // Lactozilla: Renderer switching + if (needpatchrecache) + { + Y_CleanupData(); + safetorender = false; + } + + if (!usebuffer || !safetorender) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + if (!safetorender) + goto dontdrawbg; + if (useinterpic) V_DrawScaledPatch(0, 0, 0, interpic); else if (!usetile) @@ -377,6 +390,7 @@ void Y_IntermissionDrawer(void) goto skiptallydrawer; #endif +dontdrawbg: if (intertype == int_coop) { INT32 bonusy; @@ -426,14 +440,17 @@ void Y_IntermissionDrawer(void) bonusy = 150; // Total - V_DrawScaledPatch(152, bonusy, 0, data.coop.ptotal); - V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.total); + if (safetorender) + { + V_DrawScaledPatch(152, bonusy, 0, data.coop.ptotal); + V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.total); + } bonusy -= (3*SHORT(tallnum[0]->height)/2) + 1; // Draw bonuses for (i = 3; i >= 0; --i) { - if (data.coop.bonuses[i].display) + if (data.coop.bonuses[i].display && safetorender) { V_DrawScaledPatch(152, bonusy, 0, data.coop.bonuspatches[i]); V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.bonuses[i].points); @@ -662,7 +679,8 @@ void Y_IntermissionDrawer(void) char strtime[10]; // draw the header - V_DrawScaledPatch(112, 2, 0, data.match.result); + if (safetorender) + V_DrawScaledPatch(112, 2, 0, data.match.result); // draw the level name V_DrawCenteredString(BASEVIDWIDTH/2, 20, 0, data.match.levelstring); @@ -1194,6 +1212,8 @@ void Y_StartIntermission(void) I_Error("endtic is dirty"); #endif + safetorender = true; + if (!multiplayer) { timer = 0; @@ -1249,20 +1269,20 @@ void Y_StartIntermission(void) data.coop.tics = players[consoleplayer].realtime; for (i = 0; i < 4; ++i) - data.coop.bonuspatches[i] = W_CachePatchName(data.coop.bonuses[i].patch, PU_STATIC); - data.coop.ptotal = W_CachePatchName("YB_TOTAL", PU_STATIC); + data.coop.bonuspatches[i] = W_CachePatchName(data.coop.bonuses[i].patch, PU_PATCH); + data.coop.ptotal = W_CachePatchName("YB_TOTAL", PU_PATCH); // get act number data.coop.actnum = mapheaderinfo[gamemap-1]->actnum; // get background patches - widebgpatch = W_CachePatchName("INTERSCW", PU_STATIC); - bgpatch = W_CachePatchName("INTERSCR", PU_STATIC); + widebgpatch = W_CachePatchName("INTERSCW", PU_PATCH); + bgpatch = W_CachePatchName("INTERSCR", PU_PATCH); // grab an interscreen if appropriate if (mapheaderinfo[gamemap-1]->interscreen[0] != '#') { - interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_STATIC); + interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_PATCH); useinterpic = true; usebuffer = false; } @@ -1320,18 +1340,18 @@ void Y_StartIntermission(void) Y_AwardSpecialStageBonus(); for (i = 0; i < 2; ++i) - data.spec.bonuspatches[i] = W_CachePatchName(data.spec.bonuses[i].patch, PU_STATIC); + data.spec.bonuspatches[i] = W_CachePatchName(data.spec.bonuses[i].patch, PU_PATCH); - data.spec.pscore = W_CachePatchName("YB_SCORE", PU_STATIC); - data.spec.pcontinues = W_CachePatchName("YB_CONTI", PU_STATIC); + data.spec.pscore = W_CachePatchName("YB_SCORE", PU_PATCH); + data.spec.pcontinues = W_CachePatchName("YB_CONTI", PU_PATCH); // get background tile - bgtile = W_CachePatchName("SPECTILE", PU_STATIC); + bgtile = W_CachePatchName("SPECTILE", PU_PATCH); // grab an interscreen if appropriate if (mapheaderinfo[gamemap-1]->interscreen[0] != '#') { - interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_STATIC); + interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_PATCH); useinterpic = true; } else @@ -1343,14 +1363,14 @@ void Y_StartIntermission(void) // get special stage specific patches /* if (!stagefailed && ALL7EMERALDS(emeralds)) { - data.spec.cemerald = W_CachePatchName("GOTEMALL", PU_STATIC); + data.spec.cemerald = W_CachePatchName("GOTEMALL", PU_PATCH); data.spec.headx = 70; data.spec.nowsuper = players[consoleplayer].skin - ? NULL : W_CachePatchName("NOWSUPER", PU_STATIC); + ? NULL : W_CachePatchName("NOWSUPER", PU_PATCH); } else { - data.spec.cemerald = W_CachePatchName("CEMERALD", PU_STATIC); + data.spec.cemerald = W_CachePatchName("CEMERALD", PU_PATCH); data.spec.headx = 48; data.spec.nowsuper = NULL; } */ @@ -1428,9 +1448,9 @@ void Y_StartIntermission(void) // get RESULT header data.match.result = - W_CachePatchName("RESULT", PU_STATIC); + W_CachePatchName("RESULT", PU_PATCH); - bgtile = W_CachePatchName("SRB2BACK", PU_STATIC); + bgtile = W_CachePatchName("SRB2BACK", PU_PATCH); usetile = true; useinterpic = false; break; @@ -1456,9 +1476,9 @@ void Y_StartIntermission(void) data.match.levelstring[sizeof data.match.levelstring - 1] = '\0'; // get RESULT header - data.match.result = W_CachePatchName("RESULT", PU_STATIC); + data.match.result = W_CachePatchName("RESULT", PU_PATCH); - bgtile = W_CachePatchName("SRB2BACK", PU_STATIC); + bgtile = W_CachePatchName("SRB2BACK", PU_PATCH); usetile = true; useinterpic = false; break; @@ -1495,7 +1515,7 @@ void Y_StartIntermission(void) data.match.blueflag = bmatcico; } - bgtile = W_CachePatchName("SRB2BACK", PU_STATIC); + bgtile = W_CachePatchName("SRB2BACK", PU_PATCH); usetile = true; useinterpic = false; break; @@ -1521,7 +1541,7 @@ void Y_StartIntermission(void) data.competition.levelstring[sizeof data.competition.levelstring - 1] = '\0'; // get background tile - bgtile = W_CachePatchName("SRB2BACK", PU_STATIC); + bgtile = W_CachePatchName("SRB2BACK", PU_PATCH); usetile = true; useinterpic = false; break; @@ -1977,7 +1997,7 @@ static void Y_AwardCoopBonuses(void) if (i == consoleplayer) { - data.coop.gotlife = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0 : ptlives); + data.coop.gotlife = (((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 0) ? 0 : ptlives); M_Memcpy(&data.coop.bonuses, &localbonuses, sizeof(data.coop.bonuses)); } } @@ -2032,7 +2052,7 @@ static void Y_AwardSpecialStageBonus(void) if (i == consoleplayer) { - data.spec.gotlife = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0 : ptlives); + data.spec.gotlife = (((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 0) ? 0 : ptlives); M_Memcpy(&data.spec.bonuses, &localbonuses, sizeof(data.spec.bonuses)); // Continues related @@ -2059,7 +2079,8 @@ void Y_EndIntermission(void) usebuffer = false; } -#define UNLOAD(x) Z_ChangeTag(x, PU_CACHE); x = NULL +#define UNLOAD(x) if (x) {Z_ChangeTag(x, PU_CACHE);} x = NULL; +#define CLEANUP(x) x = NULL; // // Y_UnloadData @@ -2110,5 +2131,47 @@ static void Y_UnloadData(void) //are not handled break; } - +} + +static void Y_CleanupData(void) +{ + // unload the background patches + CLEANUP(bgpatch); + CLEANUP(widebgpatch); + CLEANUP(bgtile); + CLEANUP(interpic); + + switch (intertype) + { + case int_coop: + // unload the coop and single player patches + CLEANUP(data.coop.bonuspatches[3]); + CLEANUP(data.coop.bonuspatches[2]); + CLEANUP(data.coop.bonuspatches[1]); + CLEANUP(data.coop.bonuspatches[0]); + CLEANUP(data.coop.ptotal); + break; + case int_spec: + // unload the special stage patches + //CLEANUP(data.spec.cemerald); + //CLEANUP(data.spec.nowsuper); + CLEANUP(data.spec.bonuspatches[1]); + CLEANUP(data.spec.bonuspatches[0]); + CLEANUP(data.spec.pscore); + CLEANUP(data.spec.pcontinues); + break; + case int_match: + case int_race: + CLEANUP(data.match.result); + break; + case int_ctf: + CLEANUP(data.match.blueflag); + CLEANUP(data.match.redflag); + break; + default: + //without this default, + //int_none, int_tag, int_chaos, and int_classicrace + //are not handled + break; + } } diff --git a/src/z_zone.c b/src/z_zone.c index b1a44b392..0abd77257 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -27,6 +27,7 @@ #include "doomdef.h" #include "doomstat.h" +#include "r_patch.h" #include "i_system.h" // I_GetFreeMem #include "i_video.h" // rendermode #include "z_zone.h" @@ -497,6 +498,35 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag) // Utility functions // ----------------- +// for renderer switching, free a bunch of stuff +boolean needpatchflush = false; +boolean needpatchrecache = false; + +// flush all patches from memory +// (also frees memory tagged with PU_CACHE) +// (which are not necessarily patches but I don't care) +void Z_FlushCachedPatches(void) +{ + CONS_Debug(DBG_RENDER, "Z_FlushCachedPatches()...\n"); + Z_FreeTag(PU_CACHE); + Z_FreeTag(PU_PATCH); + Z_FreeTag(PU_HUDGFX); + Z_FreeTag(PU_HWRPATCHINFO); + Z_FreeTag(PU_HWRMODELTEXTURE); + Z_FreeTag(PU_HWRCACHE); + Z_FreeTag(PU_HWRCACHE_UNLOCKED); + Z_FreeTag(PU_HWRPATCHINFO_UNLOCKED); +} + +// happens before a renderer switch +void Z_PreparePatchFlush(void) +{ + CONS_Debug(DBG_RENDER, "Z_PreparePatchFlush()...\n"); +#ifdef ROTSPRITE + R_FreeAllRotSprite(); +#endif +} + // starting value of nextcleanup #define CLEANUPCOUNT 2000 diff --git a/src/z_zone.h b/src/z_zone.h index 635c334cf..9e5f74343 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -43,6 +43,7 @@ enum PU_SOUND = 11, // static while playing PU_MUSIC = 12, // static while playing PU_HUDGFX = 13, // static until WAD added + PU_PATCH = 14, // static until renderer change PU_HWRPATCHINFO = 21, // Hardware GLPatch_t struct for OpenGL texture cache PU_HWRPATCHCOLMIPMAP = 22, // Hardware GLMipmap_t struct colormap variation of patch @@ -142,4 +143,10 @@ size_t Z_TagsUsage(INT32 lowtag, INT32 hightag); char *Z_StrDup(const char *in); #define Z_Unlock(p) (void)p // TODO: remove this now that NDS code has been removed +// For renderer switching +extern boolean needpatchflush; +extern boolean needpatchrecache; +void Z_FlushCachedPatches(void); +void Z_PreparePatchFlush(void); + #endif