diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 124a89b090987d5bfed337387ee32f16f884952f..d35e774e934d5b624b4d2bcc5c19b5bc24b6abf6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,6 +13,9 @@ set(SRB2_CORE_SOURCES d_netcmd.c d_netfil.c dehacked.c + deh_soc.c + deh_lua.c + deh_tables.c f_finale.c f_wipe.c filesrch.c @@ -66,6 +69,9 @@ set(SRB2_CORE_HEADERS d_think.h d_ticcmd.h dehacked.h + deh_soc.h + deh_lua.h + deh_tables.h doomdata.h doomdef.h doomstat.h @@ -130,6 +136,8 @@ set(SRB2_CORE_RENDER_SOURCES r_splats.c r_things.c r_textures.c + r_patch.c + r_patchrotation.c r_picformats.c r_portal.c @@ -147,6 +155,8 @@ set(SRB2_CORE_RENDER_SOURCES r_state.h r_things.h r_textures.h + r_patch.h + r_patchrotation.h r_picformats.h r_portal.h ) diff --git a/src/Makefile b/src/Makefile index 2cd6d5f6b309b76ace6073ffb1cd5580851e71d1..0c1626fc955c5465f9ae23b62875bf9395c73e25 100644 --- a/src/Makefile +++ b/src/Makefile @@ -465,6 +465,9 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/d_netfil.o \ $(OBJDIR)/d_netcmd.o \ $(OBJDIR)/dehacked.o \ + $(OBJDIR)/deh_soc.o \ + $(OBJDIR)/deh_lua.o \ + $(OBJDIR)/deh_tables.o \ $(OBJDIR)/z_zone.o \ $(OBJDIR)/f_finale.o \ $(OBJDIR)/f_wipe.o \ @@ -519,6 +522,8 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/r_splats.o \ $(OBJDIR)/r_things.o \ $(OBJDIR)/r_textures.o \ + $(OBJDIR)/r_patch.o \ + $(OBJDIR)/r_patchrotation.o \ $(OBJDIR)/r_picformats.o \ $(OBJDIR)/r_portal.o \ $(OBJDIR)/screen.o \ @@ -539,6 +544,15 @@ OBJS:=$(i_main_o) \ $(i_sound_o) \ $(OBJS) + +ifndef ECHO +ifndef NOECHOFILENAMES +define echoName = + @echo -- $< ... +endef +endif +endif + # List of languages to compile. # For reference, this is the command I use to build a srb2.pot file from the source code. # (The listed source files are the ones containing translated strings). @@ -699,6 +713,7 @@ $(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ else $(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \ @@ -708,6 +723,7 @@ $(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -I/usr/X11R6/include -c $< -o $@ endif endif @@ -736,43 +752,55 @@ endif ifdef VALGRIND $(OBJDIR)/z_zone.o: z_zone.c + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -DHAVE_VALGRIND $(VALGRIND_CFLAGS) -c $< -o $@ endif $(OBJDIR)/comptime.o: comptime.c pre-build + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ $(BIN)/%.mo: locale/%.po -$(MKDIR) $(BIN) + $(echoName) $(MSGFMT) -f -o $@ $< $(OBJDIR)/%.o: %.c + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ $(OBJDIR)/%.o: $(INTERFACE)/%.c + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ ifdef MACOSX $(OBJDIR)/%.o: sdl/macosx/%.c + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ endif $(OBJDIR)/%.o: hardware/%.c + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ $(OBJDIR)/%.o: blua/%.c + $(echoName) $(CC) $(CFLAGS) $(LUA_CFLAGS) $(WFLAGS) -c $< -o $@ $(OBJDIR)/%.o: %.nas + $(echoName) $(NASM) $(NASMOPTS) -o $@ -f $(NASMFORMAT) $< $(OBJDIR)/vid_copy.o: vid_copy.s asm_defs.inc + $(echoName) $(CC) $(OPTS) $(ASFLAGS) -x assembler-with-cpp -c $< -o $@ $(OBJDIR)/%.o: %.s + $(echoName) $(CC) $(OPTS) -x assembler-with-cpp -c $< -o $@ $(OBJDIR)/SRB2.res: win32/Srb2win.rc win32/afxres.h win32/resource.h + $(echoName) $(WINDRES) -i $< -O rc $(WINDRESFLAGS) --include-dir=win32 -o $@ -O coff @@ -786,6 +814,7 @@ $(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@ $(OBJDIR)/ogl_win.o: hardware/r_opengl/ogl_win.c hardware/r_opengl/r_opengl.h \ @@ -795,6 +824,7 @@ $(OBJDIR)/ogl_win.o: hardware/r_opengl/ogl_win.c hardware/r_opengl/r_opengl.h \ hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@ endif @@ -805,31 +835,37 @@ ifdef SDL ifdef MINGW $(OBJDIR)/win_dbg.o: win32/win_dbg.c + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ endif ifdef STATICHS $(OBJDIR)/s_openal.o: hardware/s_openal/s_openal.c hardware/hw3dsdrv.h \ hardware/hw_dll.h + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ $(OBJDIR)/s_fmod.o: hardware/s_fmod/s_fmod.c hardware/hw3dsdrv.h \ hardware/hw_dll.h + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ ifdef MINGW $(OBJDIR)/s_ds3d.o: hardware/s_ds3d/s_ds3d.c hardware/hw3dsdrv.h \ hardware/hw_dll.h + $(echoName) $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ endif else $(OBJDIR)/s_fmod.o: hardware/s_fmod/s_fmod.c hardware/hw3dsdrv.h \ hardware/hw_dll.h + $(echoName) $(CC) $(ARCHOPTS) -Os -o $(OBJDIR)/s_fmod.o -DHW3SOUND -DUNIXCOMMON -shared -nostartfiles -c hardware/s_fmod/s_fmod.c $(OBJDIR)/s_openal.o: hardware/s_openal/s_openal.c hardware/hw3dsdrv.h \ hardware/hw_dll.h + $(echoName) $(CC) $(ARCHOPTS) -Os -o $(OBJDIR)/s_openal.o -DHW3SOUND -DUNIXCOMMON -shared -nostartfiles -c hardware/s_openal/s_openal.c endif endif diff --git a/src/android/i_video.c b/src/android/i_video.c index 18f92955a7e3cba7f6b31ef8f929664a3b700770..bf0decb74118385ff2b776d8d470e5ea3a03a2ba 100644 --- a/src/android/i_video.c +++ b/src/android/i_video.c @@ -9,6 +9,7 @@ #include "utils/Log.h" rendermode_t rendermode = render_soft; +rendermode_t chosenrendermode = render_none; boolean highcolor = false; @@ -52,8 +53,15 @@ INT32 VID_SetMode(INT32 modenum) return 0; } -void VID_CheckRenderer(void) {} -void VID_CheckGLLoaded(rendermode_t oldrender) {} +boolean VID_CheckRenderer(void) +{ + return false; +} + +void VID_CheckGLLoaded(rendermode_t oldrender) +{ + (void)oldrender; +} const char *VID_GetModeName(INT32 modenum) { diff --git a/src/blua/liolib.c b/src/blua/liolib.c index a055aad3f600a4482502da148467bfe622751fe3..5eec97fb4b7b4e5e4f47637b34b0444c1750a334 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -277,6 +277,9 @@ void Got_LuaFile(UINT8 **cp, INT32 playernum) if (!luafiletransfers) I_Error("No Lua file transfer\n"); + lua_settop(gL, 0); // Just in case... + lua_pushcfunction(gL, LUA_GetErrorMessage); + // Retrieve the callback and push it on the stack lua_pushfstring(gL, FMT_FILECALLBACKID, luafiletransfers->id); lua_gettable(gL, LUA_REGISTRYINDEX); @@ -304,7 +307,8 @@ void Got_LuaFile(UINT8 **cp, INT32 playernum) lua_pushstring(gL, luafiletransfers->filename); // Call the callback - LUA_Call(gL, 2); + LUA_Call(gL, 2, 0, 1); + lua_settop(gL, 0); if (success) { diff --git a/src/console.c b/src/console.c index 3eee67bb843e2479c0b86bcd3734288601cb0417..b19b8818d709bca4e55f61c033cdd5e97d5f8413 100644 --- a/src/console.c +++ b/src/console.c @@ -56,7 +56,8 @@ I_mutex con_mutex; #endif/*HAVE_THREADS*/ static boolean con_started = false; // console has been initialised - boolean con_startup = false; // true at game startup, screen need refreshing + boolean con_startup = false; // true at game startup + boolean con_refresh = false; // screen needs refreshing static boolean con_forcepic = true; // at startup toggle console translucency when first off boolean con_recalc; // set true when screen size has changed @@ -439,7 +440,8 @@ void CON_Init(void) Lock_state(); con_started = true; - con_startup = true; // need explicit screen refresh until we are in Doom loop + con_startup = true; + con_refresh = true; // needs explicit screen refresh until we are in the main game loop consoletoggle = false; Unlock_state(); @@ -457,7 +459,8 @@ void CON_Init(void) Lock_state(); con_started = true; - con_startup = false; // need explicit screen refresh until we are in Doom loop + con_startup = false; + con_refresh = false; // disable explicit screen refresh consoletoggle = true; Unlock_state(); @@ -1438,7 +1441,7 @@ void CONS_Printf(const char *fmt, ...) { va_list argptr; static char *txt = NULL; - boolean startup; + boolean refresh; if (txt == NULL) txt = malloc(8192); @@ -1454,32 +1457,21 @@ void CONS_Printf(const char *fmt, ...) if (con_started) CON_Print(txt); - CON_LogMessage(txt); + CON_LogMessage(txt); Lock_state(); // make sure new text is visible con_scrollup = 0; - startup = con_startup; + refresh = con_refresh; Unlock_state(); // if not in display loop, force screen update - if (startup && (!setrenderneeded)) + if (refresh) { -#ifdef _WINDOWS - patch_t *con_backpic = W_CachePatchName("CONSBACK", PU_PATCH); - - // Jimita: CON_DrawBackpic just called V_DrawScaledPatch - V_DrawScaledPatch(0, 0, 0, con_backpic); - - W_UnlockCachedPatch(con_backpic); - I_LoadingScreen(txt); // Win32/OS2 only -#else - // here we display the console text - CON_Drawer(); + CON_Drawer(); // here we display the console text I_FinishUpdate(); // page flip or blit buffer -#endif } } @@ -1541,7 +1533,7 @@ void CONS_Debug(INT32 debugflags, const char *fmt, ...) // void CONS_Error(const char *msg) { -#ifdef RPC_NO_WINDOWS_H +#if defined(RPC_NO_WINDOWS_H) && defined(_WINDOWS) if (!graphics_started) { MessageBoxA(vid.WndParent, msg, "SRB2 Warning", MB_OK); @@ -1690,7 +1682,7 @@ static void CON_DrawHudlines(void) ;//charwidth = 4 * con_scalefactor; else { - //charwidth = SHORT(hu_font['A'-HU_FONTSTART]->width) * con_scalefactor; + //charwidth = (hu_font['A'-HU_FONTSTART]->width) * con_scalefactor; V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true); } } @@ -1719,8 +1711,8 @@ static void CON_DrawBackpic(void) if (piclump == LUMPERROR) piclump = W_GetNumForName("MISSING"); - // Cache the Software patch. - con_backpic = W_CacheSoftwarePatchNum(piclump, PU_PATCH); + // Cache the patch. + con_backpic = W_CachePatchNum(piclump, PU_PATCH); // Center the backpic, and draw a vertically cropped patch. w = (con_backpic->width * vid.dupx); @@ -1731,7 +1723,7 @@ static void CON_DrawBackpic(void) // then fill the sides with a solid color. if (x > 0) { - column_t *column = (column_t *)((UINT8 *)(con_backpic) + LONG(con_backpic->columnofs[0])); + column_t *column = (column_t *)((UINT8 *)(con_backpic->columns) + (con_backpic->columnofs[0])); if (!column->topdelta) { UINT8 *source = (UINT8 *)(column) + 3; @@ -1743,8 +1735,7 @@ static void CON_DrawBackpic(void) } } - // Cache the patch normally. - con_backpic = W_CachePatchNum(piclump, PU_PATCH); + // Draw the patch. V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, V_NOSCALESTART, con_backpic, 0, ( BASEVIDHEIGHT - h ), BASEVIDWIDTH, h); @@ -1829,9 +1820,6 @@ void CON_Drawer(void) return; } - if (needpatchrecache) - HU_LoadGraphics(); - if (con_recalc) { CON_RecalcSize(); diff --git a/src/console.h b/src/console.h index c8dd9e3de4485b3ce75eb5b1ecef05237e889f95..0296f4f6e658e82a01d78a2ae05f636d90e411ed 100644 --- a/src/console.h +++ b/src/console.h @@ -25,8 +25,12 @@ extern I_mutex con_mutex; // set true when screen size has changed, to adapt console extern boolean con_recalc; +// console being displayed at game startup extern boolean con_startup; +// needs explicit screen refresh until we are in the main game loop +extern boolean con_refresh; + // top clip value for view render: do not draw part of view hidden by console extern INT32 con_clipviewtop; diff --git a/src/d_main.c b/src/d_main.c index fe8327e986ba488c99c71c30150780b98bbac0e0..1045d4d99b86d2295f26d5342bf195d8da9a71f1 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -107,8 +107,6 @@ 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; @@ -237,7 +235,6 @@ INT16 wipetypepost = -1; static void D_Display(void) { - INT32 setrenderstillneeded = 0; boolean forcerefresh = false; static boolean wipe = false; INT32 wipedefindex = 0; @@ -260,48 +257,28 @@ static void D_Display(void) // 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! - - // stop movie if needs to change renderer - if (setrenderneeded && (moviemode == MM_APNG)) - M_StopMovie(); + // 4. The frame is ready to be drawn! - // check for change of renderer or screen size (video mode) + // 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) - { + // Recalc the screen + if (vid.recalc) SCR_Recalc(); // NOTE! setsizeneeded is set by SCR_Recalc() -#ifdef HWRENDER - // Shoot! The screen texture was flushed! - if ((rendermode == render_opengl) && (gamestate == GS_INTERMISSION)) - usebuffer = false; -#endif - } + // View morph if (rendermode == render_soft && !splitscreen) R_CheckViewMorph(); - // change the view size if needed - if (setsizeneeded || setrenderstillneeded) + // Change the view size if needed + // Set by changing video mode or renderer + if (setsizeneeded) { 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(); @@ -530,7 +507,7 @@ static void D_Display(void) else py = viewwindowy + 4; patch = W_CachePatchName("M_PAUSE", PU_PATCH); - V_DrawScaledPatch(viewwindowx + (BASEVIDWIDTH - SHORT(patch->width))/2, py, 0, patch); + V_DrawScaledPatch(viewwindowx + (BASEVIDWIDTH - patch->width)/2, py, 0, patch); #else INT32 y = ((automapactive) ? (32) : (BASEVIDHEIGHT/2)); M_DrawTextBox((BASEVIDWIDTH/2) - (60), y - (16), 13, 2); @@ -642,26 +619,6 @@ static void D_Display(void) I_FinishUpdate(); // page flip or blit buffer ps_swaptime = I_GetTimeMicros() - ps_swaptime; } - - needpatchflush = false; - needpatchrecache = false; -} - -// Check the renderer's state -// after a possible renderer switch. -void D_CheckRendererState(void) -{ - // flush all patches from memory - if (needpatchflush) - { - Z_FlushCachedPatches(); - needpatchflush = false; - } - - // some patches have been freed, - // so cache them again - if (needpatchrecache) - R_ReloadHUDGraphics(); } // ========================================================================= @@ -688,12 +645,15 @@ void D_SRB2Loop(void) oldentertics = I_GetTime(); // end of loading screen: CONS_Printf() will no more call FinishUpdate() + con_refresh = false; con_startup = false; // make sure to do a d_display to init mode _before_ load a level SCR_SetMode(); // change video mode SCR_Recalc(); + chosenrendermode = render_none; + // Check and print which version is executed. // Use this as the border between setup and the main game loop being entered. CONS_Printf( @@ -1338,24 +1298,6 @@ 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)) - { - CONS_Printf(M_GetText("Switching the renderer...\n")); - Z_PreparePatchFlush(); - - // set needpatchflush / needpatchrecache true for D_CheckRendererState - needpatchflush = true; - needpatchrecache = true; - - // Set cv_renderer to the new render mode - VID_CheckRenderer(); - SCR_ChangeRendererCVars(rendermode); - - // check the renderer's state - 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 87abd596a1520b1b6088eacb476af290abcefa84..31c10f58a8e0dbe7f709c0ffd98e63772fe175d6 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -374,6 +374,7 @@ consvar_t cv_sleep = CVAR_INIT ("cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL) static CV_PossibleValue_t perfstats_cons_t[] = { {0, "Off"}, {1, "Rendering"}, {2, "Logic"}, {3, "ThinkFrame"}, {0, NULL}}; consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", 0, perfstats_cons_t, NULL); +consvar_t cv_freedemocamera = CVAR_INIT("freedemocamera", "Off", CV_SAVE, CV_OnOff, NULL); char timedemo_name[256]; boolean timedemo_csv; @@ -675,10 +676,6 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_gif_dynamicdelay); CV_RegisterVar(&cv_gif_localcolortable); -#ifdef WALLSPLATS - CV_RegisterVar(&cv_splats); -#endif - // register these so it is saved to config CV_RegisterVar(&cv_playername); CV_RegisterVar(&cv_playercolor); @@ -880,6 +877,8 @@ void D_RegisterClientCommands(void) // CV_RegisterVar(&cv_grid); // CV_RegisterVar(&cv_snapto); + CV_RegisterVar(&cv_freedemocamera); + // add cheat commands COM_AddCommand("noclip", Command_CheatNoClip_f); COM_AddCommand("god", Command_CheatGod_f); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 841f71acd6692341af29928b117b36699e295080..98d8f142576e46d18dd84a2820a1812b3289d7d6 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -75,9 +75,6 @@ extern consvar_t cv_teamscramble; extern consvar_t cv_scrambleonchange; extern consvar_t cv_netstat; -#ifdef WALLSPLATS -extern consvar_t cv_splats; -#endif extern consvar_t cv_countdowntime; extern consvar_t cv_runscripts; @@ -121,6 +118,8 @@ extern boolean timedemo_csv; extern char timedemo_csv_id[256]; extern boolean timedemo_quit; +extern consvar_t cv_freedemocamera; + typedef enum { XD_NAMEANDCOLOR = 1, diff --git a/src/deh_lua.c b/src/deh_lua.c new file mode 100644 index 0000000000000000000000000000000000000000..e6a436421cc14096bb1bc02689455a48df499dc1 --- /dev/null +++ b/src/deh_lua.c @@ -0,0 +1,697 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file deh_lua.c +/// \brief Lua SOC library + +#include "g_game.h" +#include "s_sound.h" +#include "z_zone.h" +#include "m_menu.h" +#include "m_misc.h" +#include "p_local.h" +#include "st_stuff.h" +#include "fastcmp.h" +#include "lua_script.h" +#include "lua_libs.h" + +#include "dehacked.h" +#include "deh_lua.h" +#include "deh_tables.h" + +#ifdef MUSICSLOT_COMPATIBILITY +#include "deh_soc.h" // for get_mus +#endif + +// freeslot takes a name (string only!) +// and allocates it to the appropriate free slot. +// Returns the slot number allocated for it or nil if failed. +// ex. freeslot("MT_MYTHING","S_MYSTATE1","S_MYSTATE2") +// TODO: Error checking! @.@; There's currently no way to know which ones failed and why! +// +static inline int lib_freeslot(lua_State *L) +{ + int n = lua_gettop(L); + int r = 0; // args returned + char *s, *type,*word; + + if (!lua_lumploading) + return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); + + while (n-- > 0) + { + s = Z_StrDup(luaL_checkstring(L,1)); + type = strtok(s, "_"); + if (type) + strupr(type); + else { + Z_Free(s); + return luaL_error(L, "Unknown enum type in '%s'\n", luaL_checkstring(L, 1)); + } + + word = strtok(NULL, "\n"); + if (word) + strupr(word); + else { + Z_Free(s); + return luaL_error(L, "Missing enum name in '%s'\n", luaL_checkstring(L, 1)); + } + if (fastcmp(type, "SFX")) { + sfxenum_t sfx; + strlwr(word); + CONS_Printf("Sound sfx_%s allocated.\n",word); + sfx = S_AddSoundFx(word, false, 0, false); + if (sfx != sfx_None) { + lua_pushinteger(L, sfx); + r++; + } else + CONS_Alert(CONS_WARNING, "Ran out of free SFX slots!\n"); + } + else if (fastcmp(type, "SPR")) + { + char wad; + spritenum_t j; + lua_getfield(L, LUA_REGISTRYINDEX, "WAD"); + wad = (char)lua_tointeger(L, -1); + lua_pop(L, 1); + for (j = SPR_FIRSTFREESLOT; j <= SPR_LASTFREESLOT; j++) + { + if (used_spr[(j-SPR_FIRSTFREESLOT)/8] & (1<<(j%8))) + { + if (!sprnames[j][4] && memcmp(sprnames[j],word,4)==0) + sprnames[j][4] = wad; + continue; // Already allocated, next. + } + // Found a free slot! + CONS_Printf("Sprite SPR_%s allocated.\n",word); + strncpy(sprnames[j],word,4); + //sprnames[j][4] = 0; + used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now. + lua_pushinteger(L, j); + r++; + break; + } + if (j > SPR_LASTFREESLOT) + CONS_Alert(CONS_WARNING, "Ran out of free sprite slots!\n"); + } + else if (fastcmp(type, "S")) + { + statenum_t i; + for (i = 0; i < NUMSTATEFREESLOTS; i++) + if (!FREE_STATES[i]) { + CONS_Printf("State S_%s allocated.\n",word); + FREE_STATES[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); + strcpy(FREE_STATES[i],word); + lua_pushinteger(L, S_FIRSTFREESLOT + i); + r++; + break; + } + if (i == NUMSTATEFREESLOTS) + CONS_Alert(CONS_WARNING, "Ran out of free State slots!\n"); + } + else if (fastcmp(type, "MT")) + { + mobjtype_t i; + for (i = 0; i < NUMMOBJFREESLOTS; i++) + if (!FREE_MOBJS[i]) { + CONS_Printf("MobjType MT_%s allocated.\n",word); + FREE_MOBJS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); + strcpy(FREE_MOBJS[i],word); + lua_pushinteger(L, MT_FIRSTFREESLOT + i); + r++; + break; + } + if (i == NUMMOBJFREESLOTS) + CONS_Alert(CONS_WARNING, "Ran out of free MobjType slots!\n"); + } + else if (fastcmp(type, "SKINCOLOR")) + { + skincolornum_t i; + for (i = 0; i < NUMCOLORFREESLOTS; i++) + if (!FREE_SKINCOLORS[i]) { + CONS_Printf("Skincolor SKINCOLOR_%s allocated.\n",word); + FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); + strcpy(FREE_SKINCOLORS[i],word); + M_AddMenuColor(numskincolors++); + lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT + i); + r++; + break; + } + if (i == NUMCOLORFREESLOTS) + CONS_Alert(CONS_WARNING, "Ran out of free skincolor slots!\n"); + } + else if (fastcmp(type, "SPR2")) + { + // Search if we already have an SPR2 by that name... + playersprite_t i; + for (i = SPR2_FIRSTFREESLOT; i < free_spr2; i++) + if (memcmp(spr2names[i],word,4) == 0) + break; + // We don't, so allocate a new one. + if (i >= free_spr2) { + if (free_spr2 < NUMPLAYERSPRITES) + { + CONS_Printf("Sprite SPR2_%s allocated.\n",word); + strncpy(spr2names[free_spr2],word,4); + spr2defaults[free_spr2] = 0; + lua_pushinteger(L, free_spr2); + r++; + spr2names[free_spr2++][4] = 0; + } else + CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n"); + } + } + else if (fastcmp(type, "TOL")) + { + // Search if we already have a typeoflevel by that name... + int i; + for (i = 0; TYPEOFLEVEL[i].name; i++) + if (fastcmp(word, TYPEOFLEVEL[i].name)) + break; + + // We don't, so allocate a new one. + if (TYPEOFLEVEL[i].name == NULL) { + if (lastcustomtol == (UINT32)MAXTOL) // Unless you have way too many, since they're flags. + CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n"); + else { + CONS_Printf("TypeOfLevel TOL_%s allocated.\n",word); + G_AddTOL(lastcustomtol, word); + lua_pushinteger(L, lastcustomtol); + lastcustomtol <<= 1; + r++; + } + } + } + Z_Free(s); + lua_remove(L, 1); + continue; + } + return r; +} + +// Wrapper for ALL A_Action functions. +// Arguments: mobj_t actor, int var1, int var2 +static int action_call(lua_State *L) +{ + //actionf_t *action = lua_touserdata(L,lua_upvalueindex(1)); + actionf_t *action = *((actionf_t **)luaL_checkudata(L, 1, META_ACTION)); + mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + var1 = (INT32)luaL_optinteger(L, 3, 0); + var2 = (INT32)luaL_optinteger(L, 4, 0); + if (!actor) + return LUA_ErrInvalid(L, "mobj_t"); + action->acp1(actor); + return 0; +} + +// Hardcoded A_Action name to call for super() or NULL if super() would be invalid. +// Set in lua_infolib. +const char *superactions[MAXRECURSION]; +UINT8 superstack = 0; + +static int lib_dummysuper(lua_State *L) +{ + return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions being called by state changes!"); // convoluted, I know. @_@;; +} + +static inline int lib_getenum(lua_State *L) +{ + const char *word, *p; + fixed_t i; + boolean mathlib = lua_toboolean(L, lua_upvalueindex(1)); + if (lua_type(L,2) != LUA_TSTRING) + return 0; + word = lua_tostring(L,2); + if (strlen(word) == 1) { // Assume sprite frame if length 1. + if (*word >= 'A' && *word <= '~') + { + lua_pushinteger(L, *word-'A'); + return 1; + } + if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word); + return 0; + } + else if (fastncmp("MF_", word, 3)) { + p = word+3; + for (i = 0; MOBJFLAG_LIST[i]; i++) + if (fastcmp(p, MOBJFLAG_LIST[i])) { + lua_pushinteger(L, ((lua_Integer)1<<i)); + return 1; + } + if (mathlib) return luaL_error(L, "mobjflag '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("MF2_", word, 4)) { + p = word+4; + for (i = 0; MOBJFLAG2_LIST[i]; i++) + if (fastcmp(p, MOBJFLAG2_LIST[i])) { + lua_pushinteger(L, ((lua_Integer)1<<i)); + return 1; + } + if (mathlib) return luaL_error(L, "mobjflag2 '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("MFE_", word, 4)) { + p = word+4; + for (i = 0; MOBJEFLAG_LIST[i]; i++) + if (fastcmp(p, MOBJEFLAG_LIST[i])) { + lua_pushinteger(L, ((lua_Integer)1<<i)); + return 1; + } + if (mathlib) return luaL_error(L, "mobjeflag '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("MTF_", word, 4)) { + p = word+4; + for (i = 0; i < 4; i++) + if (MAPTHINGFLAG_LIST[i] && fastcmp(p, MAPTHINGFLAG_LIST[i])) { + lua_pushinteger(L, ((lua_Integer)1<<i)); + return 1; + } + if (mathlib) return luaL_error(L, "mapthingflag '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("PF_", word, 3)) { + p = word+3; + for (i = 0; PLAYERFLAG_LIST[i]; i++) + if (fastcmp(p, PLAYERFLAG_LIST[i])) { + lua_pushinteger(L, ((lua_Integer)1<<i)); + return 1; + } + if (fastcmp(p, "FULLSTASIS")) + { + lua_pushinteger(L, (lua_Integer)PF_FULLSTASIS); + return 1; + } + else if (fastcmp(p, "USEDOWN")) // Remove case when 2.3 nears release... + { + lua_pushinteger(L, (lua_Integer)PF_SPINDOWN); + return 1; + } + if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("GT_", word, 3)) { + p = word; + for (i = 0; Gametype_ConstantNames[i]; i++) + if (fastcmp(p, Gametype_ConstantNames[i])) { + lua_pushinteger(L, i); + return 1; + } + if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("GTR_", word, 4)) { + p = word+4; + for (i = 0; GAMETYPERULE_LIST[i]; i++) + if (fastcmp(p, GAMETYPERULE_LIST[i])) { + lua_pushinteger(L, ((lua_Integer)1<<i)); + return 1; + } + if (mathlib) return luaL_error(L, "game type rule '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("TOL_", word, 4)) { + p = word+4; + for (i = 0; TYPEOFLEVEL[i].name; i++) + if (fastcmp(p, TYPEOFLEVEL[i].name)) { + lua_pushinteger(L, TYPEOFLEVEL[i].flag); + return 1; + } + if (mathlib) return luaL_error(L, "typeoflevel '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("ML_", word, 3)) { + p = word+3; + for (i = 0; i < 16; i++) + if (ML_LIST[i] && fastcmp(p, ML_LIST[i])) { + lua_pushinteger(L, ((lua_Integer)1<<i)); + return 1; + } + if (mathlib) return luaL_error(L, "linedef flag '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("S_",word,2)) { + p = word+2; + for (i = 0; i < NUMSTATEFREESLOTS; i++) { + if (!FREE_STATES[i]) + break; + if (fastcmp(p, FREE_STATES[i])) { + lua_pushinteger(L, S_FIRSTFREESLOT+i); + return 1; + } + } + for (i = 0; i < S_FIRSTFREESLOT; i++) + if (fastcmp(p, STATE_LIST[i]+2)) { + lua_pushinteger(L, i); + return 1; + } + return luaL_error(L, "state '%s' does not exist.\n", word); + } + else if (fastncmp("MT_",word,3)) { + p = word+3; + for (i = 0; i < NUMMOBJFREESLOTS; i++) { + if (!FREE_MOBJS[i]) + break; + if (fastcmp(p, FREE_MOBJS[i])) { + lua_pushinteger(L, MT_FIRSTFREESLOT+i); + return 1; + } + } + for (i = 0; i < MT_FIRSTFREESLOT; i++) + if (fastcmp(p, MOBJTYPE_LIST[i]+3)) { + lua_pushinteger(L, i); + return 1; + } + return luaL_error(L, "mobjtype '%s' does not exist.\n", word); + } + else if (fastncmp("SPR_",word,4)) { + p = word+4; + for (i = 0; i < NUMSPRITES; i++) + if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) { + lua_pushinteger(L, i); + return 1; + } + if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("SPR2_",word,5)) { + p = word+5; + for (i = 0; i < (fixed_t)free_spr2; i++) + if (!spr2names[i][4]) + { + // special 3-char cases, e.g. SPR2_RUN + // the spr2names entry will have "_" on the end, as in "RUN_" + if (spr2names[i][3] == '_' && !p[3]) { + if (fastncmp(p,spr2names[i],3)) { + lua_pushinteger(L, i); + return 1; + } + } + else if (fastncmp(p,spr2names[i],4)) { + lua_pushinteger(L, i); + return 1; + } + } + if (mathlib) return luaL_error(L, "player sprite '%s' could not be found.\n", word); + return 0; + } + else if (!mathlib && fastncmp("sfx_",word,4)) { + p = word+4; + for (i = 0; i < NUMSFX; i++) + if (S_sfx[i].name && fastcmp(p, S_sfx[i].name)) { + lua_pushinteger(L, i); + return 1; + } + return 0; + } + else if (mathlib && fastncmp("SFX_",word,4)) { // SOCs are ALL CAPS! + p = word+4; + for (i = 0; i < NUMSFX; i++) + if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) { + lua_pushinteger(L, i); + return 1; + } + return luaL_error(L, "sfx '%s' could not be found.\n", word); + } + else if (mathlib && fastncmp("DS",word,2)) { + p = word+2; + for (i = 0; i < NUMSFX; i++) + if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) { + lua_pushinteger(L, i); + return 1; + } + if (mathlib) return luaL_error(L, "sfx '%s' could not be found.\n", word); + return 0; + } +#ifdef MUSICSLOT_COMPATIBILITY + else if (!mathlib && fastncmp("mus_",word,4)) { + p = word+4; + if ((i = get_mus(p, false)) == 0) + return 0; + lua_pushinteger(L, i); + return 1; + } + else if (mathlib && fastncmp("MUS_",word,4)) { // SOCs are ALL CAPS! + p = word+4; + if ((i = get_mus(p, false)) == 0) + return luaL_error(L, "music '%s' could not be found.\n", word); + lua_pushinteger(L, i); + return 1; + } + else if (mathlib && (fastncmp("O_",word,2) || fastncmp("D_",word,2))) { + p = word+2; + if ((i = get_mus(p, false)) == 0) + return luaL_error(L, "music '%s' could not be found.\n", word); + lua_pushinteger(L, i); + return 1; + } +#endif + else if (!mathlib && fastncmp("pw_",word,3)) { + p = word+3; + for (i = 0; i < NUMPOWERS; i++) + if (fasticmp(p, POWERS_LIST[i])) { + lua_pushinteger(L, i); + return 1; + } + return 0; + } + else if (mathlib && fastncmp("PW_",word,3)) { // SOCs are ALL CAPS! + p = word+3; + for (i = 0; i < NUMPOWERS; i++) + if (fastcmp(p, POWERS_LIST[i])) { + lua_pushinteger(L, i); + return 1; + } + return luaL_error(L, "power '%s' could not be found.\n", word); + } + else if (fastncmp("HUD_",word,4)) { + p = word+4; + for (i = 0; i < NUMHUDITEMS; i++) + if (fastcmp(p, HUDITEMS_LIST[i])) { + lua_pushinteger(L, i); + return 1; + } + if (mathlib) return luaL_error(L, "huditem '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("SKINCOLOR_",word,10)) { + p = word+10; + for (i = 0; i < NUMCOLORFREESLOTS; i++) { + if (!FREE_SKINCOLORS[i]) + break; + if (fastcmp(p, FREE_SKINCOLORS[i])) { + lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT+i); + return 1; + } + } + for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++) + if (fastcmp(p, COLOR_ENUMS[i])) { + lua_pushinteger(L, i); + return 1; + } + return luaL_error(L, "skincolor '%s' could not be found.\n", word); + } + else if (fastncmp("GRADE_",word,6)) + { + p = word+6; + for (i = 0; NIGHTSGRADE_LIST[i]; i++) + if (*p == NIGHTSGRADE_LIST[i]) + { + lua_pushinteger(L, i); + return 1; + } + if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word); + return 0; + } + else if (fastncmp("MN_",word,3)) { + p = word+3; + for (i = 0; i < NUMMENUTYPES; i++) + if (fastcmp(p, MENUTYPES_LIST[i])) { + lua_pushinteger(L, i); + return 1; + } + if (mathlib) return luaL_error(L, "menutype '%s' could not be found.\n", word); + return 0; + } + else if (!mathlib && fastncmp("A_",word,2)) { + char *caps; + // Try to get a Lua action first. + /// \todo Push a closure that sets superactions[] and superstack. + lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS); + // actions are stored in all uppercase. + caps = Z_StrDup(word); + strupr(caps); + lua_getfield(L, -1, caps); + Z_Free(caps); + if (!lua_isnil(L, -1)) + return 1; // Success! :D That was easy. + // Welp, that failed. + lua_pop(L, 2); // pop nil and LREG_ACTIONS + + // Hardcoded actions as callable Lua functions! + // Retrieving them from this metatable allows them to be case-insensitive! + for (i = 0; actionpointers[i].name; i++) + if (fasticmp(word, actionpointers[i].name)) { + // We push the actionf_t* itself as userdata! + LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION); + return 1; + } + return 0; + } + else if (!mathlib && fastcmp("super",word)) + { + if (!superstack) + { + lua_pushcfunction(L, lib_dummysuper); + return 1; + } + for (i = 0; actionpointers[i].name; i++) + if (fasticmp(superactions[superstack-1], actionpointers[i].name)) { + LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION); + return 1; + } + return 0; + } + + if (fastcmp(word, "BT_USE")) // Remove case when 2.3 nears release... + { + lua_pushinteger(L, (lua_Integer)BT_SPIN); + return 1; + } + + for (i = 0; INT_CONST[i].n; i++) + if (fastcmp(word,INT_CONST[i].n)) { + lua_pushinteger(L, INT_CONST[i].v); + return 1; + } + + if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word); + + // DYNAMIC variables too!! + // Try not to add anything that would break netgames or timeattack replays here. + // You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime. + return LUA_PushGlobals(L, word); +} + +int LUA_EnumLib(lua_State *L) +{ + if (lua_gettop(L) == 0) + lua_pushboolean(L, 0); + + // Set the global metatable + lua_createtable(L, 0, 1); + lua_pushvalue(L, 1); // boolean passed to LUA_EnumLib as first argument. + lua_pushcclosure(L, lib_getenum, 1); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, LUA_GLOBALSINDEX); + return 0; +} + +// getActionName(action) -> return action's string name +static int lib_getActionName(lua_State *L) +{ + if (lua_isuserdata(L, 1)) // arg 1 is built-in action, expect action userdata + { + actionf_t *action = *((actionf_t **)luaL_checkudata(L, 1, META_ACTION)); + const char *name = NULL; + if (!action) + return luaL_error(L, "not a valid action?"); + name = LUA_GetActionName(action); + if (!name) // that can't be right? + return luaL_error(L, "no name string could be found for this action"); + lua_pushstring(L, name); + return 1; + } + else if (lua_isfunction(L, 1)) // arg 1 is a function (either C or Lua) + { + lua_settop(L, 1); // set top of stack to 1 (removing any extra args, which there shouldn't be) + // get the name for this action, if possible. + lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS); + lua_pushnil(L); + // Lua stack at this point: + // 1 ... -2 -1 + // arg ... LREG_ACTIONS nil + while (lua_next(L, -2)) + { + // Lua stack at this point: + // 1 ... -3 -2 -1 + // arg ... LREG_ACTIONS "A_ACTION" function + if (lua_rawequal(L, -1, 1)) // is this the same as the arg? + { + // make sure the key (i.e. "A_ACTION") is a string first + // (note: we don't use lua_isstring because it also returns true for numbers) + if (lua_type(L, -2) == LUA_TSTRING) + { + lua_pushvalue(L, -2); // push "A_ACTION" string to top of stack + return 1; + } + lua_pop(L, 2); // pop the name and function + break; // probably should have succeeded but we didn't, so end the loop + } + lua_pop(L, 1); + } + lua_pop(L, 1); // pop LREG_ACTIONS + return 0; // return nothing (don't error) + } + + return luaL_typerror(L, 1, "action userdata or Lua function"); +} + + + +int LUA_SOCLib(lua_State *L) +{ + lua_register(L,"freeslot",lib_freeslot); + lua_register(L,"getActionName",lib_getActionName); + + luaL_newmetatable(L, META_ACTION); + lua_pushcfunction(L, action_call); + lua_setfield(L, -2, "__call"); + lua_pop(L, 1); + + return 0; +} + +const char *LUA_GetActionName(void *action) +{ + actionf_t *act = (actionf_t *)action; + size_t z; + for (z = 0; actionpointers[z].name; z++) + { + if (actionpointers[z].action.acv == act->acv) + return actionpointers[z].name; + } + return NULL; +} + +void LUA_SetActionByName(void *state, const char *actiontocompare) +{ + state_t *st = (state_t *)state; + size_t z; + for (z = 0; actionpointers[z].name; z++) + { + if (fasticmp(actiontocompare, actionpointers[z].name)) + { + st->action = actionpointers[z].action; + st->action.acv = actionpointers[z].action.acv; // assign + st->action.acp1 = actionpointers[z].action.acp1; + return; + } + } +} + +enum actionnum LUA_GetActionNumByName(const char *actiontocompare) +{ + size_t z; + for (z = 0; actionpointers[z].name; z++) + if (fasticmp(actiontocompare, actionpointers[z].name)) + return z; + return z; +} diff --git a/src/deh_lua.h b/src/deh_lua.h new file mode 100644 index 0000000000000000000000000000000000000000..cd927b9fd51bb98f3d6674dd129d9df29726ae33 --- /dev/null +++ b/src/deh_lua.h @@ -0,0 +1,21 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file deh_lua.h +/// \brief Lua SOC library + +#ifndef __DEH_LUA_H__ +#define __DEH_LUA_H__ + +boolean LUA_SetLuaAction(void *state, const char *actiontocompare); +const char *LUA_GetActionName(void *action); +void LUA_SetActionByName(void *state, const char *actiontocompare); +enum actionnum LUA_GetActionNumByName(const char *actiontocompare); + +#endif diff --git a/src/deh_soc.c b/src/deh_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..5b12ea1b0b9b0339890b094516e0593e252d6556 --- /dev/null +++ b/src/deh_soc.c @@ -0,0 +1,4527 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file deh_soc.c +/// \brief Load SOC file and change tables and text + +#include "doomdef.h" +#include "d_main.h" // for srb2home +#include "g_game.h" +#include "sounds.h" +#include "info.h" +#include "d_think.h" +#include "m_argv.h" +#include "z_zone.h" +#include "w_wad.h" +#include "y_inter.h" +#include "m_menu.h" +#include "m_misc.h" +#include "f_finale.h" +#include "st_stuff.h" +#include "i_system.h" +#include "p_setup.h" +#include "r_data.h" +#include "r_textures.h" +#include "r_draw.h" +#include "r_picformats.h" +#include "r_things.h" // R_Char2Frame +#include "r_sky.h" +#include "fastcmp.h" +#include "lua_script.h" // Reluctantly included for LUA_EvalMath +#include "d_clisrv.h" + +#ifdef HWRENDER +#include "hardware/hw_light.h" +#endif + +#include "m_cond.h" + +#include "dehacked.h" +#include "deh_soc.h" +#include "deh_lua.h" // included due to some LUA_SetLuaAction hack smh +#include "deh_tables.h" + +// Loops through every constant and operation in word and performs its calculations, returning the final value. +fixed_t get_number(const char *word) +{ + return LUA_EvalMath(word); + + /*// DESPERATELY NEEDED: Order of operations support! :x + fixed_t i = find_const(&word); + INT32 o; + while(*word) { + o = operation_pad(&word); + if (o != -1) + i = OPERATIONS[o].v(i,find_const(&word)); + else + break; + } + return i;*/ +} + +#define PARAMCHECK(n) do { if (!params[n]) { deh_warning("Too few parameters, need %d", n); return; }} while (0) + +/* ======================================================================== */ +// Load a dehacked file format +/* ======================================================================== */ +/* a sample to see + Thing 1 (Player) { // MT_PLAYER +INT32 doomednum; ID # = 3232 -1, // doomednum +INT32 spawnstate; Initial frame = 32 "PLAY", // spawnstate +INT32 spawnhealth; Hit points = 3232 100, // spawnhealth +INT32 seestate; First moving frame = 32 "PLAY_RUN1", // seestate +INT32 seesound; Alert sound = 32 sfx_None, // seesound +INT32 reactiontime; Reaction time = 3232 0, // reactiontime +INT32 attacksound; Attack sound = 32 sfx_None, // attacksound +INT32 painstate; Injury frame = 32 "PLAY_PAIN", // painstate +INT32 painchance; Pain chance = 3232 255, // painchance +INT32 painsound; Pain sound = 32 sfx_plpain, // painsound +INT32 meleestate; Close attack frame = 32 "NULL", // meleestate +INT32 missilestate; Far attack frame = 32 "PLAY_ATK1", // missilestate +INT32 deathstate; Death frame = 32 "PLAY_DIE1", // deathstate +INT32 xdeathstate; Exploding frame = 32 "PLAY_XDIE1", // xdeathstate +INT32 deathsound; Death sound = 32 sfx_pldeth, // deathsound +INT32 speed; Speed = 3232 0, // speed +INT32 radius; Width = 211812352 16*FRACUNIT, // radius +INT32 height; Height = 211812352 56*FRACUNIT, // height +INT32 dispoffset; DispOffset = 0 0, // dispoffset +INT32 mass; Mass = 3232 100, // mass +INT32 damage; Missile damage = 3232 0, // damage +INT32 activesound; Action sound = 32 sfx_None, // activesound +INT32 flags; Bits = 3232 MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, +INT32 raisestate; Respawn frame = 32 S_NULL // raisestate + }, */ + +#ifdef HWRENDER +static INT32 searchvalue(const char *s) +{ + while (s[0] != '=' && s[0]) + s++; + if (s[0] == '=') + return atoi(&s[1]); + else + { + deh_warning("No value found"); + return 0; + } +} + +static float searchfvalue(const char *s) +{ + while (s[0] != '=' && s[0]) + s++; + if (s[0] == '=') + return (float)atof(&s[1]); + else + { + deh_warning("No value found"); + return 0; + } +} +#endif + +// These are for clearing all of various things +void clear_conditionsets(void) +{ + UINT8 i; + for (i = 0; i < MAXCONDITIONSETS; ++i) + M_ClearConditionSet(i+1); +} + +void clear_levels(void) +{ + INT16 i; + + // This is potentially dangerous but if we're resetting these headers, + // we may as well try to save some memory, right? + for (i = 0; i < NUMMAPS; ++i) + { + if (!mapheaderinfo[i] || i == (tutorialmap-1)) + continue; + + // Custom map header info + // (no need to set num to 0, we're freeing the entire header shortly) + Z_Free(mapheaderinfo[i]->customopts); + + P_DeleteFlickies(i); + P_DeleteGrades(i); + + Z_Free(mapheaderinfo[i]); + mapheaderinfo[i] = NULL; + } + + // Realloc the one for the current gamemap as a safeguard + P_AllocMapHeader(gamemap-1); +} + +static boolean findFreeSlot(INT32 *num) +{ + // Send the character select entry to a free slot. + while (*num < MAXSKINS && (description[*num].used)) + *num = *num+1; + + // No more free slots. :( + if (*num >= MAXSKINS) + return false; + + // Redesign your logo. (See M_DrawSetupChoosePlayerMenu in m_menu.c...) + description[*num].picname[0] = '\0'; + description[*num].nametag[0] = '\0'; + description[*num].displayname[0] = '\0'; + description[*num].oppositecolor = SKINCOLOR_NONE; + description[*num].tagtextcolor = SKINCOLOR_NONE; + description[*num].tagoutlinecolor = SKINCOLOR_NONE; + + // Found one! ^_^ + return (description[*num].used = true); +} + +// Reads a player. +// For modifying the character select screen +void readPlayer(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2; + char *displayname = ZZ_Alloc(MAXLINELEN+1); + INT32 i; + boolean slotfound = false; + + #define SLOTFOUND \ + if (!slotfound && (slotfound = findFreeSlot(&num)) == false) \ + goto done; + + displayname[MAXLINELEN] = '\0'; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + for (i = 0; i < MAXLINELEN-3; i++) + { + char *tmp; + if (s[i] == '=') + { + tmp = &s[i+2]; + strncpy(displayname, tmp, SKINNAMESIZE); + break; + } + } + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + if (fastcmp(word, "PLAYERTEXT")) + { + char *playertext = NULL; + + SLOTFOUND + + for (i = 0; i < MAXLINELEN-3; i++) + { + if (s[i] == '=') + { + playertext = &s[i+2]; + break; + } + } + if (playertext) + { + strcpy(description[num].notes, playertext); + strcat(description[num].notes, myhashfgets(playertext, sizeof (description[num].notes), f)); + } + else + strcpy(description[num].notes, ""); + + // For some reason, cutting the string did not work above. Most likely due to strcpy or strcat... + // It works down here, though. + { + INT32 numline = 0; + for (i = 0; (size_t)i < sizeof(description[num].notes)-1; i++) + { + if (numline < 20 && description[num].notes[i] == '\n') + numline++; + + if (numline >= 20 || description[num].notes[i] == '\0' || description[num].notes[i] == '#') + break; + } + } + description[num].notes[strlen(description[num].notes)-1] = '\0'; + description[num].notes[i] = '\0'; + continue; + } + + word2 = strtok(NULL, " = "); + if (word2) + strupr(word2); + else + break; + + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + i = atoi(word2); + + if (fastcmp(word, "PICNAME")) + { + SLOTFOUND + strncpy(description[num].picname, word2, 8); + } + // new character select + else if (fastcmp(word, "DISPLAYNAME")) + { + SLOTFOUND + // replace '#' with line breaks + // (also remove any '\n') + { + char *cur = NULL; + + // remove '\n' + cur = strchr(displayname, '\n'); + if (cur) + *cur = '\0'; + + // turn '#' into '\n' + cur = strchr(displayname, '#'); + while (cur) + { + *cur = '\n'; + cur = strchr(cur, '#'); + } + } + // copy final string + strncpy(description[num].displayname, displayname, SKINNAMESIZE); + } + else if (fastcmp(word, "OPPOSITECOLOR") || fastcmp(word, "OPPOSITECOLOUR")) + { + SLOTFOUND + description[num].oppositecolor = (UINT16)get_number(word2); + } + else if (fastcmp(word, "NAMETAG") || fastcmp(word, "TAGNAME")) + { + SLOTFOUND + strncpy(description[num].nametag, word2, 8); + } + else if (fastcmp(word, "TAGTEXTCOLOR") || fastcmp(word, "TAGTEXTCOLOUR")) + { + SLOTFOUND + description[num].tagtextcolor = (UINT16)get_number(word2); + } + else if (fastcmp(word, "TAGOUTLINECOLOR") || fastcmp(word, "TAGOUTLINECOLOUR")) + { + SLOTFOUND + description[num].tagoutlinecolor = (UINT16)get_number(word2); + } + else if (fastcmp(word, "STATUS")) + { + /* + You MAY disable previous entries if you so desire... + But try to enable something that's already enabled and you will be sent to a free slot. + + Because of this, you are allowed to edit any previous entries you like, but only if you + signal that you are purposely doing so by disabling and then reenabling the slot. + */ + if (i && !slotfound && (slotfound = findFreeSlot(&num)) == false) + goto done; + + description[num].used = (!!i); + } + else if (fastcmp(word, "SKINNAME")) + { + // Send to free slot. + SLOTFOUND + strlcpy(description[num].skinname, word2, sizeof description[num].skinname); + strlwr(description[num].skinname); + } + else + deh_warning("readPlayer %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + #undef SLOTFOUND +done: + Z_Free(displayname); + Z_Free(s); +} + +// TODO: Figure out how to do undolines for this.... +// TODO: Warnings for running out of freeslots +void readfreeslots(MYFILE *f) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word,*type; + char *tmp; + int i; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + type = strtok(s, "_"); + if (type) + strupr(type); + else + break; + + word = strtok(NULL, "\n"); + if (word) + strupr(word); + else + break; + + // TODO: Check for existing freeslot mobjs/states/etc. and make errors. + // TODO: Out-of-slots warnings/errors. + // TODO: Name too long (truncated) warnings. + if (fastcmp(type, "SFX")) + S_AddSoundFx(word, false, 0, false); + else if (fastcmp(type, "SPR")) + { + for (i = SPR_FIRSTFREESLOT; i <= SPR_LASTFREESLOT; i++) + { + if (used_spr[(i-SPR_FIRSTFREESLOT)/8] & (1<<(i%8))) + { + if (!sprnames[i][4] && memcmp(sprnames[i],word,4)==0) + sprnames[i][4] = (char)f->wad; + continue; // Already allocated, next. + } + // Found a free slot! + strncpy(sprnames[i],word,4); + //sprnames[i][4] = 0; + used_spr[(i-SPR_FIRSTFREESLOT)/8] |= 1<<(i%8); // Okay, this sprite slot has been named now. + break; + } + } + else if (fastcmp(type, "S")) + { + for (i = 0; i < NUMSTATEFREESLOTS; i++) + if (!FREE_STATES[i]) { + FREE_STATES[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); + strcpy(FREE_STATES[i],word); + break; + } + } + else if (fastcmp(type, "MT")) + { + for (i = 0; i < NUMMOBJFREESLOTS; i++) + if (!FREE_MOBJS[i]) { + FREE_MOBJS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); + strcpy(FREE_MOBJS[i],word); + break; + } + } + else if (fastcmp(type, "SKINCOLOR")) + { + for (i = 0; i < NUMCOLORFREESLOTS; i++) + if (!FREE_SKINCOLORS[i]) { + FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); + strcpy(FREE_SKINCOLORS[i],word); + M_AddMenuColor(numskincolors++); + break; + } + } + else if (fastcmp(type, "SPR2")) + { + // Search if we already have an SPR2 by that name... + for (i = SPR2_FIRSTFREESLOT; i < (int)free_spr2; i++) + if (memcmp(spr2names[i],word,4) == 0) + break; + // We found it? (Two mods using the same SPR2 name?) Then don't allocate another one. + if (i < (int)free_spr2) + continue; + // Copy in the spr2 name and increment free_spr2. + if (free_spr2 < NUMPLAYERSPRITES) { + strncpy(spr2names[free_spr2],word,4); + spr2defaults[free_spr2] = 0; + spr2names[free_spr2++][4] = 0; + } else + deh_warning("Ran out of free SPR2 slots!\n"); + } + else if (fastcmp(type, "TOL")) + { + // Search if we already have a typeoflevel by that name... + for (i = 0; TYPEOFLEVEL[i].name; i++) + if (fastcmp(word, TYPEOFLEVEL[i].name)) + break; + + // We found it? Then don't allocate another one. + if (TYPEOFLEVEL[i].name) + continue; + + // We don't, so freeslot it. + if (lastcustomtol == (UINT32)MAXTOL) // Unless you have way too many, since they're flags. + deh_warning("Ran out of free typeoflevel slots!\n"); + else + { + G_AddTOL(lastcustomtol, word); + lastcustomtol <<= 1; + } + } + else + deh_warning("Freeslots: unknown enum class '%s' for '%s_%s'", type, type, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +void readthing(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word, *word2; + char *tmp; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + word2 = strtok(NULL, " = "); + if (word2) + strupr(word2); + else + break; + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + + if (fastcmp(word, "MAPTHINGNUM") || fastcmp(word, "DOOMEDNUM")) + { + mobjinfo[num].doomednum = (INT32)atoi(word2); + } + else if (fastcmp(word, "SPAWNSTATE")) + { + mobjinfo[num].spawnstate = get_number(word2); + } + else if (fastcmp(word, "SPAWNHEALTH")) + { + mobjinfo[num].spawnhealth = (INT32)get_number(word2); + } + else if (fastcmp(word, "SEESTATE")) + { + mobjinfo[num].seestate = get_number(word2); + } + else if (fastcmp(word, "SEESOUND")) + { + mobjinfo[num].seesound = get_number(word2); + } + else if (fastcmp(word, "REACTIONTIME")) + { + mobjinfo[num].reactiontime = (INT32)get_number(word2); + } + else if (fastcmp(word, "ATTACKSOUND")) + { + mobjinfo[num].attacksound = get_number(word2); + } + else if (fastcmp(word, "PAINSTATE")) + { + mobjinfo[num].painstate = get_number(word2); + } + else if (fastcmp(word, "PAINCHANCE")) + { + mobjinfo[num].painchance = (INT32)get_number(word2); + } + else if (fastcmp(word, "PAINSOUND")) + { + mobjinfo[num].painsound = get_number(word2); + } + else if (fastcmp(word, "MELEESTATE")) + { + mobjinfo[num].meleestate = get_number(word2); + } + else if (fastcmp(word, "MISSILESTATE")) + { + mobjinfo[num].missilestate = get_number(word2); + } + else if (fastcmp(word, "DEATHSTATE")) + { + mobjinfo[num].deathstate = get_number(word2); + } + else if (fastcmp(word, "DEATHSOUND")) + { + mobjinfo[num].deathsound = get_number(word2); + } + else if (fastcmp(word, "XDEATHSTATE")) + { + mobjinfo[num].xdeathstate = get_number(word2); + } + else if (fastcmp(word, "SPEED")) + { + mobjinfo[num].speed = get_number(word2); + } + else if (fastcmp(word, "RADIUS")) + { + mobjinfo[num].radius = get_number(word2); + } + else if (fastcmp(word, "HEIGHT")) + { + mobjinfo[num].height = get_number(word2); + } + else if (fastcmp(word, "DISPOFFSET")) + { + mobjinfo[num].dispoffset = get_number(word2); + } + else if (fastcmp(word, "MASS")) + { + mobjinfo[num].mass = (INT32)get_number(word2); + } + else if (fastcmp(word, "DAMAGE")) + { + mobjinfo[num].damage = (INT32)get_number(word2); + } + else if (fastcmp(word, "ACTIVESOUND")) + { + mobjinfo[num].activesound = get_number(word2); + } + else if (fastcmp(word, "FLAGS")) + { + mobjinfo[num].flags = (INT32)get_number(word2); + } + else if (fastcmp(word, "RAISESTATE")) + { + mobjinfo[num].raisestate = get_number(word2); + } + else + deh_warning("Thing %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +void readskincolor(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + + Color_cons_t[num].value = num; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + + if (fastcmp(word, "NAME")) + { + size_t namesize = sizeof(skincolors[num].name); + char truncword[namesize]; + UINT16 dupecheck; + + deh_strlcpy(truncword, word2, namesize, va("Skincolor %d: name", num)); // truncate here to check for dupes + dupecheck = R_GetColorByName(truncword); + if (truncword[0] != '\0' && (!stricmp(truncword, skincolors[SKINCOLOR_NONE].name) || (dupecheck && dupecheck != num))) + { + size_t lastchar = strlen(truncword); + char oldword[lastchar+1]; + char dupenum = '1'; + + strlcpy(oldword, truncword, lastchar+1); + lastchar--; + if (lastchar == namesize-2) // exactly max length, replace last character with 0 + truncword[lastchar] = '0'; + else // append 0 + { + strcat(truncword, "0"); + lastchar++; + } + + while (R_GetColorByName(truncword)) + { + truncword[lastchar] = dupenum; + if (dupenum == '9') + dupenum = 'A'; + else if (dupenum == 'Z') // give up :? + break; + else + dupenum++; + } + + deh_warning("Skincolor %d: name %s is a duplicate of another skincolor's name - renamed to %s", num, oldword, truncword); + } + + strlcpy(skincolors[num].name, truncword, namesize); // already truncated + } + else if (fastcmp(word, "RAMP")) + { + UINT8 i; + tmp = strtok(word2,","); + for (i = 0; i < COLORRAMPSIZE; i++) { + skincolors[num].ramp[i] = (UINT8)get_number(tmp); + if ((tmp = strtok(NULL,",")) == NULL) + break; + } + skincolor_modified[num] = true; + } + else if (fastcmp(word, "INVCOLOR")) + { + UINT16 v = (UINT16)get_number(word2); + if (v < numskincolors) + skincolors[num].invcolor = v; + else + skincolors[num].invcolor = SKINCOLOR_GREEN; + } + else if (fastcmp(word, "INVSHADE")) + { + skincolors[num].invshade = get_number(word2)%COLORRAMPSIZE; + } + else if (fastcmp(word, "CHATCOLOR")) + { + skincolors[num].chatcolor = get_number(word2); + } + else if (fastcmp(word, "ACCESSIBLE")) + { + if (num > FIRSTSUPERCOLOR) + skincolors[num].accessible = (boolean)(atoi(word2) || word2[0] == 'T' || word2[0] == 'Y'); + } + else + deh_warning("Skincolor %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +#ifdef HWRENDER +void readlight(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *tmp; + INT32 value; + float fvalue; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + fvalue = searchfvalue(s); + value = searchvalue(s); + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + if (fastcmp(word, "TYPE")) + { + lspr[num].type = (UINT16)value; + } + else if (fastcmp(word, "OFFSETX")) + { + lspr[num].light_xoffset = fvalue; + } + else if (fastcmp(word, "OFFSETY")) + { + lspr[num].light_yoffset = fvalue; + } + else if (fastcmp(word, "CORONACOLOR")) + { + lspr[num].corona_color = value; + } + else if (fastcmp(word, "CORONARADIUS")) + { + lspr[num].corona_radius = fvalue; + } + else if (fastcmp(word, "DYNAMICCOLOR")) + { + lspr[num].dynamic_color = value; + } + else if (fastcmp(word, "DYNAMICRADIUS")) + { + lspr[num].dynamic_radius = fvalue; + + /// \note Update the sqrradius! unnecessary? + lspr[num].dynamic_sqrradius = fvalue * fvalue; + } + else + deh_warning("Light %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} +#endif // HWRENDER + +static void readspriteframe(MYFILE *f, spriteinfo_t *sprinfo, UINT8 frame) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word, *word2; + char *tmp; + INT32 value; + char *lastline; + + do + { + lastline = f->curpos; + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Set / reset word + word = s; + while ((*word == '\t') || (*word == ' ')) + word++; + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + { + *(tmp-1) = '\0'; + // Now get the part after + word2 = tmp += 2; + } + else + { + // Get the part before the " " + tmp = strchr(s, ' '); + if (tmp) + { + *tmp = '\0'; + // Now get the part after + tmp++; + word2 = tmp; + } + else + break; + } + strupr(word); + value = atoi(word2); // used for numerical settings + + if (fastcmp(word, "XPIVOT")) + sprinfo->pivot[frame].x = value; + else if (fastcmp(word, "YPIVOT")) + sprinfo->pivot[frame].y = value; + else if (fastcmp(word, "ROTAXIS")) + sprinfo->pivot[frame].rotaxis = value; + else + { + f->curpos = lastline; + break; + } + } + } while (!myfeof(f)); // finish when the line is empty + Z_Free(s); +} + +void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word, *word2; + char *tmp; +#ifdef HWRENDER + INT32 value; +#endif + char *lastline; + INT32 skinnumbers[MAXSKINS]; + INT32 foundskins = 0; + + // allocate a spriteinfo + spriteinfo_t *info = Z_Calloc(sizeof(spriteinfo_t), PU_STATIC, NULL); + info->available = true; + + do + { + lastline = f->curpos; + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Set / reset word + word = s; + while ((*word == '\t') || (*word == ' ')) + word++; + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + { + *(tmp-1) = '\0'; + // Now get the part after + word2 = tmp += 2; + } + else + { + // Get the part before the " " + tmp = strchr(s, ' '); + if (tmp) + { + *tmp = '\0'; + // Now get the part after + tmp++; + word2 = tmp; + } + else + break; + } + strupr(word); +#ifdef HWRENDER + value = atoi(word2); // used for numerical settings + + if (fastcmp(word, "LIGHTTYPE")) + { + if (sprite2) + deh_warning("Sprite2 %s: invalid word '%s'", spr2names[num], word); + else + { + INT32 oldvar; + for (oldvar = 0; t_lspr[num] != &lspr[oldvar]; oldvar++) + ; + t_lspr[num] = &lspr[value]; + } + } + else +#endif + if (fastcmp(word, "SKIN")) + { + INT32 skinnum = -1; + if (!sprite2) + { + deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", spr2names[num], word); + continue; + } + + // make lowercase + strlwr(word2); + skinnum = R_SkinAvailable(word2); + if (skinnum == -1) + { + deh_warning("Sprite2 %s: unknown skin %s", spr2names[num], word2); + break; + } + + skinnumbers[foundskins] = skinnum; + foundskins++; + } + else if (fastcmp(word, "DEFAULT")) + { + if (!sprite2) + { + deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", spr2names[num], word); + continue; + } + if (num < (INT32)free_spr2 && num >= (INT32)SPR2_FIRSTFREESLOT) + spr2defaults[num] = get_number(word2); + else + { + deh_warning("Sprite2 %s: out of range (%d - %d), ignoring", spr2names[num], SPR2_FIRSTFREESLOT, free_spr2-1); + continue; + } + } + else if (fastcmp(word, "FRAME")) + { + UINT8 frame = R_Char2Frame(word2[0]); + // frame number too high + if (frame >= 64) + { + if (sprite2) + deh_warning("Sprite2 %s: invalid frame %s", spr2names[num], word2); + else + deh_warning("Sprite %s: invalid frame %s", sprnames[num], word2); + break; + } + + // read sprite frame and store it in the spriteinfo_t struct + readspriteframe(f, info, frame); + if (sprite2) + { + INT32 i; + if (!foundskins) + { + deh_warning("Sprite2 %s: no skins specified", spr2names[num]); + break; + } + for (i = 0; i < foundskins; i++) + { + size_t skinnum = skinnumbers[i]; + skin_t *skin = &skins[skinnum]; + spriteinfo_t *sprinfo = skin->sprinfo; + M_Memcpy(&sprinfo[num], info, sizeof(spriteinfo_t)); + } + } + else + M_Memcpy(&spriteinfo[num], info, sizeof(spriteinfo_t)); + } + else + { + //deh_warning("Sprite %s: unknown word '%s'", sprnames[num], word); + f->curpos = lastline; + break; + } + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); + Z_Free(info); +} + +void readsprite2(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word, *word2; + char *tmp; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + word2 = strtok(NULL, " = "); + if (word2) + strupr(word2); + else + break; + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + + if (fastcmp(word, "DEFAULT")) + spr2defaults[num] = get_number(word2); + else + deh_warning("Sprite2 %s: unknown word '%s'", spr2names[num], word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +// copypasted from readPlayer :] +void readgametype(MYFILE *f, char *gtname) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2, *word2lwr = NULL; + char *tmp; + INT32 i, j; + + INT16 newgtidx = 0; + UINT32 newgtrules = 0; + UINT32 newgttol = 0; + INT32 newgtpointlimit = 0; + INT32 newgttimelimit = 0; + UINT8 newgtleftcolor = 0; + UINT8 newgtrightcolor = 0; + INT16 newgtrankingstype = -1; + int newgtinttype = 0; + char gtdescription[441]; + char gtconst[MAXLINELEN]; + + // Empty strings. + gtdescription[0] = '\0'; + gtconst[0] = '\0'; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + if (fastcmp(word, "DESCRIPTION")) + { + char *descr = NULL; + + for (i = 0; i < MAXLINELEN-3; i++) + { + if (s[i] == '=') + { + descr = &s[i+2]; + break; + } + } + if (descr) + { + strcpy(gtdescription, descr); + strcat(gtdescription, myhashfgets(descr, sizeof (gtdescription), f)); + } + else + strcpy(gtdescription, ""); + + // For some reason, cutting the string did not work above. Most likely due to strcpy or strcat... + // It works down here, though. + { + INT32 numline = 0; + for (i = 0; (size_t)i < sizeof(gtdescription)-1; i++) + { + if (numline < 20 && gtdescription[i] == '\n') + numline++; + + if (numline >= 20 || gtdescription[i] == '\0' || gtdescription[i] == '#') + break; + } + } + gtdescription[strlen(gtdescription)-1] = '\0'; + gtdescription[i] = '\0'; + continue; + } + + word2 = strtok(NULL, " = "); + if (word2) + { + if (!word2lwr) + word2lwr = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + strcpy(word2lwr, word2); + strupr(word2); + } + else + break; + + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + i = atoi(word2); + + // Game type rules + if (fastcmp(word, "RULES")) + { + // GTR_ + newgtrules = (UINT32)get_number(word2); + } + // Identifier + else if (fastcmp(word, "IDENTIFIER")) + { + // GT_ + strncpy(gtconst, word2, MAXLINELEN); + } + // Point and time limits + else if (fastcmp(word, "DEFAULTPOINTLIMIT")) + newgtpointlimit = (INT32)i; + else if (fastcmp(word, "DEFAULTTIMELIMIT")) + newgttimelimit = (INT32)i; + // Level platter + else if (fastcmp(word, "HEADERCOLOR") || fastcmp(word, "HEADERCOLOUR")) + newgtleftcolor = newgtrightcolor = (UINT8)get_number(word2); + else if (fastcmp(word, "HEADERLEFTCOLOR") || fastcmp(word, "HEADERLEFTCOLOUR")) + newgtleftcolor = (UINT8)get_number(word2); + else if (fastcmp(word, "HEADERRIGHTCOLOR") || fastcmp(word, "HEADERRIGHTCOLOUR")) + newgtrightcolor = (UINT8)get_number(word2); + // Rankings type + else if (fastcmp(word, "RANKINGTYPE")) + { + // Case insensitive + newgtrankingstype = (int)get_number(word2); + } + // Intermission type + else if (fastcmp(word, "INTERMISSIONTYPE")) + { + // Case sensitive + newgtinttype = (int)get_number(word2lwr); + } + // Type of level + else if (fastcmp(word, "TYPEOFLEVEL")) + { + if (i) // it's just a number + newgttol = (UINT32)i; + else + { + UINT32 tol = 0; + tmp = strtok(word2,","); + do { + for (i = 0; TYPEOFLEVEL[i].name; i++) + if (fasticmp(tmp, TYPEOFLEVEL[i].name)) + break; + if (!TYPEOFLEVEL[i].name) + deh_warning("readgametype %s: unknown typeoflevel flag %s\n", gtname, tmp); + tol |= TYPEOFLEVEL[i].flag; + } while((tmp = strtok(NULL,",")) != NULL); + newgttol = tol; + } + } + // The SOC probably provided gametype rules as words, + // instead of using the RULES keyword. + // Like for example "NOSPECTATORSPAWN = TRUE". + // This is completely valid, and looks better anyway. + else + { + UINT32 wordgt = 0; + for (j = 0; GAMETYPERULE_LIST[j]; j++) + if (fastcmp(word, GAMETYPERULE_LIST[j])) { + wordgt |= (1<<j); + if (i || word2[0] == 'T' || word2[0] == 'Y') + newgtrules |= wordgt; + break; + } + if (!wordgt) + deh_warning("readgametype %s: unknown word '%s'", gtname, word); + } + } + } while (!myfeof(f)); // finish when the line is empty + + // Free strings. + Z_Free(s); + if (word2lwr) + Z_Free(word2lwr); + + // Ran out of gametype slots + if (gametypecount == NUMGAMETYPEFREESLOTS) + { + CONS_Alert(CONS_WARNING, "Ran out of free gametype slots!\n"); + return; + } + + // Add the new gametype + newgtidx = G_AddGametype(newgtrules); + G_AddGametypeTOL(newgtidx, newgttol); + G_SetGametypeDescription(newgtidx, gtdescription, newgtleftcolor, newgtrightcolor); + + // Not covered by G_AddGametype alone. + if (newgtrankingstype == -1) + newgtrankingstype = newgtidx; + gametyperankings[newgtidx] = newgtrankingstype; + intermissiontypes[newgtidx] = newgtinttype; + pointlimits[newgtidx] = newgtpointlimit; + timelimits[newgtidx] = newgttimelimit; + + // Write the new gametype name. + Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname); + + // Write the constant name. + if (gtconst[0] == '\0') + strncpy(gtconst, gtname, MAXLINELEN); + G_AddGametypeConstant(newgtidx, (const char *)gtconst); + + // Update gametype_cons_t accordingly. + G_UpdateGametypeSelections(); + + CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]); +} + +void readlevelheader(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2; + //char *word3; // Non-uppercase version of word2 + char *tmp; + INT32 i; + + // Reset all previous map header information + P_AllocMapHeader((INT16)(num-1)); + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Set / reset word, because some things (Lua.) move it + word = s; + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + i = atoi(word2); // used for numerical settings + + + if (fastcmp(word, "LEVELNAME")) + { + deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2, + sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num)); + strlcpy(mapheaderinfo[num-1]->selectheading, word2, sizeof(mapheaderinfo[num-1]->selectheading)); // not deh_ so only complains once + continue; + } + // CHEAP HACK: move this over here for lowercase subtitles + if (fastcmp(word, "SUBTITLE")) + { + deh_strlcpy(mapheaderinfo[num-1]->subttl, word2, + sizeof(mapheaderinfo[num-1]->subttl), va("Level header %d: subtitle", num)); + continue; + } + + // Lua custom options also go above, contents may be case sensitive. + if (fastncmp(word, "LUA.", 4)) + { + UINT8 j; + customoption_t *modoption; + + // Note: we actualy strlwr word here, so things are made a little easier for Lua + strlwr(word); + word += 4; // move past "lua." + + // ... and do a simple name sanity check; the name must start with a letter + if (*word < 'a' || *word > 'z') + { + deh_warning("Level header %d: invalid custom option name \"%s\"", num, word); + continue; + } + + // Sanity limit of 128 params + if (mapheaderinfo[num-1]->numCustomOptions == 128) + { + deh_warning("Level header %d: too many custom parameters", num); + continue; + } + j = mapheaderinfo[num-1]->numCustomOptions++; + + mapheaderinfo[num-1]->customopts = + Z_Realloc(mapheaderinfo[num-1]->customopts, + sizeof(customoption_t) * mapheaderinfo[num-1]->numCustomOptions, PU_STATIC, NULL); + + // Newly allocated + modoption = &mapheaderinfo[num-1]->customopts[j]; + + strncpy(modoption->option, word, 31); + modoption->option[31] = '\0'; + strncpy(modoption->value, word2, 255); + modoption->value[255] = '\0'; + continue; + } + + // Now go to uppercase + strupr(word2); + + // List of flickies that are be freed in this map + if (fastcmp(word, "FLICKYLIST") || fastcmp(word, "ANIMALLIST")) + { + if (fastcmp(word2, "NONE")) + P_DeleteFlickies(num-1); + else if (fastcmp(word2, "DEMO")) + P_SetDemoFlickies(num-1); + else if (fastcmp(word2, "ALL")) + { + mobjtype_t tmpflickies[MAXFLICKIES]; + + for (mapheaderinfo[num-1]->numFlickies = 0; + ((mapheaderinfo[num-1]->numFlickies < MAXFLICKIES) && FLICKYTYPES[mapheaderinfo[num-1]->numFlickies].type); + mapheaderinfo[num-1]->numFlickies++) + tmpflickies[mapheaderinfo[num-1]->numFlickies] = FLICKYTYPES[mapheaderinfo[num-1]->numFlickies].type; + + if (mapheaderinfo[num-1]->numFlickies) // just in case... + { + size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num-1]->numFlickies; + mapheaderinfo[num-1]->flickies = Z_Realloc(mapheaderinfo[num-1]->flickies, newsize, PU_STATIC, NULL); + M_Memcpy(mapheaderinfo[num-1]->flickies, tmpflickies, newsize); + } + } + else + { + mobjtype_t tmpflickies[MAXFLICKIES]; + mapheaderinfo[num-1]->numFlickies = 0; + tmp = strtok(word2,","); + // get up to the first MAXFLICKIES flickies + do { + if (mapheaderinfo[num-1]->numFlickies == MAXFLICKIES) // never going to get above that number + { + deh_warning("Level header %d: too many flickies\n", num); + break; + } + + if (fastncmp(tmp, "MT_", 3)) // support for specified mobjtypes... + { + i = get_mobjtype(tmp); + if (!i) + { + //deh_warning("Level header %d: unknown flicky mobj type %s\n", num, tmp); -- no need for this line as get_mobjtype complains too + continue; + } + tmpflickies[mapheaderinfo[num-1]->numFlickies] = i; + } + else // ...or a quick, limited selection of default flickies! + { + for (i = 0; FLICKYTYPES[i].name; i++) + if (fastcmp(tmp, FLICKYTYPES[i].name)) + break; + + if (!FLICKYTYPES[i].name) + { + deh_warning("Level header %d: unknown flicky selection %s\n", num, tmp); + continue; + } + tmpflickies[mapheaderinfo[num-1]->numFlickies] = FLICKYTYPES[i].type; + } + mapheaderinfo[num-1]->numFlickies++; + } while ((tmp = strtok(NULL,",")) != NULL); + + if (mapheaderinfo[num-1]->numFlickies) + { + size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num-1]->numFlickies; + mapheaderinfo[num-1]->flickies = Z_Realloc(mapheaderinfo[num-1]->flickies, newsize, PU_STATIC, NULL); + // now we add them to the list! + M_Memcpy(mapheaderinfo[num-1]->flickies, tmpflickies, newsize); + } + else + deh_warning("Level header %d: no valid flicky types found\n", num); + } + } + + // NiGHTS grades + else if (fastncmp(word, "GRADES", 6)) + { + UINT8 mare = (UINT8)atoi(word + 6); + + if (mare <= 0 || mare > 8) + { + deh_warning("Level header %d: unknown word '%s'", num, word); + continue; + } + + P_AddGradesForMare((INT16)(num-1), mare-1, word2); + } + + // Strings that can be truncated + else if (fastcmp(word, "SELECTHEADING")) + { + deh_strlcpy(mapheaderinfo[num-1]->selectheading, word2, + sizeof(mapheaderinfo[num-1]->selectheading), va("Level header %d: selectheading", num)); + } + else if (fastcmp(word, "SCRIPTNAME")) + { + deh_strlcpy(mapheaderinfo[num-1]->scriptname, word2, + sizeof(mapheaderinfo[num-1]->scriptname), va("Level header %d: scriptname", num)); + } + else if (fastcmp(word, "RUNSOC")) + { + deh_strlcpy(mapheaderinfo[num-1]->runsoc, word2, + sizeof(mapheaderinfo[num-1]->runsoc), va("Level header %d: runsoc", num)); + } + else if (fastcmp(word, "ACT")) + { + if (i >= 0 && i <= 99) // 0 for no act number + mapheaderinfo[num-1]->actnum = (UINT8)i; + else + deh_warning("Level header %d: invalid act number %d", num, i); + } + else if (fastcmp(word, "NEXTLEVEL")) + { + if (fastcmp(word2, "TITLE")) i = 1100; + else if (fastcmp(word2, "EVALUATION")) i = 1101; + else if (fastcmp(word2, "CREDITS")) i = 1102; + else if (fastcmp(word2, "ENDING")) i = 1103; + else + // Support using the actual map name, + // i.e., Nextlevel = AB, Nextlevel = FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') + i = M_MapNumber(word2[0], word2[1]); + + mapheaderinfo[num-1]->nextlevel = (INT16)i; + } + else if (fastcmp(word, "MARATHONNEXT")) + { + if (fastcmp(word2, "TITLE")) i = 1100; + else if (fastcmp(word2, "EVALUATION")) i = 1101; + else if (fastcmp(word2, "CREDITS")) i = 1102; + else if (fastcmp(word2, "ENDING")) i = 1103; + else + // Support using the actual map name, + // i.e., MarathonNext = AB, MarathonNext = FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') + i = M_MapNumber(word2[0], word2[1]); + + mapheaderinfo[num-1]->marathonnext = (INT16)i; + } + else if (fastcmp(word, "TYPEOFLEVEL")) + { + if (i) // it's just a number + mapheaderinfo[num-1]->typeoflevel = (UINT32)i; + else + { + UINT32 tol = 0; + tmp = strtok(word2,","); + do { + for (i = 0; TYPEOFLEVEL[i].name; i++) + if (fastcmp(tmp, TYPEOFLEVEL[i].name)) + break; + if (!TYPEOFLEVEL[i].name) + deh_warning("Level header %d: unknown typeoflevel flag %s\n", num, tmp); + tol |= TYPEOFLEVEL[i].flag; + } while((tmp = strtok(NULL,",")) != NULL); + mapheaderinfo[num-1]->typeoflevel = tol; + } + } + else if (fastcmp(word, "KEYWORDS")) + { + deh_strlcpy(mapheaderinfo[num-1]->keywords, word2, + sizeof(mapheaderinfo[num-1]->keywords), va("Level header %d: keywords", num)); + } + else if (fastcmp(word, "MUSIC")) + { + if (fastcmp(word2, "NONE")) + mapheaderinfo[num-1]->musname[0] = 0; // becomes empty string + else + { + deh_strlcpy(mapheaderinfo[num-1]->musname, word2, + sizeof(mapheaderinfo[num-1]->musname), va("Level header %d: music", num)); + } + } +#ifdef MUSICSLOT_COMPATIBILITY + else if (fastcmp(word, "MUSICSLOT")) + { + i = get_mus(word2, true); + if (i && i <= 1035) + snprintf(mapheaderinfo[num-1]->musname, 7, "%sM", G_BuildMapName(i)); + else if (i && i <= 1050) + strncpy(mapheaderinfo[num-1]->musname, compat_special_music_slots[i - 1036], 7); + else + mapheaderinfo[num-1]->musname[0] = 0; // becomes empty string + mapheaderinfo[num-1]->musname[6] = 0; + } +#endif + else if (fastcmp(word, "MUSICTRACK")) + mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1); + else if (fastcmp(word, "MUSICPOS")) + mapheaderinfo[num-1]->muspos = (UINT32)get_number(word2); + else if (fastcmp(word, "MUSICINTERFADEOUT")) + mapheaderinfo[num-1]->musinterfadeout = (UINT32)get_number(word2); + else if (fastcmp(word, "MUSICINTER")) + deh_strlcpy(mapheaderinfo[num-1]->musintername, word2, + sizeof(mapheaderinfo[num-1]->musintername), va("Level header %d: intermission music", num)); + else if (fastcmp(word, "MUSICPOSTBOSS")) + deh_strlcpy(mapheaderinfo[num-1]->muspostbossname, word2, + sizeof(mapheaderinfo[num-1]->muspostbossname), va("Level header %d: post-boss music", num)); + else if (fastcmp(word, "MUSICPOSTBOSSTRACK")) + mapheaderinfo[num-1]->muspostbosstrack = ((UINT16)i - 1); + else if (fastcmp(word, "MUSICPOSTBOSSPOS")) + mapheaderinfo[num-1]->muspostbosspos = (UINT32)get_number(word2); + else if (fastcmp(word, "MUSICPOSTBOSSFADEIN")) + mapheaderinfo[num-1]->muspostbossfadein = (UINT32)get_number(word2); + else if (fastcmp(word, "FORCERESETMUSIC")) + { + // This is a weird one because "FALSE"/"NO" could either apply to "leave to default preference" (cv_resetmusic) + // or "force off". Let's assume it means "force off", and let an unspecified value mean "default preference" + if (fastcmp(word2, "OFF") || word2[0] == 'F' || word2[0] == 'N') i = 0; + else if (fastcmp(word2, "ON") || word2[0] == 'T' || word2[0] == 'Y') i = 1; + else i = -1; // (fastcmp(word2, "DEFAULT")) + + if (i >= -1 && i <= 1) // -1 to force off, 1 to force on, 0 to honor default. + // This behavior can be disabled with cv_resetmusicbyheader + mapheaderinfo[num-1]->musforcereset = (SINT8)i; + else + deh_warning("Level header %d: invalid forceresetmusic option %d", num, i); + } + else if (fastcmp(word, "FORCECHARACTER")) + { + strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1); + strlwr(mapheaderinfo[num-1]->forcecharacter); // skin names are lowercase + } + else if (fastcmp(word, "WEATHER")) + mapheaderinfo[num-1]->weather = (UINT8)get_number(word2); + else if (fastcmp(word, "SKYNUM")) + mapheaderinfo[num-1]->skynum = (INT16)i; + else if (fastcmp(word, "INTERSCREEN")) + strncpy(mapheaderinfo[num-1]->interscreen, word2, 8); + else if (fastcmp(word, "PRECUTSCENENUM")) + mapheaderinfo[num-1]->precutscenenum = (UINT8)i; + else if (fastcmp(word, "CUTSCENENUM")) + mapheaderinfo[num-1]->cutscenenum = (UINT8)i; + else if (fastcmp(word, "COUNTDOWN")) + mapheaderinfo[num-1]->countdown = (INT16)i; + else if (fastcmp(word, "PALETTE")) + mapheaderinfo[num-1]->palette = (UINT16)i; + else if (fastcmp(word, "NUMLAPS")) + mapheaderinfo[num-1]->numlaps = (UINT8)i; + else if (fastcmp(word, "UNLOCKABLE")) + { + if (i >= 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something + mapheaderinfo[num-1]->unlockrequired = (SINT8)i - 1; + else + deh_warning("Level header %d: invalid unlockable number %d", num, i); + } + else if (fastcmp(word, "LEVELSELECT")) + mapheaderinfo[num-1]->levelselect = (UINT8)i; + else if (fastcmp(word, "SKYBOXSCALE")) + mapheaderinfo[num-1]->skybox_scalex = mapheaderinfo[num-1]->skybox_scaley = mapheaderinfo[num-1]->skybox_scalez = (INT16)i; + else if (fastcmp(word, "SKYBOXSCALEX")) + mapheaderinfo[num-1]->skybox_scalex = (INT16)i; + else if (fastcmp(word, "SKYBOXSCALEY")) + mapheaderinfo[num-1]->skybox_scaley = (INT16)i; + else if (fastcmp(word, "SKYBOXSCALEZ")) + mapheaderinfo[num-1]->skybox_scalez = (INT16)i; + + else if (fastcmp(word, "BONUSTYPE")) + { + if (fastcmp(word2, "NONE")) i = -1; + else if (fastcmp(word2, "NORMAL")) i = 0; + else if (fastcmp(word2, "BOSS")) i = 1; + else if (fastcmp(word2, "ERZ3")) i = 2; + else if (fastcmp(word2, "NIGHTS")) i = 3; + else if (fastcmp(word2, "NIGHTSLINK")) i = 4; + + if (i >= -1 && i <= 4) // -1 for no bonus. Max is 4. + mapheaderinfo[num-1]->bonustype = (SINT8)i; + else + deh_warning("Level header %d: invalid bonus type number %d", num, i); + } + + // Title card + else if (fastcmp(word, "TITLECARDZIGZAG")) + { + deh_strlcpy(mapheaderinfo[num-1]->ltzzpatch, word2, + sizeof(mapheaderinfo[num-1]->ltzzpatch), va("Level header %d: title card zigzag patch name", num)); + } + else if (fastcmp(word, "TITLECARDZIGZAGTEXT")) + { + deh_strlcpy(mapheaderinfo[num-1]->ltzztext, word2, + sizeof(mapheaderinfo[num-1]->ltzztext), va("Level header %d: title card zigzag text patch name", num)); + } + else if (fastcmp(word, "TITLECARDACTDIAMOND")) + { + deh_strlcpy(mapheaderinfo[num-1]->ltactdiamond, word2, + sizeof(mapheaderinfo[num-1]->ltactdiamond), va("Level header %d: title card act diamond patch name", num)); + } + + else if (fastcmp(word, "MAXBONUSLIVES")) + mapheaderinfo[num-1]->maxbonuslives = (SINT8)i; + else if (fastcmp(word, "LEVELFLAGS")) + mapheaderinfo[num-1]->levelflags = (UINT16)i; + else if (fastcmp(word, "MENUFLAGS")) + mapheaderinfo[num-1]->menuflags = (UINT8)i; + + // Individual triggers for level flags, for ease of use (and 2.0 compatibility) + else if (fastcmp(word, "SCRIPTISFILE")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->levelflags |= LF_SCRIPTISFILE; + else + mapheaderinfo[num-1]->levelflags &= ~LF_SCRIPTISFILE; + } + else if (fastcmp(word, "SPEEDMUSIC")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->levelflags |= LF_SPEEDMUSIC; + else + mapheaderinfo[num-1]->levelflags &= ~LF_SPEEDMUSIC; + } + else if (fastcmp(word, "NOSSMUSIC")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->levelflags |= LF_NOSSMUSIC; + else + mapheaderinfo[num-1]->levelflags &= ~LF_NOSSMUSIC; + } + else if (fastcmp(word, "NORELOAD")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->levelflags |= LF_NORELOAD; + else + mapheaderinfo[num-1]->levelflags &= ~LF_NORELOAD; + } + else if (fastcmp(word, "NOZONE")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->levelflags |= LF_NOZONE; + else + mapheaderinfo[num-1]->levelflags &= ~LF_NOZONE; + } + else if (fastcmp(word, "SAVEGAME")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->levelflags |= LF_SAVEGAME; + else + mapheaderinfo[num-1]->levelflags &= ~LF_SAVEGAME; + } + else if (fastcmp(word, "MIXNIGHTSCOUNTDOWN")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->levelflags |= LF_MIXNIGHTSCOUNTDOWN; + else + mapheaderinfo[num-1]->levelflags &= ~LF_MIXNIGHTSCOUNTDOWN; + } + else if (fastcmp(word, "WARNINGTITLE")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->levelflags |= LF_WARNINGTITLE; + else + mapheaderinfo[num-1]->levelflags &= ~LF_WARNINGTITLE; + } + else if (fastcmp(word, "NOTITLECARD")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->levelflags |= LF_NOTITLECARD; + else + mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARD; + } + else if (fastcmp(word, "SHOWTITLECARDFOR")) + { + mapheaderinfo[num-1]->levelflags |= LF_NOTITLECARD; + tmp = strtok(word2,","); + do { + if (fastcmp(tmp, "FIRST")) + mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARDFIRST; + else if (fastcmp(tmp, "RESPAWN")) + mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARDRESPAWN; + else if (fastcmp(tmp, "RECORDATTACK")) + mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARDRECORDATTACK; + else if (fastcmp(tmp, "ALL")) + mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARD; + else if (!fastcmp(tmp, "NONE")) + deh_warning("Level header %d: unknown titlecard show option %s\n", num, tmp); + + } while((tmp = strtok(NULL,",")) != NULL); + } + + // Individual triggers for menu flags + else if (fastcmp(word, "HIDDEN")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->menuflags |= LF2_HIDEINMENU; + else + mapheaderinfo[num-1]->menuflags &= ~LF2_HIDEINMENU; + } + else if (fastcmp(word, "HIDEINSTATS")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->menuflags |= LF2_HIDEINSTATS; + else + mapheaderinfo[num-1]->menuflags &= ~LF2_HIDEINSTATS; + } + else if (fastcmp(word, "RECORDATTACK") || fastcmp(word, "TIMEATTACK")) + { // TIMEATTACK is an accepted alias + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->menuflags |= LF2_RECORDATTACK; + else + mapheaderinfo[num-1]->menuflags &= ~LF2_RECORDATTACK; + } + else if (fastcmp(word, "NIGHTSATTACK")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->menuflags |= LF2_NIGHTSATTACK; + else + mapheaderinfo[num-1]->menuflags &= LF2_NIGHTSATTACK; + } + else if (fastcmp(word, "NOVISITNEEDED")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->menuflags |= LF2_NOVISITNEEDED; + else + mapheaderinfo[num-1]->menuflags &= ~LF2_NOVISITNEEDED; + } + else if (fastcmp(word, "WIDEICON")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->menuflags |= LF2_WIDEICON; + else + mapheaderinfo[num-1]->menuflags &= ~LF2_WIDEICON; + } + else if (fastcmp(word, "STARTRINGS")) + mapheaderinfo[num-1]->startrings = (UINT16)i; + else if (fastcmp(word, "SPECIALSTAGETIME")) + mapheaderinfo[num-1]->sstimer = i; + else if (fastcmp(word, "SPECIALSTAGESPHERES")) + mapheaderinfo[num-1]->ssspheres = i; + else if (fastcmp(word, "GRAVITY")) + mapheaderinfo[num-1]->gravity = FLOAT_TO_FIXED(atof(word2)); + else + deh_warning("Level header %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) +{ + char *s = Z_Calloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2; + INT32 i; + UINT16 usi; + UINT8 picid; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + if (fastcmp(word, "SCENETEXT")) + { + char *scenetext = NULL; + char *buffer; + const int bufferlen = 4096; + + for (i = 0; i < MAXLINELEN; i++) + { + if (s[i] == '=') + { + scenetext = &s[i+2]; + break; + } + } + + if (!scenetext) + { + Z_Free(cutscenes[num]->scene[scenenum].text); + cutscenes[num]->scene[scenenum].text = NULL; + continue; + } + + for (i = 0; i < MAXLINELEN; i++) + { + if (s[i] == '\0') + { + s[i] = '\n'; + s[i+1] = '\0'; + break; + } + } + + buffer = Z_Malloc(4096, PU_STATIC, NULL); + strcpy(buffer, scenetext); + + strcat(buffer, + myhashfgets(scenetext, bufferlen + - strlen(buffer) - 1, f)); + + // A cutscene overwriting another one... + Z_Free(cutscenes[num]->scene[scenenum].text); + + cutscenes[num]->scene[scenenum].text = Z_StrDup(buffer); + + Z_Free(buffer); + + continue; + } + + word2 = strtok(NULL, " = "); + if (word2) + strupr(word2); + else + break; + + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + i = atoi(word2); + usi = (UINT16)i; + + + if (fastcmp(word, "NUMBEROFPICS")) + { + cutscenes[num]->scene[scenenum].numpics = (UINT8)i; + } + else if (fastncmp(word, "PIC", 3)) + { + picid = (UINT8)atoi(word + 3); + if (picid > 8 || picid == 0) + { + deh_warning("CutSceneScene %d: unknown word '%s'", num, word); + continue; + } + --picid; + + if (fastcmp(word+4, "NAME")) + { + strncpy(cutscenes[num]->scene[scenenum].picname[picid], word2, 8); + } + else if (fastcmp(word+4, "HIRES")) + { + cutscenes[num]->scene[scenenum].pichires[picid] = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); + } + else if (fastcmp(word+4, "DURATION")) + { + cutscenes[num]->scene[scenenum].picduration[picid] = usi; + } + else if (fastcmp(word+4, "XCOORD")) + { + cutscenes[num]->scene[scenenum].xcoord[picid] = usi; + } + else if (fastcmp(word+4, "YCOORD")) + { + cutscenes[num]->scene[scenenum].ycoord[picid] = usi; + } + else + deh_warning("CutSceneScene %d: unknown word '%s'", num, word); + } + else if (fastcmp(word, "MUSIC")) + { + strncpy(cutscenes[num]->scene[scenenum].musswitch, word2, 7); + cutscenes[num]->scene[scenenum].musswitch[6] = 0; + } +#ifdef MUSICSLOT_COMPATIBILITY + else if (fastcmp(word, "MUSICSLOT")) + { + i = get_mus(word2, true); + if (i && i <= 1035) + snprintf(cutscenes[num]->scene[scenenum].musswitch, 7, "%sM", G_BuildMapName(i)); + else if (i && i <= 1050) + strncpy(cutscenes[num]->scene[scenenum].musswitch, compat_special_music_slots[i - 1036], 7); + else + cutscenes[num]->scene[scenenum].musswitch[0] = 0; // becomes empty string + cutscenes[num]->scene[scenenum].musswitch[6] = 0; + } +#endif + else if (fastcmp(word, "MUSICTRACK")) + { + cutscenes[num]->scene[scenenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; + } + else if (fastcmp(word, "MUSICPOS")) + { + cutscenes[num]->scene[scenenum].musswitchposition = (UINT32)get_number(word2); + } + else if (fastcmp(word, "MUSICLOOP")) + { + cutscenes[num]->scene[scenenum].musicloop = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); + } + else if (fastcmp(word, "TEXTXPOS")) + { + cutscenes[num]->scene[scenenum].textxpos = usi; + } + else if (fastcmp(word, "TEXTYPOS")) + { + cutscenes[num]->scene[scenenum].textypos = usi; + } + else if (fastcmp(word, "FADEINID")) + { + cutscenes[num]->scene[scenenum].fadeinid = (UINT8)i; + } + else if (fastcmp(word, "FADEOUTID")) + { + cutscenes[num]->scene[scenenum].fadeoutid = (UINT8)i; + } + else if (fastcmp(word, "FADECOLOR")) + { + cutscenes[num]->scene[scenenum].fadecolor = (UINT8)i; + } + else + deh_warning("CutSceneScene %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +void readcutscene(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2; + char *tmp; + INT32 value; + + // Allocate memory for this cutscene if we don't yet have any + if (!cutscenes[num]) + cutscenes[num] = Z_Calloc(sizeof (cutscene_t), PU_STATIC, NULL); + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + word2 = strtok(NULL, " "); + if (word2) + value = atoi(word2); + else + { + deh_warning("No value for token %s", word); + continue; + } + + if (fastcmp(word, "NUMSCENES")) + { + cutscenes[num]->numscenes = value; + } + else if (fastcmp(word, "SCENE")) + { + if (1 <= value && value <= 128) + { + readcutscenescene(f, num, value - 1); + } + else + deh_warning("Scene number %d out of range (1 - 128)", value); + + } + else + deh_warning("Cutscene %d: unknown word '%s', Scene <num> expected.", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) +{ + char *s = Z_Calloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2; + INT32 i; + UINT16 usi; + UINT8 picid; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + if (fastcmp(word, "PAGETEXT")) + { + char *pagetext = NULL; + char *buffer; + const int bufferlen = 4096; + + for (i = 0; i < MAXLINELEN; i++) + { + if (s[i] == '=') + { + pagetext = &s[i+2]; + break; + } + } + + if (!pagetext) + { + Z_Free(textprompts[num]->page[pagenum].text); + textprompts[num]->page[pagenum].text = NULL; + continue; + } + + for (i = 0; i < MAXLINELEN; i++) + { + if (s[i] == '\0') + { + s[i] = '\n'; + s[i+1] = '\0'; + break; + } + } + + buffer = Z_Malloc(4096, PU_STATIC, NULL); + strcpy(buffer, pagetext); + + // \todo trim trailing whitespace before the # + // and also support # at the end of a PAGETEXT with no line break + + strcat(buffer, + myhashfgets(pagetext, bufferlen + - strlen(buffer) - 1, f)); + + // A text prompt overwriting another one... + Z_Free(textprompts[num]->page[pagenum].text); + + textprompts[num]->page[pagenum].text = Z_StrDup(buffer); + + Z_Free(buffer); + + continue; + } + + word2 = strtok(NULL, " = "); + if (word2) + strupr(word2); + else + break; + + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + i = atoi(word2); + usi = (UINT16)i; + + // copypasta from readcutscenescene + if (fastcmp(word, "NUMBEROFPICS")) + { + textprompts[num]->page[pagenum].numpics = (UINT8)i; + } + else if (fastcmp(word, "PICMODE")) + { + UINT8 picmode = 0; // PROMPT_PIC_PERSIST + if (usi == 1 || word2[0] == 'L') picmode = PROMPT_PIC_LOOP; + else if (usi == 2 || word2[0] == 'D' || word2[0] == 'H') picmode = PROMPT_PIC_DESTROY; + textprompts[num]->page[pagenum].picmode = picmode; + } + else if (fastcmp(word, "PICTOLOOP")) + textprompts[num]->page[pagenum].pictoloop = (UINT8)i; + else if (fastcmp(word, "PICTOSTART")) + textprompts[num]->page[pagenum].pictostart = (UINT8)i; + else if (fastcmp(word, "PICSMETAPAGE")) + { + if (usi && usi <= textprompts[num]->numpages) + { + UINT8 metapagenum = usi - 1; + + textprompts[num]->page[pagenum].numpics = textprompts[num]->page[metapagenum].numpics; + textprompts[num]->page[pagenum].picmode = textprompts[num]->page[metapagenum].picmode; + textprompts[num]->page[pagenum].pictoloop = textprompts[num]->page[metapagenum].pictoloop; + textprompts[num]->page[pagenum].pictostart = textprompts[num]->page[metapagenum].pictostart; + + for (picid = 0; picid < MAX_PROMPT_PICS; picid++) + { + strncpy(textprompts[num]->page[pagenum].picname[picid], textprompts[num]->page[metapagenum].picname[picid], 8); + textprompts[num]->page[pagenum].pichires[picid] = textprompts[num]->page[metapagenum].pichires[picid]; + textprompts[num]->page[pagenum].picduration[picid] = textprompts[num]->page[metapagenum].picduration[picid]; + textprompts[num]->page[pagenum].xcoord[picid] = textprompts[num]->page[metapagenum].xcoord[picid]; + textprompts[num]->page[pagenum].ycoord[picid] = textprompts[num]->page[metapagenum].ycoord[picid]; + } + } + } + else if (fastncmp(word, "PIC", 3)) + { + picid = (UINT8)atoi(word + 3); + if (picid > MAX_PROMPT_PICS || picid == 0) + { + deh_warning("textpromptscene %d: unknown word '%s'", num, word); + continue; + } + --picid; + + if (fastcmp(word+4, "NAME")) + { + strncpy(textprompts[num]->page[pagenum].picname[picid], word2, 8); + } + else if (fastcmp(word+4, "HIRES")) + { + textprompts[num]->page[pagenum].pichires[picid] = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); + } + else if (fastcmp(word+4, "DURATION")) + { + textprompts[num]->page[pagenum].picduration[picid] = usi; + } + else if (fastcmp(word+4, "XCOORD")) + { + textprompts[num]->page[pagenum].xcoord[picid] = usi; + } + else if (fastcmp(word+4, "YCOORD")) + { + textprompts[num]->page[pagenum].ycoord[picid] = usi; + } + else + deh_warning("textpromptscene %d: unknown word '%s'", num, word); + } + else if (fastcmp(word, "MUSIC")) + { + strncpy(textprompts[num]->page[pagenum].musswitch, word2, 7); + textprompts[num]->page[pagenum].musswitch[6] = 0; + } +#ifdef MUSICSLOT_COMPATIBILITY + else if (fastcmp(word, "MUSICSLOT")) + { + i = get_mus(word2, true); + if (i && i <= 1035) + snprintf(textprompts[num]->page[pagenum].musswitch, 7, "%sM", G_BuildMapName(i)); + else if (i && i <= 1050) + strncpy(textprompts[num]->page[pagenum].musswitch, compat_special_music_slots[i - 1036], 7); + else + textprompts[num]->page[pagenum].musswitch[0] = 0; // becomes empty string + textprompts[num]->page[pagenum].musswitch[6] = 0; + } +#endif + else if (fastcmp(word, "MUSICTRACK")) + { + textprompts[num]->page[pagenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; + } + else if (fastcmp(word, "MUSICLOOP")) + { + textprompts[num]->page[pagenum].musicloop = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); + } + // end copypasta from readcutscenescene + else if (fastcmp(word, "NAME")) + { + if (*word2 != '\0') + { + INT32 j; + + // HACK: Add yellow control char now + // so the drawing function doesn't call it repeatedly + char name[34]; + name[0] = '\x82'; // color yellow + name[1] = 0; + strncat(name, word2, 33); + name[33] = 0; + + // Replace _ with ' ' + for (j = 0; j < 32 && name[j]; j++) + { + if (name[j] == '_') + name[j] = ' '; + } + + strncpy(textprompts[num]->page[pagenum].name, name, 32); + } + else + *textprompts[num]->page[pagenum].name = '\0'; + } + else if (fastcmp(word, "ICON")) + strncpy(textprompts[num]->page[pagenum].iconname, word2, 8); + else if (fastcmp(word, "ICONALIGN")) + textprompts[num]->page[pagenum].rightside = (i || word2[0] == 'R'); + else if (fastcmp(word, "ICONFLIP")) + textprompts[num]->page[pagenum].iconflip = (i || word2[0] == 'T' || word2[0] == 'Y'); + else if (fastcmp(word, "LINES")) + textprompts[num]->page[pagenum].lines = usi; + else if (fastcmp(word, "BACKCOLOR")) + { + INT32 backcolor; + if (i == 0 || fastcmp(word2, "WHITE")) backcolor = 0; + else if (i == 1 || fastcmp(word2, "GRAY") || fastcmp(word2, "GREY") || + fastcmp(word2, "BLACK")) backcolor = 1; + else if (i == 2 || fastcmp(word2, "SEPIA")) backcolor = 2; + else if (i == 3 || fastcmp(word2, "BROWN")) backcolor = 3; + else if (i == 4 || fastcmp(word2, "PINK")) backcolor = 4; + else if (i == 5 || fastcmp(word2, "RASPBERRY")) backcolor = 5; + else if (i == 6 || fastcmp(word2, "RED")) backcolor = 6; + else if (i == 7 || fastcmp(word2, "CREAMSICLE")) backcolor = 7; + else if (i == 8 || fastcmp(word2, "ORANGE")) backcolor = 8; + else if (i == 9 || fastcmp(word2, "GOLD")) backcolor = 9; + else if (i == 10 || fastcmp(word2, "YELLOW")) backcolor = 10; + else if (i == 11 || fastcmp(word2, "EMERALD")) backcolor = 11; + else if (i == 12 || fastcmp(word2, "GREEN")) backcolor = 12; + else if (i == 13 || fastcmp(word2, "CYAN") || fastcmp(word2, "AQUA")) backcolor = 13; + else if (i == 14 || fastcmp(word2, "STEEL")) backcolor = 14; + else if (i == 15 || fastcmp(word2, "PERIWINKLE")) backcolor = 15; + else if (i == 16 || fastcmp(word2, "BLUE")) backcolor = 16; + else if (i == 17 || fastcmp(word2, "PURPLE")) backcolor = 17; + else if (i == 18 || fastcmp(word2, "LAVENDER")) backcolor = 18; + else if (i >= 256 && i < 512) backcolor = i; // non-transparent palette index + else if (i < 0) backcolor = INT32_MAX; // CONS_BACKCOLOR user-configured + else backcolor = 1; // default gray + textprompts[num]->page[pagenum].backcolor = backcolor; + } + else if (fastcmp(word, "ALIGN")) + { + UINT8 align = 0; // left + if (usi == 1 || word2[0] == 'R') align = 1; + else if (usi == 2 || word2[0] == 'C' || word2[0] == 'M') align = 2; + textprompts[num]->page[pagenum].align = align; + } + else if (fastcmp(word, "VERTICALALIGN")) + { + UINT8 align = 0; // top + if (usi == 1 || word2[0] == 'B') align = 1; + else if (usi == 2 || word2[0] == 'C' || word2[0] == 'M') align = 2; + textprompts[num]->page[pagenum].verticalalign = align; + } + else if (fastcmp(word, "TEXTSPEED")) + textprompts[num]->page[pagenum].textspeed = get_number(word2); + else if (fastcmp(word, "TEXTSFX")) + textprompts[num]->page[pagenum].textsfx = get_number(word2); + else if (fastcmp(word, "HIDEHUD")) + { + UINT8 hidehud = 0; + if ((word2[0] == 'F' && (word2[1] == 'A' || !word2[1])) || word2[0] == 'N') hidehud = 0; // false + else if (usi == 1 || word2[0] == 'T' || word2[0] == 'Y') hidehud = 1; // true (hide appropriate HUD elements) + else if (usi == 2 || word2[0] == 'A' || (word2[0] == 'F' && word2[1] == 'O')) hidehud = 2; // force (hide all HUD elements) + textprompts[num]->page[pagenum].hidehud = hidehud; + } + else if (fastcmp(word, "METAPAGE")) + { + if (usi && usi <= textprompts[num]->numpages) + { + UINT8 metapagenum = usi - 1; + + strncpy(textprompts[num]->page[pagenum].name, textprompts[num]->page[metapagenum].name, 32); + strncpy(textprompts[num]->page[pagenum].iconname, textprompts[num]->page[metapagenum].iconname, 8); + textprompts[num]->page[pagenum].rightside = textprompts[num]->page[metapagenum].rightside; + textprompts[num]->page[pagenum].iconflip = textprompts[num]->page[metapagenum].iconflip; + textprompts[num]->page[pagenum].lines = textprompts[num]->page[metapagenum].lines; + textprompts[num]->page[pagenum].backcolor = textprompts[num]->page[metapagenum].backcolor; + textprompts[num]->page[pagenum].align = textprompts[num]->page[metapagenum].align; + textprompts[num]->page[pagenum].verticalalign = textprompts[num]->page[metapagenum].verticalalign; + textprompts[num]->page[pagenum].textspeed = textprompts[num]->page[metapagenum].textspeed; + textprompts[num]->page[pagenum].textsfx = textprompts[num]->page[metapagenum].textsfx; + textprompts[num]->page[pagenum].hidehud = textprompts[num]->page[metapagenum].hidehud; + + // music: don't copy, else each page change may reset the music + } + } + else if (fastcmp(word, "TAG")) + strncpy(textprompts[num]->page[pagenum].tag, word2, 33); + else if (fastcmp(word, "NEXTPROMPT")) + textprompts[num]->page[pagenum].nextprompt = usi; + else if (fastcmp(word, "NEXTPAGE")) + textprompts[num]->page[pagenum].nextpage = usi; + else if (fastcmp(word, "NEXTTAG")) + strncpy(textprompts[num]->page[pagenum].nexttag, word2, 33); + else if (fastcmp(word, "TIMETONEXT")) + textprompts[num]->page[pagenum].timetonext = get_number(word2); + else + deh_warning("PromptPage %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +void readtextprompt(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2; + char *tmp; + INT32 value; + + // Allocate memory for this prompt if we don't yet have any + if (!textprompts[num]) + textprompts[num] = Z_Calloc(sizeof (textprompt_t), PU_STATIC, NULL); + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + word2 = strtok(NULL, " "); + if (word2) + value = atoi(word2); + else + { + deh_warning("No value for token %s", word); + continue; + } + + if (fastcmp(word, "NUMPAGES")) + { + textprompts[num]->numpages = min(max(value, 0), MAX_PAGES); + } + else if (fastcmp(word, "PAGE")) + { + if (1 <= value && value <= MAX_PAGES) + { + textprompts[num]->page[value - 1].backcolor = 1; // default to gray + textprompts[num]->page[value - 1].hidehud = 1; // hide appropriate HUD elements + readtextpromptpage(f, num, value - 1); + } + else + deh_warning("Page number %d out of range (1 - %d)", value, MAX_PAGES); + + } + else + deh_warning("Prompt %d: unknown word '%s', Page <num> expected.", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +void readmenu(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + INT32 value; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = (tmp += 2); + strupr(word2); + + value = atoi(word2); // used for numerical settings + + if (fastcmp(word, "BACKGROUNDNAME")) + { + strncpy(menupres[num].bgname, word2, 8); + titlechanged = true; + } + else if (fastcmp(word, "HIDEBACKGROUND")) + { + menupres[num].bghide = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "BACKGROUNDCOLOR")) + { + menupres[num].bgcolor = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "HIDEPICS") || fastcmp(word, "TITLEPICSHIDE")) + { + // true by default, except MM_MAIN + menupres[num].hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSMODE")) + { + if (fastcmp(word2, "USER")) + menupres[num].ttmode = TTMODE_USER; + else if (fastcmp(word2, "ALACROIX")) + menupres[num].ttmode = TTMODE_ALACROIX; + else if (fastcmp(word2, "HIDE") || fastcmp(word2, "HIDDEN") || fastcmp(word2, "NONE")) + { + menupres[num].ttmode = TTMODE_USER; + menupres[num].ttname[0] = 0; + menupres[num].hidetitlepics = true; + } + else // if (fastcmp(word2, "OLD") || fastcmp(word2, "SSNTAILS")) + menupres[num].ttmode = TTMODE_OLD; + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSSCALE")) + { + // Don't handle Alacroix special case here; see Maincfg section. + menupres[num].ttscale = max(1, min(8, (UINT8)get_number(word2))); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSNAME")) + { + strncpy(menupres[num].ttname, word2, 9); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSX")) + { + menupres[num].ttx = (INT16)get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSY")) + { + menupres[num].tty = (INT16)get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSLOOP")) + { + menupres[num].ttloop = (INT16)get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSTICS")) + { + menupres[num].tttics = (UINT16)get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLESCROLLSPEED") || fastcmp(word, "TITLESCROLLXSPEED") + || fastcmp(word, "SCROLLSPEED") || fastcmp(word, "SCROLLXSPEED")) + { + menupres[num].titlescrollxspeed = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLESCROLLYSPEED") || fastcmp(word, "SCROLLYSPEED")) + { + menupres[num].titlescrollyspeed = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "MUSIC")) + { + strncpy(menupres[num].musname, word2, 7); + menupres[num].musname[6] = 0; + titlechanged = true; + } +#ifdef MUSICSLOT_COMPATIBILITY + else if (fastcmp(word, "MUSICSLOT")) + { + value = get_mus(word2, true); + if (value && value <= 1035) + snprintf(menupres[num].musname, 7, "%sM", G_BuildMapName(value)); + else if (value && value <= 1050) + strncpy(menupres[num].musname, compat_special_music_slots[value - 1036], 7); + else + menupres[num].musname[0] = 0; // becomes empty string + menupres[num].musname[6] = 0; + titlechanged = true; + } +#endif + else if (fastcmp(word, "MUSICTRACK")) + { + menupres[num].mustrack = ((UINT16)value - 1); + titlechanged = true; + } + else if (fastcmp(word, "MUSICLOOP")) + { + // true by default except MM_MAIN + menupres[num].muslooping = (value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "NOMUSIC")) + { + menupres[num].musstop = (value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "IGNOREMUSIC")) + { + menupres[num].musignore = (value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "FADESTRENGTH")) + { + // one-based, <= 0 means use default value. 1-32 + menupres[num].fadestrength = get_number(word2)-1; + titlechanged = true; + } + else if (fastcmp(word, "NOENTERBUBBLE")) + { + menupres[num].enterbubble = !(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "NOEXITBUBBLE")) + { + menupres[num].exitbubble = !(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "ENTERTAG")) + { + menupres[num].entertag = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "EXITTAG")) + { + menupres[num].exittag = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "ENTERWIPE")) + { + menupres[num].enterwipe = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "EXITWIPE")) + { + menupres[num].exitwipe = get_number(word2); + titlechanged = true; + } + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +void readhuditem(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + INT32 i; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + strupr(word2); + + i = atoi(word2); // used for numerical settings + + if (fastcmp(word, "X")) + { + hudinfo[num].x = i; + } + else if (fastcmp(word, "Y")) + { + hudinfo[num].y = i; + } + else if (fastcmp(word, "F")) + { + hudinfo[num].f = i; + } + else + deh_warning("Level header %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +void readframe(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word1; + char *word2 = NULL; + char *tmp; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + word1 = strtok(s, " "); + if (word1) + strupr(word1); + else + break; + + word2 = strtok(NULL, " = "); + if (word2) + strupr(word2); + else + break; + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + + if (fastcmp(word1, "SPRITENUMBER") || fastcmp(word1, "SPRITENAME")) + { + states[num].sprite = get_sprite(word2); + } + else if (fastcmp(word1, "SPRITESUBNUMBER") || fastcmp(word1, "SPRITEFRAME")) + { + states[num].frame = (INT32)get_number(word2); // So the FF_ flags get calculated + } + else if (fastcmp(word1, "DURATION")) + { + states[num].tics = (INT32)get_number(word2); // So TICRATE can be used + } + else if (fastcmp(word1, "NEXT")) + { + states[num].nextstate = get_state(word2); + } + else if (fastcmp(word1, "VAR1")) + { + states[num].var1 = (INT32)get_number(word2); + } + else if (fastcmp(word1, "VAR2")) + { + states[num].var2 = (INT32)get_number(word2); + } + else if (fastcmp(word1, "ACTION")) + { + size_t z; + boolean found = false; + char actiontocompare[32]; + + memset(actiontocompare, 0x00, sizeof(actiontocompare)); + strlcpy(actiontocompare, word2, sizeof (actiontocompare)); + strupr(actiontocompare); + + for (z = 0; z < 32; z++) + { + if (actiontocompare[z] == '\n' || actiontocompare[z] == '\r') + { + actiontocompare[z] = '\0'; + break; + } + } + + for (z = 0; actionpointers[z].name; z++) + { + if (actionpointers[z].action.acv == states[num].action.acv) + break; + } + + z = 0; + found = LUA_SetLuaAction(&states[num], actiontocompare); + if (!found) + while (actionpointers[z].name) + { + if (fastcmp(actiontocompare, actionpointers[z].name)) + { + states[num].action = actionpointers[z].action; + states[num].action.acv = actionpointers[z].action.acv; // assign + states[num].action.acp1 = actionpointers[z].action.acp1; + found = true; + break; + } + z++; + } + + if (!found) + deh_warning("Unknown action %s", actiontocompare); + } + else + deh_warning("Frame %d: unknown word '%s'", num, word1); + } + } while (!myfeof(f)); + + Z_Free(s); +} + +void readsound(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2; + char *tmp; + INT32 value; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + word2 = strtok(NULL, " "); + if (word2) + value = atoi(word2); + else + { + deh_warning("No value for token %s", word); + continue; + } + + if (fastcmp(word, "SINGULAR")) + { + S_sfx[num].singularity = value; + } + else if (fastcmp(word, "PRIORITY")) + { + S_sfx[num].priority = value; + } + else if (fastcmp(word, "FLAGS")) + { + S_sfx[num].pitch = value; + } + else if (fastcmp(word, "CAPTION") || fastcmp(word, "DESCRIPTION")) + { + deh_strlcpy(S_sfx[num].caption, word2, + sizeof(S_sfx[num].caption), va("Sound effect %d: caption", num)); + } + else + deh_warning("Sound %d : unknown word '%s'",num,word); + } + } while (!myfeof(f)); + + Z_Free(s); +} + +/** Checks if a game data file name for a mod is good. + * "Good" means that it contains only alphanumerics, _, and -; + * ends in ".dat"; has at least one character before the ".dat"; + * and is not "gamedata.dat" (tested case-insensitively). + * + * Assumption: that gamedata.dat is the only .dat file that will + * ever be treated specially by the game. + * + * Note: Check for the tail ".dat" case-insensitively since at + * present, we get passed the filename in all uppercase. + * + * \param s Filename string to check. + * \return True if the filename is good. + * \sa readmaincfg() + * \author Graue <graue@oceanbase.org> + */ +static boolean GoodDataFileName(const char *s) +{ + const char *p; + const char *tail = ".dat"; + + for (p = s; *p != '\0'; p++) + if (!isalnum(*p) && *p != '_' && *p != '-' && *p != '.') + return false; + + p = s + strlen(s) - strlen(tail); + if (p <= s) return false; // too short + if (!fasticmp(p, tail)) return false; // doesn't end in .dat + if (fasticmp(s, "gamedata.dat")) return false; + + return true; +} + +void reademblemdata(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + INT32 value; + + memset(&emblemlocations[num-1], 0, sizeof(emblem_t)); + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + value = atoi(word2); // used for numerical settings + + // Up here to allow lowercase in hints + if (fastcmp(word, "HINT")) + { + while ((tmp = strchr(word2, '\\'))) + *tmp = '\n'; + deh_strlcpy(emblemlocations[num-1].hint, word2, sizeof (emblemlocations[num-1].hint), va("Emblem %d: hint", num)); + continue; + } + strupr(word2); + + if (fastcmp(word, "TYPE")) + { + if (fastcmp(word2, "GLOBAL")) + emblemlocations[num-1].type = ET_GLOBAL; + else if (fastcmp(word2, "SKIN")) + emblemlocations[num-1].type = ET_SKIN; + else if (fastcmp(word2, "SCORE")) + emblemlocations[num-1].type = ET_SCORE; + else if (fastcmp(word2, "TIME")) + emblemlocations[num-1].type = ET_TIME; + else if (fastcmp(word2, "RINGS")) + emblemlocations[num-1].type = ET_RINGS; + else if (fastcmp(word2, "MAP")) + emblemlocations[num-1].type = ET_MAP; + else if (fastcmp(word2, "NGRADE")) + emblemlocations[num-1].type = ET_NGRADE; + else if (fastcmp(word2, "NTIME")) + emblemlocations[num-1].type = ET_NTIME; + else + emblemlocations[num-1].type = (UINT8)value; + } + else if (fastcmp(word, "TAG")) + emblemlocations[num-1].tag = (INT16)value; + else if (fastcmp(word, "MAPNUM")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + + emblemlocations[num-1].level = (INT16)value; + } + else if (fastcmp(word, "SPRITE")) + { + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = word2[0]; + else + value += 'A'-1; + + if (value < 'A' || value > 'Z') + deh_warning("Emblem %d: sprite must be from A - Z (1 - 26)", num); + else + emblemlocations[num-1].sprite = (UINT8)value; + } + else if (fastcmp(word, "COLOR")) + emblemlocations[num-1].color = get_number(word2); + else if (fastcmp(word, "VAR")) + emblemlocations[num-1].var = get_number(word2); + else + deh_warning("Emblem %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); + + // Default sprite and color definitions for lazy people like me + if (!emblemlocations[num-1].sprite) switch (emblemlocations[num-1].type) + { + case ET_RINGS: + emblemlocations[num-1].sprite = 'R'; break; + case ET_SCORE: case ET_NGRADE: + emblemlocations[num-1].sprite = 'S'; break; + case ET_TIME: case ET_NTIME: + emblemlocations[num-1].sprite = 'T'; break; + default: + emblemlocations[num-1].sprite = 'A'; break; + } + if (!emblemlocations[num-1].color) switch (emblemlocations[num-1].type) + { + case ET_RINGS: + emblemlocations[num-1].color = SKINCOLOR_GOLD; break; + case ET_SCORE: + emblemlocations[num-1].color = SKINCOLOR_BROWN; break; + case ET_NGRADE: + emblemlocations[num-1].color = SKINCOLOR_TEAL; break; + case ET_TIME: case ET_NTIME: + emblemlocations[num-1].color = SKINCOLOR_GREY; break; + default: + emblemlocations[num-1].color = SKINCOLOR_BLUE; break; + } + + Z_Free(s); +} + +void readextraemblemdata(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + INT32 value; + + memset(&extraemblems[num-1], 0, sizeof(extraemblem_t)); + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + + value = atoi(word2); // used for numerical settings + + if (fastcmp(word, "NAME")) + deh_strlcpy(extraemblems[num-1].name, word2, + sizeof (extraemblems[num-1].name), va("Extra emblem %d: name", num)); + else if (fastcmp(word, "OBJECTIVE")) + deh_strlcpy(extraemblems[num-1].description, word2, + sizeof (extraemblems[num-1].description), va("Extra emblem %d: objective", num)); + else if (fastcmp(word, "CONDITIONSET")) + extraemblems[num-1].conditionset = (UINT8)value; + else if (fastcmp(word, "SHOWCONDITIONSET")) + extraemblems[num-1].showconditionset = (UINT8)value; + else + { + strupr(word2); + if (fastcmp(word, "SPRITE")) + { + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = word2[0]; + else + value += 'A'-1; + + if (value < 'A' || value > 'Z') + deh_warning("Emblem %d: sprite must be from A - Z (1 - 26)", num); + else + extraemblems[num-1].sprite = (UINT8)value; + } + else if (fastcmp(word, "COLOR")) + extraemblems[num-1].color = get_number(word2); + else + deh_warning("Extra emblem %d: unknown word '%s'", num, word); + } + } + } while (!myfeof(f)); + + if (!extraemblems[num-1].sprite) + extraemblems[num-1].sprite = 'X'; + if (!extraemblems[num-1].color) + extraemblems[num-1].color = SKINCOLOR_BLUE; + + Z_Free(s); +} + +void readunlockable(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + INT32 i; + + memset(&unlockables[num], 0, sizeof(unlockable_t)); + unlockables[num].objective[0] = '/'; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + + i = atoi(word2); // used for numerical settings + + if (fastcmp(word, "NAME")) + deh_strlcpy(unlockables[num].name, word2, + sizeof (unlockables[num].name), va("Unlockable %d: name", num)); + else if (fastcmp(word, "OBJECTIVE")) + deh_strlcpy(unlockables[num].objective, word2, + sizeof (unlockables[num].objective), va("Unlockable %d: objective", num)); + else + { + strupr(word2); + if (fastcmp(word, "HEIGHT")) + unlockables[num].height = (UINT16)i; + else if (fastcmp(word, "CONDITIONSET")) + unlockables[num].conditionset = (UINT8)i; + else if (fastcmp(word, "SHOWCONDITIONSET")) + unlockables[num].showconditionset = (UINT8)i; + else if (fastcmp(word, "NOCECHO")) + unlockables[num].nocecho = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); + else if (fastcmp(word, "NOCHECKLIST")) + unlockables[num].nochecklist = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); + else if (fastcmp(word, "TYPE")) + { + if (fastcmp(word2, "NONE")) + unlockables[num].type = SECRET_NONE; + else if (fastcmp(word2, "ITEMFINDER")) + unlockables[num].type = SECRET_ITEMFINDER; + else if (fastcmp(word2, "EMBLEMHINTS")) + unlockables[num].type = SECRET_EMBLEMHINTS; + else if (fastcmp(word2, "PANDORA")) + unlockables[num].type = SECRET_PANDORA; + else if (fastcmp(word2, "CREDITS")) + unlockables[num].type = SECRET_CREDITS; + else if (fastcmp(word2, "RECORDATTACK")) + unlockables[num].type = SECRET_RECORDATTACK; + else if (fastcmp(word2, "NIGHTSMODE")) + unlockables[num].type = SECRET_NIGHTSMODE; + else if (fastcmp(word2, "HEADER")) + unlockables[num].type = SECRET_HEADER; + else if (fastcmp(word2, "LEVELSELECT")) + unlockables[num].type = SECRET_LEVELSELECT; + else if (fastcmp(word2, "WARP")) + unlockables[num].type = SECRET_WARP; + else if (fastcmp(word2, "SOUNDTEST")) + unlockables[num].type = SECRET_SOUNDTEST; + else + unlockables[num].type = (INT16)i; + } + else if (fastcmp(word, "VAR")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + i = M_MapNumber(word2[0], word2[1]); + + unlockables[num].variable = (INT16)i; + } + else + deh_warning("Unlockable %d: unknown word '%s'", num+1, word); + } + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +static void readcondition(UINT8 set, UINT32 id, char *word2) +{ + INT32 i; + char *params[4]; // condition, requirement, extra info, extra info + char *spos; + + conditiontype_t ty; + INT32 re; + INT16 x1 = 0, x2 = 0; + + INT32 offset = 0; + + spos = strtok(word2, " "); + + for (i = 0; i < 4; ++i) + { + if (spos != NULL) + { + params[i] = spos; + spos = strtok(NULL, " "); + } + else + params[i] = NULL; + } + + if (!params[0]) + { + deh_warning("condition line is empty"); + return; + } + + if (fastcmp(params[0], "PLAYTIME")) + { + PARAMCHECK(1); + ty = UC_PLAYTIME; + re = atoi(params[1]); + } + else if (fastcmp(params[0], "GAMECLEAR") + || (++offset && fastcmp(params[0], "ALLEMERALDS")) + || (++offset && fastcmp(params[0], "ULTIMATECLEAR"))) + { + ty = UC_GAMECLEAR + offset; + re = (params[1]) ? atoi(params[1]) : 1; + } + else if ((offset=0) || fastcmp(params[0], "OVERALLSCORE") + || (++offset && fastcmp(params[0], "OVERALLTIME")) + || (++offset && fastcmp(params[0], "OVERALLRINGS"))) + { + PARAMCHECK(1); + ty = UC_OVERALLSCORE + offset; + re = atoi(params[1]); + } + else if ((offset=0) || fastcmp(params[0], "MAPVISITED") + || (++offset && fastcmp(params[0], "MAPBEATEN")) + || (++offset && fastcmp(params[0], "MAPALLEMERALDS")) + || (++offset && fastcmp(params[0], "MAPULTIMATE")) + || (++offset && fastcmp(params[0], "MAPPERFECT"))) + { + PARAMCHECK(1); + ty = UC_MAPVISITED + offset; + + // Convert to map number if it appears to be one + if (params[1][0] >= 'A' && params[1][0] <= 'Z') + re = M_MapNumber(params[1][0], params[1][1]); + else + re = atoi(params[1]); + + if (re < 0 || re >= NUMMAPS) + { + deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); + return; + } + } + else if ((offset=0) || fastcmp(params[0], "MAPSCORE") + || (++offset && fastcmp(params[0], "MAPTIME")) + || (++offset && fastcmp(params[0], "MAPRINGS"))) + { + PARAMCHECK(2); + ty = UC_MAPSCORE + offset; + re = atoi(params[2]); + + // Convert to map number if it appears to be one + if (params[1][0] >= 'A' && params[1][0] <= 'Z') + x1 = (INT16)M_MapNumber(params[1][0], params[1][1]); + else + x1 = (INT16)atoi(params[1]); + + if (x1 < 0 || x1 >= NUMMAPS) + { + deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); + return; + } + } + else if ((offset=0) || fastcmp(params[0], "NIGHTSSCORE") + || (++offset && fastcmp(params[0], "NIGHTSTIME")) + || (++offset && fastcmp(params[0], "NIGHTSGRADE"))) + { + PARAMCHECK(2); // one optional one + + ty = UC_NIGHTSSCORE + offset; + i = (params[3] ? 3 : 2); + if (fastncmp("GRADE_",params[i],6)) + { + char *p = params[i]+6; + for (re = 0; NIGHTSGRADE_LIST[re]; re++) + if (*p == NIGHTSGRADE_LIST[re]) + break; + if (!NIGHTSGRADE_LIST[re]) + { + deh_warning("Invalid NiGHTS grade %s\n", params[i]); + return; + } + } + else + re = atoi(params[i]); + + // Convert to map number if it appears to be one + if (params[1][0] >= 'A' && params[1][0] <= 'Z') + x1 = (INT16)M_MapNumber(params[1][0], params[1][1]); + else + x1 = (INT16)atoi(params[1]); + + if (x1 < 0 || x1 >= NUMMAPS) + { + deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); + return; + } + + // Mare number (0 for overall) + if (params[3]) // Only if we actually got 3 params (so the second one == mare and not requirement) + x2 = (INT16)atoi(params[2]); + else + x2 = 0; + + } + else if (fastcmp(params[0], "TRIGGER")) + { + PARAMCHECK(1); + ty = UC_TRIGGER; + re = atoi(params[1]); + + // constrained by 32 bits + if (re < 0 || re > 31) + { + deh_warning("Trigger ID %d out of range (0 - 31)", re); + return; + } + } + else if (fastcmp(params[0], "TOTALEMBLEMS")) + { + PARAMCHECK(1); + ty = UC_TOTALEMBLEMS; + re = atoi(params[1]); + } + else if (fastcmp(params[0], "EMBLEM")) + { + PARAMCHECK(1); + ty = UC_EMBLEM; + re = atoi(params[1]); + + if (re <= 0 || re > MAXEMBLEMS) + { + deh_warning("Emblem %d out of range (1 - %d)", re, MAXEMBLEMS); + return; + } + } + else if (fastcmp(params[0], "EXTRAEMBLEM")) + { + PARAMCHECK(1); + ty = UC_EXTRAEMBLEM; + re = atoi(params[1]); + + if (re <= 0 || re > MAXEXTRAEMBLEMS) + { + deh_warning("Extra emblem %d out of range (1 - %d)", re, MAXEXTRAEMBLEMS); + return; + } + } + else if (fastcmp(params[0], "CONDITIONSET")) + { + PARAMCHECK(1); + ty = UC_CONDITIONSET; + re = atoi(params[1]); + + if (re <= 0 || re > MAXCONDITIONSETS) + { + deh_warning("Condition set %d out of range (1 - %d)", re, MAXCONDITIONSETS); + return; + } + } + else + { + deh_warning("Invalid condition name %s", params[0]); + return; + } + + M_AddRawCondition(set, (UINT8)id, ty, re, x1, x2); +} + +void readconditionset(MYFILE *f, UINT8 setnum) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + UINT8 id; + UINT8 previd = 0; + + M_ClearConditionSet(setnum); + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + strupr(word2); + + if (fastncmp(word, "CONDITION", 9)) + { + id = (UINT8)atoi(word + 9); + if (id == 0) + { + deh_warning("Condition set %d: unknown word '%s'", setnum, word); + continue; + } + else if (previd > id) + { + // out of order conditions can cause problems, so enforce proper order + deh_warning("Condition set %d: conditions are out of order, ignoring this line", setnum); + continue; + } + previd = id; + + readcondition(setnum, id, word2); + } + else + deh_warning("Condition set %d: unknown word '%s'", setnum, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +void readmaincfg(MYFILE *f) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + INT32 value; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + strupr(word2); + + value = atoi(word2); // used for numerical settings + + if (fastcmp(word, "EXECCFG")) + { + if (strchr(word2, '.')) + COM_BufAddText(va("exec %s\n", word2)); + else + { + lumpnum_t lumpnum; + char newname[9]; + + strncpy(newname, word2, 8); + + newname[8] = '\0'; + + lumpnum = W_CheckNumForName(newname); + + if (lumpnum == LUMPERROR || W_LumpLength(lumpnum) == 0) + CONS_Debug(DBG_SETUP, "SOC Error: script lump %s not found/not valid.\n", newname); + else + COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE)); + } + } + + else if (fastcmp(word, "SPSTAGE_START")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + spstage_start = spmarathon_start = (INT16)value; + } + else if (fastcmp(word, "SPMARATHON_START")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + spmarathon_start = (INT16)value; + } + else if (fastcmp(word, "SSTAGE_START")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + sstage_start = (INT16)value; + sstage_end = (INT16)(sstage_start+7); // 7 special stages total plus one weirdo + } + else if (fastcmp(word, "SMPSTAGE_START")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + smpstage_start = (INT16)value; + smpstage_end = (INT16)(smpstage_start+6); // 7 special stages total + } + else if (fastcmp(word, "REDTEAM")) + { + skincolor_redteam = (UINT16)get_number(word2); + } + else if (fastcmp(word, "BLUETEAM")) + { + skincolor_blueteam = (UINT16)get_number(word2); + } + else if (fastcmp(word, "REDRING")) + { + skincolor_redring = (UINT16)get_number(word2); + } + else if (fastcmp(word, "BLUERING")) + { + skincolor_bluering = (UINT16)get_number(word2); + } + else if (fastcmp(word, "INVULNTICS")) + { + invulntics = (UINT16)get_number(word2); + } + else if (fastcmp(word, "SNEAKERTICS")) + { + sneakertics = (UINT16)get_number(word2); + } + else if (fastcmp(word, "FLASHINGTICS")) + { + flashingtics = (UINT16)get_number(word2); + } + else if (fastcmp(word, "TAILSFLYTICS")) + { + tailsflytics = (UINT16)get_number(word2); + } + else if (fastcmp(word, "UNDERWATERTICS")) + { + underwatertics = (UINT16)get_number(word2); + } + else if (fastcmp(word, "SPACETIMETICS")) + { + spacetimetics = (UINT16)get_number(word2); + } + else if (fastcmp(word, "EXTRALIFETICS")) + { + extralifetics = (UINT16)get_number(word2); + } + else if (fastcmp(word, "NIGHTSLINKTICS")) + { + nightslinktics = (UINT16)get_number(word2); + } + else if (fastcmp(word, "GAMEOVERTICS")) + { + gameovertics = get_number(word2); + } + else if (fastcmp(word, "AMMOREMOVALTICS")) + { + ammoremovaltics = get_number(word2); + } + else if (fastcmp(word, "INTROTOPLAY")) + { + introtoplay = (UINT8)get_number(word2); + // range check, you morons. + if (introtoplay > 128) + introtoplay = 128; + introchanged = true; + } + else if (fastcmp(word, "CREDITSCUTSCENE")) + { + creditscutscene = (UINT8)get_number(word2); + // range check, you morons. + if (creditscutscene > 128) + creditscutscene = 128; + } + else if (fastcmp(word, "USEBLACKROCK")) + { + useBlackRock = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); + } + else if (fastcmp(word, "LOOPTITLE")) + { + looptitle = (value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "TITLEMAP")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + titlemap = (INT16)value; + titlechanged = true; + } + else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "TITLEPICSHIDE")) + { + hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSMODE")) + { + if (fastcmp(word2, "USER")) + ttmode = TTMODE_USER; + else if (fastcmp(word2, "ALACROIX")) + ttmode = TTMODE_ALACROIX; + else if (fastcmp(word2, "HIDE") || fastcmp(word2, "HIDDEN") || fastcmp(word2, "NONE")) + { + ttmode = TTMODE_USER; + ttname[0] = 0; + hidetitlepics = true; + } + else // if (fastcmp(word2, "OLD") || fastcmp(word2, "SSNTAILS")) + ttmode = TTMODE_OLD; + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSSCALE")) + { + ttscale = max(1, min(8, (UINT8)get_number(word2))); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSSCALESAVAILABLE")) + { + // SPECIAL CASE for Alacroix: Comma-separated list of resolutions that are available + // for gfx loading. + ttavailable[0] = ttavailable[1] = ttavailable[2] = ttavailable[3] =\ + ttavailable[4] = ttavailable[5] = false; + + if (strstr(word2, "1") != NULL) + ttavailable[0] = true; + if (strstr(word2, "2") != NULL) + ttavailable[1] = true; + if (strstr(word2, "3") != NULL) + ttavailable[2] = true; + if (strstr(word2, "4") != NULL) + ttavailable[3] = true; + if (strstr(word2, "5") != NULL) + ttavailable[4] = true; + if (strstr(word2, "6") != NULL) + ttavailable[5] = true; + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSNAME")) + { + strncpy(ttname, word2, 9); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSX")) + { + ttx = (INT16)get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSY")) + { + tty = (INT16)get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSLOOP")) + { + ttloop = (INT16)get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLEPICSTICS")) + { + tttics = (UINT16)get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLESCROLLSPEED") || fastcmp(word, "TITLESCROLLXSPEED")) + { + titlescrollxspeed = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLESCROLLYSPEED")) + { + titlescrollyspeed = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "DISABLESPEEDADJUST")) + { + disableSpeedAdjust = (value || word2[0] == 'T' || word2[0] == 'Y'); + } + else if (fastcmp(word, "NUMDEMOS")) + { + numDemos = (UINT8)get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "DEMODELAYTIME")) + { + demoDelayTime = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "DEMOIDLETIME")) + { + demoIdleTime = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "USE1UPSOUND")) + { + use1upSound = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); + } + else if (fastcmp(word, "MAXXTRALIFE")) + { + maxXtraLife = (UINT8)get_number(word2); + } + else if (fastcmp(word, "USECONTINUES")) + { + useContinues = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); + } + + else if (fastcmp(word, "GAMEDATA")) + { + size_t filenamelen; + + // Check the data filename so that mods + // can't write arbitrary files. + if (!GoodDataFileName(word2)) + I_Error("Maincfg: bad data file name '%s'\n", word2); + + G_SaveGameData(); + strlcpy(gamedatafilename, word2, sizeof (gamedatafilename)); + strlwr(gamedatafilename); + savemoddata = true; + + // Also save a time attack folder + filenamelen = strlen(gamedatafilename)-4; // Strip off the extension + strncpy(timeattackfolder, gamedatafilename, min(filenamelen, sizeof (timeattackfolder))); + timeattackfolder[min(filenamelen, sizeof (timeattackfolder) - 1)] = '\0'; + + strcpy(savegamename, timeattackfolder); + strlcat(savegamename, "%u.ssg", sizeof(savegamename)); + // can't use sprintf since there is %u in savegamename + strcatbf(savegamename, srb2home, PATHSEP); + + strcpy(liveeventbackup, va("live%s.bkp", timeattackfolder)); + strcatbf(liveeventbackup, srb2home, PATHSEP); + + gamedataadded = true; + titlechanged = true; + } + else if (fastcmp(word, "RESETDATA")) + { + P_ResetData(value); + titlechanged = true; + } + else if (fastcmp(word, "CUSTOMVERSION")) + { + strlcpy(customversionstring, word2, sizeof (customversionstring)); + //titlechanged = true; + } + else if (fastcmp(word, "BOOTMAP")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + bootmap = (INT16)value; + //titlechanged = true; + } + else if (fastcmp(word, "STARTCHAR")) + { + startchar = (INT16)value; + char_on = -1; + } + else if (fastcmp(word, "TUTORIALMAP")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + tutorialmap = (INT16)value; + } + else + deh_warning("Maincfg: unknown word '%s'", word); + } + } while (!myfeof(f)); + + Z_Free(s); +} + +void readwipes(MYFILE *f) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *pword = word; + char *word2; + char *tmp; + INT32 value; + INT32 wipeoffset; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + value = atoi(word2); // used for numerical settings + + if (value < -1 || value > 99) + { + deh_warning("Wipes: bad value '%s'", word2); + continue; + } + else if (value == -1) + value = UINT8_MAX; + + // error catching + wipeoffset = -1; + + if (fastncmp(word, "LEVEL_", 6)) + { + pword = word + 6; + if (fastcmp(pword, "TOBLACK")) + wipeoffset = wipe_level_toblack; + else if (fastcmp(pword, "FINAL")) + wipeoffset = wipe_level_final; + } + else if (fastncmp(word, "INTERMISSION_", 13)) + { + pword = word + 13; + if (fastcmp(pword, "TOBLACK")) + wipeoffset = wipe_intermission_toblack; + else if (fastcmp(pword, "FINAL")) + wipeoffset = wipe_intermission_final; + } + else if (fastncmp(word, "SPECINTER_", 10)) + { + pword = word + 10; + if (fastcmp(pword, "TOBLACK")) + wipeoffset = wipe_specinter_toblack; + else if (fastcmp(pword, "FINAL")) + wipeoffset = wipe_specinter_final; + } + else if (fastncmp(word, "MULTINTER_", 10)) + { + pword = word + 10; + if (fastcmp(pword, "TOBLACK")) + wipeoffset = wipe_multinter_toblack; + else if (fastcmp(pword, "FINAL")) + wipeoffset = wipe_multinter_final; + } + else if (fastncmp(word, "CONTINUING_", 11)) + { + pword = word + 11; + if (fastcmp(pword, "TOBLACK")) + wipeoffset = wipe_continuing_toblack; + else if (fastcmp(pword, "FINAL")) + wipeoffset = wipe_continuing_final; + } + else if (fastncmp(word, "TITLESCREEN_", 12)) + { + pword = word + 12; + if (fastcmp(pword, "TOBLACK")) + wipeoffset = wipe_titlescreen_toblack; + else if (fastcmp(pword, "FINAL")) + wipeoffset = wipe_titlescreen_final; + } + else if (fastncmp(word, "TIMEATTACK_", 11)) + { + pword = word + 11; + if (fastcmp(pword, "TOBLACK")) + wipeoffset = wipe_timeattack_toblack; + else if (fastcmp(pword, "FINAL")) + wipeoffset = wipe_timeattack_final; + } + else if (fastncmp(word, "CREDITS_", 8)) + { + pword = word + 8; + if (fastcmp(pword, "TOBLACK")) + wipeoffset = wipe_credits_toblack; + else if (fastcmp(pword, "FINAL")) + wipeoffset = wipe_credits_final; + else if (fastcmp(pword, "INTERMEDIATE")) + wipeoffset = wipe_credits_intermediate; + } + else if (fastncmp(word, "EVALUATION_", 11)) + { + pword = word + 11; + if (fastcmp(pword, "TOBLACK")) + wipeoffset = wipe_evaluation_toblack; + else if (fastcmp(pword, "FINAL")) + wipeoffset = wipe_evaluation_final; + } + else if (fastncmp(word, "GAMEEND_", 8)) + { + pword = word + 8; + if (fastcmp(pword, "TOBLACK")) + wipeoffset = wipe_gameend_toblack; + else if (fastcmp(pword, "FINAL")) + wipeoffset = wipe_gameend_final; + } + else if (fastncmp(word, "SPECLEVEL_", 10)) + { + pword = word + 10; + if (fastcmp(pword, "TOWHITE")) + wipeoffset = wipe_speclevel_towhite; + } + + if (wipeoffset < 0) + { + deh_warning("Wipes: unknown word '%s'", word); + continue; + } + + if (value == UINT8_MAX + && (wipeoffset <= wipe_level_toblack || wipeoffset >= wipe_speclevel_towhite)) + { + // Cannot disable non-toblack wipes + // (or the level toblack wipe, or the special towhite wipe) + deh_warning("Wipes: can't disable wipe of type '%s'", word); + continue; + } + + wipedefs[wipeoffset] = (UINT8)value; + } + } while (!myfeof(f)); + + Z_Free(s); +} + +mobjtype_t get_mobjtype(const char *word) +{ // Returns the value of MT_ enumerations + mobjtype_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("MT_",word,3)) + word += 3; // take off the MT_ + for (i = 0; i < NUMMOBJFREESLOTS; i++) { + if (!FREE_MOBJS[i]) + break; + if (fastcmp(word, FREE_MOBJS[i])) + return MT_FIRSTFREESLOT+i; + } + for (i = 0; i < MT_FIRSTFREESLOT; i++) + if (fastcmp(word, MOBJTYPE_LIST[i]+3)) + return i; + deh_warning("Couldn't find mobjtype named 'MT_%s'",word); + return MT_NULL; +} + +statenum_t get_state(const char *word) +{ // Returns the value of S_ enumerations + statenum_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("S_",word,2)) + word += 2; // take off the S_ + for (i = 0; i < NUMSTATEFREESLOTS; i++) { + if (!FREE_STATES[i]) + break; + if (fastcmp(word, FREE_STATES[i])) + return S_FIRSTFREESLOT+i; + } + for (i = 0; i < S_FIRSTFREESLOT; i++) + if (fastcmp(word, STATE_LIST[i]+2)) + return i; + deh_warning("Couldn't find state named 'S_%s'",word); + return S_NULL; +} + +skincolornum_t get_skincolor(const char *word) +{ // Returns the value of SKINCOLOR_ enumerations + skincolornum_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("SKINCOLOR_",word,10)) + word += 10; // take off the SKINCOLOR_ + for (i = 0; i < NUMCOLORFREESLOTS; i++) { + if (!FREE_SKINCOLORS[i]) + break; + if (fastcmp(word, FREE_SKINCOLORS[i])) + return SKINCOLOR_FIRSTFREESLOT+i; + } + for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++) + if (fastcmp(word, COLOR_ENUMS[i])) + return i; + deh_warning("Couldn't find skincolor named 'SKINCOLOR_%s'",word); + return SKINCOLOR_GREEN; +} + +spritenum_t get_sprite(const char *word) +{ // Returns the value of SPR_ enumerations + spritenum_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("SPR_",word,4)) + word += 4; // take off the SPR_ + for (i = 0; i < NUMSPRITES; i++) + if (!sprnames[i][4] && memcmp(word,sprnames[i],4)==0) + return i; + deh_warning("Couldn't find sprite named 'SPR_%s'",word); + return SPR_NULL; +} + +playersprite_t get_sprite2(const char *word) +{ // Returns the value of SPR2_ enumerations + playersprite_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("SPR2_",word,5)) + word += 5; // take off the SPR2_ + for (i = 0; i < NUMPLAYERSPRITES; i++) + if (!spr2names[i][4] && memcmp(word,spr2names[i],4)==0) + return i; + deh_warning("Couldn't find sprite named 'SPR2_%s'",word); + return SPR2_STND; +} + +sfxenum_t get_sfx(const char *word) +{ // Returns the value of SFX_ enumerations + sfxenum_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("SFX_",word,4)) + word += 4; // take off the SFX_ + else if (fastncmp("DS",word,2)) + word += 2; // take off the DS + for (i = 0; i < NUMSFX; i++) + if (S_sfx[i].name && fasticmp(word, S_sfx[i].name)) + return i; + deh_warning("Couldn't find sfx named 'SFX_%s'",word); + return sfx_None; +} + +#ifdef MUSICSLOT_COMPATIBILITY +UINT16 get_mus(const char *word, UINT8 dehacked_mode) +{ // Returns the value of MUS_ enumerations + UINT16 i; + char lumptmp[4]; + + if (*word >= '0' && *word <= '9') + return atoi(word); + if (!word[2] && toupper(word[0]) >= 'A' && toupper(word[0]) <= 'Z') + return (UINT16)M_MapNumber(word[0], word[1]); + + if (fastncmp("MUS_",word,4)) + word += 4; // take off the MUS_ + else if (fastncmp("O_",word,2) || fastncmp("D_",word,2)) + word += 2; // take off the O_ or D_ + + strncpy(lumptmp, word, 4); + lumptmp[3] = 0; + if (fasticmp("MAP",lumptmp)) + { + word += 3; + if (toupper(word[0]) >= 'A' && toupper(word[0]) <= 'Z') + return (UINT16)M_MapNumber(word[0], word[1]); + else if ((i = atoi(word))) + return i; + + word -= 3; + if (dehacked_mode) + deh_warning("Couldn't find music named 'MUS_%s'",word); + return 0; + } + for (i = 0; compat_special_music_slots[i][0]; ++i) + if (fasticmp(word, compat_special_music_slots[i])) + return i + 1036; + if (dehacked_mode) + deh_warning("Couldn't find music named 'MUS_%s'",word); + return 0; +} +#endif + +hudnum_t get_huditem(const char *word) +{ // Returns the value of HUD_ enumerations + hudnum_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("HUD_",word,4)) + word += 4; // take off the HUD_ + for (i = 0; i < NUMHUDITEMS; i++) + if (fastcmp(word, HUDITEMS_LIST[i])) + return i; + deh_warning("Couldn't find huditem named 'HUD_%s'",word); + return HUD_LIVES; +} + +menutype_t get_menutype(const char *word) +{ // Returns the value of MN_ enumerations + menutype_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("MN_",word,3)) + word += 3; // take off the MN_ + for (i = 0; i < NUMMENUTYPES; i++) + if (fastcmp(word, MENUTYPES_LIST[i])) + return i; + deh_warning("Couldn't find menutype named 'MN_%s'",word); + return MN_NONE; +} + +/*static INT16 get_gametype(const char *word) +{ // Returns the value of GT_ enumerations + INT16 i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("GT_",word,3)) + word += 3; // take off the GT_ + for (i = 0; i < NUMGAMETYPES; i++) + if (fastcmp(word, Gametype_ConstantNames[i]+3)) + return i; + deh_warning("Couldn't find gametype named 'GT_%s'",word); + return GT_COOP; +} + +static powertype_t get_power(const char *word) +{ // Returns the value of pw_ enumerations + powertype_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("PW_",word,3)) + word += 3; // take off the pw_ + for (i = 0; i < NUMPOWERS; i++) + if (fastcmp(word, POWERS_LIST[i])) + return i; + deh_warning("Couldn't find power named 'pw_%s'",word); + return pw_invulnerability; +}*/ + +/// \todo Make ANY of this completely over-the-top math craziness obey the order of operations. +static fixed_t op_mul(fixed_t a, fixed_t b) { return a*b; } +static fixed_t op_div(fixed_t a, fixed_t b) { return a/b; } +static fixed_t op_add(fixed_t a, fixed_t b) { return a+b; } +static fixed_t op_sub(fixed_t a, fixed_t b) { return a-b; } +static fixed_t op_or(fixed_t a, fixed_t b) { return a|b; } +static fixed_t op_and(fixed_t a, fixed_t b) { return a&b; } +static fixed_t op_lshift(fixed_t a, fixed_t b) { return a<<b; } +static fixed_t op_rshift(fixed_t a, fixed_t b) { return a>>b; } + +struct { + const char c; + fixed_t (*v)(fixed_t,fixed_t); +} OPERATIONS[] = { + {'*',op_mul}, + {'/',op_div}, + {'+',op_add}, + {'-',op_sub}, + {'|',op_or}, + {'&',op_and}, + {'<',op_lshift}, + {'>',op_rshift}, + {0,NULL} +}; + +// Returns the full word, cut at the first symbol or whitespace +/*static char *read_word(const char *line) +{ + // Part 1: You got the start of the word, now find the end. + const char *p; + INT32 i; + for (p = line+1; *p; p++) { + if (*p == ' ' || *p == '\t') + break; + for (i = 0; OPERATIONS[i].c; i++) + if (*p == OPERATIONS[i].c) { + i = -1; + break; + } + if (i == -1) + break; + } + + // Part 2: Make a copy of the word and return it. + { + size_t len = (p-line); + char *word = malloc(len+1); + M_Memcpy(word,line,len); + word[len] = '\0'; + return word; + } +} + +static INT32 operation_pad(const char **word) +{ // Brings word the next operation and returns the operation number. + INT32 i; + for (; **word; (*word)++) { + if (**word == ' ' || **word == '\t') + continue; + for (i = 0; OPERATIONS[i].c; i++) + if (**word == OPERATIONS[i].c) + { + if ((**word == '<' && *(*word+1) == '<') || (**word == '>' && *(*word+1) == '>')) (*word)++; // These operations are two characters long. + else if (**word == '<' || **word == '>') continue; // ... do not accept one character long. + (*word)++; + return i; + } + deh_warning("Unknown operation '%c'",**word); + return -1; + } + return -1; +} + +static void const_warning(const char *type, const char *word) +{ + deh_warning("Couldn't find %s named '%s'",type,word); +} + +static fixed_t find_const(const char **rword) +{ // Finds the value of constants and returns it, bringing word to the next operation. + INT32 i; + fixed_t r; + char *word = read_word(*rword); + *rword += strlen(word); + if ((*word >= '0' && *word <= '9') || *word == '-') { // Parse a number + r = atoi(word); + free(word); + return r; + } + if (!*(word+1) && // Turn a single A-z symbol into numbers, like sprite frames. + ((*word >= 'A' && *word <= 'Z') || (*word >= 'a' && *word <= 'z'))) { + r = R_Char2Frame(*word); + free(word); + return r; + } + if (fastncmp("MF_", word, 3)) { + char *p = word+3; + for (i = 0; MOBJFLAG_LIST[i]; i++) + if (fastcmp(p, MOBJFLAG_LIST[i])) { + free(word); + return (1<<i); + } + + // Not found error + const_warning("mobj flag",word); + free(word); + return 0; + } + else if (fastncmp("MF2_", word, 4)) { + char *p = word+4; + for (i = 0; MOBJFLAG2_LIST[i]; i++) + if (fastcmp(p, MOBJFLAG2_LIST[i])) { + free(word); + return (1<<i); + } + + // Not found error + const_warning("mobj flag2",word); + free(word); + return 0; + } + else if (fastncmp("MFE_", word, 4)) { + char *p = word+4; + for (i = 0; MOBJEFLAG_LIST[i]; i++) + if (fastcmp(p, MOBJEFLAG_LIST[i])) { + free(word); + return (1<<i); + } + + // Not found error + const_warning("mobj eflag",word); + free(word); + return 0; + } + else if (fastncmp("PF_", word, 3)) { + char *p = word+3; + for (i = 0; PLAYERFLAG_LIST[i]; i++) + if (fastcmp(p, PLAYERFLAG_LIST[i])) { + free(word); + return (1<<i); + } + if (fastcmp(p, "FULLSTASIS")) + return PF_FULLSTASIS; + + // Not found error + const_warning("player flag",word); + free(word); + return 0; + } + else if (fastncmp("S_",word,2)) { + r = get_state(word); + free(word); + return r; + } + else if (fastncmp("SKINCOLOR_",word,10)) { + r = get_skincolor(word); + free(word); + return r; + } + else if (fastncmp("MT_",word,3)) { + r = get_mobjtype(word); + free(word); + return r; + } + else if (fastncmp("SPR_",word,4)) { + r = get_sprite(word); + free(word); + return r; + } + else if (fastncmp("SFX_",word,4) || fastncmp("DS",word,2)) { + r = get_sfx(word); + free(word); + return r; + } +#ifdef MUSICSLOT_COMPATIBILITY + else if (fastncmp("MUS_",word,4) || fastncmp("O_",word,2)) { + r = get_mus(word, true); + free(word); + return r; + } +#endif + else if (fastncmp("PW_",word,3)) { + r = get_power(word); + free(word); + return r; + } + else if (fastncmp("MN_",word,3)) { + r = get_menutype(word); + free(word); + return r; + } + else if (fastncmp("GT_",word,3)) { + r = get_gametype(word); + free(word); + return r; + } + else if (fastncmp("GTR_", word, 4)) { + char *p = word+4; + for (i = 0; GAMETYPERULE_LIST[i]; i++) + if (fastcmp(p, GAMETYPERULE_LIST[i])) { + free(word); + return (1<<i); + } + + // Not found error + const_warning("game type rule",word); + free(word); + return 0; + } + else if (fastncmp("TOL_", word, 4)) { + char *p = word+4; + for (i = 0; TYPEOFLEVEL[i].name; i++) + if (fastcmp(p, TYPEOFLEVEL[i].name)) { + free(word); + return TYPEOFLEVEL[i].flag; + } + + // Not found error + const_warning("typeoflevel",word); + free(word); + return 0; + } + else if (fastncmp("HUD_",word,4)) { + r = get_huditem(word); + free(word); + return r; + } + else if (fastncmp("GRADE_",word,6)) + { + char *p = word+6; + for (i = 0; NIGHTSGRADE_LIST[i]; i++) + if (*p == NIGHTSGRADE_LIST[i]) + { + free(word); + return i; + } + const_warning("NiGHTS grade",word); + free(word); + return 0; + } + for (i = 0; INT_CONST[i].n; i++) + if (fastcmp(word,INT_CONST[i].n)) { + free(word); + return INT_CONST[i].v; + } + + // Not found error. + const_warning("constant",word); + free(word); + return 0; +}*/ diff --git a/src/deh_soc.h b/src/deh_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..2bcb52e709e9ef1003753fdf68ee6647af9c3e60 --- /dev/null +++ b/src/deh_soc.h @@ -0,0 +1,89 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file deh_soc.h +/// \brief Load SOC file and change tables and text + +#ifndef __DEH_SOC_H__ +#define __DEH_SOC_H__ + +#include "doomdef.h" +#include "g_game.h" +#include "sounds.h" +#include "info.h" +#include "d_think.h" +#include "m_argv.h" +#include "z_zone.h" +#include "w_wad.h" +#include "m_menu.h" +#include "m_misc.h" +#include "f_finale.h" +#include "st_stuff.h" +#include "i_system.h" +#include "p_setup.h" +#include "r_data.h" +#include "r_textures.h" +#include "r_draw.h" +#include "r_picformats.h" +#include "r_things.h" // R_Char2Frame +#include "r_sky.h" +#include "fastcmp.h" +#include "lua_script.h" // Reluctantly included for LUA_EvalMath +#include "d_clisrv.h" + +#ifdef HWRENDER +#include "hardware/hw_light.h" +#endif + +#include "info.h" +#include "dehacked.h" +#include "doomdef.h" // MUSICSLOT_COMPATIBILITY, HWRENDER + +// Crazy word-reading stuff +/// \todo Put these in a seperate file or something. +mobjtype_t get_mobjtype(const char *word); +statenum_t get_state(const char *word); +spritenum_t get_sprite(const char *word); +playersprite_t get_sprite2(const char *word); +sfxenum_t get_sfx(const char *word); +#ifdef MUSICSLOT_COMPATIBILITY +UINT16 get_mus(const char *word, UINT8 dehacked_mode); +#endif +hudnum_t get_huditem(const char *word); +menutype_t get_menutype(const char *word); +//INT16 get_gametype(const char *word); +//powertype_t get_power(const char *word); +skincolornum_t get_skincolor(const char *word); + +void readwipes(MYFILE *f); +void readmaincfg(MYFILE *f); +void readconditionset(MYFILE *f, UINT8 setnum); +void readunlockable(MYFILE *f, INT32 num); +void readextraemblemdata(MYFILE *f, INT32 num); +void reademblemdata(MYFILE *f, INT32 num); +void readsound(MYFILE *f, INT32 num); +void readframe(MYFILE *f, INT32 num); +void readhuditem(MYFILE *f, INT32 num); +void readmenu(MYFILE *f, INT32 num); +void readtextprompt(MYFILE *f, INT32 num); +void readcutscene(MYFILE *f, INT32 num); +void readlevelheader(MYFILE *f, INT32 num); +void readgametype(MYFILE *f, char *gtname); +void readsprite2(MYFILE *f, INT32 num); +void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2); +#ifdef HWRENDER +void readlight(MYFILE *f, INT32 num); +#endif +void readskincolor(MYFILE *f, INT32 num); +void readthing(MYFILE *f, INT32 num); +void readfreeslots(MYFILE *f); +void readPlayer(MYFILE *f, INT32 num); +void clear_levels(void); +void clear_conditionsets(void); +#endif diff --git a/src/deh_tables.c b/src/deh_tables.c new file mode 100644 index 0000000000000000000000000000000000000000..93c49362373fc0e2dbb18ef62e5cf60aa3f36e1b --- /dev/null +++ b/src/deh_tables.c @@ -0,0 +1,5433 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file deh_tables.c +/// \brief Define DeHackEd tables. + +#include "doomdef.h" // Constants +#include "s_sound.h" // Sound constants +#include "info.h" // Mobj, state, sprite, etc constants +#include "m_menu.h" // Menu constants +#include "y_inter.h" // Intermission constants +#include "p_local.h" // some more constants +#include "r_draw.h" // Colormap constants +#include "lua_script.h" // Lua stuff +#include "m_cond.h" // Emblem constants +#include "v_video.h" // video flags (for lua) +#include "i_sound.h" // musictype_t (for lua) +#include "g_state.h" // gamestate_t (for lua) + +#include "deh_tables.h" + +char *FREE_STATES[NUMSTATEFREESLOTS]; +char *FREE_MOBJS[NUMMOBJFREESLOTS]; +char *FREE_SKINCOLORS[NUMCOLORFREESLOTS]; +UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway. + +const char NIGHTSGRADE_LIST[] = { + 'F', // GRADE_F + 'E', // GRADE_E + 'D', // GRADE_D + 'C', // GRADE_C + 'B', // GRADE_B + 'A', // GRADE_A + 'S', // GRADE_S + '\0' +}; + +struct flickytypes_s FLICKYTYPES[] = { + {"BLUEBIRD", MT_FLICKY_01}, // Flicky (Flicky) + {"RABBIT", MT_FLICKY_02}, // Pocky (1) + {"CHICKEN", MT_FLICKY_03}, // Cucky (1) + {"SEAL", MT_FLICKY_04}, // Rocky (1) + {"PIG", MT_FLICKY_05}, // Picky (1) + {"CHIPMUNK", MT_FLICKY_06}, // Ricky (1) + {"PENGUIN", MT_FLICKY_07}, // Pecky (1) + {"FISH", MT_FLICKY_08}, // Nicky (CD) + {"RAM", MT_FLICKY_09}, // Flocky (CD) + {"PUFFIN", MT_FLICKY_10}, // Wicky (CD) + {"COW", MT_FLICKY_11}, // Macky (SRB2) + {"RAT", MT_FLICKY_12}, // Micky (2) + {"BEAR", MT_FLICKY_13}, // Becky (2) + {"DOVE", MT_FLICKY_14}, // Docky (CD) + {"CAT", MT_FLICKY_15}, // Nyannyan (Flicky) + {"CANARY", MT_FLICKY_16}, // Lucky (CD) + {"a", 0}, // End of normal flickies - a lower case character so will never fastcmp valid with uppercase tmp + //{"FLICKER", MT_FLICKER}, // Flacky (SRB2) + {"SPIDER", MT_SECRETFLICKY_01}, // Sticky (SRB2) + {"BAT", MT_SECRETFLICKY_02}, // Backy (SRB2) + {"SEED", MT_SEED}, // Seed (CD) + {NULL, 0} +}; + +// IMPORTANT! +// DO NOT FORGET TO SYNC THIS LIST WITH THE ACTIONNUM ENUM IN INFO.H +actionpointer_t actionpointers[] = +{ + {{A_Explode}, "A_EXPLODE"}, + {{A_Pain}, "A_PAIN"}, + {{A_Fall}, "A_FALL"}, + {{A_MonitorPop}, "A_MONITORPOP"}, + {{A_GoldMonitorPop}, "A_GOLDMONITORPOP"}, + {{A_GoldMonitorRestore}, "A_GOLDMONITORRESTORE"}, + {{A_GoldMonitorSparkle}, "A_GOLDMONITORSPARKLE"}, + {{A_Look}, "A_LOOK"}, + {{A_Chase}, "A_CHASE"}, + {{A_FaceStabChase}, "A_FACESTABCHASE"}, + {{A_FaceStabRev}, "A_FACESTABREV"}, + {{A_FaceStabHurl}, "A_FACESTABHURL"}, + {{A_FaceStabMiss}, "A_FACESTABMISS"}, + {{A_StatueBurst}, "A_STATUEBURST"}, + {{A_FaceTarget}, "A_FACETARGET"}, + {{A_FaceTracer}, "A_FACETRACER"}, + {{A_Scream}, "A_SCREAM"}, + {{A_BossDeath}, "A_BOSSDEATH"}, + {{A_CustomPower}, "A_CUSTOMPOWER"}, + {{A_GiveWeapon}, "A_GIVEWEAPON"}, + {{A_RingBox}, "A_RINGBOX"}, + {{A_Invincibility}, "A_INVINCIBILITY"}, + {{A_SuperSneakers}, "A_SUPERSNEAKERS"}, + {{A_BunnyHop}, "A_BUNNYHOP"}, + {{A_BubbleSpawn}, "A_BUBBLESPAWN"}, + {{A_FanBubbleSpawn}, "A_FANBUBBLESPAWN"}, + {{A_BubbleRise}, "A_BUBBLERISE"}, + {{A_BubbleCheck}, "A_BUBBLECHECK"}, + {{A_AwardScore}, "A_AWARDSCORE"}, + {{A_ExtraLife}, "A_EXTRALIFE"}, + {{A_GiveShield}, "A_GIVESHIELD"}, + {{A_GravityBox}, "A_GRAVITYBOX"}, + {{A_ScoreRise}, "A_SCORERISE"}, + {{A_AttractChase}, "A_ATTRACTCHASE"}, + {{A_DropMine}, "A_DROPMINE"}, + {{A_FishJump}, "A_FISHJUMP"}, + {{A_ThrownRing}, "A_THROWNRING"}, + {{A_SetSolidSteam}, "A_SETSOLIDSTEAM"}, + {{A_UnsetSolidSteam}, "A_UNSETSOLIDSTEAM"}, + {{A_SignSpin}, "A_SIGNSPIN"}, + {{A_SignPlayer}, "A_SIGNPLAYER"}, + {{A_OverlayThink}, "A_OVERLAYTHINK"}, + {{A_JetChase}, "A_JETCHASE"}, + {{A_JetbThink}, "A_JETBTHINK"}, + {{A_JetgThink}, "A_JETGTHINK"}, + {{A_JetgShoot}, "A_JETGSHOOT"}, + {{A_ShootBullet}, "A_SHOOTBULLET"}, + {{A_MinusDigging}, "A_MINUSDIGGING"}, + {{A_MinusPopup}, "A_MINUSPOPUP"}, + {{A_MinusCheck}, "A_MINUSCHECK"}, + {{A_ChickenCheck}, "A_CHICKENCHECK"}, + {{A_MouseThink}, "A_MOUSETHINK"}, + {{A_DetonChase}, "A_DETONCHASE"}, + {{A_CapeChase}, "A_CAPECHASE"}, + {{A_RotateSpikeBall}, "A_ROTATESPIKEBALL"}, + {{A_SlingAppear}, "A_SLINGAPPEAR"}, + {{A_UnidusBall}, "A_UNIDUSBALL"}, + {{A_RockSpawn}, "A_ROCKSPAWN"}, + {{A_SetFuse}, "A_SETFUSE"}, + {{A_CrawlaCommanderThink}, "A_CRAWLACOMMANDERTHINK"}, + {{A_SmokeTrailer}, "A_SMOKETRAILER"}, + {{A_RingExplode}, "A_RINGEXPLODE"}, + {{A_OldRingExplode}, "A_OLDRINGEXPLODE"}, + {{A_MixUp}, "A_MIXUP"}, + {{A_RecyclePowers}, "A_RECYCLEPOWERS"}, + {{A_Boss1Chase}, "A_BOSS1CHASE"}, + {{A_FocusTarget}, "A_FOCUSTARGET"}, + {{A_Boss2Chase}, "A_BOSS2CHASE"}, + {{A_Boss2Pogo}, "A_BOSS2POGO"}, + {{A_BossZoom}, "A_BOSSZOOM"}, + {{A_BossScream}, "A_BOSSSCREAM"}, + {{A_Boss2TakeDamage}, "A_BOSS2TAKEDAMAGE"}, + {{A_Boss7Chase}, "A_BOSS7CHASE"}, + {{A_GoopSplat}, "A_GOOPSPLAT"}, + {{A_Boss2PogoSFX}, "A_BOSS2POGOSFX"}, + {{A_Boss2PogoTarget}, "A_BOSS2POGOTARGET"}, + {{A_BossJetFume}, "A_BOSSJETFUME"}, + {{A_EggmanBox}, "A_EGGMANBOX"}, + {{A_TurretFire}, "A_TURRETFIRE"}, + {{A_SuperTurretFire}, "A_SUPERTURRETFIRE"}, + {{A_TurretStop}, "A_TURRETSTOP"}, + {{A_JetJawRoam}, "A_JETJAWROAM"}, + {{A_JetJawChomp}, "A_JETJAWCHOMP"}, + {{A_PointyThink}, "A_POINTYTHINK"}, + {{A_CheckBuddy}, "A_CHECKBUDDY"}, + {{A_HoodFire}, "A_HOODFIRE"}, + {{A_HoodThink}, "A_HOODTHINK"}, + {{A_HoodFall}, "A_HOODFALL"}, + {{A_ArrowBonks}, "A_ARROWBONKS"}, + {{A_SnailerThink}, "A_SNAILERTHINK"}, + {{A_SharpChase}, "A_SHARPCHASE"}, + {{A_SharpSpin}, "A_SHARPSPIN"}, + {{A_SharpDecel}, "A_SHARPDECEL"}, + {{A_CrushstaceanWalk}, "A_CRUSHSTACEANWALK"}, + {{A_CrushstaceanPunch}, "A_CRUSHSTACEANPUNCH"}, + {{A_CrushclawAim}, "A_CRUSHCLAWAIM"}, + {{A_CrushclawLaunch}, "A_CRUSHCLAWLAUNCH"}, + {{A_VultureVtol}, "A_VULTUREVTOL"}, + {{A_VultureCheck}, "A_VULTURECHECK"}, + {{A_VultureHover}, "A_VULTUREHOVER"}, + {{A_VultureBlast}, "A_VULTUREBLAST"}, + {{A_VultureFly}, "A_VULTUREFLY"}, + {{A_SkimChase}, "A_SKIMCHASE"}, + {{A_1upThinker}, "A_1UPTHINKER"}, + {{A_SkullAttack}, "A_SKULLATTACK"}, + {{A_LobShot}, "A_LOBSHOT"}, + {{A_FireShot}, "A_FIRESHOT"}, + {{A_SuperFireShot}, "A_SUPERFIRESHOT"}, + {{A_BossFireShot}, "A_BOSSFIRESHOT"}, + {{A_Boss7FireMissiles}, "A_BOSS7FIREMISSILES"}, + {{A_Boss1Laser}, "A_BOSS1LASER"}, + {{A_Boss4Reverse}, "A_BOSS4REVERSE"}, + {{A_Boss4SpeedUp}, "A_BOSS4SPEEDUP"}, + {{A_Boss4Raise}, "A_BOSS4RAISE"}, + {{A_SparkFollow}, "A_SPARKFOLLOW"}, + {{A_BuzzFly}, "A_BUZZFLY"}, + {{A_GuardChase}, "A_GUARDCHASE"}, + {{A_EggShield}, "A_EGGSHIELD"}, + {{A_SetReactionTime}, "A_SETREACTIONTIME"}, + {{A_Boss1Spikeballs}, "A_BOSS1SPIKEBALLS"}, + {{A_Boss3TakeDamage}, "A_BOSS3TAKEDAMAGE"}, + {{A_Boss3Path}, "A_BOSS3PATH"}, + {{A_Boss3ShockThink}, "A_BOSS3SHOCKTHINK"}, + {{A_LinedefExecute}, "A_LINEDEFEXECUTE"}, + {{A_PlaySeeSound}, "A_PLAYSEESOUND"}, + {{A_PlayAttackSound}, "A_PLAYATTACKSOUND"}, + {{A_PlayActiveSound}, "A_PLAYACTIVESOUND"}, + {{A_SpawnObjectAbsolute}, "A_SPAWNOBJECTABSOLUTE"}, + {{A_SpawnObjectRelative}, "A_SPAWNOBJECTRELATIVE"}, + {{A_ChangeAngleRelative}, "A_CHANGEANGLERELATIVE"}, + {{A_ChangeAngleAbsolute}, "A_CHANGEANGLEABSOLUTE"}, + {{A_RollAngle}, "A_ROLLANGLE"}, + {{A_ChangeRollAngleRelative},"A_CHANGEROLLANGLERELATIVE"}, + {{A_ChangeRollAngleAbsolute},"A_CHANGEROLLANGLEABSOLUTE"}, + {{A_PlaySound}, "A_PLAYSOUND"}, + {{A_FindTarget}, "A_FINDTARGET"}, + {{A_FindTracer}, "A_FINDTRACER"}, + {{A_SetTics}, "A_SETTICS"}, + {{A_SetRandomTics}, "A_SETRANDOMTICS"}, + {{A_ChangeColorRelative}, "A_CHANGECOLORRELATIVE"}, + {{A_ChangeColorAbsolute}, "A_CHANGECOLORABSOLUTE"}, + {{A_Dye}, "A_DYE"}, + {{A_MoveRelative}, "A_MOVERELATIVE"}, + {{A_MoveAbsolute}, "A_MOVEABSOLUTE"}, + {{A_Thrust}, "A_THRUST"}, + {{A_ZThrust}, "A_ZTHRUST"}, + {{A_SetTargetsTarget}, "A_SETTARGETSTARGET"}, + {{A_SetObjectFlags}, "A_SETOBJECTFLAGS"}, + {{A_SetObjectFlags2}, "A_SETOBJECTFLAGS2"}, + {{A_RandomState}, "A_RANDOMSTATE"}, + {{A_RandomStateRange}, "A_RANDOMSTATERANGE"}, + {{A_DualAction}, "A_DUALACTION"}, + {{A_RemoteAction}, "A_REMOTEACTION"}, + {{A_ToggleFlameJet}, "A_TOGGLEFLAMEJET"}, + {{A_OrbitNights}, "A_ORBITNIGHTS"}, + {{A_GhostMe}, "A_GHOSTME"}, + {{A_SetObjectState}, "A_SETOBJECTSTATE"}, + {{A_SetObjectTypeState}, "A_SETOBJECTTYPESTATE"}, + {{A_KnockBack}, "A_KNOCKBACK"}, + {{A_PushAway}, "A_PUSHAWAY"}, + {{A_RingDrain}, "A_RINGDRAIN"}, + {{A_SplitShot}, "A_SPLITSHOT"}, + {{A_MissileSplit}, "A_MISSILESPLIT"}, + {{A_MultiShot}, "A_MULTISHOT"}, + {{A_InstaLoop}, "A_INSTALOOP"}, + {{A_Custom3DRotate}, "A_CUSTOM3DROTATE"}, + {{A_SearchForPlayers}, "A_SEARCHFORPLAYERS"}, + {{A_CheckRandom}, "A_CHECKRANDOM"}, + {{A_CheckTargetRings}, "A_CHECKTARGETRINGS"}, + {{A_CheckRings}, "A_CHECKRINGS"}, + {{A_CheckTotalRings}, "A_CHECKTOTALRINGS"}, + {{A_CheckHealth}, "A_CHECKHEALTH"}, + {{A_CheckRange}, "A_CHECKRANGE"}, + {{A_CheckHeight}, "A_CHECKHEIGHT"}, + {{A_CheckTrueRange}, "A_CHECKTRUERANGE"}, + {{A_CheckThingCount}, "A_CHECKTHINGCOUNT"}, + {{A_CheckAmbush}, "A_CHECKAMBUSH"}, + {{A_CheckCustomValue}, "A_CHECKCUSTOMVALUE"}, + {{A_CheckCusValMemo}, "A_CHECKCUSVALMEMO"}, + {{A_SetCustomValue}, "A_SETCUSTOMVALUE"}, + {{A_UseCusValMemo}, "A_USECUSVALMEMO"}, + {{A_RelayCustomValue}, "A_RELAYCUSTOMVALUE"}, + {{A_CusValAction}, "A_CUSVALACTION"}, + {{A_ForceStop}, "A_FORCESTOP"}, + {{A_ForceWin}, "A_FORCEWIN"}, + {{A_SpikeRetract}, "A_SPIKERETRACT"}, + {{A_InfoState}, "A_INFOSTATE"}, + {{A_Repeat}, "A_REPEAT"}, + {{A_SetScale}, "A_SETSCALE"}, + {{A_RemoteDamage}, "A_REMOTEDAMAGE"}, + {{A_HomingChase}, "A_HOMINGCHASE"}, + {{A_TrapShot}, "A_TRAPSHOT"}, + {{A_VileTarget}, "A_VILETARGET"}, + {{A_VileAttack}, "A_VILEATTACK"}, + {{A_VileFire}, "A_VILEFIRE"}, + {{A_BrakChase}, "A_BRAKCHASE"}, + {{A_BrakFireShot}, "A_BRAKFIRESHOT"}, + {{A_BrakLobShot}, "A_BRAKLOBSHOT"}, + {{A_NapalmScatter}, "A_NAPALMSCATTER"}, + {{A_SpawnFreshCopy}, "A_SPAWNFRESHCOPY"}, + {{A_FlickySpawn}, "A_FLICKYSPAWN"}, + {{A_FlickyCenter}, "A_FLICKYCENTER"}, + {{A_FlickyAim}, "A_FLICKYAIM"}, + {{A_FlickyFly}, "A_FLICKYFLY"}, + {{A_FlickySoar}, "A_FLICKYSOAR"}, + {{A_FlickyCoast}, "A_FLICKYCOAST"}, + {{A_FlickyHop}, "A_FLICKYHOP"}, + {{A_FlickyFlounder}, "A_FLICKYFLOUNDER"}, + {{A_FlickyCheck}, "A_FLICKYCHECK"}, + {{A_FlickyHeightCheck}, "A_FLICKYHEIGHTCHECK"}, + {{A_FlickyFlutter}, "A_FLICKYFLUTTER"}, + {{A_FlameParticle}, "A_FLAMEPARTICLE"}, + {{A_FadeOverlay}, "A_FADEOVERLAY"}, + {{A_Boss5Jump}, "A_BOSS5JUMP"}, + {{A_LightBeamReset}, "A_LIGHTBEAMRESET"}, + {{A_MineExplode}, "A_MINEEXPLODE"}, + {{A_MineRange}, "A_MINERANGE"}, + {{A_ConnectToGround}, "A_CONNECTTOGROUND"}, + {{A_SpawnParticleRelative}, "A_SPAWNPARTICLERELATIVE"}, + {{A_MultiShotDist}, "A_MULTISHOTDIST"}, + {{A_WhoCaresIfYourSonIsABee},"A_WHOCARESIFYOURSONISABEE"}, + {{A_ParentTriesToSleep}, "A_PARENTTRIESTOSLEEP"}, + {{A_CryingToMomma}, "A_CRYINGTOMOMMA"}, + {{A_CheckFlags2}, "A_CHECKFLAGS2"}, + {{A_Boss5FindWaypoint}, "A_BOSS5FINDWAYPOINT"}, + {{A_DoNPCSkid}, "A_DONPCSKID"}, + {{A_DoNPCPain}, "A_DONPCPAIN"}, + {{A_PrepareRepeat}, "A_PREPAREREPEAT"}, + {{A_Boss5ExtraRepeat}, "A_BOSS5EXTRAREPEAT"}, + {{A_Boss5Calm}, "A_BOSS5CALM"}, + {{A_Boss5CheckOnGround}, "A_BOSS5CHECKONGROUND"}, + {{A_Boss5CheckFalling}, "A_BOSS5CHECKFALLING"}, + {{A_Boss5PinchShot}, "A_BOSS5PINCHSHOT"}, + {{A_Boss5MakeItRain}, "A_BOSS5MAKEITRAIN"}, + {{A_Boss5MakeJunk}, "A_BOSS5MAKEJUNK"}, + {{A_LookForBetter}, "A_LOOKFORBETTER"}, + {{A_Boss5BombExplode}, "A_BOSS5BOMBEXPLODE"}, + {{A_DustDevilThink}, "A_DUSTDEVILTHINK"}, + {{A_TNTExplode}, "A_TNTEXPLODE"}, + {{A_DebrisRandom}, "A_DEBRISRANDOM"}, + {{A_TrainCameo}, "A_TRAINCAMEO"}, + {{A_TrainCameo2}, "A_TRAINCAMEO2"}, + {{A_CanarivoreGas}, "A_CANARIVOREGAS"}, + {{A_KillSegments}, "A_KILLSEGMENTS"}, + {{A_SnapperSpawn}, "A_SNAPPERSPAWN"}, + {{A_SnapperThinker}, "A_SNAPPERTHINKER"}, + {{A_SaloonDoorSpawn}, "A_SALOONDOORSPAWN"}, + {{A_MinecartSparkThink}, "A_MINECARTSPARKTHINK"}, + {{A_ModuloToState}, "A_MODULOTOSTATE"}, + {{A_LavafallRocks}, "A_LAVAFALLROCKS"}, + {{A_LavafallLava}, "A_LAVAFALLLAVA"}, + {{A_FallingLavaCheck}, "A_FALLINGLAVACHECK"}, + {{A_FireShrink}, "A_FIRESHRINK"}, + {{A_SpawnPterabytes}, "A_SPAWNPTERABYTES"}, + {{A_PterabyteHover}, "A_PTERABYTEHOVER"}, + {{A_RolloutSpawn}, "A_ROLLOUTSPAWN"}, + {{A_RolloutRock}, "A_ROLLOUTROCK"}, + {{A_DragonbomberSpawn}, "A_DRAGONBOMBERSPAWN"}, + {{A_DragonWing}, "A_DRAGONWING"}, + {{A_DragonSegment}, "A_DRAGONSEGMENT"}, + {{A_ChangeHeight}, "A_CHANGEHEIGHT"}, + {{NULL}, "NONE"}, + + // This NULL entry must be the last in the list + {{NULL}, NULL}, +}; + +//////////////////////////////////////////////////////////////////////////////// +// CRAZY LIST OF STATE NAMES AND ALL FROM HERE DOWN +// TODO: Make this all a seperate file or something, like part of info.c?? +// TODO: Read the list from a text lump in a WAD as necessary instead +// or something, don't just keep it all in memory like this. +// TODO: Make the lists public so we can start using actual mobj +// and state names in warning and error messages! :D + +// RegEx to generate this from info.h: ^\tS_([^,]+), --> \t"S_\1", +// I am leaving the prefixes solely for clarity to programmers, +// because sadly no one remembers this place while searching for full state names. +const char *const STATE_LIST[] = { // array length left dynamic for sanity testing later. + "S_NULL", + "S_UNKNOWN", + "S_INVISIBLE", // state for invisible sprite + + "S_SPAWNSTATE", + "S_SEESTATE", + "S_MELEESTATE", + "S_MISSILESTATE", + "S_DEATHSTATE", + "S_XDEATHSTATE", + "S_RAISESTATE", + + // Thok + "S_THOK", + + // Player + "S_PLAY_STND", + "S_PLAY_WAIT", + "S_PLAY_WALK", + "S_PLAY_SKID", + "S_PLAY_RUN", + "S_PLAY_DASH", + "S_PLAY_PAIN", + "S_PLAY_STUN", + "S_PLAY_DEAD", + "S_PLAY_DRWN", + "S_PLAY_ROLL", + "S_PLAY_GASP", + "S_PLAY_JUMP", + "S_PLAY_SPRING", + "S_PLAY_FALL", + "S_PLAY_EDGE", + "S_PLAY_RIDE", + + // CA2_SPINDASH + "S_PLAY_SPINDASH", + + // CA_FLY/SWIM + "S_PLAY_FLY", + "S_PLAY_SWIM", + "S_PLAY_FLY_TIRED", + + // CA_GLIDEANDCLIMB + "S_PLAY_GLIDE", + "S_PLAY_GLIDE_LANDING", + "S_PLAY_CLING", + "S_PLAY_CLIMB", + + // CA_FLOAT/CA_SLOWFALL + "S_PLAY_FLOAT", + "S_PLAY_FLOAT_RUN", + + // CA_BOUNCE + "S_PLAY_BOUNCE", + "S_PLAY_BOUNCE_LANDING", + + // CA2_GUNSLINGER + "S_PLAY_FIRE", + "S_PLAY_FIRE_FINISH", + + // CA_TWINSPIN + "S_PLAY_TWINSPIN", + + // CA2_MELEE + "S_PLAY_MELEE", + "S_PLAY_MELEE_FINISH", + "S_PLAY_MELEE_LANDING", + + // SF_SUPER + "S_PLAY_SUPER_TRANS1", + "S_PLAY_SUPER_TRANS2", + "S_PLAY_SUPER_TRANS3", + "S_PLAY_SUPER_TRANS4", + "S_PLAY_SUPER_TRANS5", + "S_PLAY_SUPER_TRANS6", + + // technically the player goes here but it's an infinite tic state + "S_OBJPLACE_DUMMY", + + // 1-Up Box Sprites overlay (uses player sprite) + "S_PLAY_BOX1", + "S_PLAY_BOX2", + "S_PLAY_ICON1", + "S_PLAY_ICON2", + "S_PLAY_ICON3", + + // Level end sign overlay (uses player sprite) + "S_PLAY_SIGN", + + // NiGHTS character (uses player sprite) + "S_PLAY_NIGHTS_TRANS1", + "S_PLAY_NIGHTS_TRANS2", + "S_PLAY_NIGHTS_TRANS3", + "S_PLAY_NIGHTS_TRANS4", + "S_PLAY_NIGHTS_TRANS5", + "S_PLAY_NIGHTS_TRANS6", + "S_PLAY_NIGHTS_STAND", + "S_PLAY_NIGHTS_FLOAT", + "S_PLAY_NIGHTS_FLY", + "S_PLAY_NIGHTS_DRILL", + "S_PLAY_NIGHTS_STUN", + "S_PLAY_NIGHTS_PULL", + "S_PLAY_NIGHTS_ATTACK", + + // c: + "S_TAILSOVERLAY_STAND", + "S_TAILSOVERLAY_0DEGREES", + "S_TAILSOVERLAY_PLUS30DEGREES", + "S_TAILSOVERLAY_PLUS60DEGREES", + "S_TAILSOVERLAY_MINUS30DEGREES", + "S_TAILSOVERLAY_MINUS60DEGREES", + "S_TAILSOVERLAY_RUN", + "S_TAILSOVERLAY_FLY", + "S_TAILSOVERLAY_TIRE", + "S_TAILSOVERLAY_PAIN", + "S_TAILSOVERLAY_GASP", + "S_TAILSOVERLAY_EDGE", + "S_TAILSOVERLAY_DASH", + + // [: + "S_JETFUMEFLASH", + + // Blue Crawla + "S_POSS_STND", + "S_POSS_RUN1", + "S_POSS_RUN2", + "S_POSS_RUN3", + "S_POSS_RUN4", + "S_POSS_RUN5", + "S_POSS_RUN6", + + // Red Crawla + "S_SPOS_STND", + "S_SPOS_RUN1", + "S_SPOS_RUN2", + "S_SPOS_RUN3", + "S_SPOS_RUN4", + "S_SPOS_RUN5", + "S_SPOS_RUN6", + + // Greenflower Fish + "S_FISH1", + "S_FISH2", + "S_FISH3", + "S_FISH4", + + // Buzz (Gold) + "S_BUZZLOOK1", + "S_BUZZLOOK2", + "S_BUZZFLY1", + "S_BUZZFLY2", + + // Buzz (Red) + "S_RBUZZLOOK1", + "S_RBUZZLOOK2", + "S_RBUZZFLY1", + "S_RBUZZFLY2", + + // Jetty-Syn Bomber + "S_JETBLOOK1", + "S_JETBLOOK2", + "S_JETBZOOM1", + "S_JETBZOOM2", + + // Jetty-Syn Gunner + "S_JETGLOOK1", + "S_JETGLOOK2", + "S_JETGZOOM1", + "S_JETGZOOM2", + "S_JETGSHOOT1", + "S_JETGSHOOT2", + + // Crawla Commander + "S_CCOMMAND1", + "S_CCOMMAND2", + "S_CCOMMAND3", + "S_CCOMMAND4", + + // Deton + "S_DETON1", + "S_DETON2", + "S_DETON3", + "S_DETON4", + "S_DETON5", + "S_DETON6", + "S_DETON7", + "S_DETON8", + "S_DETON9", + "S_DETON10", + "S_DETON11", + "S_DETON12", + "S_DETON13", + "S_DETON14", + "S_DETON15", + + // Skim Mine Dropper + "S_SKIM1", + "S_SKIM2", + "S_SKIM3", + "S_SKIM4", + + // THZ Turret + "S_TURRET", + "S_TURRETFIRE", + "S_TURRETSHOCK1", + "S_TURRETSHOCK2", + "S_TURRETSHOCK3", + "S_TURRETSHOCK4", + "S_TURRETSHOCK5", + "S_TURRETSHOCK6", + "S_TURRETSHOCK7", + "S_TURRETSHOCK8", + "S_TURRETSHOCK9", + + // Popup Turret + "S_TURRETLOOK", + "S_TURRETSEE", + "S_TURRETPOPUP1", + "S_TURRETPOPUP2", + "S_TURRETPOPUP3", + "S_TURRETPOPUP4", + "S_TURRETPOPUP5", + "S_TURRETPOPUP6", + "S_TURRETPOPUP7", + "S_TURRETPOPUP8", + "S_TURRETSHOOT", + "S_TURRETPOPDOWN1", + "S_TURRETPOPDOWN2", + "S_TURRETPOPDOWN3", + "S_TURRETPOPDOWN4", + "S_TURRETPOPDOWN5", + "S_TURRETPOPDOWN6", + "S_TURRETPOPDOWN7", + "S_TURRETPOPDOWN8", + + // Spincushion + "S_SPINCUSHION_LOOK", + "S_SPINCUSHION_CHASE1", + "S_SPINCUSHION_CHASE2", + "S_SPINCUSHION_CHASE3", + "S_SPINCUSHION_CHASE4", + "S_SPINCUSHION_AIM1", + "S_SPINCUSHION_AIM2", + "S_SPINCUSHION_AIM3", + "S_SPINCUSHION_AIM4", + "S_SPINCUSHION_AIM5", + "S_SPINCUSHION_SPIN1", + "S_SPINCUSHION_SPIN2", + "S_SPINCUSHION_SPIN3", + "S_SPINCUSHION_SPIN4", + "S_SPINCUSHION_STOP1", + "S_SPINCUSHION_STOP2", + "S_SPINCUSHION_STOP3", + "S_SPINCUSHION_STOP4", + + // Crushstacean + "S_CRUSHSTACEAN_ROAM1", + "S_CRUSHSTACEAN_ROAM2", + "S_CRUSHSTACEAN_ROAM3", + "S_CRUSHSTACEAN_ROAM4", + "S_CRUSHSTACEAN_ROAMPAUSE", + "S_CRUSHSTACEAN_PUNCH1", + "S_CRUSHSTACEAN_PUNCH2", + "S_CRUSHCLAW_AIM", + "S_CRUSHCLAW_OUT", + "S_CRUSHCLAW_STAY", + "S_CRUSHCLAW_IN", + "S_CRUSHCLAW_WAIT", + "S_CRUSHCHAIN", + + // Banpyura + "S_BANPYURA_ROAM1", + "S_BANPYURA_ROAM2", + "S_BANPYURA_ROAM3", + "S_BANPYURA_ROAM4", + "S_BANPYURA_ROAMPAUSE", + "S_CDIAG1", + "S_CDIAG2", + "S_CDIAG3", + "S_CDIAG4", + "S_CDIAG5", + "S_CDIAG6", + "S_CDIAG7", + "S_CDIAG8", + + // Jet Jaw + "S_JETJAW_ROAM1", + "S_JETJAW_ROAM2", + "S_JETJAW_ROAM3", + "S_JETJAW_ROAM4", + "S_JETJAW_ROAM5", + "S_JETJAW_ROAM6", + "S_JETJAW_ROAM7", + "S_JETJAW_ROAM8", + "S_JETJAW_CHOMP1", + "S_JETJAW_CHOMP2", + "S_JETJAW_CHOMP3", + "S_JETJAW_CHOMP4", + "S_JETJAW_CHOMP5", + "S_JETJAW_CHOMP6", + "S_JETJAW_CHOMP7", + "S_JETJAW_CHOMP8", + "S_JETJAW_CHOMP9", + "S_JETJAW_CHOMP10", + "S_JETJAW_CHOMP11", + "S_JETJAW_CHOMP12", + "S_JETJAW_CHOMP13", + "S_JETJAW_CHOMP14", + "S_JETJAW_CHOMP15", + "S_JETJAW_CHOMP16", + "S_JETJAW_SOUND", + + // Snailer + "S_SNAILER1", + "S_SNAILER_FLICKY", + + // Vulture + "S_VULTURE_STND", + "S_VULTURE_DRIFT", + "S_VULTURE_ZOOM1", + "S_VULTURE_ZOOM2", + "S_VULTURE_STUNNED", + + // Pointy + "S_POINTY1", + "S_POINTYBALL1", + + // Robo-Hood + "S_ROBOHOOD_LOOK", + "S_ROBOHOOD_STAND", + "S_ROBOHOOD_FIRE1", + "S_ROBOHOOD_FIRE2", + "S_ROBOHOOD_JUMP1", + "S_ROBOHOOD_JUMP2", + "S_ROBOHOOD_JUMP3", + + // Castlebot Facestabber + "S_FACESTABBER_STND1", + "S_FACESTABBER_STND2", + "S_FACESTABBER_STND3", + "S_FACESTABBER_STND4", + "S_FACESTABBER_STND5", + "S_FACESTABBER_STND6", + "S_FACESTABBER_CHARGE1", + "S_FACESTABBER_CHARGE2", + "S_FACESTABBER_CHARGE3", + "S_FACESTABBER_CHARGE4", + "S_FACESTABBER_PAIN", + "S_FACESTABBER_DIE1", + "S_FACESTABBER_DIE2", + "S_FACESTABBER_DIE3", + "S_FACESTABBERSPEAR", + + // Egg Guard + "S_EGGGUARD_STND", + "S_EGGGUARD_WALK1", + "S_EGGGUARD_WALK2", + "S_EGGGUARD_WALK3", + "S_EGGGUARD_WALK4", + "S_EGGGUARD_MAD1", + "S_EGGGUARD_MAD2", + "S_EGGGUARD_MAD3", + "S_EGGGUARD_RUN1", + "S_EGGGUARD_RUN2", + "S_EGGGUARD_RUN3", + "S_EGGGUARD_RUN4", + + // Egg Shield for Egg Guard + "S_EGGSHIELD", + "S_EGGSHIELDBREAK", + + // Green Snapper + "S_SNAPPER_SPAWN", + "S_SNAPPER_SPAWN2", + "S_GSNAPPER_STND", + "S_GSNAPPER1", + "S_GSNAPPER2", + "S_GSNAPPER3", + "S_GSNAPPER4", + "S_SNAPPER_XPLD", + "S_SNAPPER_LEG", + "S_SNAPPER_LEGRAISE", + "S_SNAPPER_HEAD", + + // Minus + "S_MINUS_INIT", + "S_MINUS_STND", + "S_MINUS_DIGGING1", + "S_MINUS_DIGGING2", + "S_MINUS_DIGGING3", + "S_MINUS_DIGGING4", + "S_MINUS_BURST0", + "S_MINUS_BURST1", + "S_MINUS_BURST2", + "S_MINUS_BURST3", + "S_MINUS_BURST4", + "S_MINUS_BURST5", + "S_MINUS_POPUP", + "S_MINUS_AERIAL1", + "S_MINUS_AERIAL2", + "S_MINUS_AERIAL3", + "S_MINUS_AERIAL4", + + // Minus dirt + "S_MINUSDIRT1", + "S_MINUSDIRT2", + "S_MINUSDIRT3", + "S_MINUSDIRT4", + "S_MINUSDIRT5", + "S_MINUSDIRT6", + "S_MINUSDIRT7", + + // Spring Shell + "S_SSHELL_STND", + "S_SSHELL_RUN1", + "S_SSHELL_RUN2", + "S_SSHELL_RUN3", + "S_SSHELL_RUN4", + "S_SSHELL_SPRING1", + "S_SSHELL_SPRING2", + "S_SSHELL_SPRING3", + "S_SSHELL_SPRING4", + + // Spring Shell (yellow) + "S_YSHELL_STND", + "S_YSHELL_RUN1", + "S_YSHELL_RUN2", + "S_YSHELL_RUN3", + "S_YSHELL_RUN4", + "S_YSHELL_SPRING1", + "S_YSHELL_SPRING2", + "S_YSHELL_SPRING3", + "S_YSHELL_SPRING4", + + // Unidus + "S_UNIDUS_STND", + "S_UNIDUS_RUN", + "S_UNIDUS_BALL", + + // Canarivore + "S_CANARIVORE_LOOK", + "S_CANARIVORE_AWAKEN1", + "S_CANARIVORE_AWAKEN2", + "S_CANARIVORE_AWAKEN3", + "S_CANARIVORE_GAS1", + "S_CANARIVORE_GAS2", + "S_CANARIVORE_GAS3", + "S_CANARIVORE_GAS4", + "S_CANARIVORE_GAS5", + "S_CANARIVORE_GASREPEAT", + "S_CANARIVORE_CLOSE1", + "S_CANARIVORE_CLOSE2", + "S_CANARIVOREGAS_1", + "S_CANARIVOREGAS_2", + "S_CANARIVOREGAS_3", + "S_CANARIVOREGAS_4", + "S_CANARIVOREGAS_5", + "S_CANARIVOREGAS_6", + "S_CANARIVOREGAS_7", + "S_CANARIVOREGAS_8", + + // Pyre Fly + "S_PYREFLY_FLY", + "S_PYREFLY_BURN", + "S_PYREFIRE1", + "S_PYREFIRE2", + + // Pterabyte + "S_PTERABYTESPAWNER", + "S_PTERABYTEWAYPOINT", + "S_PTERABYTE_FLY1", + "S_PTERABYTE_FLY2", + "S_PTERABYTE_FLY3", + "S_PTERABYTE_FLY4", + "S_PTERABYTE_SWOOPDOWN", + "S_PTERABYTE_SWOOPUP", + + // Dragonbomber + "S_DRAGONBOMBER", + "S_DRAGONWING1", + "S_DRAGONWING2", + "S_DRAGONWING3", + "S_DRAGONWING4", + "S_DRAGONTAIL_LOADED", + "S_DRAGONTAIL_EMPTY", + "S_DRAGONTAIL_EMPTYLOOP", + "S_DRAGONTAIL_RELOAD", + "S_DRAGONMINE", + "S_DRAGONMINE_LAND1", + "S_DRAGONMINE_LAND2", + "S_DRAGONMINE_SLOWFLASH1", + "S_DRAGONMINE_SLOWFLASH2", + "S_DRAGONMINE_SLOWLOOP", + "S_DRAGONMINE_FASTFLASH1", + "S_DRAGONMINE_FASTFLASH2", + "S_DRAGONMINE_FASTLOOP", + + // Boss Explosion + "S_BOSSEXPLODE", + + // S3&K Boss Explosion + "S_SONIC3KBOSSEXPLOSION1", + "S_SONIC3KBOSSEXPLOSION2", + "S_SONIC3KBOSSEXPLOSION3", + "S_SONIC3KBOSSEXPLOSION4", + "S_SONIC3KBOSSEXPLOSION5", + "S_SONIC3KBOSSEXPLOSION6", + + "S_JETFUME1", + + // Boss 1 + "S_EGGMOBILE_STND", + "S_EGGMOBILE_ROFL", + "S_EGGMOBILE_LATK1", + "S_EGGMOBILE_LATK2", + "S_EGGMOBILE_LATK3", + "S_EGGMOBILE_LATK4", + "S_EGGMOBILE_LATK5", + "S_EGGMOBILE_LATK6", + "S_EGGMOBILE_LATK7", + "S_EGGMOBILE_LATK8", + "S_EGGMOBILE_LATK9", + "S_EGGMOBILE_RATK1", + "S_EGGMOBILE_RATK2", + "S_EGGMOBILE_RATK3", + "S_EGGMOBILE_RATK4", + "S_EGGMOBILE_RATK5", + "S_EGGMOBILE_RATK6", + "S_EGGMOBILE_RATK7", + "S_EGGMOBILE_RATK8", + "S_EGGMOBILE_RATK9", + "S_EGGMOBILE_PANIC1", + "S_EGGMOBILE_PANIC2", + "S_EGGMOBILE_PANIC3", + "S_EGGMOBILE_PANIC4", + "S_EGGMOBILE_PANIC5", + "S_EGGMOBILE_PANIC6", + "S_EGGMOBILE_PANIC7", + "S_EGGMOBILE_PANIC8", + "S_EGGMOBILE_PANIC9", + "S_EGGMOBILE_PANIC10", + "S_EGGMOBILE_PANIC11", + "S_EGGMOBILE_PANIC12", + "S_EGGMOBILE_PANIC13", + "S_EGGMOBILE_PANIC14", + "S_EGGMOBILE_PANIC15", + "S_EGGMOBILE_PAIN", + "S_EGGMOBILE_PAIN2", + "S_EGGMOBILE_DIE1", + "S_EGGMOBILE_DIE2", + "S_EGGMOBILE_DIE3", + "S_EGGMOBILE_DIE4", + "S_EGGMOBILE_FLEE1", + "S_EGGMOBILE_FLEE2", + "S_EGGMOBILE_BALL", + "S_EGGMOBILE_TARGET", + + "S_BOSSEGLZ1", + "S_BOSSEGLZ2", + + // Boss 2 + "S_EGGMOBILE2_STND", + "S_EGGMOBILE2_POGO1", + "S_EGGMOBILE2_POGO2", + "S_EGGMOBILE2_POGO3", + "S_EGGMOBILE2_POGO4", + "S_EGGMOBILE2_POGO5", + "S_EGGMOBILE2_POGO6", + "S_EGGMOBILE2_POGO7", + "S_EGGMOBILE2_PAIN", + "S_EGGMOBILE2_PAIN2", + "S_EGGMOBILE2_DIE1", + "S_EGGMOBILE2_DIE2", + "S_EGGMOBILE2_DIE3", + "S_EGGMOBILE2_DIE4", + "S_EGGMOBILE2_FLEE1", + "S_EGGMOBILE2_FLEE2", + + "S_BOSSTANK1", + "S_BOSSTANK2", + "S_BOSSSPIGOT", + + // Boss 2 Goop + "S_GOOP1", + "S_GOOP2", + "S_GOOP3", + "S_GOOPTRAIL", + + // Boss 3 + "S_EGGMOBILE3_STND", + "S_EGGMOBILE3_SHOCK", + "S_EGGMOBILE3_ATK1", + "S_EGGMOBILE3_ATK2", + "S_EGGMOBILE3_ATK3A", + "S_EGGMOBILE3_ATK3B", + "S_EGGMOBILE3_ATK3C", + "S_EGGMOBILE3_ATK3D", + "S_EGGMOBILE3_ATK4", + "S_EGGMOBILE3_ATK5", + "S_EGGMOBILE3_ROFL", + "S_EGGMOBILE3_PAIN", + "S_EGGMOBILE3_PAIN2", + "S_EGGMOBILE3_DIE1", + "S_EGGMOBILE3_DIE2", + "S_EGGMOBILE3_DIE3", + "S_EGGMOBILE3_DIE4", + "S_EGGMOBILE3_FLEE1", + "S_EGGMOBILE3_FLEE2", + + // Boss 3 Pinch + "S_FAKEMOBILE_INIT", + "S_FAKEMOBILE", + "S_FAKEMOBILE_ATK1", + "S_FAKEMOBILE_ATK2", + "S_FAKEMOBILE_ATK3A", + "S_FAKEMOBILE_ATK3B", + "S_FAKEMOBILE_ATK3C", + "S_FAKEMOBILE_ATK3D", + "S_FAKEMOBILE_DIE1", + "S_FAKEMOBILE_DIE2", + + "S_BOSSSEBH1", + "S_BOSSSEBH2", + + // Boss 3 Shockwave + "S_SHOCKWAVE1", + "S_SHOCKWAVE2", + + // Boss 4 + "S_EGGMOBILE4_STND", + "S_EGGMOBILE4_LATK1", + "S_EGGMOBILE4_LATK2", + "S_EGGMOBILE4_LATK3", + "S_EGGMOBILE4_LATK4", + "S_EGGMOBILE4_LATK5", + "S_EGGMOBILE4_LATK6", + "S_EGGMOBILE4_RATK1", + "S_EGGMOBILE4_RATK2", + "S_EGGMOBILE4_RATK3", + "S_EGGMOBILE4_RATK4", + "S_EGGMOBILE4_RATK5", + "S_EGGMOBILE4_RATK6", + "S_EGGMOBILE4_RAISE1", + "S_EGGMOBILE4_RAISE2", + "S_EGGMOBILE4_PAIN1", + "S_EGGMOBILE4_PAIN2", + "S_EGGMOBILE4_DIE1", + "S_EGGMOBILE4_DIE2", + "S_EGGMOBILE4_DIE3", + "S_EGGMOBILE4_DIE4", + "S_EGGMOBILE4_FLEE1", + "S_EGGMOBILE4_FLEE2", + "S_EGGMOBILE4_MACE", + "S_EGGMOBILE4_MACE_DIE1", + "S_EGGMOBILE4_MACE_DIE2", + "S_EGGMOBILE4_MACE_DIE3", + + // Boss 4 jet flame + "S_JETFLAME", + + // Boss 4 Spectator Eggrobo + "S_EGGROBO1_STND", + "S_EGGROBO1_BSLAP1", + "S_EGGROBO1_BSLAP2", + "S_EGGROBO1_PISSED", + + // Boss 4 Spectator Eggrobo jet flame + "S_EGGROBOJET", + + // Boss 5 + "S_FANG_SETUP", + "S_FANG_INTRO0", + "S_FANG_INTRO1", + "S_FANG_INTRO2", + "S_FANG_INTRO3", + "S_FANG_INTRO4", + "S_FANG_INTRO5", + "S_FANG_INTRO6", + "S_FANG_INTRO7", + "S_FANG_INTRO8", + "S_FANG_INTRO9", + "S_FANG_INTRO10", + "S_FANG_INTRO11", + "S_FANG_INTRO12", + "S_FANG_CLONE1", + "S_FANG_CLONE2", + "S_FANG_CLONE3", + "S_FANG_CLONE4", + "S_FANG_IDLE0", + "S_FANG_IDLE1", + "S_FANG_IDLE2", + "S_FANG_IDLE3", + "S_FANG_IDLE4", + "S_FANG_IDLE5", + "S_FANG_IDLE6", + "S_FANG_IDLE7", + "S_FANG_IDLE8", + "S_FANG_PAIN1", + "S_FANG_PAIN2", + "S_FANG_PATHINGSTART1", + "S_FANG_PATHINGSTART2", + "S_FANG_PATHING", + "S_FANG_BOUNCE1", + "S_FANG_BOUNCE2", + "S_FANG_BOUNCE3", + "S_FANG_BOUNCE4", + "S_FANG_FALL1", + "S_FANG_FALL2", + "S_FANG_CHECKPATH1", + "S_FANG_CHECKPATH2", + "S_FANG_PATHINGCONT1", + "S_FANG_PATHINGCONT2", + "S_FANG_PATHINGCONT3", + "S_FANG_SKID1", + "S_FANG_SKID2", + "S_FANG_SKID3", + "S_FANG_CHOOSEATTACK", + "S_FANG_FIRESTART1", + "S_FANG_FIRESTART2", + "S_FANG_FIRE1", + "S_FANG_FIRE2", + "S_FANG_FIRE3", + "S_FANG_FIRE4", + "S_FANG_FIREREPEAT", + "S_FANG_LOBSHOT0", + "S_FANG_LOBSHOT1", + "S_FANG_LOBSHOT2", + "S_FANG_WAIT1", + "S_FANG_WAIT2", + "S_FANG_WALLHIT", + "S_FANG_PINCHPATHINGSTART1", + "S_FANG_PINCHPATHINGSTART2", + "S_FANG_PINCHPATHING", + "S_FANG_PINCHBOUNCE0", + "S_FANG_PINCHBOUNCE1", + "S_FANG_PINCHBOUNCE2", + "S_FANG_PINCHBOUNCE3", + "S_FANG_PINCHBOUNCE4", + "S_FANG_PINCHFALL0", + "S_FANG_PINCHFALL1", + "S_FANG_PINCHFALL2", + "S_FANG_PINCHSKID1", + "S_FANG_PINCHSKID2", + "S_FANG_PINCHLOBSHOT0", + "S_FANG_PINCHLOBSHOT1", + "S_FANG_PINCHLOBSHOT2", + "S_FANG_PINCHLOBSHOT3", + "S_FANG_PINCHLOBSHOT4", + "S_FANG_DIE1", + "S_FANG_DIE2", + "S_FANG_DIE3", + "S_FANG_DIE4", + "S_FANG_DIE5", + "S_FANG_DIE6", + "S_FANG_DIE7", + "S_FANG_DIE8", + "S_FANG_FLEEPATHING1", + "S_FANG_FLEEPATHING2", + "S_FANG_FLEEBOUNCE1", + "S_FANG_FLEEBOUNCE2", + "S_FANG_KO", + + "S_BROKENROBOTRANDOM", + "S_BROKENROBOTA", + "S_BROKENROBOTB", + "S_BROKENROBOTC", + "S_BROKENROBOTD", + "S_BROKENROBOTE", + "S_BROKENROBOTF", + + "S_ALART1", + "S_ALART2", + + "S_VWREF", + "S_VWREB", + + "S_PROJECTORLIGHT1", + "S_PROJECTORLIGHT2", + "S_PROJECTORLIGHT3", + "S_PROJECTORLIGHT4", + "S_PROJECTORLIGHT5", + + "S_FBOMB1", + "S_FBOMB2", + "S_FBOMB_EXPL1", + "S_FBOMB_EXPL2", + "S_FBOMB_EXPL3", + "S_FBOMB_EXPL4", + "S_FBOMB_EXPL5", + "S_FBOMB_EXPL6", + "S_TNTDUST_1", + "S_TNTDUST_2", + "S_TNTDUST_3", + "S_TNTDUST_4", + "S_TNTDUST_5", + "S_TNTDUST_6", + "S_TNTDUST_7", + "S_TNTDUST_8", + "S_FSGNA", + "S_FSGNB", + "S_FSGNC", + "S_FSGND", + + // Black Eggman (Boss 7) + "S_BLACKEGG_STND", + "S_BLACKEGG_STND2", + "S_BLACKEGG_WALK1", + "S_BLACKEGG_WALK2", + "S_BLACKEGG_WALK3", + "S_BLACKEGG_WALK4", + "S_BLACKEGG_WALK5", + "S_BLACKEGG_WALK6", + "S_BLACKEGG_SHOOT1", + "S_BLACKEGG_SHOOT2", + "S_BLACKEGG_PAIN1", + "S_BLACKEGG_PAIN2", + "S_BLACKEGG_PAIN3", + "S_BLACKEGG_PAIN4", + "S_BLACKEGG_PAIN5", + "S_BLACKEGG_PAIN6", + "S_BLACKEGG_PAIN7", + "S_BLACKEGG_PAIN8", + "S_BLACKEGG_PAIN9", + "S_BLACKEGG_PAIN10", + "S_BLACKEGG_PAIN11", + "S_BLACKEGG_PAIN12", + "S_BLACKEGG_PAIN13", + "S_BLACKEGG_PAIN14", + "S_BLACKEGG_PAIN15", + "S_BLACKEGG_PAIN16", + "S_BLACKEGG_PAIN17", + "S_BLACKEGG_PAIN18", + "S_BLACKEGG_PAIN19", + "S_BLACKEGG_PAIN20", + "S_BLACKEGG_PAIN21", + "S_BLACKEGG_PAIN22", + "S_BLACKEGG_PAIN23", + "S_BLACKEGG_PAIN24", + "S_BLACKEGG_PAIN25", + "S_BLACKEGG_PAIN26", + "S_BLACKEGG_PAIN27", + "S_BLACKEGG_PAIN28", + "S_BLACKEGG_PAIN29", + "S_BLACKEGG_PAIN30", + "S_BLACKEGG_PAIN31", + "S_BLACKEGG_PAIN32", + "S_BLACKEGG_PAIN33", + "S_BLACKEGG_PAIN34", + "S_BLACKEGG_PAIN35", + "S_BLACKEGG_HITFACE1", + "S_BLACKEGG_HITFACE2", + "S_BLACKEGG_HITFACE3", + "S_BLACKEGG_HITFACE4", + "S_BLACKEGG_DIE1", + "S_BLACKEGG_DIE2", + "S_BLACKEGG_DIE3", + "S_BLACKEGG_DIE4", + "S_BLACKEGG_DIE5", + "S_BLACKEGG_MISSILE1", + "S_BLACKEGG_MISSILE2", + "S_BLACKEGG_MISSILE3", + "S_BLACKEGG_GOOP", + "S_BLACKEGG_JUMP1", + "S_BLACKEGG_JUMP2", + "S_BLACKEGG_DESTROYPLAT1", + "S_BLACKEGG_DESTROYPLAT2", + "S_BLACKEGG_DESTROYPLAT3", + + "S_BLACKEGG_HELPER", // Collision helper + + "S_BLACKEGG_GOOP1", + "S_BLACKEGG_GOOP2", + "S_BLACKEGG_GOOP3", + "S_BLACKEGG_GOOP4", + "S_BLACKEGG_GOOP5", + "S_BLACKEGG_GOOP6", + "S_BLACKEGG_GOOP7", + + "S_BLACKEGG_MISSILE", + + // New Very-Last-Minute 2.1 Brak Eggman (Cy-Brak-demon) + "S_CYBRAKDEMON_IDLE", + "S_CYBRAKDEMON_WALK1", + "S_CYBRAKDEMON_WALK2", + "S_CYBRAKDEMON_WALK3", + "S_CYBRAKDEMON_WALK4", + "S_CYBRAKDEMON_WALK5", + "S_CYBRAKDEMON_WALK6", + "S_CYBRAKDEMON_CHOOSE_ATTACK1", + "S_CYBRAKDEMON_MISSILE_ATTACK1", // Aim + "S_CYBRAKDEMON_MISSILE_ATTACK2", // Fire + "S_CYBRAKDEMON_MISSILE_ATTACK3", // Aim + "S_CYBRAKDEMON_MISSILE_ATTACK4", // Fire + "S_CYBRAKDEMON_MISSILE_ATTACK5", // Aim + "S_CYBRAKDEMON_MISSILE_ATTACK6", // Fire + "S_CYBRAKDEMON_FLAME_ATTACK1", // Reset + "S_CYBRAKDEMON_FLAME_ATTACK2", // Aim + "S_CYBRAKDEMON_FLAME_ATTACK3", // Fire + "S_CYBRAKDEMON_FLAME_ATTACK4", // Loop + "S_CYBRAKDEMON_CHOOSE_ATTACK2", + "S_CYBRAKDEMON_VILE_ATTACK1", + "S_CYBRAKDEMON_VILE_ATTACK2", + "S_CYBRAKDEMON_VILE_ATTACK3", + "S_CYBRAKDEMON_VILE_ATTACK4", + "S_CYBRAKDEMON_VILE_ATTACK5", + "S_CYBRAKDEMON_VILE_ATTACK6", + "S_CYBRAKDEMON_NAPALM_ATTACK1", + "S_CYBRAKDEMON_NAPALM_ATTACK2", + "S_CYBRAKDEMON_NAPALM_ATTACK3", + "S_CYBRAKDEMON_FINISH_ATTACK1", // If just attacked, remove MF2_FRET w/out going back to spawnstate + "S_CYBRAKDEMON_FINISH_ATTACK2", // Force a delay between attacks so you don't get bombarded with them back-to-back + "S_CYBRAKDEMON_PAIN1", + "S_CYBRAKDEMON_PAIN2", + "S_CYBRAKDEMON_PAIN3", + "S_CYBRAKDEMON_DIE1", + "S_CYBRAKDEMON_DIE2", + "S_CYBRAKDEMON_DIE3", + "S_CYBRAKDEMON_DIE4", + "S_CYBRAKDEMON_DIE5", + "S_CYBRAKDEMON_DIE6", + "S_CYBRAKDEMON_DIE7", + "S_CYBRAKDEMON_DIE8", + "S_CYBRAKDEMON_DEINVINCIBLERIZE", + "S_CYBRAKDEMON_INVINCIBLERIZE", + + "S_CYBRAKDEMONMISSILE", + "S_CYBRAKDEMONMISSILE_EXPLODE1", + "S_CYBRAKDEMONMISSILE_EXPLODE2", + "S_CYBRAKDEMONMISSILE_EXPLODE3", + + "S_CYBRAKDEMONFLAMESHOT_FLY1", + "S_CYBRAKDEMONFLAMESHOT_FLY2", + "S_CYBRAKDEMONFLAMESHOT_FLY3", + "S_CYBRAKDEMONFLAMESHOT_DIE", + + "S_CYBRAKDEMONFLAMEREST", + + "S_CYBRAKDEMONELECTRICBARRIER_INIT1", + "S_CYBRAKDEMONELECTRICBARRIER_INIT2", + "S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND", + "S_CYBRAKDEMONELECTRICBARRIER1", + "S_CYBRAKDEMONELECTRICBARRIER2", + "S_CYBRAKDEMONELECTRICBARRIER3", + "S_CYBRAKDEMONELECTRICBARRIER4", + "S_CYBRAKDEMONELECTRICBARRIER5", + "S_CYBRAKDEMONELECTRICBARRIER6", + "S_CYBRAKDEMONELECTRICBARRIER7", + "S_CYBRAKDEMONELECTRICBARRIER8", + "S_CYBRAKDEMONELECTRICBARRIER9", + "S_CYBRAKDEMONELECTRICBARRIER10", + "S_CYBRAKDEMONELECTRICBARRIER11", + "S_CYBRAKDEMONELECTRICBARRIER12", + "S_CYBRAKDEMONELECTRICBARRIER13", + "S_CYBRAKDEMONELECTRICBARRIER14", + "S_CYBRAKDEMONELECTRICBARRIER15", + "S_CYBRAKDEMONELECTRICBARRIER16", + "S_CYBRAKDEMONELECTRICBARRIER17", + "S_CYBRAKDEMONELECTRICBARRIER18", + "S_CYBRAKDEMONELECTRICBARRIER19", + "S_CYBRAKDEMONELECTRICBARRIER20", + "S_CYBRAKDEMONELECTRICBARRIER21", + "S_CYBRAKDEMONELECTRICBARRIER22", + "S_CYBRAKDEMONELECTRICBARRIER23", + "S_CYBRAKDEMONELECTRICBARRIER24", + "S_CYBRAKDEMONELECTRICBARRIER_DIE1", + "S_CYBRAKDEMONELECTRICBARRIER_DIE2", + "S_CYBRAKDEMONELECTRICBARRIER_DIE3", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHOOSE", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM2", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM3", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM4", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM5", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM6", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM7", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM8", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM9", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM10", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM11", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM12", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMFAIL", + "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP", + "S_CYBRAKDEMONELECTRICBARRIER_REVIVE1", + "S_CYBRAKDEMONELECTRICBARRIER_REVIVE2", + "S_CYBRAKDEMONELECTRICBARRIER_REVIVE3", + + "S_CYBRAKDEMONTARGETRETICULE1", + "S_CYBRAKDEMONTARGETRETICULE2", + "S_CYBRAKDEMONTARGETRETICULE3", + "S_CYBRAKDEMONTARGETRETICULE4", + "S_CYBRAKDEMONTARGETRETICULE5", + "S_CYBRAKDEMONTARGETRETICULE6", + "S_CYBRAKDEMONTARGETRETICULE7", + "S_CYBRAKDEMONTARGETRETICULE8", + "S_CYBRAKDEMONTARGETRETICULE9", + "S_CYBRAKDEMONTARGETRETICULE10", + "S_CYBRAKDEMONTARGETRETICULE11", + "S_CYBRAKDEMONTARGETRETICULE12", + "S_CYBRAKDEMONTARGETRETICULE13", + "S_CYBRAKDEMONTARGETRETICULE14", + + "S_CYBRAKDEMONTARGETDOT", + + "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1", + "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2", + "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3", + "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4", + "S_CYBRAKDEMONNAPALMBOMBLARGE_DIE1", // Explode + "S_CYBRAKDEMONNAPALMBOMBLARGE_DIE2", // Outer ring + "S_CYBRAKDEMONNAPALMBOMBLARGE_DIE3", // Center + "S_CYBRAKDEMONNAPALMBOMBLARGE_DIE4", // Sound + + "S_CYBRAKDEMONNAPALMBOMBSMALL", + "S_CYBRAKDEMONNAPALMBOMBSMALL_DIE1", // Explode + "S_CYBRAKDEMONNAPALMBOMBSMALL_DIE2", // Outer ring + "S_CYBRAKDEMONNAPALMBOMBSMALL_DIE3", // Inner ring + "S_CYBRAKDEMONNAPALMBOMBSMALL_DIE4", // Center + "S_CYBRAKDEMONNAPALMBOMBSMALL_DIE5", // Sound + + "S_CYBRAKDEMONNAPALMFLAME_FLY1", + "S_CYBRAKDEMONNAPALMFLAME_FLY2", + "S_CYBRAKDEMONNAPALMFLAME_FLY3", + "S_CYBRAKDEMONNAPALMFLAME_FLY4", + "S_CYBRAKDEMONNAPALMFLAME_FLY5", + "S_CYBRAKDEMONNAPALMFLAME_FLY6", + "S_CYBRAKDEMONNAPALMFLAME_DIE", + + "S_CYBRAKDEMONVILEEXPLOSION1", + "S_CYBRAKDEMONVILEEXPLOSION2", + "S_CYBRAKDEMONVILEEXPLOSION3", + + // Metal Sonic (Race) + "S_METALSONIC_RACE", + // Metal Sonic (Battle) + "S_METALSONIC_FLOAT", + "S_METALSONIC_VECTOR", + "S_METALSONIC_STUN", + "S_METALSONIC_RAISE", + "S_METALSONIC_GATHER", + "S_METALSONIC_DASH", + "S_METALSONIC_BOUNCE", + "S_METALSONIC_BADBOUNCE", + "S_METALSONIC_SHOOT", + "S_METALSONIC_PAIN", + "S_METALSONIC_DEATH1", + "S_METALSONIC_DEATH2", + "S_METALSONIC_DEATH3", + "S_METALSONIC_DEATH4", + "S_METALSONIC_FLEE1", + "S_METALSONIC_FLEE2", + + "S_MSSHIELD_F1", + "S_MSSHIELD_F2", + + // Ring + "S_RING", + + // Blue Sphere for special stages + "S_BLUESPHERE", + "S_BLUESPHEREBONUS", + "S_BLUESPHERESPARK", + + // Bomb Sphere + "S_BOMBSPHERE1", + "S_BOMBSPHERE2", + "S_BOMBSPHERE3", + "S_BOMBSPHERE4", + + // NiGHTS Chip + "S_NIGHTSCHIP", + "S_NIGHTSCHIPBONUS", + + // NiGHTS Star + "S_NIGHTSSTAR", + "S_NIGHTSSTARXMAS", + + // Gravity Wells for special stages + "S_GRAVWELLGREEN", + "S_GRAVWELLRED", + + // Individual Team Rings + "S_TEAMRING", + + // Special Stage Token + "S_TOKEN", + + // CTF Flags + "S_REDFLAG", + "S_BLUEFLAG", + + // Emblem + "S_EMBLEM1", + "S_EMBLEM2", + "S_EMBLEM3", + "S_EMBLEM4", + "S_EMBLEM5", + "S_EMBLEM6", + "S_EMBLEM7", + "S_EMBLEM8", + "S_EMBLEM9", + "S_EMBLEM10", + "S_EMBLEM11", + "S_EMBLEM12", + "S_EMBLEM13", + "S_EMBLEM14", + "S_EMBLEM15", + "S_EMBLEM16", + "S_EMBLEM17", + "S_EMBLEM18", + "S_EMBLEM19", + "S_EMBLEM20", + "S_EMBLEM21", + "S_EMBLEM22", + "S_EMBLEM23", + "S_EMBLEM24", + "S_EMBLEM25", + "S_EMBLEM26", + + // Chaos Emeralds + "S_CEMG1", + "S_CEMG2", + "S_CEMG3", + "S_CEMG4", + "S_CEMG5", + "S_CEMG6", + "S_CEMG7", + + // Emerald hunt shards + "S_SHRD1", + "S_SHRD2", + "S_SHRD3", + + // Bubble Source + "S_BUBBLES1", + "S_BUBBLES2", + "S_BUBBLES3", + "S_BUBBLES4", + + // Level End Sign + "S_SIGN", + "S_SIGNSPIN1", + "S_SIGNSPIN2", + "S_SIGNSPIN3", + "S_SIGNSPIN4", + "S_SIGNSPIN5", + "S_SIGNSPIN6", + "S_SIGNPLAYER", + "S_SIGNSLOW", + "S_SIGNSTOP", + "S_SIGNBOARD", + "S_EGGMANSIGN", + "S_CLEARSIGN", + + // Spike Ball + "S_SPIKEBALL1", + "S_SPIKEBALL2", + "S_SPIKEBALL3", + "S_SPIKEBALL4", + "S_SPIKEBALL5", + "S_SPIKEBALL6", + "S_SPIKEBALL7", + "S_SPIKEBALL8", + + // Elemental Shield's Spawn + "S_SPINFIRE1", + "S_SPINFIRE2", + "S_SPINFIRE3", + "S_SPINFIRE4", + "S_SPINFIRE5", + "S_SPINFIRE6", + + // Spikes + "S_SPIKE1", + "S_SPIKE2", + "S_SPIKE3", + "S_SPIKE4", + "S_SPIKE5", + "S_SPIKE6", + "S_SPIKED1", + "S_SPIKED2", + + // Wall spikes + "S_WALLSPIKE1", + "S_WALLSPIKE2", + "S_WALLSPIKE3", + "S_WALLSPIKE4", + "S_WALLSPIKE5", + "S_WALLSPIKE6", + "S_WALLSPIKEBASE", + "S_WALLSPIKED1", + "S_WALLSPIKED2", + + // Starpost + "S_STARPOST_IDLE", + "S_STARPOST_FLASH", + "S_STARPOST_STARTSPIN", + "S_STARPOST_SPIN", + "S_STARPOST_ENDSPIN", + + // Big floating mine + "S_BIGMINE_IDLE", + "S_BIGMINE_ALERT1", + "S_BIGMINE_ALERT2", + "S_BIGMINE_ALERT3", + "S_BIGMINE_SET1", + "S_BIGMINE_SET2", + "S_BIGMINE_SET3", + "S_BIGMINE_BLAST1", + "S_BIGMINE_BLAST2", + "S_BIGMINE_BLAST3", + "S_BIGMINE_BLAST4", + "S_BIGMINE_BLAST5", + + // Cannon Launcher + "S_CANNONLAUNCHER1", + "S_CANNONLAUNCHER2", + "S_CANNONLAUNCHER3", + + // Monitor Miscellany + "S_BOXSPARKLE1", + "S_BOXSPARKLE2", + "S_BOXSPARKLE3", + "S_BOXSPARKLE4", + + "S_BOX_FLICKER", + "S_BOX_POP1", + "S_BOX_POP2", + + "S_GOLDBOX_FLICKER", + "S_GOLDBOX_OFF1", + "S_GOLDBOX_OFF2", + "S_GOLDBOX_OFF3", + "S_GOLDBOX_OFF4", + "S_GOLDBOX_OFF5", + "S_GOLDBOX_OFF6", + "S_GOLDBOX_OFF7", + + // Monitor States (one per box) + "S_MYSTERY_BOX", + "S_RING_BOX", + "S_PITY_BOX", + "S_ATTRACT_BOX", + "S_FORCE_BOX", + "S_ARMAGEDDON_BOX", + "S_WHIRLWIND_BOX", + "S_ELEMENTAL_BOX", + "S_SNEAKERS_BOX", + "S_INVULN_BOX", + "S_1UP_BOX", + "S_EGGMAN_BOX", + "S_MIXUP_BOX", + "S_GRAVITY_BOX", + "S_RECYCLER_BOX", + "S_SCORE1K_BOX", + "S_SCORE10K_BOX", + "S_FLAMEAURA_BOX", + "S_BUBBLEWRAP_BOX", + "S_THUNDERCOIN_BOX", + + // Gold Repeat Monitor States (one per box) + "S_PITY_GOLDBOX", + "S_ATTRACT_GOLDBOX", + "S_FORCE_GOLDBOX", + "S_ARMAGEDDON_GOLDBOX", + "S_WHIRLWIND_GOLDBOX", + "S_ELEMENTAL_GOLDBOX", + "S_SNEAKERS_GOLDBOX", + "S_INVULN_GOLDBOX", + "S_EGGMAN_GOLDBOX", + "S_GRAVITY_GOLDBOX", + "S_FLAMEAURA_GOLDBOX", + "S_BUBBLEWRAP_GOLDBOX", + "S_THUNDERCOIN_GOLDBOX", + + // Team Ring Boxes (these are special) + "S_RING_REDBOX1", + "S_RING_REDBOX2", + "S_REDBOX_POP1", + "S_REDBOX_POP2", + + "S_RING_BLUEBOX1", + "S_RING_BLUEBOX2", + "S_BLUEBOX_POP1", + "S_BLUEBOX_POP2", + + // Box Icons -- 2 states each, animation and action + "S_RING_ICON1", + "S_RING_ICON2", + + "S_PITY_ICON1", + "S_PITY_ICON2", + + "S_ATTRACT_ICON1", + "S_ATTRACT_ICON2", + + "S_FORCE_ICON1", + "S_FORCE_ICON2", + + "S_ARMAGEDDON_ICON1", + "S_ARMAGEDDON_ICON2", + + "S_WHIRLWIND_ICON1", + "S_WHIRLWIND_ICON2", + + "S_ELEMENTAL_ICON1", + "S_ELEMENTAL_ICON2", + + "S_SNEAKERS_ICON1", + "S_SNEAKERS_ICON2", + + "S_INVULN_ICON1", + "S_INVULN_ICON2", + + "S_1UP_ICON1", + "S_1UP_ICON2", + + "S_EGGMAN_ICON1", + "S_EGGMAN_ICON2", + + "S_MIXUP_ICON1", + "S_MIXUP_ICON2", + + "S_GRAVITY_ICON1", + "S_GRAVITY_ICON2", + + "S_RECYCLER_ICON1", + "S_RECYCLER_ICON2", + + "S_SCORE1K_ICON1", + "S_SCORE1K_ICON2", + + "S_SCORE10K_ICON1", + "S_SCORE10K_ICON2", + + "S_FLAMEAURA_ICON1", + "S_FLAMEAURA_ICON2", + + "S_BUBBLEWRAP_ICON1", + "S_BUBBLEWRAP_ICON2", + + "S_THUNDERCOIN_ICON1", + "S_THUNDERCOIN_ICON2", + + // --- + + "S_ROCKET", + + "S_LASER", + "S_LASER2", + "S_LASERFLASH", + + "S_LASERFLAME1", + "S_LASERFLAME2", + "S_LASERFLAME3", + "S_LASERFLAME4", + "S_LASERFLAME5", + + "S_TORPEDO", + + "S_ENERGYBALL1", + "S_ENERGYBALL2", + + // Skim Mine, also used by Jetty-Syn bomber + "S_MINE1", + "S_MINE_BOOM1", + "S_MINE_BOOM2", + "S_MINE_BOOM3", + "S_MINE_BOOM4", + + // Jetty-Syn Bullet + "S_JETBULLET1", + "S_JETBULLET2", + + "S_TURRETLASER", + "S_TURRETLASEREXPLODE1", + "S_TURRETLASEREXPLODE2", + + // Cannonball + "S_CANNONBALL1", + + // Arrow + "S_ARROW", + "S_ARROWBONK", + + // Glaregoyle Demon fire + "S_DEMONFIRE", + + // The letter + "S_LETTER", + + // GFZ flowers + "S_GFZFLOWERA", + "S_GFZFLOWERB", + "S_GFZFLOWERC", + + "S_BLUEBERRYBUSH", + "S_BERRYBUSH", + "S_BUSH", + + // Trees (both GFZ and misc) + "S_GFZTREE", + "S_GFZBERRYTREE", + "S_GFZCHERRYTREE", + "S_CHECKERTREE", + "S_CHECKERSUNSETTREE", + "S_FHZTREE", // Frozen Hillside + "S_FHZPINKTREE", + "S_POLYGONTREE", + "S_BUSHTREE", + "S_BUSHREDTREE", + "S_SPRINGTREE", + + // THZ flowers + "S_THZFLOWERA", // THZ1 Steam flower + "S_THZFLOWERB", // THZ1 Spin flower (red) + "S_THZFLOWERC", // THZ1 Spin flower (yellow) + + // THZ Steam Whistle tree/bush + "S_THZTREE", + "S_THZTREEBRANCH1", + "S_THZTREEBRANCH2", + "S_THZTREEBRANCH3", + "S_THZTREEBRANCH4", + "S_THZTREEBRANCH5", + "S_THZTREEBRANCH6", + "S_THZTREEBRANCH7", + "S_THZTREEBRANCH8", + "S_THZTREEBRANCH9", + "S_THZTREEBRANCH10", + "S_THZTREEBRANCH11", + "S_THZTREEBRANCH12", + "S_THZTREEBRANCH13", + + // THZ Alarm + "S_ALARM1", + + // Deep Sea Gargoyle + "S_GARGOYLE", + "S_BIGGARGOYLE", + + // DSZ Seaweed + "S_SEAWEED1", + "S_SEAWEED2", + "S_SEAWEED3", + "S_SEAWEED4", + "S_SEAWEED5", + "S_SEAWEED6", + + // Dripping Water + "S_DRIPA1", + "S_DRIPA2", + "S_DRIPA3", + "S_DRIPA4", + "S_DRIPB1", + "S_DRIPC1", + "S_DRIPC2", + + // Coral + "S_CORAL1", + "S_CORAL2", + "S_CORAL3", + "S_CORAL4", + "S_CORAL5", + + // Blue Crystal + "S_BLUECRYSTAL1", + + // Kelp, + "S_KELP", + + // Animated algae + "S_ANIMALGAETOP1", + "S_ANIMALGAETOP2", + "S_ANIMALGAESEG", + + // DSZ Stalagmites + "S_DSZSTALAGMITE", + "S_DSZ2STALAGMITE", + + // DSZ Light beam + "S_LIGHTBEAM1", + "S_LIGHTBEAM2", + "S_LIGHTBEAM3", + "S_LIGHTBEAM4", + "S_LIGHTBEAM5", + "S_LIGHTBEAM6", + "S_LIGHTBEAM7", + "S_LIGHTBEAM8", + "S_LIGHTBEAM9", + "S_LIGHTBEAM10", + "S_LIGHTBEAM11", + "S_LIGHTBEAM12", + + // CEZ Chain + "S_CEZCHAIN", + + // Flame + "S_FLAME", + "S_FLAMEPARTICLE", + "S_FLAMEREST", + + // Eggman Statue + "S_EGGSTATUE1", + + // CEZ hidden sling + "S_SLING1", + "S_SLING2", + + // CEZ maces and chains + "S_SMALLMACECHAIN", + "S_BIGMACECHAIN", + "S_SMALLMACE", + "S_BIGMACE", + "S_SMALLGRABCHAIN", + "S_BIGGRABCHAIN", + + // Yellow spring on a ball + "S_YELLOWSPRINGBALL", + "S_YELLOWSPRINGBALL2", + "S_YELLOWSPRINGBALL3", + "S_YELLOWSPRINGBALL4", + "S_YELLOWSPRINGBALL5", + + // Red spring on a ball + "S_REDSPRINGBALL", + "S_REDSPRINGBALL2", + "S_REDSPRINGBALL3", + "S_REDSPRINGBALL4", + "S_REDSPRINGBALL5", + + // Small Firebar + "S_SMALLFIREBAR1", + "S_SMALLFIREBAR2", + "S_SMALLFIREBAR3", + "S_SMALLFIREBAR4", + "S_SMALLFIREBAR5", + "S_SMALLFIREBAR6", + "S_SMALLFIREBAR7", + "S_SMALLFIREBAR8", + "S_SMALLFIREBAR9", + "S_SMALLFIREBAR10", + "S_SMALLFIREBAR11", + "S_SMALLFIREBAR12", + "S_SMALLFIREBAR13", + "S_SMALLFIREBAR14", + "S_SMALLFIREBAR15", + "S_SMALLFIREBAR16", + + // Big Firebar + "S_BIGFIREBAR1", + "S_BIGFIREBAR2", + "S_BIGFIREBAR3", + "S_BIGFIREBAR4", + "S_BIGFIREBAR5", + "S_BIGFIREBAR6", + "S_BIGFIREBAR7", + "S_BIGFIREBAR8", + "S_BIGFIREBAR9", + "S_BIGFIREBAR10", + "S_BIGFIREBAR11", + "S_BIGFIREBAR12", + "S_BIGFIREBAR13", + "S_BIGFIREBAR14", + "S_BIGFIREBAR15", + "S_BIGFIREBAR16", + + "S_CEZFLOWER", + "S_CEZPOLE", + "S_CEZBANNER1", + "S_CEZBANNER2", + "S_PINETREE", + "S_CEZBUSH1", + "S_CEZBUSH2", + "S_CANDLE", + "S_CANDLEPRICKET", + "S_FLAMEHOLDER", + "S_FIRETORCH", + "S_WAVINGFLAG", + "S_WAVINGFLAGSEG1", + "S_WAVINGFLAGSEG2", + "S_CRAWLASTATUE", + "S_FACESTABBERSTATUE", + "S_SUSPICIOUSFACESTABBERSTATUE_WAIT", + "S_SUSPICIOUSFACESTABBERSTATUE_BURST1", + "S_SUSPICIOUSFACESTABBERSTATUE_BURST2", + "S_BRAMBLES", + + // Big Tumbleweed + "S_BIGTUMBLEWEED", + "S_BIGTUMBLEWEED_ROLL1", + "S_BIGTUMBLEWEED_ROLL2", + "S_BIGTUMBLEWEED_ROLL3", + "S_BIGTUMBLEWEED_ROLL4", + "S_BIGTUMBLEWEED_ROLL5", + "S_BIGTUMBLEWEED_ROLL6", + "S_BIGTUMBLEWEED_ROLL7", + "S_BIGTUMBLEWEED_ROLL8", + + // Little Tumbleweed + "S_LITTLETUMBLEWEED", + "S_LITTLETUMBLEWEED_ROLL1", + "S_LITTLETUMBLEWEED_ROLL2", + "S_LITTLETUMBLEWEED_ROLL3", + "S_LITTLETUMBLEWEED_ROLL4", + "S_LITTLETUMBLEWEED_ROLL5", + "S_LITTLETUMBLEWEED_ROLL6", + "S_LITTLETUMBLEWEED_ROLL7", + "S_LITTLETUMBLEWEED_ROLL8", + + // Cacti + "S_CACTI1", + "S_CACTI2", + "S_CACTI3", + "S_CACTI4", + "S_CACTI5", + "S_CACTI6", + "S_CACTI7", + "S_CACTI8", + "S_CACTI9", + "S_CACTI10", + "S_CACTI11", + "S_CACTITINYSEG", + "S_CACTISMALLSEG", + + // Warning signs + "S_ARIDSIGN_CAUTION", + "S_ARIDSIGN_CACTI", + "S_ARIDSIGN_SHARPTURN", + + // Oil lamp + "S_OILLAMP", + "S_OILLAMPFLARE", + + // TNT barrel + "S_TNTBARREL_STND1", + "S_TNTBARREL_EXPL1", + "S_TNTBARREL_EXPL2", + "S_TNTBARREL_EXPL3", + "S_TNTBARREL_EXPL4", + "S_TNTBARREL_EXPL5", + "S_TNTBARREL_EXPL6", + "S_TNTBARREL_EXPL7", + "S_TNTBARREL_FLYING", + + // TNT proximity shell + "S_PROXIMITY_TNT", + "S_PROXIMITY_TNT_TRIGGER1", + "S_PROXIMITY_TNT_TRIGGER2", + "S_PROXIMITY_TNT_TRIGGER3", + "S_PROXIMITY_TNT_TRIGGER4", + "S_PROXIMITY_TNT_TRIGGER5", + "S_PROXIMITY_TNT_TRIGGER6", + "S_PROXIMITY_TNT_TRIGGER7", + "S_PROXIMITY_TNT_TRIGGER8", + "S_PROXIMITY_TNT_TRIGGER9", + "S_PROXIMITY_TNT_TRIGGER10", + "S_PROXIMITY_TNT_TRIGGER11", + "S_PROXIMITY_TNT_TRIGGER12", + "S_PROXIMITY_TNT_TRIGGER13", + "S_PROXIMITY_TNT_TRIGGER14", + "S_PROXIMITY_TNT_TRIGGER15", + "S_PROXIMITY_TNT_TRIGGER16", + "S_PROXIMITY_TNT_TRIGGER17", + "S_PROXIMITY_TNT_TRIGGER18", + "S_PROXIMITY_TNT_TRIGGER19", + "S_PROXIMITY_TNT_TRIGGER20", + "S_PROXIMITY_TNT_TRIGGER21", + "S_PROXIMITY_TNT_TRIGGER22", + "S_PROXIMITY_TNT_TRIGGER23", + + // Dust devil + "S_DUSTDEVIL", + "S_DUSTLAYER1", + "S_DUSTLAYER2", + "S_DUSTLAYER3", + "S_DUSTLAYER4", + "S_DUSTLAYER5", + "S_ARIDDUST1", + "S_ARIDDUST2", + "S_ARIDDUST3", + + // Minecart + "S_MINECART_IDLE", + "S_MINECART_DTH1", + "S_MINECARTEND", + "S_MINECARTSEG_FRONT", + "S_MINECARTSEG_BACK", + "S_MINECARTSEG_LEFT", + "S_MINECARTSEG_RIGHT", + "S_MINECARTSIDEMARK1", + "S_MINECARTSIDEMARK2", + "S_MINECARTSPARK", + + // Saloon door + "S_SALOONDOOR", + "S_SALOONDOORCENTER", + + // Train cameo + "S_TRAINCAMEOSPAWNER_1", + "S_TRAINCAMEOSPAWNER_2", + "S_TRAINCAMEOSPAWNER_3", + "S_TRAINCAMEOSPAWNER_4", + "S_TRAINCAMEOSPAWNER_5", + "S_TRAINPUFFMAKER", + + // Train + "S_TRAINDUST", + "S_TRAINSTEAM", + + // Flame jet + "S_FLAMEJETSTND", + "S_FLAMEJETSTART", + "S_FLAMEJETSTOP", + "S_FLAMEJETFLAME1", + "S_FLAMEJETFLAME2", + "S_FLAMEJETFLAME3", + "S_FLAMEJETFLAME4", + "S_FLAMEJETFLAME5", + "S_FLAMEJETFLAME6", + "S_FLAMEJETFLAME7", + "S_FLAMEJETFLAME8", + "S_FLAMEJETFLAME9", + + // Spinning flame jets + "S_FJSPINAXISA1", // Counter-clockwise + "S_FJSPINAXISA2", + "S_FJSPINAXISB1", // Clockwise + "S_FJSPINAXISB2", + + // Blade's flame + "S_FLAMEJETFLAMEB1", + "S_FLAMEJETFLAMEB2", + "S_FLAMEJETFLAMEB3", + + // Lavafall + "S_LAVAFALL_DORMANT", + "S_LAVAFALL_TELL", + "S_LAVAFALL_SHOOT", + "S_LAVAFALL_LAVA1", + "S_LAVAFALL_LAVA2", + "S_LAVAFALL_LAVA3", + "S_LAVAFALLROCK", + + // Rollout Rock + "S_ROLLOUTSPAWN", + "S_ROLLOUTROCK", + + // RVZ scenery + "S_BIGFERNLEAF", + "S_BIGFERN1", + "S_BIGFERN2", + "S_JUNGLEPALM", + "S_TORCHFLOWER", + "S_WALLVINE_LONG", + "S_WALLVINE_SHORT", + + // Glaregoyles + "S_GLAREGOYLE", + "S_GLAREGOYLE_CHARGE", + "S_GLAREGOYLE_BLINK", + "S_GLAREGOYLE_HOLD", + "S_GLAREGOYLE_FIRE", + "S_GLAREGOYLE_LOOP", + "S_GLAREGOYLE_COOLDOWN", + "S_GLAREGOYLEUP", + "S_GLAREGOYLEUP_CHARGE", + "S_GLAREGOYLEUP_BLINK", + "S_GLAREGOYLEUP_HOLD", + "S_GLAREGOYLEUP_FIRE", + "S_GLAREGOYLEUP_LOOP", + "S_GLAREGOYLEUP_COOLDOWN", + "S_GLAREGOYLEDOWN", + "S_GLAREGOYLEDOWN_CHARGE", + "S_GLAREGOYLEDOWN_BLINK", + "S_GLAREGOYLEDOWN_HOLD", + "S_GLAREGOYLEDOWN_FIRE", + "S_GLAREGOYLEDOWN_LOOP", + "S_GLAREGOYLEDOWN_COOLDOWN", + "S_GLAREGOYLELONG", + "S_GLAREGOYLELONG_CHARGE", + "S_GLAREGOYLELONG_BLINK", + "S_GLAREGOYLELONG_HOLD", + "S_GLAREGOYLELONG_FIRE", + "S_GLAREGOYLELONG_LOOP", + "S_GLAREGOYLELONG_COOLDOWN", + + // ATZ's Red Crystal/Target + "S_TARGET_IDLE", + "S_TARGET_HIT1", + "S_TARGET_HIT2", + "S_TARGET_RESPAWN", + "S_TARGET_ALLDONE", + + // ATZ's green flame + "S_GREENFLAME", + + // ATZ Blue Gargoyle + "S_BLUEGARGOYLE", + + // Stalagmites + "S_STG0", + "S_STG1", + "S_STG2", + "S_STG3", + "S_STG4", + "S_STG5", + "S_STG6", + "S_STG7", + "S_STG8", + "S_STG9", + + // Xmas-specific stuff + "S_XMASPOLE", + "S_CANDYCANE", + "S_SNOWMAN", // normal + "S_SNOWMANHAT", // with hat + scarf + "S_LAMPPOST1", // normal + "S_LAMPPOST2", // with snow + "S_HANGSTAR", + "S_MISTLETOE", + // Xmas GFZ bushes + "S_XMASBLUEBERRYBUSH", + "S_XMASBERRYBUSH", + "S_XMASBUSH", + // FHZ + "S_FHZICE1", + "S_FHZICE2", + "S_ROSY_IDLE1", + "S_ROSY_IDLE2", + "S_ROSY_IDLE3", + "S_ROSY_IDLE4", + "S_ROSY_JUMP", + "S_ROSY_WALK", + "S_ROSY_HUG", + "S_ROSY_PAIN", + "S_ROSY_STND", + "S_ROSY_UNHAPPY", + + // Halloween Scenery + // Pumpkins + "S_JACKO1", + "S_JACKO1OVERLAY_1", + "S_JACKO1OVERLAY_2", + "S_JACKO1OVERLAY_3", + "S_JACKO1OVERLAY_4", + "S_JACKO2", + "S_JACKO2OVERLAY_1", + "S_JACKO2OVERLAY_2", + "S_JACKO2OVERLAY_3", + "S_JACKO2OVERLAY_4", + "S_JACKO3", + "S_JACKO3OVERLAY_1", + "S_JACKO3OVERLAY_2", + "S_JACKO3OVERLAY_3", + "S_JACKO3OVERLAY_4", + // Dr Seuss Trees + "S_HHZTREE_TOP", + "S_HHZTREE_TRUNK", + "S_HHZTREE_LEAF", + // Mushroom + "S_HHZSHROOM_1", + "S_HHZSHROOM_2", + "S_HHZSHROOM_3", + "S_HHZSHROOM_4", + "S_HHZSHROOM_5", + "S_HHZSHROOM_6", + "S_HHZSHROOM_7", + "S_HHZSHROOM_8", + "S_HHZSHROOM_9", + "S_HHZSHROOM_10", + "S_HHZSHROOM_11", + "S_HHZSHROOM_12", + "S_HHZSHROOM_13", + "S_HHZSHROOM_14", + "S_HHZSHROOM_15", + "S_HHZSHROOM_16", + // Misc + "S_HHZGRASS", + "S_HHZTENT1", + "S_HHZTENT2", + "S_HHZSTALAGMITE_TALL", + "S_HHZSTALAGMITE_SHORT", + + // Botanic Serenity's loads of scenery states + "S_BSZTALLFLOWER_RED", + "S_BSZTALLFLOWER_PURPLE", + "S_BSZTALLFLOWER_BLUE", + "S_BSZTALLFLOWER_CYAN", + "S_BSZTALLFLOWER_YELLOW", + "S_BSZTALLFLOWER_ORANGE", + "S_BSZFLOWER_RED", + "S_BSZFLOWER_PURPLE", + "S_BSZFLOWER_BLUE", + "S_BSZFLOWER_CYAN", + "S_BSZFLOWER_YELLOW", + "S_BSZFLOWER_ORANGE", + "S_BSZSHORTFLOWER_RED", + "S_BSZSHORTFLOWER_PURPLE", + "S_BSZSHORTFLOWER_BLUE", + "S_BSZSHORTFLOWER_CYAN", + "S_BSZSHORTFLOWER_YELLOW", + "S_BSZSHORTFLOWER_ORANGE", + "S_BSZTULIP_RED", + "S_BSZTULIP_PURPLE", + "S_BSZTULIP_BLUE", + "S_BSZTULIP_CYAN", + "S_BSZTULIP_YELLOW", + "S_BSZTULIP_ORANGE", + "S_BSZCLUSTER_RED", + "S_BSZCLUSTER_PURPLE", + "S_BSZCLUSTER_BLUE", + "S_BSZCLUSTER_CYAN", + "S_BSZCLUSTER_YELLOW", + "S_BSZCLUSTER_ORANGE", + "S_BSZBUSH_RED", + "S_BSZBUSH_PURPLE", + "S_BSZBUSH_BLUE", + "S_BSZBUSH_CYAN", + "S_BSZBUSH_YELLOW", + "S_BSZBUSH_ORANGE", + "S_BSZVINE_RED", + "S_BSZVINE_PURPLE", + "S_BSZVINE_BLUE", + "S_BSZVINE_CYAN", + "S_BSZVINE_YELLOW", + "S_BSZVINE_ORANGE", + "S_BSZSHRUB", + "S_BSZCLOVER", + "S_BIG_PALMTREE_TRUNK", + "S_BIG_PALMTREE_TOP", + "S_PALMTREE_TRUNK", + "S_PALMTREE_TOP", + + "S_DBALL1", + "S_DBALL2", + "S_DBALL3", + "S_DBALL4", + "S_DBALL5", + "S_DBALL6", + "S_EGGSTATUE2", + + // Shield Orb + "S_ARMA1", + "S_ARMA2", + "S_ARMA3", + "S_ARMA4", + "S_ARMA5", + "S_ARMA6", + "S_ARMA7", + "S_ARMA8", + "S_ARMA9", + "S_ARMA10", + "S_ARMA11", + "S_ARMA12", + "S_ARMA13", + "S_ARMA14", + "S_ARMA15", + "S_ARMA16", + + "S_ARMF1", + "S_ARMF2", + "S_ARMF3", + "S_ARMF4", + "S_ARMF5", + "S_ARMF6", + "S_ARMF7", + "S_ARMF8", + "S_ARMF9", + "S_ARMF10", + "S_ARMF11", + "S_ARMF12", + "S_ARMF13", + "S_ARMF14", + "S_ARMF15", + "S_ARMF16", + "S_ARMF17", + "S_ARMF18", + "S_ARMF19", + "S_ARMF20", + "S_ARMF21", + "S_ARMF22", + "S_ARMF23", + "S_ARMF24", + "S_ARMF25", + "S_ARMF26", + "S_ARMF27", + "S_ARMF28", + "S_ARMF29", + "S_ARMF30", + "S_ARMF31", + "S_ARMF32", + + "S_ARMB1", + "S_ARMB2", + "S_ARMB3", + "S_ARMB4", + "S_ARMB5", + "S_ARMB6", + "S_ARMB7", + "S_ARMB8", + "S_ARMB9", + "S_ARMB10", + "S_ARMB11", + "S_ARMB12", + "S_ARMB13", + "S_ARMB14", + "S_ARMB15", + "S_ARMB16", + "S_ARMB17", + "S_ARMB18", + "S_ARMB19", + "S_ARMB20", + "S_ARMB21", + "S_ARMB22", + "S_ARMB23", + "S_ARMB24", + "S_ARMB25", + "S_ARMB26", + "S_ARMB27", + "S_ARMB28", + "S_ARMB29", + "S_ARMB30", + "S_ARMB31", + "S_ARMB32", + + "S_WIND1", + "S_WIND2", + "S_WIND3", + "S_WIND4", + "S_WIND5", + "S_WIND6", + "S_WIND7", + "S_WIND8", + + "S_MAGN1", + "S_MAGN2", + "S_MAGN3", + "S_MAGN4", + "S_MAGN5", + "S_MAGN6", + "S_MAGN7", + "S_MAGN8", + "S_MAGN9", + "S_MAGN10", + "S_MAGN11", + "S_MAGN12", + "S_MAGN13", + + "S_FORC1", + "S_FORC2", + "S_FORC3", + "S_FORC4", + "S_FORC5", + "S_FORC6", + "S_FORC7", + "S_FORC8", + "S_FORC9", + "S_FORC10", + + "S_FORC11", + "S_FORC12", + "S_FORC13", + "S_FORC14", + "S_FORC15", + "S_FORC16", + "S_FORC17", + "S_FORC18", + "S_FORC19", + "S_FORC20", + + "S_FORC21", + + "S_ELEM1", + "S_ELEM2", + "S_ELEM3", + "S_ELEM4", + "S_ELEM5", + "S_ELEM6", + "S_ELEM7", + "S_ELEM8", + "S_ELEM9", + "S_ELEM10", + "S_ELEM11", + "S_ELEM12", + + "S_ELEM13", + "S_ELEM14", + + "S_ELEMF1", + "S_ELEMF2", + "S_ELEMF3", + "S_ELEMF4", + "S_ELEMF5", + "S_ELEMF6", + "S_ELEMF7", + "S_ELEMF8", + "S_ELEMF9", + "S_ELEMF10", + + "S_PITY1", + "S_PITY2", + "S_PITY3", + "S_PITY4", + "S_PITY5", + "S_PITY6", + "S_PITY7", + "S_PITY8", + "S_PITY9", + "S_PITY10", + "S_PITY11", + "S_PITY12", + + "S_FIRS1", + "S_FIRS2", + "S_FIRS3", + "S_FIRS4", + "S_FIRS5", + "S_FIRS6", + "S_FIRS7", + "S_FIRS8", + "S_FIRS9", + + "S_FIRS10", + "S_FIRS11", + + "S_FIRSB1", + "S_FIRSB2", + "S_FIRSB3", + "S_FIRSB4", + "S_FIRSB5", + "S_FIRSB6", + "S_FIRSB7", + "S_FIRSB8", + "S_FIRSB9", + + "S_FIRSB10", + + "S_BUBS1", + "S_BUBS2", + "S_BUBS3", + "S_BUBS4", + "S_BUBS5", + "S_BUBS6", + "S_BUBS7", + "S_BUBS8", + "S_BUBS9", + + "S_BUBS10", + "S_BUBS11", + + "S_BUBSB1", + "S_BUBSB2", + "S_BUBSB3", + "S_BUBSB4", + + "S_BUBSB5", + "S_BUBSB6", + + "S_ZAPS1", + "S_ZAPS2", + "S_ZAPS3", + "S_ZAPS4", + "S_ZAPS5", + "S_ZAPS6", + "S_ZAPS7", + "S_ZAPS8", + "S_ZAPS9", + "S_ZAPS10", + "S_ZAPS11", + "S_ZAPS12", + "S_ZAPS13", // blank frame + "S_ZAPS14", + "S_ZAPS15", + "S_ZAPS16", + + "S_ZAPSB1", // blank frame + "S_ZAPSB2", + "S_ZAPSB3", + "S_ZAPSB4", + "S_ZAPSB5", + "S_ZAPSB6", + "S_ZAPSB7", + "S_ZAPSB8", + "S_ZAPSB9", + "S_ZAPSB10", + "S_ZAPSB11", // blank frame + + //Thunder spark + "S_THUNDERCOIN_SPARK", + + // Invincibility Sparkles + "S_IVSP", + + // Super Sonic Spark + "S_SSPK1", + "S_SSPK2", + "S_SSPK3", + "S_SSPK4", + "S_SSPK5", + + // Flicky-sized bubble + "S_FLICKY_BUBBLE", + + // Bluebird + "S_FLICKY_01_OUT", + "S_FLICKY_01_FLAP1", + "S_FLICKY_01_FLAP2", + "S_FLICKY_01_FLAP3", + "S_FLICKY_01_STAND", + "S_FLICKY_01_CENTER", + + // Rabbit + "S_FLICKY_02_OUT", + "S_FLICKY_02_AIM", + "S_FLICKY_02_HOP", + "S_FLICKY_02_UP", + "S_FLICKY_02_DOWN", + "S_FLICKY_02_STAND", + "S_FLICKY_02_CENTER", + + // Chicken + "S_FLICKY_03_OUT", + "S_FLICKY_03_AIM", + "S_FLICKY_03_HOP", + "S_FLICKY_03_UP", + "S_FLICKY_03_FLAP1", + "S_FLICKY_03_FLAP2", + "S_FLICKY_03_STAND", + "S_FLICKY_03_CENTER", + + // Seal + "S_FLICKY_04_OUT", + "S_FLICKY_04_AIM", + "S_FLICKY_04_HOP", + "S_FLICKY_04_UP", + "S_FLICKY_04_DOWN", + "S_FLICKY_04_SWIM1", + "S_FLICKY_04_SWIM2", + "S_FLICKY_04_SWIM3", + "S_FLICKY_04_SWIM4", + "S_FLICKY_04_STAND", + "S_FLICKY_04_CENTER", + + // Pig + "S_FLICKY_05_OUT", + "S_FLICKY_05_AIM", + "S_FLICKY_05_HOP", + "S_FLICKY_05_UP", + "S_FLICKY_05_DOWN", + "S_FLICKY_05_STAND", + "S_FLICKY_05_CENTER", + + // Chipmunk + "S_FLICKY_06_OUT", + "S_FLICKY_06_AIM", + "S_FLICKY_06_HOP", + "S_FLICKY_06_UP", + "S_FLICKY_06_DOWN", + "S_FLICKY_06_STAND", + "S_FLICKY_06_CENTER", + + // Penguin + "S_FLICKY_07_OUT", + "S_FLICKY_07_AIML", + "S_FLICKY_07_HOPL", + "S_FLICKY_07_UPL", + "S_FLICKY_07_DOWNL", + "S_FLICKY_07_AIMR", + "S_FLICKY_07_HOPR", + "S_FLICKY_07_UPR", + "S_FLICKY_07_DOWNR", + "S_FLICKY_07_SWIM1", + "S_FLICKY_07_SWIM2", + "S_FLICKY_07_SWIM3", + "S_FLICKY_07_STAND", + "S_FLICKY_07_CENTER", + + // Fish + "S_FLICKY_08_OUT", + "S_FLICKY_08_AIM", + "S_FLICKY_08_HOP", + "S_FLICKY_08_FLAP1", + "S_FLICKY_08_FLAP2", + "S_FLICKY_08_FLAP3", + "S_FLICKY_08_FLAP4", + "S_FLICKY_08_SWIM1", + "S_FLICKY_08_SWIM2", + "S_FLICKY_08_SWIM3", + "S_FLICKY_08_SWIM4", + "S_FLICKY_08_STAND", + "S_FLICKY_08_CENTER", + + // Ram + "S_FLICKY_09_OUT", + "S_FLICKY_09_AIM", + "S_FLICKY_09_HOP", + "S_FLICKY_09_UP", + "S_FLICKY_09_DOWN", + "S_FLICKY_09_STAND", + "S_FLICKY_09_CENTER", + + // Puffin + "S_FLICKY_10_OUT", + "S_FLICKY_10_FLAP1", + "S_FLICKY_10_FLAP2", + "S_FLICKY_10_STAND", + "S_FLICKY_10_CENTER", + + // Cow + "S_FLICKY_11_OUT", + "S_FLICKY_11_AIM", + "S_FLICKY_11_RUN1", + "S_FLICKY_11_RUN2", + "S_FLICKY_11_RUN3", + "S_FLICKY_11_STAND", + "S_FLICKY_11_CENTER", + + // Rat + "S_FLICKY_12_OUT", + "S_FLICKY_12_AIM", + "S_FLICKY_12_RUN1", + "S_FLICKY_12_RUN2", + "S_FLICKY_12_RUN3", + "S_FLICKY_12_STAND", + "S_FLICKY_12_CENTER", + + // Bear + "S_FLICKY_13_OUT", + "S_FLICKY_13_AIM", + "S_FLICKY_13_HOP", + "S_FLICKY_13_UP", + "S_FLICKY_13_DOWN", + "S_FLICKY_13_STAND", + "S_FLICKY_13_CENTER", + + // Dove + "S_FLICKY_14_OUT", + "S_FLICKY_14_FLAP1", + "S_FLICKY_14_FLAP2", + "S_FLICKY_14_FLAP3", + "S_FLICKY_14_STAND", + "S_FLICKY_14_CENTER", + + // Cat + "S_FLICKY_15_OUT", + "S_FLICKY_15_AIM", + "S_FLICKY_15_HOP", + "S_FLICKY_15_UP", + "S_FLICKY_15_DOWN", + "S_FLICKY_15_STAND", + "S_FLICKY_15_CENTER", + + // Canary + "S_FLICKY_16_OUT", + "S_FLICKY_16_FLAP1", + "S_FLICKY_16_FLAP2", + "S_FLICKY_16_FLAP3", + "S_FLICKY_16_STAND", + "S_FLICKY_16_CENTER", + + // Spider + "S_SECRETFLICKY_01_OUT", + "S_SECRETFLICKY_01_AIM", + "S_SECRETFLICKY_01_HOP", + "S_SECRETFLICKY_01_UP", + "S_SECRETFLICKY_01_DOWN", + "S_SECRETFLICKY_01_STAND", + "S_SECRETFLICKY_01_CENTER", + + // Bat + "S_SECRETFLICKY_02_OUT", + "S_SECRETFLICKY_02_FLAP1", + "S_SECRETFLICKY_02_FLAP2", + "S_SECRETFLICKY_02_FLAP3", + "S_SECRETFLICKY_02_STAND", + "S_SECRETFLICKY_02_CENTER", + + // Fan + "S_FAN", + "S_FAN2", + "S_FAN3", + "S_FAN4", + "S_FAN5", + + // Steam Riser + "S_STEAM1", + "S_STEAM2", + "S_STEAM3", + "S_STEAM4", + "S_STEAM5", + "S_STEAM6", + "S_STEAM7", + "S_STEAM8", + + // Bumpers + "S_BUMPER", + "S_BUMPERHIT", + + // Balloons + "S_BALLOON", + "S_BALLOONPOP1", + "S_BALLOONPOP2", + "S_BALLOONPOP3", + "S_BALLOONPOP4", + "S_BALLOONPOP5", + "S_BALLOONPOP6", + + // Yellow Spring + "S_YELLOWSPRING", + "S_YELLOWSPRING2", + "S_YELLOWSPRING3", + "S_YELLOWSPRING4", + "S_YELLOWSPRING5", + + // Red Spring + "S_REDSPRING", + "S_REDSPRING2", + "S_REDSPRING3", + "S_REDSPRING4", + "S_REDSPRING5", + + // Blue Spring + "S_BLUESPRING", + "S_BLUESPRING2", + "S_BLUESPRING3", + "S_BLUESPRING4", + "S_BLUESPRING5", + + // Yellow Diagonal Spring + "S_YDIAG1", + "S_YDIAG2", + "S_YDIAG3", + "S_YDIAG4", + "S_YDIAG5", + "S_YDIAG6", + "S_YDIAG7", + "S_YDIAG8", + + // Red Diagonal Spring + "S_RDIAG1", + "S_RDIAG2", + "S_RDIAG3", + "S_RDIAG4", + "S_RDIAG5", + "S_RDIAG6", + "S_RDIAG7", + "S_RDIAG8", + + // Blue Diagonal Spring + "S_BDIAG1", + "S_BDIAG2", + "S_BDIAG3", + "S_BDIAG4", + "S_BDIAG5", + "S_BDIAG6", + "S_BDIAG7", + "S_BDIAG8", + + // Yellow Side Spring + "S_YHORIZ1", + "S_YHORIZ2", + "S_YHORIZ3", + "S_YHORIZ4", + "S_YHORIZ5", + "S_YHORIZ6", + "S_YHORIZ7", + "S_YHORIZ8", + + // Red Side Spring + "S_RHORIZ1", + "S_RHORIZ2", + "S_RHORIZ3", + "S_RHORIZ4", + "S_RHORIZ5", + "S_RHORIZ6", + "S_RHORIZ7", + "S_RHORIZ8", + + // Blue Side Spring + "S_BHORIZ1", + "S_BHORIZ2", + "S_BHORIZ3", + "S_BHORIZ4", + "S_BHORIZ5", + "S_BHORIZ6", + "S_BHORIZ7", + "S_BHORIZ8", + + // Booster + "S_BOOSTERSOUND", + "S_YELLOWBOOSTERROLLER", + "S_YELLOWBOOSTERSEG_LEFT", + "S_YELLOWBOOSTERSEG_RIGHT", + "S_YELLOWBOOSTERSEG_FACE", + "S_REDBOOSTERROLLER", + "S_REDBOOSTERSEG_LEFT", + "S_REDBOOSTERSEG_RIGHT", + "S_REDBOOSTERSEG_FACE", + + // Rain + "S_RAIN1", + "S_RAINRETURN", + + // Snowflake + "S_SNOW1", + "S_SNOW2", + "S_SNOW3", + + // Water Splish + "S_SPLISH1", + "S_SPLISH2", + "S_SPLISH3", + "S_SPLISH4", + "S_SPLISH5", + "S_SPLISH6", + "S_SPLISH7", + "S_SPLISH8", + "S_SPLISH9", + + // Lava Splish + "S_LAVASPLISH", + + // added water splash + "S_SPLASH1", + "S_SPLASH2", + "S_SPLASH3", + + // lava/slime damage burn smoke + "S_SMOKE1", + "S_SMOKE2", + "S_SMOKE3", + "S_SMOKE4", + "S_SMOKE5", + + // Bubbles + "S_SMALLBUBBLE", + "S_MEDIUMBUBBLE", + "S_LARGEBUBBLE1", + "S_LARGEBUBBLE2", + "S_EXTRALARGEBUBBLE", // breathable + + "S_POP1", // Extra Large bubble goes POP! + + "S_WATERZAP", + + // Spindash dust + "S_SPINDUST1", + "S_SPINDUST2", + "S_SPINDUST3", + "S_SPINDUST4", + "S_SPINDUST_BUBBLE1", + "S_SPINDUST_BUBBLE2", + "S_SPINDUST_BUBBLE3", + "S_SPINDUST_BUBBLE4", + "S_SPINDUST_FIRE1", + "S_SPINDUST_FIRE2", + "S_SPINDUST_FIRE3", + "S_SPINDUST_FIRE4", + + "S_FOG1", + "S_FOG2", + "S_FOG3", + "S_FOG4", + "S_FOG5", + "S_FOG6", + "S_FOG7", + "S_FOG8", + "S_FOG9", + "S_FOG10", + "S_FOG11", + "S_FOG12", + "S_FOG13", + "S_FOG14", + + "S_SEED", + + "S_PARTICLE", + + // Score Logos + "S_SCRA", // 100 + "S_SCRB", // 200 + "S_SCRC", // 500 + "S_SCRD", // 1000 + "S_SCRE", // 10000 + "S_SCRF", // 400 (mario) + "S_SCRG", // 800 (mario) + "S_SCRH", // 2000 (mario) + "S_SCRI", // 4000 (mario) + "S_SCRJ", // 8000 (mario) + "S_SCRK", // 1UP (mario) + "S_SCRL", // 10 + + // Drowning Timer Numbers + "S_ZERO1", + "S_ONE1", + "S_TWO1", + "S_THREE1", + "S_FOUR1", + "S_FIVE1", + + "S_ZERO2", + "S_ONE2", + "S_TWO2", + "S_THREE2", + "S_FOUR2", + "S_FIVE2", + + "S_FLIGHTINDICATOR", + + "S_LOCKON1", + "S_LOCKON2", + "S_LOCKON3", + "S_LOCKON4", + "S_LOCKONINF1", + "S_LOCKONINF2", + "S_LOCKONINF3", + "S_LOCKONINF4", + + // Tag Sign + "S_TTAG", + + // Got Flag Sign + "S_GOTFLAG", + + // Finish flag + "S_FINISHFLAG", + + "S_CORK", + "S_LHRT", + + // Red Ring + "S_RRNG1", + "S_RRNG2", + "S_RRNG3", + "S_RRNG4", + "S_RRNG5", + "S_RRNG6", + "S_RRNG7", + + // Weapon Ring Ammo + "S_BOUNCERINGAMMO", + "S_RAILRINGAMMO", + "S_INFINITYRINGAMMO", + "S_AUTOMATICRINGAMMO", + "S_EXPLOSIONRINGAMMO", + "S_SCATTERRINGAMMO", + "S_GRENADERINGAMMO", + + // Weapon pickup + "S_BOUNCEPICKUP", + "S_BOUNCEPICKUPFADE1", + "S_BOUNCEPICKUPFADE2", + "S_BOUNCEPICKUPFADE3", + "S_BOUNCEPICKUPFADE4", + "S_BOUNCEPICKUPFADE5", + "S_BOUNCEPICKUPFADE6", + "S_BOUNCEPICKUPFADE7", + "S_BOUNCEPICKUPFADE8", + + "S_RAILPICKUP", + "S_RAILPICKUPFADE1", + "S_RAILPICKUPFADE2", + "S_RAILPICKUPFADE3", + "S_RAILPICKUPFADE4", + "S_RAILPICKUPFADE5", + "S_RAILPICKUPFADE6", + "S_RAILPICKUPFADE7", + "S_RAILPICKUPFADE8", + + "S_AUTOPICKUP", + "S_AUTOPICKUPFADE1", + "S_AUTOPICKUPFADE2", + "S_AUTOPICKUPFADE3", + "S_AUTOPICKUPFADE4", + "S_AUTOPICKUPFADE5", + "S_AUTOPICKUPFADE6", + "S_AUTOPICKUPFADE7", + "S_AUTOPICKUPFADE8", + + "S_EXPLODEPICKUP", + "S_EXPLODEPICKUPFADE1", + "S_EXPLODEPICKUPFADE2", + "S_EXPLODEPICKUPFADE3", + "S_EXPLODEPICKUPFADE4", + "S_EXPLODEPICKUPFADE5", + "S_EXPLODEPICKUPFADE6", + "S_EXPLODEPICKUPFADE7", + "S_EXPLODEPICKUPFADE8", + + "S_SCATTERPICKUP", + "S_SCATTERPICKUPFADE1", + "S_SCATTERPICKUPFADE2", + "S_SCATTERPICKUPFADE3", + "S_SCATTERPICKUPFADE4", + "S_SCATTERPICKUPFADE5", + "S_SCATTERPICKUPFADE6", + "S_SCATTERPICKUPFADE7", + "S_SCATTERPICKUPFADE8", + + "S_GRENADEPICKUP", + "S_GRENADEPICKUPFADE1", + "S_GRENADEPICKUPFADE2", + "S_GRENADEPICKUPFADE3", + "S_GRENADEPICKUPFADE4", + "S_GRENADEPICKUPFADE5", + "S_GRENADEPICKUPFADE6", + "S_GRENADEPICKUPFADE7", + "S_GRENADEPICKUPFADE8", + + // Thrown Weapon Rings + "S_THROWNBOUNCE1", + "S_THROWNBOUNCE2", + "S_THROWNBOUNCE3", + "S_THROWNBOUNCE4", + "S_THROWNBOUNCE5", + "S_THROWNBOUNCE6", + "S_THROWNBOUNCE7", + "S_THROWNINFINITY1", + "S_THROWNINFINITY2", + "S_THROWNINFINITY3", + "S_THROWNINFINITY4", + "S_THROWNINFINITY5", + "S_THROWNINFINITY6", + "S_THROWNINFINITY7", + "S_THROWNAUTOMATIC1", + "S_THROWNAUTOMATIC2", + "S_THROWNAUTOMATIC3", + "S_THROWNAUTOMATIC4", + "S_THROWNAUTOMATIC5", + "S_THROWNAUTOMATIC6", + "S_THROWNAUTOMATIC7", + "S_THROWNEXPLOSION1", + "S_THROWNEXPLOSION2", + "S_THROWNEXPLOSION3", + "S_THROWNEXPLOSION4", + "S_THROWNEXPLOSION5", + "S_THROWNEXPLOSION6", + "S_THROWNEXPLOSION7", + "S_THROWNGRENADE1", + "S_THROWNGRENADE2", + "S_THROWNGRENADE3", + "S_THROWNGRENADE4", + "S_THROWNGRENADE5", + "S_THROWNGRENADE6", + "S_THROWNGRENADE7", + "S_THROWNGRENADE8", + "S_THROWNGRENADE9", + "S_THROWNGRENADE10", + "S_THROWNGRENADE11", + "S_THROWNGRENADE12", + "S_THROWNGRENADE13", + "S_THROWNGRENADE14", + "S_THROWNGRENADE15", + "S_THROWNGRENADE16", + "S_THROWNGRENADE17", + "S_THROWNGRENADE18", + "S_THROWNSCATTER", + + "S_RINGEXPLODE", + + "S_COIN1", + "S_COIN2", + "S_COIN3", + "S_COINSPARKLE1", + "S_COINSPARKLE2", + "S_COINSPARKLE3", + "S_COINSPARKLE4", + "S_GOOMBA1", + "S_GOOMBA1B", + "S_GOOMBA2", + "S_GOOMBA3", + "S_GOOMBA4", + "S_GOOMBA5", + "S_GOOMBA6", + "S_GOOMBA7", + "S_GOOMBA8", + "S_GOOMBA9", + "S_GOOMBA_DEAD", + "S_BLUEGOOMBA1", + "S_BLUEGOOMBA1B", + "S_BLUEGOOMBA2", + "S_BLUEGOOMBA3", + "S_BLUEGOOMBA4", + "S_BLUEGOOMBA5", + "S_BLUEGOOMBA6", + "S_BLUEGOOMBA7", + "S_BLUEGOOMBA8", + "S_BLUEGOOMBA9", + "S_BLUEGOOMBA_DEAD", + + // Mario-specific stuff + "S_FIREFLOWER1", + "S_FIREFLOWER2", + "S_FIREFLOWER3", + "S_FIREFLOWER4", + "S_FIREBALL", + "S_FIREBALLTRAIL1", + "S_FIREBALLTRAIL2", + "S_SHELL", + "S_PUMA_START1", + "S_PUMA_START2", + "S_PUMA_UP1", + "S_PUMA_UP2", + "S_PUMA_UP3", + "S_PUMA_DOWN1", + "S_PUMA_DOWN2", + "S_PUMA_DOWN3", + "S_PUMATRAIL1", + "S_PUMATRAIL2", + "S_PUMATRAIL3", + "S_PUMATRAIL4", + "S_HAMMER", + "S_KOOPA1", + "S_KOOPA2", + "S_KOOPAFLAME1", + "S_KOOPAFLAME2", + "S_KOOPAFLAME3", + "S_AXE1", + "S_AXE2", + "S_AXE3", + "S_MARIOBUSH1", + "S_MARIOBUSH2", + "S_TOAD", + + // Nights-specific stuff + "S_NIGHTSDRONE_MAN1", + "S_NIGHTSDRONE_MAN2", + "S_NIGHTSDRONE_SPARKLING1", + "S_NIGHTSDRONE_SPARKLING2", + "S_NIGHTSDRONE_SPARKLING3", + "S_NIGHTSDRONE_SPARKLING4", + "S_NIGHTSDRONE_SPARKLING5", + "S_NIGHTSDRONE_SPARKLING6", + "S_NIGHTSDRONE_SPARKLING7", + "S_NIGHTSDRONE_SPARKLING8", + "S_NIGHTSDRONE_SPARKLING9", + "S_NIGHTSDRONE_SPARKLING10", + "S_NIGHTSDRONE_SPARKLING11", + "S_NIGHTSDRONE_SPARKLING12", + "S_NIGHTSDRONE_SPARKLING13", + "S_NIGHTSDRONE_SPARKLING14", + "S_NIGHTSDRONE_SPARKLING15", + "S_NIGHTSDRONE_SPARKLING16", + "S_NIGHTSDRONE_GOAL1", + "S_NIGHTSDRONE_GOAL2", + "S_NIGHTSDRONE_GOAL3", + "S_NIGHTSDRONE_GOAL4", + + "S_NIGHTSPARKLE1", + "S_NIGHTSPARKLE2", + "S_NIGHTSPARKLE3", + "S_NIGHTSPARKLE4", + "S_NIGHTSPARKLESUPER1", + "S_NIGHTSPARKLESUPER2", + "S_NIGHTSPARKLESUPER3", + "S_NIGHTSPARKLESUPER4", + "S_NIGHTSLOOPHELPER", + + // NiGHTS bumper + "S_NIGHTSBUMPER1", + "S_NIGHTSBUMPER2", + "S_NIGHTSBUMPER3", + "S_NIGHTSBUMPER4", + "S_NIGHTSBUMPER5", + "S_NIGHTSBUMPER6", + "S_NIGHTSBUMPER7", + "S_NIGHTSBUMPER8", + "S_NIGHTSBUMPER9", + "S_NIGHTSBUMPER10", + "S_NIGHTSBUMPER11", + "S_NIGHTSBUMPER12", + + "S_HOOP", + "S_HOOP_XMASA", + "S_HOOP_XMASB", + + "S_NIGHTSCORE10", + "S_NIGHTSCORE20", + "S_NIGHTSCORE30", + "S_NIGHTSCORE40", + "S_NIGHTSCORE50", + "S_NIGHTSCORE60", + "S_NIGHTSCORE70", + "S_NIGHTSCORE80", + "S_NIGHTSCORE90", + "S_NIGHTSCORE100", + "S_NIGHTSCORE10_2", + "S_NIGHTSCORE20_2", + "S_NIGHTSCORE30_2", + "S_NIGHTSCORE40_2", + "S_NIGHTSCORE50_2", + "S_NIGHTSCORE60_2", + "S_NIGHTSCORE70_2", + "S_NIGHTSCORE80_2", + "S_NIGHTSCORE90_2", + "S_NIGHTSCORE100_2", + + // NiGHTS Paraloop Powerups + "S_NIGHTSSUPERLOOP", + "S_NIGHTSDRILLREFILL", + "S_NIGHTSHELPER", + "S_NIGHTSEXTRATIME", + "S_NIGHTSLINKFREEZE", + "S_EGGCAPSULE", + + // Orbiting Chaos Emeralds + "S_ORBITEM1", + "S_ORBITEM2", + "S_ORBITEM3", + "S_ORBITEM4", + "S_ORBITEM5", + "S_ORBITEM6", + "S_ORBITEM7", + "S_ORBITEM8", + "S_ORBIDYA1", + "S_ORBIDYA2", + "S_ORBIDYA3", + "S_ORBIDYA4", + "S_ORBIDYA5", + + // "Flicky" helper + "S_NIGHTOPIANHELPER1", + "S_NIGHTOPIANHELPER2", + "S_NIGHTOPIANHELPER3", + "S_NIGHTOPIANHELPER4", + "S_NIGHTOPIANHELPER5", + "S_NIGHTOPIANHELPER6", + "S_NIGHTOPIANHELPER7", + "S_NIGHTOPIANHELPER8", + "S_NIGHTOPIANHELPER9", + + // Nightopian + "S_PIAN0", + "S_PIAN1", + "S_PIAN2", + "S_PIAN3", + "S_PIAN4", + "S_PIAN5", + "S_PIAN6", + "S_PIANSING", + + // Shleep + "S_SHLEEP1", + "S_SHLEEP2", + "S_SHLEEP3", + "S_SHLEEP4", + "S_SHLEEPBOUNCE1", + "S_SHLEEPBOUNCE2", + "S_SHLEEPBOUNCE3", + + // Secret badniks and hazards, shhhh + "S_PENGUINATOR_LOOK", + "S_PENGUINATOR_WADDLE1", + "S_PENGUINATOR_WADDLE2", + "S_PENGUINATOR_WADDLE3", + "S_PENGUINATOR_WADDLE4", + "S_PENGUINATOR_SLIDE1", + "S_PENGUINATOR_SLIDE2", + "S_PENGUINATOR_SLIDE3", + "S_PENGUINATOR_SLIDE4", + "S_PENGUINATOR_SLIDE5", + + "S_POPHAT_LOOK", + "S_POPHAT_SHOOT1", + "S_POPHAT_SHOOT2", + "S_POPHAT_SHOOT3", + "S_POPHAT_SHOOT4", + "S_POPSHOT", + "S_POPSHOT_TRAIL", + + "S_HIVEELEMENTAL_LOOK", + "S_HIVEELEMENTAL_PREPARE1", + "S_HIVEELEMENTAL_PREPARE2", + "S_HIVEELEMENTAL_SHOOT1", + "S_HIVEELEMENTAL_SHOOT2", + "S_HIVEELEMENTAL_DORMANT", + "S_HIVEELEMENTAL_PAIN", + "S_HIVEELEMENTAL_DIE1", + "S_HIVEELEMENTAL_DIE2", + "S_HIVEELEMENTAL_DIE3", + + "S_BUMBLEBORE_SPAWN", + "S_BUMBLEBORE_LOOK1", + "S_BUMBLEBORE_LOOK2", + "S_BUMBLEBORE_FLY1", + "S_BUMBLEBORE_FLY2", + "S_BUMBLEBORE_RAISE", + "S_BUMBLEBORE_FALL1", + "S_BUMBLEBORE_FALL2", + "S_BUMBLEBORE_STUCK1", + "S_BUMBLEBORE_STUCK2", + "S_BUMBLEBORE_DIE", + + "S_BUGGLEIDLE", + "S_BUGGLEFLY", + + "S_SMASHSPIKE_FLOAT", + "S_SMASHSPIKE_EASE1", + "S_SMASHSPIKE_EASE2", + "S_SMASHSPIKE_FALL", + "S_SMASHSPIKE_STOMP1", + "S_SMASHSPIKE_STOMP2", + "S_SMASHSPIKE_RISE1", + "S_SMASHSPIKE_RISE2", + + "S_CACO_LOOK", + "S_CACO_WAKE1", + "S_CACO_WAKE2", + "S_CACO_WAKE3", + "S_CACO_WAKE4", + "S_CACO_ROAR", + "S_CACO_CHASE", + "S_CACO_CHASE_REPEAT", + "S_CACO_RANDOM", + "S_CACO_PREPARE_SOUND", + "S_CACO_PREPARE1", + "S_CACO_PREPARE2", + "S_CACO_PREPARE3", + "S_CACO_SHOOT_SOUND", + "S_CACO_SHOOT1", + "S_CACO_SHOOT2", + "S_CACO_CLOSE", + "S_CACO_DIE_FLAGS", + "S_CACO_DIE_GIB1", + "S_CACO_DIE_GIB2", + "S_CACO_DIE_SCREAM", + "S_CACO_DIE_SHATTER", + "S_CACO_DIE_FALL", + "S_CACOSHARD_RANDOMIZE", + "S_CACOSHARD1_1", + "S_CACOSHARD1_2", + "S_CACOSHARD2_1", + "S_CACOSHARD2_2", + "S_CACOFIRE1", + "S_CACOFIRE2", + "S_CACOFIRE3", + "S_CACOFIRE_EXPLODE1", + "S_CACOFIRE_EXPLODE2", + "S_CACOFIRE_EXPLODE3", + "S_CACOFIRE_EXPLODE4", + + "S_SPINBOBERT_MOVE_FLIPUP", + "S_SPINBOBERT_MOVE_UP", + "S_SPINBOBERT_MOVE_FLIPDOWN", + "S_SPINBOBERT_MOVE_DOWN", + "S_SPINBOBERT_FIRE_MOVE", + "S_SPINBOBERT_FIRE_GHOST", + "S_SPINBOBERT_FIRE_TRAIL1", + "S_SPINBOBERT_FIRE_TRAIL2", + "S_SPINBOBERT_FIRE_TRAIL3", + + "S_HANGSTER_LOOK", + "S_HANGSTER_SWOOP1", + "S_HANGSTER_SWOOP2", + "S_HANGSTER_ARC1", + "S_HANGSTER_ARC2", + "S_HANGSTER_ARC3", + "S_HANGSTER_FLY1", + "S_HANGSTER_FLY2", + "S_HANGSTER_FLY3", + "S_HANGSTER_FLY4", + "S_HANGSTER_FLYREPEAT", + "S_HANGSTER_ARCUP1", + "S_HANGSTER_ARCUP2", + "S_HANGSTER_ARCUP3", + "S_HANGSTER_RETURN1", + "S_HANGSTER_RETURN2", + "S_HANGSTER_RETURN3", + + "S_CRUMBLE1", + "S_CRUMBLE2", + + // Spark + "S_SPRK1", + "S_SPRK2", + "S_SPRK3", + + // Robot Explosion + "S_XPLD_FLICKY", + "S_XPLD1", + "S_XPLD2", + "S_XPLD3", + "S_XPLD4", + "S_XPLD5", + "S_XPLD6", + "S_XPLD_EGGTRAP", + + // Underwater Explosion + "S_WPLD1", + "S_WPLD2", + "S_WPLD3", + "S_WPLD4", + "S_WPLD5", + "S_WPLD6", + + "S_DUST1", + "S_DUST2", + "S_DUST3", + "S_DUST4", + + "S_ROCKSPAWN", + + "S_ROCKCRUMBLEA", + "S_ROCKCRUMBLEB", + "S_ROCKCRUMBLEC", + "S_ROCKCRUMBLED", + "S_ROCKCRUMBLEE", + "S_ROCKCRUMBLEF", + "S_ROCKCRUMBLEG", + "S_ROCKCRUMBLEH", + "S_ROCKCRUMBLEI", + "S_ROCKCRUMBLEJ", + "S_ROCKCRUMBLEK", + "S_ROCKCRUMBLEL", + "S_ROCKCRUMBLEM", + "S_ROCKCRUMBLEN", + "S_ROCKCRUMBLEO", + "S_ROCKCRUMBLEP", + + // Level debris + "S_GFZDEBRIS", + "S_BRICKDEBRIS", + "S_WOODDEBRIS", + "S_REDBRICKDEBRIS", + "S_BLUEBRICKDEBRIS", + "S_YELLOWBRICKDEBRIS", + +#ifdef SEENAMES + "S_NAMECHECK", +#endif +}; + +// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", +// I am leaving the prefixes solely for clarity to programmers, +// because sadly no one remembers this place while searching for full state names. +const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity testing later. + "MT_NULL", + "MT_UNKNOWN", + + "MT_THOK", // Thok! mobj + "MT_PLAYER", + "MT_TAILSOVERLAY", // c: + "MT_METALJETFUME", + + // Enemies + "MT_BLUECRAWLA", // Crawla (Blue) + "MT_REDCRAWLA", // Crawla (Red) + "MT_GFZFISH", // SDURF + "MT_GOLDBUZZ", // Buzz (Gold) + "MT_REDBUZZ", // Buzz (Red) + "MT_JETTBOMBER", // Jetty-Syn Bomber + "MT_JETTGUNNER", // Jetty-Syn Gunner + "MT_CRAWLACOMMANDER", // Crawla Commander + "MT_DETON", // Deton + "MT_SKIM", // Skim mine dropper + "MT_TURRET", // Industrial Turret + "MT_POPUPTURRET", // Pop-Up Turret + "MT_SPINCUSHION", // Spincushion + "MT_CRUSHSTACEAN", // Crushstacean + "MT_CRUSHCLAW", // Big meaty claw + "MT_CRUSHCHAIN", // Chain + "MT_BANPYURA", // Banpyura + "MT_BANPSPRING", // Banpyura spring + "MT_JETJAW", // Jet Jaw + "MT_SNAILER", // Snailer + "MT_VULTURE", // BASH + "MT_POINTY", // Pointy + "MT_POINTYBALL", // Pointy Ball + "MT_ROBOHOOD", // Robo-Hood + "MT_FACESTABBER", // Castlebot Facestabber + "MT_FACESTABBERSPEAR", // Castlebot Facestabber spear aura + "MT_EGGGUARD", // Egg Guard + "MT_EGGSHIELD", // Egg Guard's shield + "MT_GSNAPPER", // Green Snapper + "MT_SNAPPER_LEG", // Green Snapper leg + "MT_SNAPPER_HEAD", // Green Snapper head + "MT_MINUS", // Minus + "MT_MINUSDIRT", // Minus dirt + "MT_SPRINGSHELL", // Spring Shell + "MT_YELLOWSHELL", // Spring Shell (yellow) + "MT_UNIDUS", // Unidus + "MT_UNIBALL", // Unidus Ball + "MT_CANARIVORE", // Canarivore + "MT_CANARIVORE_GAS", // Canarivore gas + "MT_PYREFLY", // Pyre Fly + "MT_PYREFLY_FIRE", // Pyre Fly fire + "MT_PTERABYTESPAWNER", // Pterabyte spawner + "MT_PTERABYTEWAYPOINT", // Pterabyte waypoint + "MT_PTERABYTE", // Pterabyte + "MT_DRAGONBOMBER", // Dragonbomber + "MT_DRAGONWING", // Dragonbomber wing + "MT_DRAGONTAIL", // Dragonbomber tail segment + "MT_DRAGONMINE", // Dragonbomber mine + + // Generic Boss Items + "MT_BOSSEXPLODE", + "MT_SONIC3KBOSSEXPLODE", + "MT_BOSSFLYPOINT", + "MT_EGGTRAP", + "MT_BOSS3WAYPOINT", + "MT_BOSS9GATHERPOINT", + "MT_BOSSJUNK", + + // Boss 1 + "MT_EGGMOBILE", + "MT_JETFUME1", + "MT_EGGMOBILE_BALL", + "MT_EGGMOBILE_TARGET", + "MT_EGGMOBILE_FIRE", + + // Boss 2 + "MT_EGGMOBILE2", + "MT_EGGMOBILE2_POGO", + "MT_GOOP", + "MT_GOOPTRAIL", + + // Boss 3 + "MT_EGGMOBILE3", + "MT_FAKEMOBILE", + "MT_SHOCKWAVE", + + // Boss 4 + "MT_EGGMOBILE4", + "MT_EGGMOBILE4_MACE", + "MT_JETFLAME", + "MT_EGGROBO1", + "MT_EGGROBO1JET", + + // Boss 5 + "MT_FANG", + "MT_BROKENROBOT", + "MT_VWREF", + "MT_VWREB", + "MT_PROJECTORLIGHT", + "MT_FBOMB", + "MT_TNTDUST", // also used by barrel + "MT_FSGNA", + "MT_FSGNB", + "MT_FANGWAYPOINT", + + // Black Eggman (Boss 7) + "MT_BLACKEGGMAN", + "MT_BLACKEGGMAN_HELPER", + "MT_BLACKEGGMAN_GOOPFIRE", + "MT_BLACKEGGMAN_MISSILE", + + // New Very-Last-Minute 2.1 Brak Eggman (Cy-Brak-demon) + "MT_CYBRAKDEMON", + "MT_CYBRAKDEMON_ELECTRIC_BARRIER", + "MT_CYBRAKDEMON_MISSILE", + "MT_CYBRAKDEMON_FLAMESHOT", + "MT_CYBRAKDEMON_FLAMEREST", + "MT_CYBRAKDEMON_TARGET_RETICULE", + "MT_CYBRAKDEMON_TARGET_DOT", + "MT_CYBRAKDEMON_NAPALM_BOMB_LARGE", + "MT_CYBRAKDEMON_NAPALM_BOMB_SMALL", + "MT_CYBRAKDEMON_NAPALM_FLAMES", + "MT_CYBRAKDEMON_VILE_EXPLOSION", + + // Metal Sonic (Boss 9) + "MT_METALSONIC_RACE", + "MT_METALSONIC_BATTLE", + "MT_MSSHIELD_FRONT", + "MT_MSGATHER", + + // Collectible Items + "MT_RING", + "MT_FLINGRING", // Lost ring + "MT_BLUESPHERE", // Blue sphere for special stages + "MT_FLINGBLUESPHERE", // Lost blue sphere + "MT_BOMBSPHERE", + "MT_REDTEAMRING", //Rings collectable by red team. + "MT_BLUETEAMRING", //Rings collectable by blue team. + "MT_TOKEN", // Special Stage token for special stage + "MT_REDFLAG", // Red CTF Flag + "MT_BLUEFLAG", // Blue CTF Flag + "MT_EMBLEM", + "MT_EMERALD1", + "MT_EMERALD2", + "MT_EMERALD3", + "MT_EMERALD4", + "MT_EMERALD5", + "MT_EMERALD6", + "MT_EMERALD7", + "MT_EMERHUNT", // Emerald Hunt + "MT_EMERALDSPAWN", // Emerald spawner w/ delay + "MT_FLINGEMERALD", // Lost emerald + + // Springs and others + "MT_FAN", + "MT_STEAM", + "MT_BUMPER", + "MT_BALLOON", + + "MT_YELLOWSPRING", + "MT_REDSPRING", + "MT_BLUESPRING", + "MT_YELLOWDIAG", + "MT_REDDIAG", + "MT_BLUEDIAG", + "MT_YELLOWHORIZ", + "MT_REDHORIZ", + "MT_BLUEHORIZ", + + "MT_BOOSTERSEG", + "MT_BOOSTERROLLER", + "MT_YELLOWBOOSTER", + "MT_REDBOOSTER", + + // Interactive Objects + "MT_BUBBLES", // Bubble source + "MT_SIGN", // Level end sign + "MT_SPIKEBALL", // Spike Ball + "MT_SPINFIRE", + "MT_SPIKE", + "MT_WALLSPIKE", + "MT_WALLSPIKEBASE", + "MT_STARPOST", + "MT_BIGMINE", + "MT_BLASTEXECUTOR", + "MT_CANNONLAUNCHER", + + // Monitor miscellany + "MT_BOXSPARKLE", + + // Monitor boxes -- regular + "MT_RING_BOX", + "MT_PITY_BOX", + "MT_ATTRACT_BOX", + "MT_FORCE_BOX", + "MT_ARMAGEDDON_BOX", + "MT_WHIRLWIND_BOX", + "MT_ELEMENTAL_BOX", + "MT_SNEAKERS_BOX", + "MT_INVULN_BOX", + "MT_1UP_BOX", + "MT_EGGMAN_BOX", + "MT_MIXUP_BOX", + "MT_MYSTERY_BOX", + "MT_GRAVITY_BOX", + "MT_RECYCLER_BOX", + "MT_SCORE1K_BOX", + "MT_SCORE10K_BOX", + "MT_FLAMEAURA_BOX", + "MT_BUBBLEWRAP_BOX", + "MT_THUNDERCOIN_BOX", + + // Monitor boxes -- repeating (big) boxes + "MT_PITY_GOLDBOX", + "MT_ATTRACT_GOLDBOX", + "MT_FORCE_GOLDBOX", + "MT_ARMAGEDDON_GOLDBOX", + "MT_WHIRLWIND_GOLDBOX", + "MT_ELEMENTAL_GOLDBOX", + "MT_SNEAKERS_GOLDBOX", + "MT_INVULN_GOLDBOX", + "MT_EGGMAN_GOLDBOX", + "MT_GRAVITY_GOLDBOX", + "MT_FLAMEAURA_GOLDBOX", + "MT_BUBBLEWRAP_GOLDBOX", + "MT_THUNDERCOIN_GOLDBOX", + + // Monitor boxes -- special + "MT_RING_REDBOX", + "MT_RING_BLUEBOX", + + // Monitor icons + "MT_RING_ICON", + "MT_PITY_ICON", + "MT_ATTRACT_ICON", + "MT_FORCE_ICON", + "MT_ARMAGEDDON_ICON", + "MT_WHIRLWIND_ICON", + "MT_ELEMENTAL_ICON", + "MT_SNEAKERS_ICON", + "MT_INVULN_ICON", + "MT_1UP_ICON", + "MT_EGGMAN_ICON", + "MT_MIXUP_ICON", + "MT_GRAVITY_ICON", + "MT_RECYCLER_ICON", + "MT_SCORE1K_ICON", + "MT_SCORE10K_ICON", + "MT_FLAMEAURA_ICON", + "MT_BUBBLEWRAP_ICON", + "MT_THUNDERCOIN_ICON", + + // Projectiles + "MT_ROCKET", + "MT_LASER", + "MT_TORPEDO", + "MT_TORPEDO2", // silent + "MT_ENERGYBALL", + "MT_MINE", // Skim/Jetty-Syn mine + "MT_JETTBULLET", // Jetty-Syn Bullet + "MT_TURRETLASER", + "MT_CANNONBALL", // Cannonball + "MT_CANNONBALLDECOR", // Decorative/still cannonball + "MT_ARROW", // Arrow + "MT_DEMONFIRE", // Glaregoyle fire + + // The letter + "MT_LETTER", + + // Greenflower Scenery + "MT_GFZFLOWER1", + "MT_GFZFLOWER2", + "MT_GFZFLOWER3", + + "MT_BLUEBERRYBUSH", + "MT_BERRYBUSH", + "MT_BUSH", + + // Trees (both GFZ and misc) + "MT_GFZTREE", + "MT_GFZBERRYTREE", + "MT_GFZCHERRYTREE", + "MT_CHECKERTREE", + "MT_CHECKERSUNSETTREE", + "MT_FHZTREE", // Frozen Hillside + "MT_FHZPINKTREE", + "MT_POLYGONTREE", + "MT_BUSHTREE", + "MT_BUSHREDTREE", + "MT_SPRINGTREE", + + // Techno Hill Scenery + "MT_THZFLOWER1", + "MT_THZFLOWER2", + "MT_THZFLOWER3", + "MT_THZTREE", // Steam whistle tree/bush + "MT_THZTREEBRANCH", // branch of said tree + "MT_ALARM", + + // Deep Sea Scenery + "MT_GARGOYLE", // Deep Sea Gargoyle + "MT_BIGGARGOYLE", // Deep Sea Gargoyle (Big) + "MT_SEAWEED", // DSZ Seaweed + "MT_WATERDRIP", // Dripping Water source + "MT_WATERDROP", // Water drop from dripping water + "MT_CORAL1", // Coral + "MT_CORAL2", + "MT_CORAL3", + "MT_CORAL4", + "MT_CORAL5", + "MT_BLUECRYSTAL", // Blue Crystal + "MT_KELP", // Kelp + "MT_ANIMALGAETOP", // Animated algae top + "MT_ANIMALGAESEG", // Animated algae segment + "MT_DSZSTALAGMITE", // Deep Sea 1 Stalagmite + "MT_DSZ2STALAGMITE", // Deep Sea 2 Stalagmite + "MT_LIGHTBEAM", // DSZ Light beam + + // Castle Eggman Scenery + "MT_CHAIN", // CEZ Chain + "MT_FLAME", // Flame (has corona) + "MT_FLAMEPARTICLE", + "MT_EGGSTATUE", // Eggman Statue + "MT_MACEPOINT", // Mace rotation point + "MT_CHAINMACEPOINT", // Combination of chains and maces point + "MT_SPRINGBALLPOINT", // Spring ball point + "MT_CHAINPOINT", // Mace chain + "MT_HIDDEN_SLING", // Spin mace chain (activatable) + "MT_FIREBARPOINT", // Firebar + "MT_CUSTOMMACEPOINT", // Custom mace + "MT_SMALLMACECHAIN", // Small Mace Chain + "MT_BIGMACECHAIN", // Big Mace Chain + "MT_SMALLMACE", // Small Mace + "MT_BIGMACE", // Big Mace + "MT_SMALLGRABCHAIN", // Small Grab Chain + "MT_BIGGRABCHAIN", // Big Grab Chain + "MT_YELLOWSPRINGBALL", // Yellow spring on a ball + "MT_REDSPRINGBALL", // Red spring on a ball + "MT_SMALLFIREBAR", // Small Firebar + "MT_BIGFIREBAR", // Big Firebar + "MT_CEZFLOWER", // Flower + "MT_CEZPOLE1", // Pole (with red banner) + "MT_CEZPOLE2", // Pole (with blue banner) + "MT_CEZBANNER1", // Banner (red) + "MT_CEZBANNER2", // Banner (blue) + "MT_PINETREE", // Pine Tree + "MT_CEZBUSH1", // Bush 1 + "MT_CEZBUSH2", // Bush 2 + "MT_CANDLE", // Candle + "MT_CANDLEPRICKET", // Candle pricket + "MT_FLAMEHOLDER", // Flame holder + "MT_FIRETORCH", // Fire torch + "MT_WAVINGFLAG1", // Waving flag (red) + "MT_WAVINGFLAG2", // Waving flag (blue) + "MT_WAVINGFLAGSEG1", // Waving flag segment (red) + "MT_WAVINGFLAGSEG2", // Waving flag segment (blue) + "MT_CRAWLASTATUE", // Crawla statue + "MT_FACESTABBERSTATUE", // Facestabber statue + "MT_SUSPICIOUSFACESTABBERSTATUE", // :eggthinking: + "MT_BRAMBLES", // Brambles + + // Arid Canyon Scenery + "MT_BIGTUMBLEWEED", + "MT_LITTLETUMBLEWEED", + "MT_CACTI1", // Tiny Red Flower Cactus + "MT_CACTI2", // Small Red Flower Cactus + "MT_CACTI3", // Tiny Blue Flower Cactus + "MT_CACTI4", // Small Blue Flower Cactus + "MT_CACTI5", // Prickly Pear + "MT_CACTI6", // Barrel Cactus + "MT_CACTI7", // Tall Barrel Cactus + "MT_CACTI8", // Armed Cactus + "MT_CACTI9", // Ball Cactus + "MT_CACTI10", // Tiny Cactus + "MT_CACTI11", // Small Cactus + "MT_CACTITINYSEG", // Tiny Cactus Segment + "MT_CACTISMALLSEG", // Small Cactus Segment + "MT_ARIDSIGN_CAUTION", // Caution Sign + "MT_ARIDSIGN_CACTI", // Cacti Sign + "MT_ARIDSIGN_SHARPTURN", // Sharp Turn Sign + "MT_OILLAMP", + "MT_TNTBARREL", + "MT_PROXIMITYTNT", + "MT_DUSTDEVIL", + "MT_DUSTLAYER", + "MT_ARIDDUST", + "MT_MINECART", + "MT_MINECARTSEG", + "MT_MINECARTSPAWNER", + "MT_MINECARTEND", + "MT_MINECARTENDSOLID", + "MT_MINECARTSIDEMARK", + "MT_MINECARTSPARK", + "MT_SALOONDOOR", + "MT_SALOONDOORCENTER", + "MT_TRAINCAMEOSPAWNER", + "MT_TRAINSEG", + "MT_TRAINDUSTSPAWNER", + "MT_TRAINSTEAMSPAWNER", + "MT_MINECARTSWITCHPOINT", + + // Red Volcano Scenery + "MT_FLAMEJET", + "MT_VERTICALFLAMEJET", + "MT_FLAMEJETFLAME", + + "MT_FJSPINAXISA", // Counter-clockwise + "MT_FJSPINAXISB", // Clockwise + + "MT_FLAMEJETFLAMEB", // Blade's flame + + "MT_LAVAFALL", + "MT_LAVAFALL_LAVA", + "MT_LAVAFALLROCK", + + "MT_ROLLOUTSPAWN", + "MT_ROLLOUTROCK", + + "MT_BIGFERNLEAF", + "MT_BIGFERN", + "MT_JUNGLEPALM", + "MT_TORCHFLOWER", + "MT_WALLVINE_LONG", + "MT_WALLVINE_SHORT", + + // Dark City Scenery + + // Egg Rock Scenery + + // Azure Temple Scenery + "MT_GLAREGOYLE", + "MT_GLAREGOYLEUP", + "MT_GLAREGOYLEDOWN", + "MT_GLAREGOYLELONG", + "MT_TARGET", // AKA Red Crystal + "MT_GREENFLAME", + "MT_BLUEGARGOYLE", + + // Stalagmites + "MT_STALAGMITE0", + "MT_STALAGMITE1", + "MT_STALAGMITE2", + "MT_STALAGMITE3", + "MT_STALAGMITE4", + "MT_STALAGMITE5", + "MT_STALAGMITE6", + "MT_STALAGMITE7", + "MT_STALAGMITE8", + "MT_STALAGMITE9", + + // Christmas Scenery + "MT_XMASPOLE", + "MT_CANDYCANE", + "MT_SNOWMAN", // normal + "MT_SNOWMANHAT", // with hat + scarf + "MT_LAMPPOST1", // normal + "MT_LAMPPOST2", // with snow + "MT_HANGSTAR", + "MT_MISTLETOE", + // Xmas GFZ bushes + "MT_XMASBLUEBERRYBUSH", + "MT_XMASBERRYBUSH", + "MT_XMASBUSH", + // FHZ + "MT_FHZICE1", + "MT_FHZICE2", + "MT_ROSY", + "MT_CDLHRT", + + // Halloween Scenery + // Pumpkins + "MT_JACKO1", + "MT_JACKO2", + "MT_JACKO3", + // Dr Seuss Trees + "MT_HHZTREE_TOP", + "MT_HHZTREE_PART", + // Misc + "MT_HHZSHROOM", + "MT_HHZGRASS", + "MT_HHZTENTACLE1", + "MT_HHZTENTACLE2", + "MT_HHZSTALAGMITE_TALL", + "MT_HHZSTALAGMITE_SHORT", + + // Botanic Serenity scenery + "MT_BSZTALLFLOWER_RED", + "MT_BSZTALLFLOWER_PURPLE", + "MT_BSZTALLFLOWER_BLUE", + "MT_BSZTALLFLOWER_CYAN", + "MT_BSZTALLFLOWER_YELLOW", + "MT_BSZTALLFLOWER_ORANGE", + "MT_BSZFLOWER_RED", + "MT_BSZFLOWER_PURPLE", + "MT_BSZFLOWER_BLUE", + "MT_BSZFLOWER_CYAN", + "MT_BSZFLOWER_YELLOW", + "MT_BSZFLOWER_ORANGE", + "MT_BSZSHORTFLOWER_RED", + "MT_BSZSHORTFLOWER_PURPLE", + "MT_BSZSHORTFLOWER_BLUE", + "MT_BSZSHORTFLOWER_CYAN", + "MT_BSZSHORTFLOWER_YELLOW", + "MT_BSZSHORTFLOWER_ORANGE", + "MT_BSZTULIP_RED", + "MT_BSZTULIP_PURPLE", + "MT_BSZTULIP_BLUE", + "MT_BSZTULIP_CYAN", + "MT_BSZTULIP_YELLOW", + "MT_BSZTULIP_ORANGE", + "MT_BSZCLUSTER_RED", + "MT_BSZCLUSTER_PURPLE", + "MT_BSZCLUSTER_BLUE", + "MT_BSZCLUSTER_CYAN", + "MT_BSZCLUSTER_YELLOW", + "MT_BSZCLUSTER_ORANGE", + "MT_BSZBUSH_RED", + "MT_BSZBUSH_PURPLE", + "MT_BSZBUSH_BLUE", + "MT_BSZBUSH_CYAN", + "MT_BSZBUSH_YELLOW", + "MT_BSZBUSH_ORANGE", + "MT_BSZVINE_RED", + "MT_BSZVINE_PURPLE", + "MT_BSZVINE_BLUE", + "MT_BSZVINE_CYAN", + "MT_BSZVINE_YELLOW", + "MT_BSZVINE_ORANGE", + "MT_BSZSHRUB", + "MT_BSZCLOVER", + "MT_BIG_PALMTREE_TRUNK", + "MT_BIG_PALMTREE_TOP", + "MT_PALMTREE_TRUNK", + "MT_PALMTREE_TOP", + + // Misc scenery + "MT_DBALL", + "MT_EGGSTATUE2", + + // Powerup Indicators + "MT_ELEMENTAL_ORB", // Elemental shield mobj + "MT_ATTRACT_ORB", // Attract shield mobj + "MT_FORCE_ORB", // Force shield mobj + "MT_ARMAGEDDON_ORB", // Armageddon shield mobj + "MT_WHIRLWIND_ORB", // Whirlwind shield mobj + "MT_PITY_ORB", // Pity shield mobj + "MT_FLAMEAURA_ORB", // Flame shield mobj + "MT_BUBBLEWRAP_ORB", // Bubble shield mobj + "MT_THUNDERCOIN_ORB", // Thunder shield mobj + "MT_THUNDERCOIN_SPARK", // Thunder spark + "MT_IVSP", // Invincibility sparkles + "MT_SUPERSPARK", // Super Sonic Spark + + // Flickies + "MT_FLICKY_01", // Bluebird + "MT_FLICKY_01_CENTER", + "MT_FLICKY_02", // Rabbit + "MT_FLICKY_02_CENTER", + "MT_FLICKY_03", // Chicken + "MT_FLICKY_03_CENTER", + "MT_FLICKY_04", // Seal + "MT_FLICKY_04_CENTER", + "MT_FLICKY_05", // Pig + "MT_FLICKY_05_CENTER", + "MT_FLICKY_06", // Chipmunk + "MT_FLICKY_06_CENTER", + "MT_FLICKY_07", // Penguin + "MT_FLICKY_07_CENTER", + "MT_FLICKY_08", // Fish + "MT_FLICKY_08_CENTER", + "MT_FLICKY_09", // Ram + "MT_FLICKY_09_CENTER", + "MT_FLICKY_10", // Puffin + "MT_FLICKY_10_CENTER", + "MT_FLICKY_11", // Cow + "MT_FLICKY_11_CENTER", + "MT_FLICKY_12", // Rat + "MT_FLICKY_12_CENTER", + "MT_FLICKY_13", // Bear + "MT_FLICKY_13_CENTER", + "MT_FLICKY_14", // Dove + "MT_FLICKY_14_CENTER", + "MT_FLICKY_15", // Cat + "MT_FLICKY_15_CENTER", + "MT_FLICKY_16", // Canary + "MT_FLICKY_16_CENTER", + "MT_SECRETFLICKY_01", // Spider + "MT_SECRETFLICKY_01_CENTER", + "MT_SECRETFLICKY_02", // Bat + "MT_SECRETFLICKY_02_CENTER", + "MT_SEED", + + // Environmental Effects + "MT_RAIN", // Rain + "MT_SNOWFLAKE", // Snowflake + "MT_SPLISH", // Water splish! + "MT_LAVASPLISH", // Lava splish! + "MT_SMOKE", + "MT_SMALLBUBBLE", // small bubble + "MT_MEDIUMBUBBLE", // medium bubble + "MT_EXTRALARGEBUBBLE", // extra large bubble + "MT_WATERZAP", + "MT_SPINDUST", // Spindash dust + "MT_TFOG", + "MT_PARTICLE", + "MT_PARTICLEGEN", // For fans, etc. + + // Game Indicators + "MT_SCORE", // score logo + "MT_DROWNNUMBERS", // Drowning Timer + "MT_GOTEMERALD", // Chaos Emerald (intangible) + "MT_LOCKON", // Target + "MT_LOCKONINF", // In-level Target + "MT_TAG", // Tag Sign + "MT_GOTFLAG", // Got Flag sign + "MT_FINISHFLAG", // Finish flag + + // Ambient Sounds + "MT_AWATERA", // Ambient Water Sound 1 + "MT_AWATERB", // Ambient Water Sound 2 + "MT_AWATERC", // Ambient Water Sound 3 + "MT_AWATERD", // Ambient Water Sound 4 + "MT_AWATERE", // Ambient Water Sound 5 + "MT_AWATERF", // Ambient Water Sound 6 + "MT_AWATERG", // Ambient Water Sound 7 + "MT_AWATERH", // Ambient Water Sound 8 + "MT_RANDOMAMBIENT", + "MT_RANDOMAMBIENT2", + "MT_MACHINEAMBIENCE", + + "MT_CORK", + "MT_LHRT", + + // Ring Weapons + "MT_REDRING", + "MT_BOUNCERING", + "MT_RAILRING", + "MT_INFINITYRING", + "MT_AUTOMATICRING", + "MT_EXPLOSIONRING", + "MT_SCATTERRING", + "MT_GRENADERING", + + "MT_BOUNCEPICKUP", + "MT_RAILPICKUP", + "MT_AUTOPICKUP", + "MT_EXPLODEPICKUP", + "MT_SCATTERPICKUP", + "MT_GRENADEPICKUP", + + "MT_THROWNBOUNCE", + "MT_THROWNINFINITY", + "MT_THROWNAUTOMATIC", + "MT_THROWNSCATTER", + "MT_THROWNEXPLOSION", + "MT_THROWNGRENADE", + + // Mario-specific stuff + "MT_COIN", + "MT_FLINGCOIN", + "MT_GOOMBA", + "MT_BLUEGOOMBA", + "MT_FIREFLOWER", + "MT_FIREBALL", + "MT_FIREBALLTRAIL", + "MT_SHELL", + "MT_PUMA", + "MT_PUMATRAIL", + "MT_HAMMER", + "MT_KOOPA", + "MT_KOOPAFLAME", + "MT_AXE", + "MT_MARIOBUSH1", + "MT_MARIOBUSH2", + "MT_TOAD", + + // NiGHTS Stuff + "MT_AXIS", + "MT_AXISTRANSFER", + "MT_AXISTRANSFERLINE", + "MT_NIGHTSDRONE", + "MT_NIGHTSDRONE_MAN", + "MT_NIGHTSDRONE_SPARKLING", + "MT_NIGHTSDRONE_GOAL", + "MT_NIGHTSPARKLE", + "MT_NIGHTSLOOPHELPER", + "MT_NIGHTSBUMPER", // NiGHTS Bumper + "MT_HOOP", + "MT_HOOPCOLLIDE", // Collision detection for NiGHTS hoops + "MT_HOOPCENTER", // Center of a hoop + "MT_NIGHTSCORE", + "MT_NIGHTSCHIP", // NiGHTS Chip + "MT_FLINGNIGHTSCHIP", // Lost NiGHTS Chip + "MT_NIGHTSSTAR", // NiGHTS Star + "MT_FLINGNIGHTSSTAR", // Lost NiGHTS Star + "MT_NIGHTSSUPERLOOP", + "MT_NIGHTSDRILLREFILL", + "MT_NIGHTSHELPER", + "MT_NIGHTSEXTRATIME", + "MT_NIGHTSLINKFREEZE", + "MT_EGGCAPSULE", + "MT_IDEYAANCHOR", + "MT_NIGHTOPIANHELPER", // the actual helper object that orbits you + "MT_PIAN", // decorative singing friend + "MT_SHLEEP", // almost-decorative sleeping enemy + + // Secret badniks and hazards, shhhh + "MT_PENGUINATOR", + "MT_POPHAT", + "MT_POPSHOT", + "MT_POPSHOT_TRAIL", + + "MT_HIVEELEMENTAL", + "MT_BUMBLEBORE", + + "MT_BUGGLE", + + "MT_SMASHINGSPIKEBALL", + "MT_CACOLANTERN", + "MT_CACOSHARD", + "MT_CACOFIRE", + "MT_SPINBOBERT", + "MT_SPINBOBERT_FIRE1", + "MT_SPINBOBERT_FIRE2", + "MT_HANGSTER", + + // Utility Objects + "MT_TELEPORTMAN", + "MT_ALTVIEWMAN", + "MT_CRUMBLEOBJ", // Sound generator for crumbling platform + "MT_TUBEWAYPOINT", + "MT_PUSH", + "MT_PULL", + "MT_GHOST", + "MT_OVERLAY", + "MT_ANGLEMAN", + "MT_POLYANCHOR", + "MT_POLYSPAWN", + + // Skybox objects + "MT_SKYBOX", + + // Debris + "MT_SPARK", //spark + "MT_EXPLODE", // Robot Explosion + "MT_UWEXPLODE", // Underwater Explosion + "MT_DUST", + "MT_ROCKSPAWNER", + "MT_FALLINGROCK", + "MT_ROCKCRUMBLE1", + "MT_ROCKCRUMBLE2", + "MT_ROCKCRUMBLE3", + "MT_ROCKCRUMBLE4", + "MT_ROCKCRUMBLE5", + "MT_ROCKCRUMBLE6", + "MT_ROCKCRUMBLE7", + "MT_ROCKCRUMBLE8", + "MT_ROCKCRUMBLE9", + "MT_ROCKCRUMBLE10", + "MT_ROCKCRUMBLE11", + "MT_ROCKCRUMBLE12", + "MT_ROCKCRUMBLE13", + "MT_ROCKCRUMBLE14", + "MT_ROCKCRUMBLE15", + "MT_ROCKCRUMBLE16", + + // Level debris + "MT_GFZDEBRIS", + "MT_BRICKDEBRIS", + "MT_WOODDEBRIS", + "MT_REDBRICKDEBRIS", + "MT_BLUEBRICKDEBRIS", + "MT_YELLOWBRICKDEBRIS", + +#ifdef SEENAMES + "MT_NAMECHECK", +#endif +}; + +const char *const MOBJFLAG_LIST[] = { + "SPECIAL", + "SOLID", + "SHOOTABLE", + "NOSECTOR", + "NOBLOCKMAP", + "PAPERCOLLISION", + "PUSHABLE", + "BOSS", + "SPAWNCEILING", + "NOGRAVITY", + "AMBIENT", + "SLIDEME", + "NOCLIP", + "FLOAT", + "BOXICON", + "MISSILE", + "SPRING", + "BOUNCE", + "MONITOR", + "NOTHINK", + "FIRE", + "NOCLIPHEIGHT", + "ENEMY", + "SCENERY", + "PAIN", + "STICKY", + "NIGHTSITEM", + "NOCLIPTHING", + "GRENADEBOUNCE", + "RUNSPAWNFUNC", + NULL +}; + +// \tMF2_(\S+).*// (.+) --> \t"\1", // \2 +const char *const MOBJFLAG2_LIST[] = { + "AXIS", // It's a NiGHTS axis! (For faster checking) + "TWOD", // Moves like it's in a 2D level + "DONTRESPAWN", // Don't respawn this object! + "DONTDRAW", // Don't generate a vissprite + "AUTOMATIC", // Thrown ring has automatic properties + "RAILRING", // Thrown ring has rail properties + "BOUNCERING", // Thrown ring has bounce properties + "EXPLOSION", // Thrown ring has explosive properties + "SCATTER", // Thrown ring has scatter properties + "BEYONDTHEGRAVE", // Source of this missile has died and has since respawned. + "SLIDEPUSH", // MF_PUSHABLE that pushes continuously. + "CLASSICPUSH", // Drops straight down when object has negative momz. + "INVERTAIMABLE", // Flips whether it's targetable by A_LookForEnemies (enemies no, decoys yes) + "INFLOAT", // Floating to a height for a move, don't auto float to target's height. + "DEBRIS", // Splash ring from explosion ring + "NIGHTSPULL", // Attracted from a paraloop + "JUSTATTACKED", // can be pushed by other moving mobjs + "FIRING", // turret fire + "SUPERFIRE", // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it. + "SHADOW", // Fuzzy draw, makes targeting harder. + "STRONGBOX", // Flag used for "strong" random monitors. + "OBJECTFLIP", // Flag for objects that always have flipped gravity. + "SKULLFLY", // Special handling: skull in flight. + "FRET", // Flashing from a previous hit + "BOSSNOTRAP", // No Egg Trap after boss + "BOSSFLEE", // Boss is fleeing! + "BOSSDEAD", // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.) + "AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH + "LINKDRAW", // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) + "SHIELD", // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use) + NULL +}; + +const char *const MOBJEFLAG_LIST[] = { + "ONGROUND", // The mobj stands on solid floor (not on another mobj or in air) + "JUSTHITFLOOR", // The mobj just hit the floor while falling, this is cleared on next frame + "TOUCHWATER", // The mobj stands in a sector with water, and touches the surface + "UNDERWATER", // The mobj stands in a sector with water, and his waist is BELOW the water surface + "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 +}; + +const char *const MAPTHINGFLAG_LIST[4] = { + "EXTRA", // Extra flag for objects. + "OBJECTFLIP", // Reverse gravity flag for objects. + "OBJECTSPECIAL", // Special flag used with certain objects. + "AMBUSH" // Deaf monsters/do not react to sound. +}; + +const char *const PLAYERFLAG_LIST[] = { + + // Cvars + "FLIPCAM", // Flip camera angle with gravity flip prefrence. + "ANALOGMODE", // Analog mode? + "DIRECTIONCHAR", // Directional character sprites? + "AUTOBRAKE", // Autobrake? + + // Cheats + "GODMODE", + "NOCLIP", + "INVIS", + + // True if button down last tic. + "ATTACKDOWN", + "SPINDOWN", + "JUMPDOWN", + "WPNDOWN", + + // Unmoving states + "STASIS", // Player is not allowed to move + "JUMPSTASIS", // and that includes jumping. + // (we don't include FULLSTASIS here I guess because it's just those two together...?) + + // Applying autobrake? + "APPLYAUTOBRAKE", + + // Character action status + "STARTJUMP", + "JUMPED", + "NOJUMPDAMAGE", + + "SPINNING", + "STARTDASH", + + "THOKKED", + "SHIELDABILITY", + "GLIDING", + "BOUNCING", + + // Sliding (usually in water) like Labyrinth/Oil Ocean + "SLIDING", + + // NiGHTS stuff + "TRANSFERTOCLOSEST", + "DRILLING", + + // Gametype-specific stuff + "GAMETYPEOVER", // Race time over, or H&S out-of-game + "TAGIT", // The player is it! For Tag Mode + + /*** misc ***/ + "FORCESTRAFE", // Translate turn inputs into strafe inputs + "CANCARRY", // Can carry? + "FINISHED", + + NULL // stop loop here. +}; + +const char *const GAMETYPERULE_LIST[] = { + "CAMPAIGN", + "RINGSLINGER", + "SPECTATORS", + "LIVES", + "TEAMS", + "FIRSTPERSON", + "POWERSTONES", + "TEAMFLAGS", + "FRIENDLY", + "SPECIALSTAGES", + "EMERALDTOKENS", + "EMERALDHUNT", + "RACE", + "TAG", + "POINTLIMIT", + "TIMELIMIT", + "OVERTIME", + "HURTMESSAGES", + "FRIENDLYFIRE", + "STARTCOUNTDOWN", + "HIDEFROZEN", + "BLINDFOLDED", + "RESPAWNDELAY", + "PITYSHIELD", + "DEATHPENALTY", + "NOSPECTATORSPAWN", + "DEATHMATCHSTARTS", + "SPAWNINVUL", + "SPAWNENEMIES", + "ALLOWEXIT", + "NOTITLECARD", + "CUTSCENES", + NULL +}; + +// Linedef flags +const char *const ML_LIST[16] = { + "IMPASSIBLE", + "BLOCKMONSTERS", + "TWOSIDED", + "DONTPEGTOP", + "DONTPEGBOTTOM", + "EFFECT1", + "NOCLIMB", + "EFFECT2", + "EFFECT3", + "EFFECT4", + "EFFECT5", + "NOSONIC", + "NOTAILS", + "NOKNUX", + "BOUNCY", + "TFERLINE" +}; + +const char *COLOR_ENUMS[] = { + "NONE", // SKINCOLOR_NONE, + + // Greyscale ranges + "WHITE", // SKINCOLOR_WHITE, + "BONE", // SKINCOLOR_BONE, + "CLOUDY", // SKINCOLOR_CLOUDY, + "GREY", // SKINCOLOR_GREY, + "SILVER", // SKINCOLOR_SILVER, + "CARBON", // SKINCOLOR_CARBON, + "JET", // SKINCOLOR_JET, + "BLACK", // SKINCOLOR_BLACK, + + // Desaturated + "AETHER", // SKINCOLOR_AETHER, + "SLATE", // SKINCOLOR_SLATE, + "BLUEBELL", // SKINCOLOR_BLUEBELL, + "PINK", // SKINCOLOR_PINK, + "YOGURT", // SKINCOLOR_YOGURT, + "BROWN", // SKINCOLOR_BROWN, + "BRONZE", // SKINCOLOR_BRONZE, + "TAN", // SKINCOLOR_TAN, + "BEIGE", // SKINCOLOR_BEIGE, + "MOSS", // SKINCOLOR_MOSS, + "AZURE", // SKINCOLOR_AZURE, + "LAVENDER", // SKINCOLOR_LAVENDER, + + // Viv's vivid colours (toast 21/07/17) + "RUBY", // SKINCOLOR_RUBY, + "SALMON", // SKINCOLOR_SALMON, + "RED", // SKINCOLOR_RED, + "CRIMSON", // SKINCOLOR_CRIMSON, + "FLAME", // SKINCOLOR_FLAME, + "KETCHUP", // SKINCOLOR_KETCHUP, + "PEACHY", // SKINCOLOR_PEACHY, + "QUAIL", // SKINCOLOR_QUAIL, + "SUNSET", // SKINCOLOR_SUNSET, + "COPPER", // SKINCOLOR_COPPER, + "APRICOT", // SKINCOLOR_APRICOT, + "ORANGE", // SKINCOLOR_ORANGE, + "RUST", // SKINCOLOR_RUST, + "GOLD", // SKINCOLOR_GOLD, + "SANDY", // SKINCOLOR_SANDY, + "YELLOW", // SKINCOLOR_YELLOW, + "OLIVE", // SKINCOLOR_OLIVE, + "LIME", // SKINCOLOR_LIME, + "PERIDOT", // SKINCOLOR_PERIDOT, + "APPLE", // SKINCOLOR_APPLE, + "GREEN", // SKINCOLOR_GREEN, + "FOREST", // SKINCOLOR_FOREST, + "EMERALD", // SKINCOLOR_EMERALD, + "MINT", // SKINCOLOR_MINT, + "SEAFOAM", // SKINCOLOR_SEAFOAM, + "AQUA", // SKINCOLOR_AQUA, + "TEAL", // SKINCOLOR_TEAL, + "WAVE", // SKINCOLOR_WAVE, + "CYAN", // SKINCOLOR_CYAN, + "SKY", // SKINCOLOR_SKY, + "CERULEAN", // SKINCOLOR_CERULEAN, + "ICY", // SKINCOLOR_ICY, + "SAPPHIRE", // SKINCOLOR_SAPPHIRE, + "CORNFLOWER", // SKINCOLOR_CORNFLOWER, + "BLUE", // SKINCOLOR_BLUE, + "COBALT", // SKINCOLOR_COBALT, + "VAPOR", // SKINCOLOR_VAPOR, + "DUSK", // SKINCOLOR_DUSK, + "PASTEL", // SKINCOLOR_PASTEL, + "PURPLE", // SKINCOLOR_PURPLE, + "BUBBLEGUM", // SKINCOLOR_BUBBLEGUM, + "MAGENTA", // SKINCOLOR_MAGENTA, + "NEON", // SKINCOLOR_NEON, + "VIOLET", // SKINCOLOR_VIOLET, + "LILAC", // SKINCOLOR_LILAC, + "PLUM", // SKINCOLOR_PLUM, + "RASPBERRY", // SKINCOLOR_RASPBERRY, + "ROSY", // SKINCOLOR_ROSY, + + // Super special awesome Super flashing colors! + "SUPERSILVER1", // SKINCOLOR_SUPERSILVER1 + "SUPERSILVER2", // SKINCOLOR_SUPERSILVER2, + "SUPERSILVER3", // SKINCOLOR_SUPERSILVER3, + "SUPERSILVER4", // SKINCOLOR_SUPERSILVER4, + "SUPERSILVER5", // SKINCOLOR_SUPERSILVER5, + + "SUPERRED1", // SKINCOLOR_SUPERRED1 + "SUPERRED2", // SKINCOLOR_SUPERRED2, + "SUPERRED3", // SKINCOLOR_SUPERRED3, + "SUPERRED4", // SKINCOLOR_SUPERRED4, + "SUPERRED5", // SKINCOLOR_SUPERRED5, + + "SUPERORANGE1", // SKINCOLOR_SUPERORANGE1 + "SUPERORANGE2", // SKINCOLOR_SUPERORANGE2, + "SUPERORANGE3", // SKINCOLOR_SUPERORANGE3, + "SUPERORANGE4", // SKINCOLOR_SUPERORANGE4, + "SUPERORANGE5", // SKINCOLOR_SUPERORANGE5, + + "SUPERGOLD1", // SKINCOLOR_SUPERGOLD1 + "SUPERGOLD2", // SKINCOLOR_SUPERGOLD2, + "SUPERGOLD3", // SKINCOLOR_SUPERGOLD3, + "SUPERGOLD4", // SKINCOLOR_SUPERGOLD4, + "SUPERGOLD5", // SKINCOLOR_SUPERGOLD5, + + "SUPERPERIDOT1", // SKINCOLOR_SUPERPERIDOT1 + "SUPERPERIDOT2", // SKINCOLOR_SUPERPERIDOT2, + "SUPERPERIDOT3", // SKINCOLOR_SUPERPERIDOT3, + "SUPERPERIDOT4", // SKINCOLOR_SUPERPERIDOT4, + "SUPERPERIDOT5", // SKINCOLOR_SUPERPERIDOT5, + + "SUPERSKY1", // SKINCOLOR_SUPERSKY1 + "SUPERSKY2", // SKINCOLOR_SUPERSKY2, + "SUPERSKY3", // SKINCOLOR_SUPERSKY3, + "SUPERSKY4", // SKINCOLOR_SUPERSKY4, + "SUPERSKY5", // SKINCOLOR_SUPERSKY5, + + "SUPERPURPLE1", // SKINCOLOR_SUPERPURPLE1, + "SUPERPURPLE2", // SKINCOLOR_SUPERPURPLE2, + "SUPERPURPLE3", // SKINCOLOR_SUPERPURPLE3, + "SUPERPURPLE4", // SKINCOLOR_SUPERPURPLE4, + "SUPERPURPLE5", // SKINCOLOR_SUPERPURPLE5, + + "SUPERRUST1", // SKINCOLOR_SUPERRUST1 + "SUPERRUST2", // SKINCOLOR_SUPERRUST2, + "SUPERRUST3", // SKINCOLOR_SUPERRUST3, + "SUPERRUST4", // SKINCOLOR_SUPERRUST4, + "SUPERRUST5", // SKINCOLOR_SUPERRUST5, + + "SUPERTAN1", // SKINCOLOR_SUPERTAN1 + "SUPERTAN2", // SKINCOLOR_SUPERTAN2, + "SUPERTAN3", // SKINCOLOR_SUPERTAN3, + "SUPERTAN4", // SKINCOLOR_SUPERTAN4, + "SUPERTAN5" // SKINCOLOR_SUPERTAN5, +}; + +const char *const POWERS_LIST[] = { + "INVULNERABILITY", + "SNEAKERS", + "FLASHING", + "SHIELD", + "CARRY", + "TAILSFLY", // tails flying + "UNDERWATER", // underwater timer + "SPACETIME", // In space, no one can hear you spin! + "EXTRALIFE", // Extra Life timer + "PUSHING", + "JUSTSPRUNG", + "NOAUTOBRAKE", + + "SUPER", // Are you super? + "GRAVITYBOOTS", // gravity boots + + // Weapon ammunition + "INFINITYRING", + "AUTOMATICRING", + "BOUNCERING", + "SCATTERRING", + "GRENADERING", + "EXPLOSIONRING", + "RAILRING", + + // Power Stones + "EMERALDS", // stored like global 'emeralds' variable + + // NiGHTS powerups + "NIGHTS_SUPERLOOP", + "NIGHTS_HELPER", + "NIGHTS_LINKFREEZE", + + //for linedef exec 427 + "NOCONTROL", + + //for dyes + "DYE", + + "JUSTLAUNCHED", + + "IGNORELATCH" +}; + +const char *const HUDITEMS_LIST[] = { + "LIVES", + + "RINGS", + "RINGSNUM", + "RINGSNUMTICS", + + "SCORE", + "SCORENUM", + + "TIME", + "MINUTES", + "TIMECOLON", + "SECONDS", + "TIMETICCOLON", + "TICS", + + "SS_TOTALRINGS", + + "GETRINGS", + "GETRINGSNUM", + "TIMELEFT", + "TIMELEFTNUM", + "TIMEUP", + "HUNTPICS", + "POWERUPS" +}; + +const char *const MENUTYPES_LIST[] = { + "NONE", + + "MAIN", + + // Single Player + "SP_MAIN", + + "SP_LOAD", + "SP_PLAYER", + + "SP_LEVELSELECT", + "SP_LEVELSTATS", + + "SP_TIMEATTACK", + "SP_TIMEATTACK_LEVELSELECT", + "SP_GUESTREPLAY", + "SP_REPLAY", + "SP_GHOST", + + "SP_NIGHTSATTACK", + "SP_NIGHTS_LEVELSELECT", + "SP_NIGHTS_GUESTREPLAY", + "SP_NIGHTS_REPLAY", + "SP_NIGHTS_GHOST", + + // Multiplayer + "MP_MAIN", + "MP_SPLITSCREEN", // SplitServer + "MP_SERVER", + "MP_CONNECT", + "MP_ROOM", + "MP_PLAYERSETUP", // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET + "MP_SERVER_OPTIONS", + + // Options + "OP_MAIN", + + "OP_P1CONTROLS", + "OP_CHANGECONTROLS", // OP_ChangeControlsDef shared with P2 + "OP_P1MOUSE", + "OP_P1JOYSTICK", + "OP_JOYSTICKSET", // OP_JoystickSetDef shared with P2 + "OP_P1CAMERA", + + "OP_P2CONTROLS", + "OP_P2MOUSE", + "OP_P2JOYSTICK", + "OP_P2CAMERA", + + "OP_PLAYSTYLE", + + "OP_VIDEO", + "OP_VIDEOMODE", + "OP_COLOR", + "OP_OPENGL", + "OP_OPENGL_LIGHTING", + + "OP_SOUND", + + "OP_SERVER", + "OP_MONITORTOGGLE", + + "OP_DATA", + "OP_ADDONS", + "OP_SCREENSHOTS", + "OP_ERASEDATA", + + // Extras + "SR_MAIN", + "SR_PANDORA", + "SR_LEVELSELECT", + "SR_UNLOCKCHECKLIST", + "SR_EMBLEMHINT", + "SR_PLAYER", + "SR_SOUNDTEST", + + // Addons (Part of MISC, but let's make it our own) + "AD_MAIN", + + // MISC + // "MESSAGE", + // "SPAUSE", + + // "MPAUSE", + // "SCRAMBLETEAM", + // "CHANGETEAM", + // "CHANGELEVEL", + + // "MAPAUSE", + // "HELP", + + "SPECIAL" +}; + +struct int_const_s const INT_CONST[] = { + // If a mod removes some variables here, + // please leave the names in-tact and just set + // the value to 0 or something. + + // integer type limits, from doomtype.h + // INT64 and UINT64 limits not included, they're too big for most purposes anyway + // signed + {"INT8_MIN",INT8_MIN}, + {"INT16_MIN",INT16_MIN}, + {"INT32_MIN",INT32_MIN}, + {"INT8_MAX",INT8_MAX}, + {"INT16_MAX",INT16_MAX}, + {"INT32_MAX",INT32_MAX}, + // unsigned + {"UINT8_MAX",UINT8_MAX}, + {"UINT16_MAX",UINT16_MAX}, + {"UINT32_MAX",UINT32_MAX}, + + // fixed_t constants, from m_fixed.h + {"FRACUNIT",FRACUNIT}, + {"FRACBITS",FRACBITS}, + + // doomdef.h constants + {"TICRATE",TICRATE}, + {"MUSICRATE",MUSICRATE}, + {"RING_DIST",RING_DIST}, + {"PUSHACCEL",PUSHACCEL}, + {"MODID",MODID}, // I don't know, I just thought it would be cool for a wad to potentially know what mod it was loaded into. + {"MODVERSION",MODVERSION}, // or what version of the mod this is. + {"CODEBASE",CODEBASE}, // or what release of SRB2 this is. + {"NEWTICRATE",NEWTICRATE}, // TICRATE*NEWTICRATERATIO + {"NEWTICRATERATIO",NEWTICRATERATIO}, + + // Special linedef executor tag numbers! + {"LE_PINCHPHASE",LE_PINCHPHASE}, // A boss entered pinch phase (and, in most cases, is preparing their pinch phase attack!) + {"LE_ALLBOSSESDEAD",LE_ALLBOSSESDEAD}, // All bosses in the map are dead (Egg capsule raise) + {"LE_BOSSDEAD",LE_BOSSDEAD}, // A boss in the map died (Chaos mode boss tally) + {"LE_BOSS4DROP",LE_BOSS4DROP}, // CEZ boss dropped its cage + {"LE_BRAKVILEATACK",LE_BRAKVILEATACK}, // Brak's doing his LOS attack, oh noes + {"LE_TURRET",LE_TURRET}, // THZ turret + {"LE_BRAKPLATFORM",LE_BRAKPLATFORM}, // v2.0 Black Eggman destroys platform + {"LE_CAPSULE2",LE_CAPSULE2}, // Egg Capsule + {"LE_CAPSULE1",LE_CAPSULE1}, // Egg Capsule + {"LE_CAPSULE0",LE_CAPSULE0}, // Egg Capsule + {"LE_KOOPA",LE_KOOPA}, // Distant cousin to Gay Bowser + {"LE_AXE",LE_AXE}, // MKB Axe object + {"LE_PARAMWIDTH",LE_PARAMWIDTH}, // If an object that calls LinedefExecute has a nonzero parameter value, this times the parameter will be subtracted. (Mostly for the purpose of coexisting bosses...) + + /// \todo Get all this stuff into its own sections, maybe. Maybe. + + // Frame settings + {"FF_FRAMEMASK",FF_FRAMEMASK}, + {"FF_SPR2SUPER",FF_SPR2SUPER}, + {"FF_SPR2ENDSTATE",FF_SPR2ENDSTATE}, + {"FF_SPR2MIDSTART",FF_SPR2MIDSTART}, + {"FF_ANIMATE",FF_ANIMATE}, + {"FF_RANDOMANIM",FF_RANDOMANIM}, + {"FF_GLOBALANIM",FF_GLOBALANIM}, + {"FF_FULLBRIGHT",FF_FULLBRIGHT}, + {"FF_VERTICALFLIP",FF_VERTICALFLIP}, + {"FF_HORIZONTALFLIP",FF_HORIZONTALFLIP}, + {"FF_PAPERSPRITE",FF_PAPERSPRITE}, + {"FF_TRANSMASK",FF_TRANSMASK}, + {"FF_TRANSSHIFT",FF_TRANSSHIFT}, + // new preshifted translucency (used in source) + {"FF_TRANS10",FF_TRANS10}, + {"FF_TRANS20",FF_TRANS20}, + {"FF_TRANS30",FF_TRANS30}, + {"FF_TRANS40",FF_TRANS40}, + {"FF_TRANS50",FF_TRANS50}, + {"FF_TRANS60",FF_TRANS60}, + {"FF_TRANS70",FF_TRANS70}, + {"FF_TRANS80",FF_TRANS80}, + {"FF_TRANS90",FF_TRANS90}, + // compatibility + // Transparency for SOCs is pre-shifted + {"TR_TRANS10",tr_trans10<<FF_TRANSSHIFT}, + {"TR_TRANS20",tr_trans20<<FF_TRANSSHIFT}, + {"TR_TRANS30",tr_trans30<<FF_TRANSSHIFT}, + {"TR_TRANS40",tr_trans40<<FF_TRANSSHIFT}, + {"TR_TRANS50",tr_trans50<<FF_TRANSSHIFT}, + {"TR_TRANS60",tr_trans60<<FF_TRANSSHIFT}, + {"TR_TRANS70",tr_trans70<<FF_TRANSSHIFT}, + {"TR_TRANS80",tr_trans80<<FF_TRANSSHIFT}, + {"TR_TRANS90",tr_trans90<<FF_TRANSSHIFT}, + // Transparency for Lua is not, unless capitalized as above. + {"tr_trans10",tr_trans10}, + {"tr_trans20",tr_trans20}, + {"tr_trans30",tr_trans30}, + {"tr_trans40",tr_trans40}, + {"tr_trans50",tr_trans50}, + {"tr_trans60",tr_trans60}, + {"tr_trans70",tr_trans70}, + {"tr_trans80",tr_trans80}, + {"tr_trans90",tr_trans90}, + {"NUMTRANSMAPS",NUMTRANSMAPS}, + + // Level flags + {"LF_SCRIPTISFILE",LF_SCRIPTISFILE}, + {"LF_SPEEDMUSIC",LF_SPEEDMUSIC}, + {"LF_NOSSMUSIC",LF_NOSSMUSIC}, + {"LF_NORELOAD",LF_NORELOAD}, + {"LF_NOZONE",LF_NOZONE}, + {"LF_SAVEGAME",LF_SAVEGAME}, + {"LF_MIXNIGHTSCOUNTDOWN",LF_MIXNIGHTSCOUNTDOWN}, + {"LF_NOTITLECARDFIRST",LF_NOTITLECARDFIRST}, + {"LF_NOTITLECARDRESPAWN",LF_NOTITLECARDRESPAWN}, + {"LF_NOTITLECARDRECORDATTACK",LF_NOTITLECARDRECORDATTACK}, + {"LF_NOTITLECARD",LF_NOTITLECARD}, + {"LF_WARNINGTITLE",LF_WARNINGTITLE}, + // And map flags + {"LF2_HIDEINMENU",LF2_HIDEINMENU}, + {"LF2_HIDEINSTATS",LF2_HIDEINSTATS}, + {"LF2_RECORDATTACK",LF2_RECORDATTACK}, + {"LF2_NIGHTSATTACK",LF2_NIGHTSATTACK}, + {"LF2_NOVISITNEEDED",LF2_NOVISITNEEDED}, + {"LF2_WIDEICON",LF2_WIDEICON}, + + // Emeralds + {"EMERALD1",EMERALD1}, + {"EMERALD2",EMERALD2}, + {"EMERALD3",EMERALD3}, + {"EMERALD4",EMERALD4}, + {"EMERALD5",EMERALD5}, + {"EMERALD6",EMERALD6}, + {"EMERALD7",EMERALD7}, + + // SKINCOLOR_ doesn't include these..! + {"MAXSKINCOLORS",MAXSKINCOLORS}, + {"FIRSTSUPERCOLOR",FIRSTSUPERCOLOR}, + {"NUMSUPERCOLORS",NUMSUPERCOLORS}, + + // Precipitation + {"PRECIP_NONE",PRECIP_NONE}, + {"PRECIP_STORM",PRECIP_STORM}, + {"PRECIP_SNOW",PRECIP_SNOW}, + {"PRECIP_RAIN",PRECIP_RAIN}, + {"PRECIP_BLANK",PRECIP_BLANK}, + {"PRECIP_STORM_NORAIN",PRECIP_STORM_NORAIN}, + {"PRECIP_STORM_NOSTRIKES",PRECIP_STORM_NOSTRIKES}, + + // Shields + {"SH_NONE",SH_NONE}, + // Shield flags + {"SH_PROTECTFIRE",SH_PROTECTFIRE}, + {"SH_PROTECTWATER",SH_PROTECTWATER}, + {"SH_PROTECTELECTRIC",SH_PROTECTELECTRIC}, + {"SH_PROTECTSPIKE",SH_PROTECTSPIKE}, + // Indivisible shields + {"SH_PITY",SH_PITY}, + {"SH_WHIRLWIND",SH_WHIRLWIND}, + {"SH_ARMAGEDDON",SH_ARMAGEDDON}, + {"SH_PINK",SH_PINK}, + // normal shields that use flags + {"SH_ATTRACT",SH_ATTRACT}, + {"SH_ELEMENTAL",SH_ELEMENTAL}, + // Sonic 3 shields + {"SH_FLAMEAURA",SH_FLAMEAURA}, + {"SH_BUBBLEWRAP",SH_BUBBLEWRAP}, + {"SH_THUNDERCOIN",SH_THUNDERCOIN}, + // The force shield uses the lower 8 bits to count how many extra hits are left. + {"SH_FORCE",SH_FORCE}, + {"SH_FORCEHP",SH_FORCEHP}, // to be used as a bitmask only + // Mostly for use with Mario mode. + {"SH_FIREFLOWER",SH_FIREFLOWER}, + {"SH_STACK",SH_STACK}, + {"SH_NOSTACK",SH_NOSTACK}, + + // Carrying + {"CR_NONE",CR_NONE}, + {"CR_GENERIC",CR_GENERIC}, + {"CR_PLAYER",CR_PLAYER}, + {"CR_NIGHTSMODE",CR_NIGHTSMODE}, + {"CR_NIGHTSFALL",CR_NIGHTSFALL}, + {"CR_BRAKGOOP",CR_BRAKGOOP}, + {"CR_ZOOMTUBE",CR_ZOOMTUBE}, + {"CR_ROPEHANG",CR_ROPEHANG}, + {"CR_MACESPIN",CR_MACESPIN}, + {"CR_MINECART",CR_MINECART}, + {"CR_ROLLOUT",CR_ROLLOUT}, + {"CR_PTERABYTE",CR_PTERABYTE}, + {"CR_DUSTDEVIL",CR_DUSTDEVIL}, + + // Ring weapons (ringweapons_t) + // Useful for A_GiveWeapon + {"RW_AUTO",RW_AUTO}, + {"RW_BOUNCE",RW_BOUNCE}, + {"RW_SCATTER",RW_SCATTER}, + {"RW_GRENADE",RW_GRENADE}, + {"RW_EXPLODE",RW_EXPLODE}, + {"RW_RAIL",RW_RAIL}, + + // Character flags (skinflags_t) + {"SF_SUPER",SF_SUPER}, + {"SF_NOSUPERSPIN",SF_NOSUPERSPIN}, + {"SF_NOSPINDASHDUST",SF_NOSPINDASHDUST}, + {"SF_HIRES",SF_HIRES}, + {"SF_NOSKID",SF_NOSKID}, + {"SF_NOSPEEDADJUST",SF_NOSPEEDADJUST}, + {"SF_RUNONWATER",SF_RUNONWATER}, + {"SF_NOJUMPSPIN",SF_NOJUMPSPIN}, + {"SF_NOJUMPDAMAGE",SF_NOJUMPDAMAGE}, + {"SF_STOMPDAMAGE",SF_STOMPDAMAGE}, + {"SF_MARIODAMAGE",SF_MARIODAMAGE}, + {"SF_MACHINE",SF_MACHINE}, + {"SF_DASHMODE",SF_DASHMODE}, + {"SF_FASTEDGE",SF_FASTEDGE}, + {"SF_MULTIABILITY",SF_MULTIABILITY}, + {"SF_NONIGHTSROTATION",SF_NONIGHTSROTATION}, + {"SF_NONIGHTSSUPER",SF_NONIGHTSSUPER}, + {"SF_NOSUPERSPRITES",SF_NOSUPERSPRITES}, + {"SF_NOSUPERJUMPBOOST",SF_NOSUPERJUMPBOOST}, + {"SF_CANBUSTWALLS",SF_CANBUSTWALLS}, + + // Dashmode constants + {"DASHMODE_THRESHOLD",DASHMODE_THRESHOLD}, + {"DASHMODE_MAX",DASHMODE_MAX}, + + // Character abilities! + // Primary + {"CA_NONE",CA_NONE}, // now slot 0! + {"CA_THOK",CA_THOK}, + {"CA_FLY",CA_FLY}, + {"CA_GLIDEANDCLIMB",CA_GLIDEANDCLIMB}, + {"CA_HOMINGTHOK",CA_HOMINGTHOK}, + {"CA_DOUBLEJUMP",CA_DOUBLEJUMP}, + {"CA_FLOAT",CA_FLOAT}, + {"CA_SLOWFALL",CA_SLOWFALL}, + {"CA_SWIM",CA_SWIM}, + {"CA_TELEKINESIS",CA_TELEKINESIS}, + {"CA_FALLSWITCH",CA_FALLSWITCH}, + {"CA_JUMPBOOST",CA_JUMPBOOST}, + {"CA_AIRDRILL",CA_AIRDRILL}, + {"CA_JUMPTHOK",CA_JUMPTHOK}, + {"CA_BOUNCE",CA_BOUNCE}, + {"CA_TWINSPIN",CA_TWINSPIN}, + // Secondary + {"CA2_NONE",CA2_NONE}, // now slot 0! + {"CA2_SPINDASH",CA2_SPINDASH}, + {"CA2_GUNSLINGER",CA2_GUNSLINGER}, + {"CA2_MELEE",CA2_MELEE}, + + // Sound flags + {"SF_TOTALLYSINGLE",SF_TOTALLYSINGLE}, + {"SF_NOMULTIPLESOUND",SF_NOMULTIPLESOUND}, + {"SF_OUTSIDESOUND",SF_OUTSIDESOUND}, + {"SF_X4AWAYSOUND",SF_X4AWAYSOUND}, + {"SF_X8AWAYSOUND",SF_X8AWAYSOUND}, + {"SF_NOINTERRUPT",SF_NOINTERRUPT}, + {"SF_X2AWAYSOUND",SF_X2AWAYSOUND}, + + // Global emblem var flags + {"GE_NIGHTSPULL",GE_NIGHTSPULL}, + {"GE_NIGHTSITEM",GE_NIGHTSITEM}, + + // Map emblem var flags + {"ME_ALLEMERALDS",ME_ALLEMERALDS}, + {"ME_ULTIMATE",ME_ULTIMATE}, + {"ME_PERFECT",ME_PERFECT}, + + // p_local.h constants + {"FLOATSPEED",FLOATSPEED}, + {"MAXSTEPMOVE",MAXSTEPMOVE}, + {"USERANGE",USERANGE}, + {"MELEERANGE",MELEERANGE}, + {"MISSILERANGE",MISSILERANGE}, + {"ONFLOORZ",ONFLOORZ}, // INT32_MIN + {"ONCEILINGZ",ONCEILINGZ}, //INT32_MAX + // for P_FlashPal + {"PAL_WHITE",PAL_WHITE}, + {"PAL_MIXUP",PAL_MIXUP}, + {"PAL_RECYCLE",PAL_RECYCLE}, + {"PAL_NUKE",PAL_NUKE}, + // for P_DamageMobj + //// Damage types + {"DMG_WATER",DMG_WATER}, + {"DMG_FIRE",DMG_FIRE}, + {"DMG_ELECTRIC",DMG_ELECTRIC}, + {"DMG_SPIKE",DMG_SPIKE}, + {"DMG_NUKE",DMG_NUKE}, + //// Death types + {"DMG_INSTAKILL",DMG_INSTAKILL}, + {"DMG_DROWNED",DMG_DROWNED}, + {"DMG_SPACEDROWN",DMG_SPACEDROWN}, + {"DMG_DEATHPIT",DMG_DEATHPIT}, + {"DMG_CRUSHED",DMG_CRUSHED}, + {"DMG_SPECTATOR",DMG_SPECTATOR}, + //// Masks + {"DMG_CANHURTSELF",DMG_CANHURTSELF}, + {"DMG_DEATHMASK",DMG_DEATHMASK}, + + // Intermission types + {"int_none",int_none}, + {"int_coop",int_coop}, + {"int_match",int_match}, + {"int_teammatch",int_teammatch}, + //{"int_tag",int_tag}, + {"int_ctf",int_ctf}, + {"int_spec",int_spec}, + {"int_race",int_race}, + {"int_comp",int_comp}, + + // Jingles (jingletype_t) + {"JT_NONE",JT_NONE}, + {"JT_OTHER",JT_OTHER}, + {"JT_MASTER",JT_MASTER}, + {"JT_1UP",JT_1UP}, + {"JT_SHOES",JT_SHOES}, + {"JT_INV",JT_INV}, + {"JT_MINV",JT_MINV}, + {"JT_DROWN",JT_DROWN}, + {"JT_SUPER",JT_SUPER}, + {"JT_GOVER",JT_GOVER}, + {"JT_NIGHTSTIMEOUT",JT_NIGHTSTIMEOUT}, + {"JT_SSTIMEOUT",JT_SSTIMEOUT}, + // {"JT_LCLEAR",JT_LCLEAR}, + // {"JT_RACENT",JT_RACENT}, + // {"JT_CONTSC",JT_CONTSC}, + + // Player state (playerstate_t) + {"PST_LIVE",PST_LIVE}, // Playing or camping. + {"PST_DEAD",PST_DEAD}, // Dead on the ground, view follows killer. + {"PST_REBORN",PST_REBORN}, // Ready to restart/respawn??? + + // Player animation (panim_t) + {"PA_ETC",PA_ETC}, + {"PA_IDLE",PA_IDLE}, + {"PA_EDGE",PA_EDGE}, + {"PA_WALK",PA_WALK}, + {"PA_RUN",PA_RUN}, + {"PA_DASH",PA_DASH}, + {"PA_PAIN",PA_PAIN}, + {"PA_ROLL",PA_ROLL}, + {"PA_JUMP",PA_JUMP}, + {"PA_SPRING",PA_SPRING}, + {"PA_FALL",PA_FALL}, + {"PA_ABILITY",PA_ABILITY}, + {"PA_ABILITY2",PA_ABILITY2}, + {"PA_RIDE",PA_RIDE}, + + // Current weapon + {"WEP_AUTO",WEP_AUTO}, + {"WEP_BOUNCE",WEP_BOUNCE}, + {"WEP_SCATTER",WEP_SCATTER}, + {"WEP_GRENADE",WEP_GRENADE}, + {"WEP_EXPLODE",WEP_EXPLODE}, + {"WEP_RAIL",WEP_RAIL}, + {"NUM_WEAPONS",NUM_WEAPONS}, + + // Value for infinite lives + {"INFLIVES",INFLIVES}, + + // Got Flags, for player->gotflag! + // Used to be MF_ for some stupid reason, now they're GF_ to stop them looking like mobjflags + {"GF_REDFLAG",GF_REDFLAG}, + {"GF_BLUEFLAG",GF_BLUEFLAG}, + + // Customisable sounds for Skins, from sounds.h + {"SKSSPIN",SKSSPIN}, + {"SKSPUTPUT",SKSPUTPUT}, + {"SKSPUDPUD",SKSPUDPUD}, + {"SKSPLPAN1",SKSPLPAN1}, // Ouchies + {"SKSPLPAN2",SKSPLPAN2}, + {"SKSPLPAN3",SKSPLPAN3}, + {"SKSPLPAN4",SKSPLPAN4}, + {"SKSPLDET1",SKSPLDET1}, // Deaths + {"SKSPLDET2",SKSPLDET2}, + {"SKSPLDET3",SKSPLDET3}, + {"SKSPLDET4",SKSPLDET4}, + {"SKSPLVCT1",SKSPLVCT1}, // Victories + {"SKSPLVCT2",SKSPLVCT2}, + {"SKSPLVCT3",SKSPLVCT3}, + {"SKSPLVCT4",SKSPLVCT4}, + {"SKSTHOK",SKSTHOK}, + {"SKSSPNDSH",SKSSPNDSH}, + {"SKSZOOM",SKSZOOM}, + {"SKSSKID",SKSSKID}, + {"SKSGASP",SKSGASP}, + {"SKSJUMP",SKSJUMP}, + + // 3D Floor/Fake Floor/FOF/whatever flags + {"FF_EXISTS",FF_EXISTS}, ///< Always set, to check for validity. + {"FF_BLOCKPLAYER",FF_BLOCKPLAYER}, ///< Solid to player, but nothing else + {"FF_BLOCKOTHERS",FF_BLOCKOTHERS}, ///< Solid to everything but player + {"FF_SOLID",FF_SOLID}, ///< Clips things. + {"FF_RENDERSIDES",FF_RENDERSIDES}, ///< Renders the sides. + {"FF_RENDERPLANES",FF_RENDERPLANES}, ///< Renders the floor/ceiling. + {"FF_RENDERALL",FF_RENDERALL}, ///< Renders everything. + {"FF_SWIMMABLE",FF_SWIMMABLE}, ///< Is a water block. + {"FF_NOSHADE",FF_NOSHADE}, ///< Messes with the lighting? + {"FF_CUTSOLIDS",FF_CUTSOLIDS}, ///< Cuts out hidden solid pixels. + {"FF_CUTEXTRA",FF_CUTEXTRA}, ///< Cuts out hidden translucent pixels. + {"FF_CUTLEVEL",FF_CUTLEVEL}, ///< Cuts out all hidden pixels. + {"FF_CUTSPRITES",FF_CUTSPRITES}, ///< Final step in making 3D water. + {"FF_BOTHPLANES",FF_BOTHPLANES}, ///< Render inside and outside planes. + {"FF_EXTRA",FF_EXTRA}, ///< Gets cut by ::FF_CUTEXTRA. + {"FF_TRANSLUCENT",FF_TRANSLUCENT}, ///< See through! + {"FF_FOG",FF_FOG}, ///< Fog "brush." + {"FF_INVERTPLANES",FF_INVERTPLANES}, ///< Only render inside planes. + {"FF_ALLSIDES",FF_ALLSIDES}, ///< Render inside and outside sides. + {"FF_INVERTSIDES",FF_INVERTSIDES}, ///< Only render inside sides. + {"FF_DOUBLESHADOW",FF_DOUBLESHADOW}, ///< Make two lightlist entries to reset light? + {"FF_FLOATBOB",FF_FLOATBOB}, ///< Floats on water and bobs if you step on it. + {"FF_NORETURN",FF_NORETURN}, ///< Used with ::FF_CRUMBLE. Will not return to its original position after falling. + {"FF_CRUMBLE",FF_CRUMBLE}, ///< Falls 2 seconds after being stepped on, and randomly brings all touching crumbling 3dfloors down with it, providing their master sectors share the same tag (allows crumble platforms above or below, to also exist). + {"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. + {"FF_MARIO",FF_MARIO}, ///< Acts like a question block when hit from underneath. Goodie spawned at top is determined by master sector. + {"FF_QUICKSAND",FF_QUICKSAND}, ///< Quicksand! + {"FF_PLATFORM",FF_PLATFORM}, ///< You can jump up through this to the top. + {"FF_REVERSEPLATFORM",FF_REVERSEPLATFORM}, ///< A fall-through floor in normal gravity, a platform in reverse gravity. + {"FF_INTANGIBLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangible, but the sides are still solid. + {"FF_INTANGABLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangable, but the sides are still solid. + {"FF_RIPPLE",FF_RIPPLE}, ///< Ripple the flats + {"FF_COLORMAPONLY",FF_COLORMAPONLY}, ///< Only copy the colormap, not the lightlevel + {"FF_BOUNCY",FF_BOUNCY}, ///< Bounces players + {"FF_SPLAT",FF_SPLAT}, ///< Use splat flat renderer (treat cyan pixels as invisible) + + // FOF special flags + {"FS_PUSHABLES",FS_PUSHABLES}, + {"FS_EXECUTOR",FS_EXECUTOR}, + {"FS_ONLYBOTTOM",FS_ONLYBOTTOM}, + {"FS_BUSTMASK",FS_BUSTMASK}, + {"FS_DAMPEN",FS_DAMPEN}, + + // Bustable FOF type + {"BT_TOUCH",BT_TOUCH}, + {"BT_SPINBUST",BT_SPINBUST}, + {"BT_REGULAR",BT_REGULAR}, + {"BT_STRONG",BT_STRONG}, + + // PolyObject flags + {"POF_CLIPLINES",POF_CLIPLINES}, ///< Test against lines for collision + {"POF_CLIPPLANES",POF_CLIPPLANES}, ///< Test against tops and bottoms for collision + {"POF_SOLID",POF_SOLID}, ///< Clips things. + {"POF_TESTHEIGHT",POF_TESTHEIGHT}, ///< Test line collision with heights + {"POF_RENDERSIDES",POF_RENDERSIDES}, ///< Renders the sides. + {"POF_RENDERTOP",POF_RENDERTOP}, ///< Renders the top. + {"POF_RENDERBOTTOM",POF_RENDERBOTTOM}, ///< Renders the bottom. + {"POF_RENDERPLANES",POF_RENDERPLANES}, ///< Renders top and bottom. + {"POF_RENDERALL",POF_RENDERALL}, ///< Renders everything. + {"POF_INVERT",POF_INVERT}, ///< Inverts collision (like a cage). + {"POF_INVERTPLANES",POF_INVERTPLANES}, ///< Render inside planes. + {"POF_INVERTPLANESONLY",POF_INVERTPLANESONLY}, ///< Only render inside planes. + {"POF_PUSHABLESTOP",POF_PUSHABLESTOP}, ///< Pushables will stop movement. + {"POF_LDEXEC",POF_LDEXEC}, ///< This PO triggers a linedef executor. + {"POF_ONESIDE",POF_ONESIDE}, ///< Only use the first side of the linedef. + {"POF_NOSPECIALS",POF_NOSPECIALS}, ///< Don't apply sector specials. + {"POF_SPLAT",POF_SPLAT}, ///< Use splat flat renderer (treat cyan pixels as invisible). + +#ifdef HAVE_LUA_SEGS + // Node flags + {"NF_SUBSECTOR",NF_SUBSECTOR}, // Indicate a leaf. +#endif + + // Slope flags + {"SL_NOPHYSICS",SL_NOPHYSICS}, + {"SL_DYNAMIC",SL_DYNAMIC}, + + // Angles + {"ANG1",ANG1}, + {"ANG2",ANG2}, + {"ANG10",ANG10}, + {"ANG15",ANG15}, + {"ANG20",ANG20}, + {"ANG30",ANG30}, + {"ANG60",ANG60}, + {"ANG64h",ANG64h}, + {"ANG105",ANG105}, + {"ANG210",ANG210}, + {"ANG255",ANG255}, + {"ANG340",ANG340}, + {"ANG350",ANG350}, + {"ANGLE_11hh",ANGLE_11hh}, + {"ANGLE_22h",ANGLE_22h}, + {"ANGLE_45",ANGLE_45}, + {"ANGLE_67h",ANGLE_67h}, + {"ANGLE_90",ANGLE_90}, + {"ANGLE_112h",ANGLE_112h}, + {"ANGLE_135",ANGLE_135}, + {"ANGLE_157h",ANGLE_157h}, + {"ANGLE_180",ANGLE_180}, + {"ANGLE_202h",ANGLE_202h}, + {"ANGLE_225",ANGLE_225}, + {"ANGLE_247h",ANGLE_247h}, + {"ANGLE_270",ANGLE_270}, + {"ANGLE_292h",ANGLE_292h}, + {"ANGLE_315",ANGLE_315}, + {"ANGLE_337h",ANGLE_337h}, + {"ANGLE_MAX",ANGLE_MAX}, + + // P_Chase directions (dirtype_t) + {"DI_NODIR",DI_NODIR}, + {"DI_EAST",DI_EAST}, + {"DI_NORTHEAST",DI_NORTHEAST}, + {"DI_NORTH",DI_NORTH}, + {"DI_NORTHWEST",DI_NORTHWEST}, + {"DI_WEST",DI_WEST}, + {"DI_SOUTHWEST",DI_SOUTHWEST}, + {"DI_SOUTH",DI_SOUTH}, + {"DI_SOUTHEAST",DI_SOUTHEAST}, + {"NUMDIRS",NUMDIRS}, + + // Sprite rotation axis (rotaxis_t) + {"ROTAXIS_X",ROTAXIS_X}, + {"ROTAXIS_Y",ROTAXIS_Y}, + {"ROTAXIS_Z",ROTAXIS_Z}, + + // Buttons (ticcmd_t) + {"BT_WEAPONMASK",BT_WEAPONMASK}, //our first four bits. + {"BT_WEAPONNEXT",BT_WEAPONNEXT}, + {"BT_WEAPONPREV",BT_WEAPONPREV}, + {"BT_ATTACK",BT_ATTACK}, // shoot rings + {"BT_SPIN",BT_SPIN}, + {"BT_CAMLEFT",BT_CAMLEFT}, // turn camera left + {"BT_CAMRIGHT",BT_CAMRIGHT}, // turn camera right + {"BT_TOSSFLAG",BT_TOSSFLAG}, + {"BT_JUMP",BT_JUMP}, + {"BT_FIRENORMAL",BT_FIRENORMAL}, // Fire a normal ring no matter what + {"BT_CUSTOM1",BT_CUSTOM1}, // Lua customizable + {"BT_CUSTOM2",BT_CUSTOM2}, // Lua customizable + {"BT_CUSTOM3",BT_CUSTOM3}, // Lua customizable + + // Lua command registration flags + {"COM_ADMIN",COM_ADMIN}, + {"COM_SPLITSCREEN",COM_SPLITSCREEN}, + {"COM_LOCAL",COM_LOCAL}, + + // cvflags_t + {"CV_SAVE",CV_SAVE}, + {"CV_CALL",CV_CALL}, + {"CV_NETVAR",CV_NETVAR}, + {"CV_NOINIT",CV_NOINIT}, + {"CV_FLOAT",CV_FLOAT}, + {"CV_NOTINNET",CV_NOTINNET}, + {"CV_MODIFIED",CV_MODIFIED}, + {"CV_SHOWMODIF",CV_SHOWMODIF}, + {"CV_SHOWMODIFONETIME",CV_SHOWMODIFONETIME}, + {"CV_NOSHOWHELP",CV_NOSHOWHELP}, + {"CV_HIDEN",CV_HIDEN}, + {"CV_HIDDEN",CV_HIDEN}, + {"CV_CHEAT",CV_CHEAT}, + {"CV_NOLUA",CV_NOLUA}, + + // v_video flags + {"V_NOSCALEPATCH",V_NOSCALEPATCH}, + {"V_SMALLSCALEPATCH",V_SMALLSCALEPATCH}, + {"V_MEDSCALEPATCH",V_MEDSCALEPATCH}, + {"V_6WIDTHSPACE",V_6WIDTHSPACE}, + {"V_OLDSPACING",V_OLDSPACING}, + {"V_MONOSPACE",V_MONOSPACE}, + + {"V_MAGENTAMAP",V_MAGENTAMAP}, + {"V_YELLOWMAP",V_YELLOWMAP}, + {"V_GREENMAP",V_GREENMAP}, + {"V_BLUEMAP",V_BLUEMAP}, + {"V_REDMAP",V_REDMAP}, + {"V_GRAYMAP",V_GRAYMAP}, + {"V_ORANGEMAP",V_ORANGEMAP}, + {"V_SKYMAP",V_SKYMAP}, + {"V_PURPLEMAP",V_PURPLEMAP}, + {"V_AQUAMAP",V_AQUAMAP}, + {"V_PERIDOTMAP",V_PERIDOTMAP}, + {"V_AZUREMAP",V_AZUREMAP}, + {"V_BROWNMAP",V_BROWNMAP}, + {"V_ROSYMAP",V_ROSYMAP}, + {"V_INVERTMAP",V_INVERTMAP}, + + {"V_TRANSLUCENT",V_TRANSLUCENT}, + {"V_10TRANS",V_10TRANS}, + {"V_20TRANS",V_20TRANS}, + {"V_30TRANS",V_30TRANS}, + {"V_40TRANS",V_40TRANS}, + {"V_50TRANS",V_TRANSLUCENT}, // alias + {"V_60TRANS",V_60TRANS}, + {"V_70TRANS",V_70TRANS}, + {"V_80TRANS",V_80TRANS}, + {"V_90TRANS",V_90TRANS}, + {"V_HUDTRANSHALF",V_HUDTRANSHALF}, + {"V_HUDTRANS",V_HUDTRANS}, + {"V_HUDTRANSDOUBLE",V_HUDTRANSDOUBLE}, + {"V_AUTOFADEOUT",V_AUTOFADEOUT}, + {"V_RETURN8",V_RETURN8}, + {"V_OFFSET",V_OFFSET}, + {"V_ALLOWLOWERCASE",V_ALLOWLOWERCASE}, + {"V_FLIP",V_FLIP}, + {"V_CENTERNAMETAG",V_CENTERNAMETAG}, + {"V_SNAPTOTOP",V_SNAPTOTOP}, + {"V_SNAPTOBOTTOM",V_SNAPTOBOTTOM}, + {"V_SNAPTOLEFT",V_SNAPTOLEFT}, + {"V_SNAPTORIGHT",V_SNAPTORIGHT}, + {"V_WRAPX",V_WRAPX}, + {"V_WRAPY",V_WRAPY}, + {"V_NOSCALESTART",V_NOSCALESTART}, + {"V_PERPLAYER",V_PERPLAYER}, + + {"V_PARAMMASK",V_PARAMMASK}, + {"V_SCALEPATCHMASK",V_SCALEPATCHMASK}, + {"V_SPACINGMASK",V_SPACINGMASK}, + {"V_CHARCOLORMASK",V_CHARCOLORMASK}, + {"V_ALPHAMASK",V_ALPHAMASK}, + + {"V_CHARCOLORSHIFT",V_CHARCOLORSHIFT}, + {"V_ALPHASHIFT",V_ALPHASHIFT}, + + //Kick Reasons + {"KR_KICK",KR_KICK}, + {"KR_PINGLIMIT",KR_PINGLIMIT}, + {"KR_SYNCH",KR_SYNCH}, + {"KR_TIMEOUT",KR_TIMEOUT}, + {"KR_BAN",KR_BAN}, + {"KR_LEAVE",KR_LEAVE}, + + // translation colormaps + {"TC_DEFAULT",TC_DEFAULT}, + {"TC_BOSS",TC_BOSS}, + {"TC_METALSONIC",TC_METALSONIC}, + {"TC_ALLWHITE",TC_ALLWHITE}, + {"TC_RAINBOW",TC_RAINBOW}, + {"TC_BLINK",TC_BLINK}, + {"TC_DASHMODE",TC_DASHMODE}, + + // marathonmode flags + {"MA_INIT",MA_INIT}, + {"MA_RUNNING",MA_RUNNING}, + {"MA_NOCUTSCENES",MA_NOCUTSCENES}, + {"MA_INGAME",MA_INGAME}, + + // music types + {"MU_NONE", MU_NONE}, + {"MU_WAV", MU_WAV}, + {"MU_MOD", MU_MOD}, + {"MU_MID", MU_MID}, + {"MU_OGG", MU_OGG}, + {"MU_MP3", MU_MP3}, + {"MU_FLAC", MU_FLAC}, + {"MU_GME", MU_GME}, + {"MU_MOD_EX", MU_MOD_EX}, + {"MU_MID_EX", MU_MID_EX}, + + // gamestates + {"GS_NULL",GS_NULL}, + {"GS_LEVEL",GS_LEVEL}, + {"GS_INTERMISSION",GS_INTERMISSION}, + {"GS_CONTINUING",GS_CONTINUING}, + {"GS_TITLESCREEN",GS_TITLESCREEN}, + {"GS_TIMEATTACK",GS_TIMEATTACK}, + {"GS_CREDITS",GS_CREDITS}, + {"GS_EVALUATION",GS_EVALUATION}, + {"GS_GAMEEND",GS_GAMEEND}, + {"GS_INTRO",GS_INTRO}, + {"GS_ENDING",GS_ENDING}, + {"GS_CUTSCENE",GS_CUTSCENE}, + {"GS_DEDICATEDSERVER",GS_DEDICATEDSERVER}, + {"GS_WAITINGPLAYERS",GS_WAITINGPLAYERS}, + + {NULL,0} +}; diff --git a/src/deh_tables.h b/src/deh_tables.h new file mode 100644 index 0000000000000000000000000000000000000000..2c6b3e20407ec454a47a9b301fcf5003cb4220a8 --- /dev/null +++ b/src/deh_tables.h @@ -0,0 +1,75 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file deh_tables.h +/// \brief Define DeHackEd tables. + +#ifndef __DEH_TABLES_H__ +#define __DEH_TABLES_H__ + +#include "doomdef.h" // Constants +#include "d_think.h" // actionf_t +#include "info.h" // Mobj, state, sprite, etc constants +#include "lua_script.h" + +// Free slot names +// The crazy word-reading stuff uses these. +extern char *FREE_STATES[NUMSTATEFREESLOTS]; +extern char *FREE_MOBJS[NUMMOBJFREESLOTS]; +extern char *FREE_SKINCOLORS[NUMCOLORFREESLOTS]; +extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway. + +#define initfreeslots() {\ + memset(FREE_STATES,0,sizeof(char *) * NUMSTATEFREESLOTS);\ + memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\ + memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\ + memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\ +} + +struct flickytypes_s { + const char *name; + const mobjtype_t type; +}; + +#define MAXFLICKIES 64 + +/** Action pointer for reading actions from Dehacked lumps. + */ +typedef struct +{ + actionf_t action; ///< Function pointer corresponding to the actual action. + const char *name; ///< Name of the action in ALL CAPS. +} actionpointer_t; + +struct int_const_s { + const char *n; + // has to be able to hold both fixed_t and angle_t, so drastic measure!! + lua_Integer v; +}; + +extern const char NIGHTSGRADE_LIST[]; +extern struct flickytypes_s FLICKYTYPES[]; +extern actionpointer_t actionpointers[]; // Array mapping action names to action functions. +extern const char *const STATE_LIST[]; +extern const char *const MOBJTYPE_LIST[]; +extern const char *const MOBJFLAG_LIST[]; +extern const char *const MOBJFLAG2_LIST[]; // \tMF2_(\S+).*// (.+) --> \t"\1", // \2 +extern const char *const MOBJEFLAG_LIST[]; +extern const char *const MAPTHINGFLAG_LIST[4]; +extern const char *const PLAYERFLAG_LIST[]; +extern const char *const GAMETYPERULE_LIST[]; +extern const char *const ML_LIST[16]; // Linedef flags +extern const char *COLOR_ENUMS[]; +extern const char *const POWERS_LIST[]; +extern const char *const HUDITEMS_LIST[]; +extern const char *const MENUTYPES_LIST[]; + +extern struct int_const_s const INT_CONST[]; + +#endif diff --git a/src/dehacked.c b/src/dehacked.c index f8f380464c5d49c426a850b26d889768408d6e16..e98ff71cf2f8a30baa8bd0e7fadd6114359fbaae 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -11,78 +11,45 @@ /// \brief Load dehacked file and change tables and text #include "doomdef.h" -#include "d_main.h" // for srb2home -#include "g_game.h" -#include "sounds.h" -#include "info.h" -#include "d_think.h" -#include "m_argv.h" -#include "z_zone.h" -#include "w_wad.h" -#include "m_menu.h" -#include "m_misc.h" -#include "f_finale.h" -#include "y_inter.h" -#include "dehacked.h" -#include "st_stuff.h" -#include "i_system.h" -#include "p_local.h" // for var1 and var2, and some constants -#include "p_setup.h" -#include "r_data.h" -#include "r_textures.h" -#include "r_draw.h" -#include "r_picformats.h" -#include "r_things.h" // R_Char2Frame -#include "r_sky.h" -#include "fastcmp.h" -#include "lua_script.h" -#include "lua_hook.h" -#include "d_clisrv.h" -#include "g_state.h" // gamestate_t (for lua) - #include "m_cond.h" +#include "deh_soc.h" +#include "deh_tables.h" -#include "v_video.h" // video flags (for lua) +boolean deh_loaded = false; -#ifdef HWRENDER -#include "hardware/hw_light.h" -#endif +boolean gamedataadded = false; +boolean titlechanged = false; +boolean introchanged = false; -// Free slot names -// The crazy word-reading stuff uses these. -static char *FREE_STATES[NUMSTATEFREESLOTS]; -static char *FREE_MOBJS[NUMMOBJFREESLOTS]; -static char *FREE_SKINCOLORS[NUMCOLORFREESLOTS]; -static UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway. -#define initfreeslots() {\ -memset(FREE_STATES,0,sizeof(char *) * NUMSTATEFREESLOTS);\ -memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\ -memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\ -memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\ -} +static int dbg_line; +static INT32 deh_num_warning = 0; -// Crazy word-reading stuff -/// \todo Put these in a seperate file or something. -static mobjtype_t get_mobjtype(const char *word); -static statenum_t get_state(const char *word); -static spritenum_t get_sprite(const char *word); -static playersprite_t get_sprite2(const char *word); -static sfxenum_t get_sfx(const char *word); -#ifdef MUSICSLOT_COMPATIBILITY -static UINT16 get_mus(const char *word, UINT8 dehacked_mode); -#endif -static hudnum_t get_huditem(const char *word); -static menutype_t get_menutype(const char *word); -//static INT16 get_gametype(const char *word); -//static powertype_t get_power(const char *word); -skincolornum_t get_skincolor(const char *word); +FUNCPRINTF void deh_warning(const char *first, ...) +{ + va_list argptr; + char *buf = Z_Malloc(1000, PU_STATIC, NULL); -boolean deh_loaded = false; -static int dbg_line; + va_start(argptr, first); + vsnprintf(buf, 1000, first, argptr); // sizeof only returned 4 here. it didn't like that pointer. + va_end(argptr); -static boolean gamedataadded = false; -static boolean titlechanged = false; -static boolean introchanged = false; + if(dbg_line == -1) // Not in a SOC, line number unknown. + CONS_Alert(CONS_WARNING, "%s\n", buf); + else + CONS_Alert(CONS_WARNING, "Line %u: %s\n", dbg_line, buf); + + deh_num_warning++; + + Z_Free(buf); +} + +void deh_strlcpy(char *dst, const char *src, size_t size, const char *warntext) +{ + size_t len = strlen(src)+1; // Used to determine if truncation has been done + if (len > size) + deh_warning("%s exceeds max length of %s", warntext, sizeu1(size-1)); + strlcpy(dst, src, size); +} ATTRINLINE static FUNCINLINE char myfget_color(MYFILE *f) { @@ -148,7 +115,7 @@ char *myfgets(char *buf, size_t bufsize, MYFILE *f) return buf; } -static char *myhashfgets(char *buf, size_t bufsize, MYFILE *f) +char *myhashfgets(char *buf, size_t bufsize, MYFILE *f) { size_t i = 0; if (myfeof(f)) @@ -180,11112 +147,517 @@ static char *myhashfgets(char *buf, size_t bufsize, MYFILE *f) return buf; } -static INT32 deh_num_warning = 0; - -FUNCPRINTF static void deh_warning(const char *first, ...) -{ - va_list argptr; - char *buf = Z_Malloc(1000, PU_STATIC, NULL); - - va_start(argptr, first); - vsnprintf(buf, 1000, first, argptr); // sizeof only returned 4 here. it didn't like that pointer. - va_end(argptr); - - if(dbg_line == -1) // Not in a SOC, line number unknown. - CONS_Alert(CONS_WARNING, "%s\n", buf); - else - CONS_Alert(CONS_WARNING, "Line %u: %s\n", dbg_line, buf); - - deh_num_warning++; - - Z_Free(buf); -} - -static void deh_strlcpy(char *dst, const char *src, size_t size, const char *warntext) -{ - size_t len = strlen(src)+1; // Used to determine if truncation has been done - if (len > size) - deh_warning("%s exceeds max length of %s", warntext, sizeu1(size-1)); - strlcpy(dst, src, size); -} - -/* ======================================================================== */ -// Load a dehacked file format -/* ======================================================================== */ -/* a sample to see - Thing 1 (Player) { // MT_PLAYER -INT32 doomednum; ID # = 3232 -1, // doomednum -INT32 spawnstate; Initial frame = 32 "PLAY", // spawnstate -INT32 spawnhealth; Hit points = 3232 100, // spawnhealth -INT32 seestate; First moving frame = 32 "PLAY_RUN1", // seestate -INT32 seesound; Alert sound = 32 sfx_None, // seesound -INT32 reactiontime; Reaction time = 3232 0, // reactiontime -INT32 attacksound; Attack sound = 32 sfx_None, // attacksound -INT32 painstate; Injury frame = 32 "PLAY_PAIN", // painstate -INT32 painchance; Pain chance = 3232 255, // painchance -INT32 painsound; Pain sound = 32 sfx_plpain, // painsound -INT32 meleestate; Close attack frame = 32 "NULL", // meleestate -INT32 missilestate; Far attack frame = 32 "PLAY_ATK1", // missilestate -INT32 deathstate; Death frame = 32 "PLAY_DIE1", // deathstate -INT32 xdeathstate; Exploding frame = 32 "PLAY_XDIE1", // xdeathstate -INT32 deathsound; Death sound = 32 sfx_pldeth, // deathsound -INT32 speed; Speed = 3232 0, // speed -INT32 radius; Width = 211812352 16*FRACUNIT, // radius -INT32 height; Height = 211812352 56*FRACUNIT, // height -INT32 dispoffset; DispOffset = 0 0, // dispoffset -INT32 mass; Mass = 3232 100, // mass -INT32 damage; Missile damage = 3232 0, // damage -INT32 activesound; Action sound = 32 sfx_None, // activesound -INT32 flags; Bits = 3232 MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH, -INT32 raisestate; Respawn frame = 32 S_NULL // raisestate - }, */ - -#ifdef HWRENDER -static INT32 searchvalue(const char *s) -{ - while (s[0] != '=' && s[0]) - s++; - if (s[0] == '=') - return atoi(&s[1]); - else - { - deh_warning("No value found"); - return 0; - } -} - -static float searchfvalue(const char *s) -{ - while (s[0] != '=' && s[0]) - s++; - if (s[0] == '=') - return (float)atof(&s[1]); - else - { - deh_warning("No value found"); - return 0; - } -} -#endif - -// These are for clearing all of various things -static void clear_conditionsets(void) -{ - UINT8 i; - for (i = 0; i < MAXCONDITIONSETS; ++i) - M_ClearConditionSet(i+1); -} - -static void clear_levels(void) +// Used when you do something invalid like read a bad item number +// to prevent extra unnecessary errors +static void ignorelines(MYFILE *f) { - INT16 i; - - // This is potentially dangerous but if we're resetting these headers, - // we may as well try to save some memory, right? - for (i = 0; i < NUMMAPS; ++i) + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + do { - if (!mapheaderinfo[i] || i == (tutorialmap-1)) - continue; - - // Custom map header info - // (no need to set num to 0, we're freeing the entire header shortly) - Z_Free(mapheaderinfo[i]->customopts); - - P_DeleteFlickies(i); - P_DeleteGrades(i); - - Z_Free(mapheaderinfo[i]); - mapheaderinfo[i] = NULL; - } - - // Realloc the one for the current gamemap as a safeguard - P_AllocMapHeader(gamemap-1); -} - -static boolean findFreeSlot(INT32 *num) -{ - // Send the character select entry to a free slot. - while (*num < MAXSKINS && (description[*num].used)) - *num = *num+1; - - // No more free slots. :( - if (*num >= MAXSKINS) - return false; - - // Redesign your logo. (See M_DrawSetupChoosePlayerMenu in m_menu.c...) - description[*num].picname[0] = '\0'; - description[*num].nametag[0] = '\0'; - description[*num].displayname[0] = '\0'; - description[*num].oppositecolor = SKINCOLOR_NONE; - description[*num].tagtextcolor = SKINCOLOR_NONE; - description[*num].tagoutlinecolor = SKINCOLOR_NONE; - - // Found one! ^_^ - return (description[*num].used = true); + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + } + } while (!myfeof(f)); + Z_Free(s); } -// Reads a player. -// For modifying the character select screen -static void readPlayer(MYFILE *f, INT32 num) +static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char textline[MAXLINELEN]; char *word; char *word2; - char *displayname = ZZ_Alloc(MAXLINELEN+1); INT32 i; - boolean slotfound = false; - #define SLOTFOUND \ - if (!slotfound && (slotfound = findFreeSlot(&num)) == false) \ - goto done; + if (!deh_loaded) + initfreeslots(); - displayname[MAXLINELEN] = '\0'; + deh_num_warning = 0; - do + gamedataadded = titlechanged = introchanged = false; + + // it doesn't test the version of SRB2 and version of dehacked file + dbg_line = -1; // start at -1 so the first line is 0. + while (!myfeof(f)) { - if (myfgets(s, MAXLINELEN, f)) + char origpos[128]; + INT32 size = 0; + char *traverse; + + myfgets(s, MAXLINELEN, f); + memcpy(textline, s, MAXLINELEN); + if (s[0] == '\n' || s[0] == '#') + continue; + + traverse = s; + + while (traverse[0] != '\n') { - if (s[0] == '\n') - break; + traverse++; + size++; + } + + strncpy(origpos, s, size); + origpos[size] = '\0'; - for (i = 0; i < MAXLINELEN-3; i++) + if (NULL != (word = strtok(s, " "))) { + strupr(word); + if (word[strlen(word)-1] == '\n') + word[strlen(word)-1] = '\0'; + } + if (word) + { + if (fastcmp(word, "FREESLOT")) + { + readfreeslots(f); + continue; + } + else if (fastcmp(word, "MAINCFG")) + { + readmaincfg(f); + continue; + } + else if (fastcmp(word, "WIPES")) + { + readwipes(f); + continue; + } + word2 = strtok(NULL, " "); + if (word2) { + strupr(word2); + if (word2[strlen(word2) - 1] == '\n') + word2[strlen(word2) - 1] = '\0'; + i = atoi(word2); + } + else + i = 0; + if (fastcmp(word, "CHARACTER")) { - char *tmp; - if (s[i] == '=') + if (i >= 0 && i < 32) + readPlayer(f, i); + else { - tmp = &s[i+2]; - strncpy(displayname, tmp, SKINNAMESIZE); - break; + deh_warning("Character %d out of range (0 - 31)", i); + ignorelines(f); } + continue; } - - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - if (fastcmp(word, "PLAYERTEXT")) + else if (fastcmp(word, "EMBLEM")) { - char *playertext = NULL; - - SLOTFOUND - - for (i = 0; i < MAXLINELEN-3; i++) + if (!mainfile && !gamedataadded) + { + deh_warning("You must define a custom gamedata to use \"%s\"", word); + ignorelines(f); + } + else { - if (s[i] == '=') + if (!word2) + i = numemblems + 1; + + if (i > 0 && i <= MAXEMBLEMS) + { + if (numemblems < i) + numemblems = i; + reademblemdata(f, i); + } + else { - playertext = &s[i+2]; - break; + deh_warning("Emblem number %d out of range (1 - %d)", i, MAXEMBLEMS); + ignorelines(f); } } - if (playertext) + continue; + } + else if (fastcmp(word, "EXTRAEMBLEM")) + { + if (!mainfile && !gamedataadded) { - strcpy(description[num].notes, playertext); - strcat(description[num].notes, myhashfgets(playertext, sizeof (description[num].notes), f)); + deh_warning("You must define a custom gamedata to use \"%s\"", word); + ignorelines(f); } else - strcpy(description[num].notes, ""); - - // For some reason, cutting the string did not work above. Most likely due to strcpy or strcat... - // It works down here, though. { - INT32 numline = 0; - for (i = 0; (size_t)i < sizeof(description[num].notes)-1; i++) - { - if (numline < 20 && description[num].notes[i] == '\n') - numline++; + if (!word2) + i = numextraemblems + 1; - if (numline >= 20 || description[num].notes[i] == '\0' || description[num].notes[i] == '#') - break; + if (i > 0 && i <= MAXEXTRAEMBLEMS) + { + if (numextraemblems < i) + numextraemblems = i; + readextraemblemdata(f, i); + } + else + { + deh_warning("Extra emblem number %d out of range (1 - %d)", i, MAXEXTRAEMBLEMS); + ignorelines(f); } } - description[num].notes[strlen(description[num].notes)-1] = '\0'; - description[num].notes[i] = '\0'; continue; } - - word2 = strtok(NULL, " = "); if (word2) - strupr(word2); - else - break; - - if (word2[strlen(word2)-1] == '\n') - word2[strlen(word2)-1] = '\0'; - i = atoi(word2); - - if (fastcmp(word, "PICNAME")) - { - SLOTFOUND - strncpy(description[num].picname, word2, 8); - } - // new character select - else if (fastcmp(word, "DISPLAYNAME")) { - SLOTFOUND - // replace '#' with line breaks - // (also remove any '\n') + if (fastcmp(word, "THING") || fastcmp(word, "MOBJ") || fastcmp(word, "OBJECT")) { - char *cur = NULL; - - // remove '\n' - cur = strchr(displayname, '\n'); - if (cur) - *cur = '\0'; - - // turn '#' into '\n' - cur = strchr(displayname, '#'); - while (cur) + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_mobjtype(word2); // find a thing by name + if (i < NUMMOBJTYPES && i > 0) + readthing(f, i); + else { - *cur = '\n'; - cur = strchr(cur, '#'); + deh_warning("Thing %d out of range (1 - %d)", i, NUMMOBJTYPES-1); + ignorelines(f); } } - // copy final string - strncpy(description[num].displayname, displayname, SKINNAMESIZE); - } - else if (fastcmp(word, "OPPOSITECOLOR") || fastcmp(word, "OPPOSITECOLOUR")) - { - SLOTFOUND - description[num].oppositecolor = (UINT16)get_number(word2); - } - else if (fastcmp(word, "NAMETAG") || fastcmp(word, "TAGNAME")) - { - SLOTFOUND - strncpy(description[num].nametag, word2, 8); - } - else if (fastcmp(word, "TAGTEXTCOLOR") || fastcmp(word, "TAGTEXTCOLOUR")) - { - SLOTFOUND - description[num].tagtextcolor = (UINT16)get_number(word2); - } - else if (fastcmp(word, "TAGOUTLINECOLOR") || fastcmp(word, "TAGOUTLINECOLOUR")) - { - SLOTFOUND - description[num].tagoutlinecolor = (UINT16)get_number(word2); - } - else if (fastcmp(word, "STATUS")) - { - /* - You MAY disable previous entries if you so desire... - But try to enable something that's already enabled and you will be sent to a free slot. - - Because of this, you are allowed to edit any previous entries you like, but only if you - signal that you are purposely doing so by disabling and then reenabling the slot. - */ - if (i && !slotfound && (slotfound = findFreeSlot(&num)) == false) - goto done; - - description[num].used = (!!i); - } - else if (fastcmp(word, "SKINNAME")) - { - // Send to free slot. - SLOTFOUND - strlcpy(description[num].skinname, word2, sizeof description[num].skinname); - strlwr(description[num].skinname); - } - else - deh_warning("readPlayer %d: unknown word '%s'", num, word); - } - } while (!myfeof(f)); // finish when the line is empty - #undef SLOTFOUND -done: - Z_Free(displayname); - Z_Free(s); -} - -// TODO: Figure out how to do undolines for this.... -// TODO: Warnings for running out of freeslots -static void readfreeslots(MYFILE *f) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word,*type; - char *tmp; - int i; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - type = strtok(s, "_"); - if (type) - strupr(type); - else - break; - - word = strtok(NULL, "\n"); - if (word) - strupr(word); - else - break; - - // TODO: Check for existing freeslot mobjs/states/etc. and make errors. - // TODO: Out-of-slots warnings/errors. - // TODO: Name too long (truncated) warnings. - if (fastcmp(type, "SFX")) - S_AddSoundFx(word, false, 0, false); - else if (fastcmp(type, "SPR")) - { - for (i = SPR_FIRSTFREESLOT; i <= SPR_LASTFREESLOT; i++) + else if (fastcmp(word, "SKINCOLOR") || fastcmp(word, "COLOR")) { - if (used_spr[(i-SPR_FIRSTFREESLOT)/8] & (1<<(i%8))) + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_skincolor(word2); // find a skincolor by name + if (i && i < numskincolors) + readskincolor(f, i); + else { - if (!sprnames[i][4] && memcmp(sprnames[i],word,4)==0) - sprnames[i][4] = (char)f->wad; - continue; // Already allocated, next. + deh_warning("Skincolor %d out of range (1 - %d)", i, numskincolors-1); + ignorelines(f); } - // Found a free slot! - strncpy(sprnames[i],word,4); - //sprnames[i][4] = 0; - used_spr[(i-SPR_FIRSTFREESLOT)/8] |= 1<<(i%8); // Okay, this sprite slot has been named now. - break; } - } - else if (fastcmp(type, "S")) - { - for (i = 0; i < NUMSTATEFREESLOTS; i++) - if (!FREE_STATES[i]) { - FREE_STATES[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); - strcpy(FREE_STATES[i],word); - break; + else if (fastcmp(word, "SPRITE2")) + { + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_sprite2(word2); // find a sprite by name + if (i < (INT32)free_spr2 && i >= (INT32)SPR2_FIRSTFREESLOT) + readsprite2(f, i); + else + { + deh_warning("Sprite2 number %d out of range (%d - %d)", i, SPR2_FIRSTFREESLOT, free_spr2-1); + ignorelines(f); } - } - else if (fastcmp(type, "MT")) - { - for (i = 0; i < NUMMOBJFREESLOTS; i++) - if (!FREE_MOBJS[i]) { - FREE_MOBJS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); - strcpy(FREE_MOBJS[i],word); - break; + } +#ifdef HWRENDER + else if (fastcmp(word, "LIGHT")) + { + // TODO: Read lights by name + if (i > 0 && i < NUMLIGHTS) + readlight(f, i); + else + { + deh_warning("Light number %d out of range (1 - %d)", i, NUMLIGHTS-1); + ignorelines(f); } - } - else if (fastcmp(type, "SKINCOLOR")) - { - for (i = 0; i < NUMCOLORFREESLOTS; i++) - if (!FREE_SKINCOLORS[i]) { - FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); - strcpy(FREE_SKINCOLORS[i],word); - M_AddMenuColor(numskincolors++); - break; + } +#endif + else if (fastcmp(word, "SPRITE") || fastcmp(word, "SPRITEINFO")) + { + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_sprite(word2); // find a sprite by name + if (i < NUMSPRITES && i > 0) + readspriteinfo(f, i, false); + else + { + deh_warning("Sprite number %d out of range (0 - %d)", i, NUMSPRITES-1); + ignorelines(f); } - } - else if (fastcmp(type, "SPR2")) - { - // Search if we already have an SPR2 by that name... - for (i = SPR2_FIRSTFREESLOT; i < (int)free_spr2; i++) - if (memcmp(spr2names[i],word,4) == 0) - break; - // We found it? (Two mods using the same SPR2 name?) Then don't allocate another one. - if (i < (int)free_spr2) - continue; - // Copy in the spr2 name and increment free_spr2. - if (free_spr2 < NUMPLAYERSPRITES) { - strncpy(spr2names[free_spr2],word,4); - spr2defaults[free_spr2] = 0; - spr2names[free_spr2++][4] = 0; - } else - deh_warning("Ran out of free SPR2 slots!\n"); - } - else if (fastcmp(type, "TOL")) - { - // Search if we already have a typeoflevel by that name... - for (i = 0; TYPEOFLEVEL[i].name; i++) - if (fastcmp(word, TYPEOFLEVEL[i].name)) - break; - - // We found it? Then don't allocate another one. - if (TYPEOFLEVEL[i].name) - continue; - - // We don't, so freeslot it. - if (lastcustomtol == (UINT32)MAXTOL) // Unless you have way too many, since they're flags. - deh_warning("Ran out of free typeoflevel slots!\n"); - else + } + else if (fastcmp(word, "SPRITE2INFO")) { - G_AddTOL(lastcustomtol, word); - lastcustomtol <<= 1; + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_sprite2(word2); // find a sprite by name + if (i < NUMPLAYERSPRITES && i >= 0) + readspriteinfo(f, i, true); + else + { + deh_warning("Sprite2 number %d out of range (0 - %d)", i, NUMPLAYERSPRITES-1); + ignorelines(f); + } } - } - else - deh_warning("Freeslots: unknown enum class '%s' for '%s_%s'", type, type, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -static void readthing(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word, *word2; - char *tmp; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - word2 = strtok(NULL, " = "); - if (word2) - strupr(word2); - else - break; - if (word2[strlen(word2)-1] == '\n') - word2[strlen(word2)-1] = '\0'; - - if (fastcmp(word, "MAPTHINGNUM") || fastcmp(word, "DOOMEDNUM")) - { - mobjinfo[num].doomednum = (INT32)atoi(word2); - } - else if (fastcmp(word, "SPAWNSTATE")) - { - mobjinfo[num].spawnstate = get_number(word2); - } - else if (fastcmp(word, "SPAWNHEALTH")) - { - mobjinfo[num].spawnhealth = (INT32)get_number(word2); - } - else if (fastcmp(word, "SEESTATE")) - { - mobjinfo[num].seestate = get_number(word2); - } - else if (fastcmp(word, "SEESOUND")) - { - mobjinfo[num].seesound = get_number(word2); - } - else if (fastcmp(word, "REACTIONTIME")) - { - mobjinfo[num].reactiontime = (INT32)get_number(word2); - } - else if (fastcmp(word, "ATTACKSOUND")) - { - mobjinfo[num].attacksound = get_number(word2); - } - else if (fastcmp(word, "PAINSTATE")) - { - mobjinfo[num].painstate = get_number(word2); - } - else if (fastcmp(word, "PAINCHANCE")) - { - mobjinfo[num].painchance = (INT32)get_number(word2); - } - else if (fastcmp(word, "PAINSOUND")) - { - mobjinfo[num].painsound = get_number(word2); - } - else if (fastcmp(word, "MELEESTATE")) - { - mobjinfo[num].meleestate = get_number(word2); - } - else if (fastcmp(word, "MISSILESTATE")) - { - mobjinfo[num].missilestate = get_number(word2); - } - else if (fastcmp(word, "DEATHSTATE")) - { - mobjinfo[num].deathstate = get_number(word2); - } - else if (fastcmp(word, "DEATHSOUND")) - { - mobjinfo[num].deathsound = get_number(word2); - } - else if (fastcmp(word, "XDEATHSTATE")) - { - mobjinfo[num].xdeathstate = get_number(word2); - } - else if (fastcmp(word, "SPEED")) - { - mobjinfo[num].speed = get_number(word2); - } - else if (fastcmp(word, "RADIUS")) - { - mobjinfo[num].radius = get_number(word2); - } - else if (fastcmp(word, "HEIGHT")) - { - mobjinfo[num].height = get_number(word2); - } - else if (fastcmp(word, "DISPOFFSET")) - { - mobjinfo[num].dispoffset = get_number(word2); - } - else if (fastcmp(word, "MASS")) - { - mobjinfo[num].mass = (INT32)get_number(word2); - } - else if (fastcmp(word, "DAMAGE")) - { - mobjinfo[num].damage = (INT32)get_number(word2); - } - else if (fastcmp(word, "ACTIVESOUND")) - { - mobjinfo[num].activesound = get_number(word2); - } - else if (fastcmp(word, "FLAGS")) - { - mobjinfo[num].flags = (INT32)get_number(word2); - } - else if (fastcmp(word, "RAISESTATE")) - { - mobjinfo[num].raisestate = get_number(word2); - } - else - deh_warning("Thing %d: unknown word '%s'", num, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -static void readskincolor(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word = s; - char *word2; - char *tmp; - - Color_cons_t[num].value = num; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - *(tmp-1) = '\0'; - else - break; - strupr(word); - - // Now get the part after - word2 = tmp += 2; - - if (fastcmp(word, "NAME")) - { - size_t namesize = sizeof(skincolors[num].name); - char truncword[namesize]; - UINT16 dupecheck; - - deh_strlcpy(truncword, word2, namesize, va("Skincolor %d: name", num)); // truncate here to check for dupes - dupecheck = R_GetColorByName(truncword); - if (truncword[0] != '\0' && (!stricmp(truncword, skincolors[SKINCOLOR_NONE].name) || (dupecheck && dupecheck != num))) + else if (fastcmp(word, "LEVEL")) { - size_t lastchar = strlen(truncword); - char oldword[lastchar+1]; - char dupenum = '1'; + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + i = M_MapNumber(word2[0], word2[1]); - strlcpy(oldword, truncword, lastchar+1); - lastchar--; - if (lastchar == namesize-2) // exactly max length, replace last character with 0 - truncword[lastchar] = '0'; - else // append 0 + if (i > 0 && i <= NUMMAPS) + readlevelheader(f, i); + else { - strcat(truncword, "0"); - lastchar++; + deh_warning("Level number %d out of range (1 - %d)", i, NUMMAPS); + ignorelines(f); } - - while (R_GetColorByName(truncword)) + } + else if (fastcmp(word, "GAMETYPE")) + { + // Get the gametype name from textline + // instead of word2, so that gametype names + // aren't allcaps + INT32 c; + for (c = 0; c < MAXLINELEN; c++) { - truncword[lastchar] = dupenum; - if (dupenum == '9') - dupenum = 'A'; - else if (dupenum == 'Z') // give up :? + if (textline[c] == '\0') + break; + if (textline[c] == ' ') + { + char *gtname = (textline+c+1); + if (gtname) + { + // remove funny characters + INT32 j; + for (j = 0; j < (MAXLINELEN - c); j++) + { + if (gtname[j] == '\0') + break; + if (gtname[j] < 32) + gtname[j] = '\0'; + } + readgametype(f, gtname); + } break; - else - dupenum++; + } } - - deh_warning("Skincolor %d: name %s is a duplicate of another skincolor's name - renamed to %s", num, oldword, truncword); } - - strlcpy(skincolors[num].name, truncword, namesize); // already truncated - } - else if (fastcmp(word, "RAMP")) - { - UINT8 i; - tmp = strtok(word2,","); - for (i = 0; i < COLORRAMPSIZE; i++) { - skincolors[num].ramp[i] = (UINT8)get_number(tmp); - if ((tmp = strtok(NULL,",")) == NULL) - break; + else if (fastcmp(word, "CUTSCENE")) + { + if (i > 0 && i < 129) + readcutscene(f, i - 1); + else + { + deh_warning("Cutscene number %d out of range (1 - 128)", i); + ignorelines(f); + } } - skincolor_modified[num] = true; - } - else if (fastcmp(word, "INVCOLOR")) - { - UINT16 v = (UINT16)get_number(word2); - if (v < numskincolors) - skincolors[num].invcolor = v; - else - skincolors[num].invcolor = SKINCOLOR_GREEN; - } - else if (fastcmp(word, "INVSHADE")) - { - skincolors[num].invshade = get_number(word2)%COLORRAMPSIZE; - } - else if (fastcmp(word, "CHATCOLOR")) - { - skincolors[num].chatcolor = get_number(word2); - } - else if (fastcmp(word, "ACCESSIBLE")) - { - if (num > FIRSTSUPERCOLOR) - skincolors[num].accessible = (boolean)(atoi(word2) || word2[0] == 'T' || word2[0] == 'Y'); - } - else - deh_warning("Skincolor %d: unknown word '%s'", num, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -#ifdef HWRENDER -static void readlight(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word; - char *tmp; - INT32 value; - float fvalue; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - fvalue = searchfvalue(s); - value = searchvalue(s); - - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - if (fastcmp(word, "TYPE")) - { - lspr[num].type = (UINT16)value; - } - else if (fastcmp(word, "OFFSETX")) - { - lspr[num].light_xoffset = fvalue; - } - else if (fastcmp(word, "OFFSETY")) - { - lspr[num].light_yoffset = fvalue; - } - else if (fastcmp(word, "CORONACOLOR")) - { - lspr[num].corona_color = value; - } - else if (fastcmp(word, "CORONARADIUS")) - { - lspr[num].corona_radius = fvalue; - } - else if (fastcmp(word, "DYNAMICCOLOR")) - { - lspr[num].dynamic_color = value; - } - else if (fastcmp(word, "DYNAMICRADIUS")) - { - lspr[num].dynamic_radius = fvalue; - - /// \note Update the sqrradius! unnecessary? - lspr[num].dynamic_sqrradius = fvalue * fvalue; - } - else - deh_warning("Light %d: unknown word '%s'", num, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} -#endif // HWRENDER - -static void readspriteframe(MYFILE *f, spriteinfo_t *sprinfo, UINT8 frame) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word, *word2; - char *tmp; - INT32 value; - char *lastline; - - do - { - lastline = f->curpos; - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Set / reset word - word = s; - while ((*word == '\t') || (*word == ' ')) - word++; - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - { - *(tmp-1) = '\0'; - // Now get the part after - word2 = tmp += 2; - } - else - { - // Get the part before the " " - tmp = strchr(s, ' '); - if (tmp) - { - *tmp = '\0'; - // Now get the part after - tmp++; - word2 = tmp; - } - else - break; - } - strupr(word); - value = atoi(word2); // used for numerical settings - - if (fastcmp(word, "XPIVOT")) - sprinfo->pivot[frame].x = value; - else if (fastcmp(word, "YPIVOT")) - sprinfo->pivot[frame].y = value; - else if (fastcmp(word, "ROTAXIS")) - sprinfo->pivot[frame].rotaxis = value; - else - { - f->curpos = lastline; - break; - } - } - } while (!myfeof(f)); // finish when the line is empty - Z_Free(s); -} - -static void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word, *word2; - char *tmp; -#ifdef HWRENDER - INT32 value; -#endif - char *lastline; - INT32 skinnumbers[MAXSKINS]; - INT32 foundskins = 0; - - // allocate a spriteinfo - spriteinfo_t *info = Z_Calloc(sizeof(spriteinfo_t), PU_STATIC, NULL); - info->available = true; - -#ifdef ROTSPRITE - if ((sprites != NULL) && (!sprite2)) - R_FreeSingleRotSprite(&sprites[num]); -#endif - - do - { - lastline = f->curpos; - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Set / reset word - word = s; - while ((*word == '\t') || (*word == ' ')) - word++; - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - { - *(tmp-1) = '\0'; - // Now get the part after - word2 = tmp += 2; - } - else - { - // Get the part before the " " - tmp = strchr(s, ' '); - if (tmp) - { - *tmp = '\0'; - // Now get the part after - tmp++; - word2 = tmp; - } - else - break; - } - strupr(word); -#ifdef HWRENDER - value = atoi(word2); // used for numerical settings - - if (fastcmp(word, "LIGHTTYPE")) - { - if (sprite2) - deh_warning("Sprite2 %s: invalid word '%s'", spr2names[num], word); - else - { - INT32 oldvar; - for (oldvar = 0; t_lspr[num] != &lspr[oldvar]; oldvar++) - ; - t_lspr[num] = &lspr[value]; - } - } - else -#endif - if (fastcmp(word, "SKIN")) - { - INT32 skinnum = -1; - if (!sprite2) - { - deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", spr2names[num], word); - continue; - } - - // make lowercase - strlwr(word2); - skinnum = R_SkinAvailable(word2); - if (skinnum == -1) - { - deh_warning("Sprite2 %s: unknown skin %s", spr2names[num], word2); - break; - } - - skinnumbers[foundskins] = skinnum; - foundskins++; - } - else if (fastcmp(word, "DEFAULT")) - { - if (!sprite2) - { - deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", spr2names[num], word); - continue; - } - if (num < (INT32)free_spr2 && num >= (INT32)SPR2_FIRSTFREESLOT) - spr2defaults[num] = get_number(word2); - else - { - deh_warning("Sprite2 %s: out of range (%d - %d), ignoring", spr2names[num], SPR2_FIRSTFREESLOT, free_spr2-1); - continue; - } - } - else if (fastcmp(word, "FRAME")) - { - UINT8 frame = R_Char2Frame(word2[0]); - // frame number too high - if (frame >= 64) + else if (fastcmp(word, "PROMPT")) { - if (sprite2) - deh_warning("Sprite2 %s: invalid frame %s", spr2names[num], word2); + if (i > 0 && i < MAX_PROMPTS) + readtextprompt(f, i - 1); else - deh_warning("Sprite %s: invalid frame %s", sprnames[num], word2); - break; - } - - // read sprite frame and store it in the spriteinfo_t struct - readspriteframe(f, info, frame); - if (sprite2) - { - INT32 i; - if (!foundskins) - { - deh_warning("Sprite2 %s: no skins specified", spr2names[num]); - break; - } - for (i = 0; i < foundskins; i++) { - size_t skinnum = skinnumbers[i]; - skin_t *skin = &skins[skinnum]; - spriteinfo_t *sprinfo = skin->sprinfo; -#ifdef ROTSPRITE - R_FreeSkinRotSprite(skinnum); -#endif - M_Memcpy(&sprinfo[num], info, sizeof(spriteinfo_t)); + deh_warning("Prompt number %d out of range (1 - %d)", i, MAX_PROMPTS); + ignorelines(f); } } - else - M_Memcpy(&spriteinfo[num], info, sizeof(spriteinfo_t)); - } - else - { - //deh_warning("Sprite %s: unknown word '%s'", sprnames[num], word); - f->curpos = lastline; - break; - } - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); - Z_Free(info); -} - -static void readsprite2(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word, *word2; - char *tmp; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - word2 = strtok(NULL, " = "); - if (word2) - strupr(word2); - else - break; - if (word2[strlen(word2)-1] == '\n') - word2[strlen(word2)-1] = '\0'; - - if (fastcmp(word, "DEFAULT")) - spr2defaults[num] = get_number(word2); - else - deh_warning("Sprite2 %s: unknown word '%s'", spr2names[num], word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -// copypasted from readPlayer :] -static const char *const GAMETYPERULE_LIST[]; -static void readgametype(MYFILE *f, char *gtname) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word; - char *word2, *word2lwr = NULL; - char *tmp; - INT32 i, j; - - INT16 newgtidx = 0; - UINT32 newgtrules = 0; - UINT32 newgttol = 0; - INT32 newgtpointlimit = 0; - INT32 newgttimelimit = 0; - UINT8 newgtleftcolor = 0; - UINT8 newgtrightcolor = 0; - INT16 newgtrankingstype = -1; - int newgtinttype = 0; - char gtdescription[441]; - char gtconst[MAXLINELEN]; - - // Empty strings. - gtdescription[0] = '\0'; - gtconst[0] = '\0'; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - if (fastcmp(word, "DESCRIPTION")) - { - char *descr = NULL; - - for (i = 0; i < MAXLINELEN-3; i++) + else if (fastcmp(word, "FRAME") || fastcmp(word, "STATE")) { - if (s[i] == '=') + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_state(word2); // find a state by name + if (i < NUMSTATES && i >= 0) + readframe(f, i); + else { - descr = &s[i+2]; - break; + deh_warning("Frame %d out of range (0 - %d)", i, NUMSTATES-1); + ignorelines(f); } } - if (descr) + else if (fastcmp(word, "SOUND")) { - strcpy(gtdescription, descr); - strcat(gtdescription, myhashfgets(descr, sizeof (gtdescription), f)); + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_sfx(word2); // find a sound by name + if (i < NUMSFX && i > 0) + readsound(f, i); + else + { + deh_warning("Sound %d out of range (1 - %d)", i, NUMSFX-1); + ignorelines(f); + } } - else - strcpy(gtdescription, ""); - - // For some reason, cutting the string did not work above. Most likely due to strcpy or strcat... - // It works down here, though. + else if (fastcmp(word, "HUDITEM")) { - INT32 numline = 0; - for (i = 0; (size_t)i < sizeof(gtdescription)-1; i++) + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_huditem(word2); // find a huditem by name + if (i >= 0 && i < NUMHUDITEMS) + readhuditem(f, i); + else { - if (numline < 20 && gtdescription[i] == '\n') - numline++; - - if (numline >= 20 || gtdescription[i] == '\0' || gtdescription[i] == '#') - break; + deh_warning("HUD item number %d out of range (0 - %d)", i, NUMHUDITEMS-1); + ignorelines(f); } } - gtdescription[strlen(gtdescription)-1] = '\0'; - gtdescription[i] = '\0'; - continue; - } - - word2 = strtok(NULL, " = "); - if (word2) - { - if (!word2lwr) - word2lwr = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - strcpy(word2lwr, word2); - strupr(word2); - } - else - break; - - if (word2[strlen(word2)-1] == '\n') - word2[strlen(word2)-1] = '\0'; - i = atoi(word2); - - // Game type rules - if (fastcmp(word, "RULES")) - { - // GTR_ - newgtrules = (UINT32)get_number(word2); - } - // Identifier - else if (fastcmp(word, "IDENTIFIER")) - { - // GT_ - strncpy(gtconst, word2, MAXLINELEN); - } - // Point and time limits - else if (fastcmp(word, "DEFAULTPOINTLIMIT")) - newgtpointlimit = (INT32)i; - else if (fastcmp(word, "DEFAULTTIMELIMIT")) - newgttimelimit = (INT32)i; - // Level platter - else if (fastcmp(word, "HEADERCOLOR") || fastcmp(word, "HEADERCOLOUR")) - newgtleftcolor = newgtrightcolor = (UINT8)get_number(word2); - else if (fastcmp(word, "HEADERLEFTCOLOR") || fastcmp(word, "HEADERLEFTCOLOUR")) - newgtleftcolor = (UINT8)get_number(word2); - else if (fastcmp(word, "HEADERRIGHTCOLOR") || fastcmp(word, "HEADERRIGHTCOLOUR")) - newgtrightcolor = (UINT8)get_number(word2); - // Rankings type - else if (fastcmp(word, "RANKINGTYPE")) - { - // Case insensitive - newgtrankingstype = (int)get_number(word2); - } - // Intermission type - else if (fastcmp(word, "INTERMISSIONTYPE")) - { - // Case sensitive - newgtinttype = (int)get_number(word2lwr); - } - // Type of level - else if (fastcmp(word, "TYPEOFLEVEL")) - { - if (i) // it's just a number - newgttol = (UINT32)i; - else + else if (fastcmp(word, "MENU")) { - UINT32 tol = 0; - tmp = strtok(word2,","); - do { - for (i = 0; TYPEOFLEVEL[i].name; i++) - if (fasticmp(tmp, TYPEOFLEVEL[i].name)) - break; - if (!TYPEOFLEVEL[i].name) - deh_warning("readgametype %s: unknown typeoflevel flag %s\n", gtname, tmp); - tol |= TYPEOFLEVEL[i].flag; - } while((tmp = strtok(NULL,",")) != NULL); - newgttol = tol; - } - } - // The SOC probably provided gametype rules as words, - // instead of using the RULES keyword. - // Like for example "NOSPECTATORSPAWN = TRUE". - // This is completely valid, and looks better anyway. - else - { - UINT32 wordgt = 0; - for (j = 0; GAMETYPERULE_LIST[j]; j++) - if (fastcmp(word, GAMETYPERULE_LIST[j])) { - wordgt |= (1<<j); - if (i || word2[0] == 'T' || word2[0] == 'Y') - newgtrules |= wordgt; - break; - } - if (!wordgt) - deh_warning("readgametype %s: unknown word '%s'", gtname, word); - } - } - } while (!myfeof(f)); // finish when the line is empty - - // Free strings. - Z_Free(s); - if (word2lwr) - Z_Free(word2lwr); - - // Ran out of gametype slots - if (gametypecount == NUMGAMETYPEFREESLOTS) - { - CONS_Alert(CONS_WARNING, "Ran out of free gametype slots!\n"); - return; - } - - // Add the new gametype - newgtidx = G_AddGametype(newgtrules); - G_AddGametypeTOL(newgtidx, newgttol); - G_SetGametypeDescription(newgtidx, gtdescription, newgtleftcolor, newgtrightcolor); - - // Not covered by G_AddGametype alone. - if (newgtrankingstype == -1) - newgtrankingstype = newgtidx; - gametyperankings[newgtidx] = newgtrankingstype; - intermissiontypes[newgtidx] = newgtinttype; - pointlimits[newgtidx] = newgtpointlimit; - timelimits[newgtidx] = newgttimelimit; - - // Write the new gametype name. - Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname); - - // Write the constant name. - if (gtconst[0] == '\0') - strncpy(gtconst, gtname, MAXLINELEN); - G_AddGametypeConstant(newgtidx, (const char *)gtconst); - - // Update gametype_cons_t accordingly. - G_UpdateGametypeSelections(); - - CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]); -} - -static const struct { - const char *name; - const mobjtype_t type; -} FLICKYTYPES[] = { - {"BLUEBIRD", MT_FLICKY_01}, // Flicky (Flicky) - {"RABBIT", MT_FLICKY_02}, // Pocky (1) - {"CHICKEN", MT_FLICKY_03}, // Cucky (1) - {"SEAL", MT_FLICKY_04}, // Rocky (1) - {"PIG", MT_FLICKY_05}, // Picky (1) - {"CHIPMUNK", MT_FLICKY_06}, // Ricky (1) - {"PENGUIN", MT_FLICKY_07}, // Pecky (1) - {"FISH", MT_FLICKY_08}, // Nicky (CD) - {"RAM", MT_FLICKY_09}, // Flocky (CD) - {"PUFFIN", MT_FLICKY_10}, // Wicky (CD) - {"COW", MT_FLICKY_11}, // Macky (SRB2) - {"RAT", MT_FLICKY_12}, // Micky (2) - {"BEAR", MT_FLICKY_13}, // Becky (2) - {"DOVE", MT_FLICKY_14}, // Docky (CD) - {"CAT", MT_FLICKY_15}, // Nyannyan (Flicky) - {"CANARY", MT_FLICKY_16}, // Lucky (CD) - {"a", 0}, // End of normal flickies - a lower case character so will never fastcmp valid with uppercase tmp - //{"FLICKER", MT_FLICKER}, // Flacky (SRB2) - {"SPIDER", MT_SECRETFLICKY_01}, // Sticky (SRB2) - {"BAT", MT_SECRETFLICKY_02}, // Backy (SRB2) - {"SEED", MT_SEED}, // Seed (CD) - {NULL, 0} -}; - -#define MAXFLICKIES 64 - -static void readlevelheader(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word; - char *word2; - //char *word3; // Non-uppercase version of word2 - char *tmp; - INT32 i; - - // Reset all previous map header information - P_AllocMapHeader((INT16)(num-1)); - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Set / reset word, because some things (Lua.) move it - word = s; - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - *(tmp-1) = '\0'; - else - break; - strupr(word); - - // Now get the part after - word2 = tmp += 2; - i = atoi(word2); // used for numerical settings - - - if (fastcmp(word, "LEVELNAME")) - { - deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2, - sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num)); - strlcpy(mapheaderinfo[num-1]->selectheading, word2, sizeof(mapheaderinfo[num-1]->selectheading)); // not deh_ so only complains once - continue; - } - // CHEAP HACK: move this over here for lowercase subtitles - if (fastcmp(word, "SUBTITLE")) - { - deh_strlcpy(mapheaderinfo[num-1]->subttl, word2, - sizeof(mapheaderinfo[num-1]->subttl), va("Level header %d: subtitle", num)); - continue; - } - - // Lua custom options also go above, contents may be case sensitive. - if (fastncmp(word, "LUA.", 4)) - { - UINT8 j; - customoption_t *modoption; - - // Note: we actualy strlwr word here, so things are made a little easier for Lua - strlwr(word); - word += 4; // move past "lua." - - // ... and do a simple name sanity check; the name must start with a letter - if (*word < 'a' || *word > 'z') - { - deh_warning("Level header %d: invalid custom option name \"%s\"", num, word); - continue; - } - - // Sanity limit of 128 params - if (mapheaderinfo[num-1]->numCustomOptions == 128) - { - deh_warning("Level header %d: too many custom parameters", num); - continue; - } - j = mapheaderinfo[num-1]->numCustomOptions++; - - mapheaderinfo[num-1]->customopts = - Z_Realloc(mapheaderinfo[num-1]->customopts, - sizeof(customoption_t) * mapheaderinfo[num-1]->numCustomOptions, PU_STATIC, NULL); - - // Newly allocated - modoption = &mapheaderinfo[num-1]->customopts[j]; - - strncpy(modoption->option, word, 31); - modoption->option[31] = '\0'; - strncpy(modoption->value, word2, 255); - modoption->value[255] = '\0'; - continue; - } - - // Now go to uppercase - strupr(word2); - - // List of flickies that are be freed in this map - if (fastcmp(word, "FLICKYLIST") || fastcmp(word, "ANIMALLIST")) - { - if (fastcmp(word2, "NONE")) - P_DeleteFlickies(num-1); - else if (fastcmp(word2, "DEMO")) - P_SetDemoFlickies(num-1); - else if (fastcmp(word2, "ALL")) - { - mobjtype_t tmpflickies[MAXFLICKIES]; - - for (mapheaderinfo[num-1]->numFlickies = 0; - ((mapheaderinfo[num-1]->numFlickies < MAXFLICKIES) && FLICKYTYPES[mapheaderinfo[num-1]->numFlickies].type); - mapheaderinfo[num-1]->numFlickies++) - tmpflickies[mapheaderinfo[num-1]->numFlickies] = FLICKYTYPES[mapheaderinfo[num-1]->numFlickies].type; - - if (mapheaderinfo[num-1]->numFlickies) // just in case... - { - size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num-1]->numFlickies; - mapheaderinfo[num-1]->flickies = Z_Realloc(mapheaderinfo[num-1]->flickies, newsize, PU_STATIC, NULL); - M_Memcpy(mapheaderinfo[num-1]->flickies, tmpflickies, newsize); - } - } - else - { - mobjtype_t tmpflickies[MAXFLICKIES]; - mapheaderinfo[num-1]->numFlickies = 0; - tmp = strtok(word2,","); - // get up to the first MAXFLICKIES flickies - do { - if (mapheaderinfo[num-1]->numFlickies == MAXFLICKIES) // never going to get above that number - { - deh_warning("Level header %d: too many flickies\n", num); - break; - } - - if (fastncmp(tmp, "MT_", 3)) // support for specified mobjtypes... - { - i = get_mobjtype(tmp); - if (!i) - { - //deh_warning("Level header %d: unknown flicky mobj type %s\n", num, tmp); -- no need for this line as get_mobjtype complains too - continue; - } - tmpflickies[mapheaderinfo[num-1]->numFlickies] = i; - } - else // ...or a quick, limited selection of default flickies! - { - for (i = 0; FLICKYTYPES[i].name; i++) - if (fastcmp(tmp, FLICKYTYPES[i].name)) - break; - - if (!FLICKYTYPES[i].name) - { - deh_warning("Level header %d: unknown flicky selection %s\n", num, tmp); - continue; - } - tmpflickies[mapheaderinfo[num-1]->numFlickies] = FLICKYTYPES[i].type; - } - mapheaderinfo[num-1]->numFlickies++; - } while ((tmp = strtok(NULL,",")) != NULL); - - if (mapheaderinfo[num-1]->numFlickies) - { - size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num-1]->numFlickies; - mapheaderinfo[num-1]->flickies = Z_Realloc(mapheaderinfo[num-1]->flickies, newsize, PU_STATIC, NULL); - // now we add them to the list! - M_Memcpy(mapheaderinfo[num-1]->flickies, tmpflickies, newsize); - } + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_menutype(word2); // find a huditem by name + if (i >= 1 && i < NUMMENUTYPES) + readmenu(f, i); else - deh_warning("Level header %d: no valid flicky types found\n", num); - } - } - - // NiGHTS grades - else if (fastncmp(word, "GRADES", 6)) - { - UINT8 mare = (UINT8)atoi(word + 6); - - if (mare <= 0 || mare > 8) - { - deh_warning("Level header %d: unknown word '%s'", num, word); - continue; - } - - P_AddGradesForMare((INT16)(num-1), mare-1, word2); - } - - // Strings that can be truncated - else if (fastcmp(word, "SELECTHEADING")) - { - deh_strlcpy(mapheaderinfo[num-1]->selectheading, word2, - sizeof(mapheaderinfo[num-1]->selectheading), va("Level header %d: selectheading", num)); - } - else if (fastcmp(word, "SCRIPTNAME")) - { - deh_strlcpy(mapheaderinfo[num-1]->scriptname, word2, - sizeof(mapheaderinfo[num-1]->scriptname), va("Level header %d: scriptname", num)); - } - else if (fastcmp(word, "RUNSOC")) - { - deh_strlcpy(mapheaderinfo[num-1]->runsoc, word2, - sizeof(mapheaderinfo[num-1]->runsoc), va("Level header %d: runsoc", num)); - } - else if (fastcmp(word, "ACT")) - { - if (i >= 0 && i <= 99) // 0 for no act number - mapheaderinfo[num-1]->actnum = (UINT8)i; - else - deh_warning("Level header %d: invalid act number %d", num, i); - } - else if (fastcmp(word, "NEXTLEVEL")) - { - if (fastcmp(word2, "TITLE")) i = 1100; - else if (fastcmp(word2, "EVALUATION")) i = 1101; - else if (fastcmp(word2, "CREDITS")) i = 1102; - else if (fastcmp(word2, "ENDING")) i = 1103; - else - // Support using the actual map name, - // i.e., Nextlevel = AB, Nextlevel = FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') - i = M_MapNumber(word2[0], word2[1]); - - mapheaderinfo[num-1]->nextlevel = (INT16)i; - } - else if (fastcmp(word, "MARATHONNEXT")) - { - if (fastcmp(word2, "TITLE")) i = 1100; - else if (fastcmp(word2, "EVALUATION")) i = 1101; - else if (fastcmp(word2, "CREDITS")) i = 1102; - else if (fastcmp(word2, "ENDING")) i = 1103; - else - // Support using the actual map name, - // i.e., MarathonNext = AB, MarathonNext = FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') - i = M_MapNumber(word2[0], word2[1]); - - mapheaderinfo[num-1]->marathonnext = (INT16)i; - } - else if (fastcmp(word, "TYPEOFLEVEL")) - { - if (i) // it's just a number - mapheaderinfo[num-1]->typeoflevel = (UINT32)i; - else - { - UINT32 tol = 0; - tmp = strtok(word2,","); - do { - for (i = 0; TYPEOFLEVEL[i].name; i++) - if (fastcmp(tmp, TYPEOFLEVEL[i].name)) - break; - if (!TYPEOFLEVEL[i].name) - deh_warning("Level header %d: unknown typeoflevel flag %s\n", num, tmp); - tol |= TYPEOFLEVEL[i].flag; - } while((tmp = strtok(NULL,",")) != NULL); - mapheaderinfo[num-1]->typeoflevel = tol; - } - } - else if (fastcmp(word, "KEYWORDS")) - { - deh_strlcpy(mapheaderinfo[num-1]->keywords, word2, - sizeof(mapheaderinfo[num-1]->keywords), va("Level header %d: keywords", num)); - } - else if (fastcmp(word, "MUSIC")) - { - if (fastcmp(word2, "NONE")) - mapheaderinfo[num-1]->musname[0] = 0; // becomes empty string - else - { - deh_strlcpy(mapheaderinfo[num-1]->musname, word2, - sizeof(mapheaderinfo[num-1]->musname), va("Level header %d: music", num)); - } - } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - i = get_mus(word2, true); - if (i && i <= 1035) - snprintf(mapheaderinfo[num-1]->musname, 7, "%sM", G_BuildMapName(i)); - else if (i && i <= 1050) - strncpy(mapheaderinfo[num-1]->musname, compat_special_music_slots[i - 1036], 7); - else - mapheaderinfo[num-1]->musname[0] = 0; // becomes empty string - mapheaderinfo[num-1]->musname[6] = 0; - } -#endif - else if (fastcmp(word, "MUSICTRACK")) - mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1); - else if (fastcmp(word, "MUSICPOS")) - mapheaderinfo[num-1]->muspos = (UINT32)get_number(word2); - else if (fastcmp(word, "MUSICINTERFADEOUT")) - mapheaderinfo[num-1]->musinterfadeout = (UINT32)get_number(word2); - else if (fastcmp(word, "MUSICINTER")) - deh_strlcpy(mapheaderinfo[num-1]->musintername, word2, - sizeof(mapheaderinfo[num-1]->musintername), va("Level header %d: intermission music", num)); - else if (fastcmp(word, "MUSICPOSTBOSS")) - deh_strlcpy(mapheaderinfo[num-1]->muspostbossname, word2, - sizeof(mapheaderinfo[num-1]->muspostbossname), va("Level header %d: post-boss music", num)); - else if (fastcmp(word, "MUSICPOSTBOSSTRACK")) - mapheaderinfo[num-1]->muspostbosstrack = ((UINT16)i - 1); - else if (fastcmp(word, "MUSICPOSTBOSSPOS")) - mapheaderinfo[num-1]->muspostbosspos = (UINT32)get_number(word2); - else if (fastcmp(word, "MUSICPOSTBOSSFADEIN")) - mapheaderinfo[num-1]->muspostbossfadein = (UINT32)get_number(word2); - else if (fastcmp(word, "FORCERESETMUSIC")) - { - // This is a weird one because "FALSE"/"NO" could either apply to "leave to default preference" (cv_resetmusic) - // or "force off". Let's assume it means "force off", and let an unspecified value mean "default preference" - if (fastcmp(word2, "OFF") || word2[0] == 'F' || word2[0] == 'N') i = 0; - else if (fastcmp(word2, "ON") || word2[0] == 'T' || word2[0] == 'Y') i = 1; - else i = -1; // (fastcmp(word2, "DEFAULT")) - - if (i >= -1 && i <= 1) // -1 to force off, 1 to force on, 0 to honor default. - // This behavior can be disabled with cv_resetmusicbyheader - mapheaderinfo[num-1]->musforcereset = (SINT8)i; - else - deh_warning("Level header %d: invalid forceresetmusic option %d", num, i); - } - else if (fastcmp(word, "FORCECHARACTER")) - { - strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1); - strlwr(mapheaderinfo[num-1]->forcecharacter); // skin names are lowercase - } - else if (fastcmp(word, "WEATHER")) - mapheaderinfo[num-1]->weather = (UINT8)get_number(word2); - else if (fastcmp(word, "SKYNUM")) - mapheaderinfo[num-1]->skynum = (INT16)i; - else if (fastcmp(word, "INTERSCREEN")) - strncpy(mapheaderinfo[num-1]->interscreen, word2, 8); - else if (fastcmp(word, "PRECUTSCENENUM")) - mapheaderinfo[num-1]->precutscenenum = (UINT8)i; - else if (fastcmp(word, "CUTSCENENUM")) - mapheaderinfo[num-1]->cutscenenum = (UINT8)i; - else if (fastcmp(word, "COUNTDOWN")) - mapheaderinfo[num-1]->countdown = (INT16)i; - else if (fastcmp(word, "PALETTE")) - mapheaderinfo[num-1]->palette = (UINT16)i; - else if (fastcmp(word, "NUMLAPS")) - mapheaderinfo[num-1]->numlaps = (UINT8)i; - else if (fastcmp(word, "UNLOCKABLE")) - { - if (i >= 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something - mapheaderinfo[num-1]->unlockrequired = (SINT8)i - 1; - else - deh_warning("Level header %d: invalid unlockable number %d", num, i); - } - else if (fastcmp(word, "LEVELSELECT")) - mapheaderinfo[num-1]->levelselect = (UINT8)i; - else if (fastcmp(word, "SKYBOXSCALE")) - mapheaderinfo[num-1]->skybox_scalex = mapheaderinfo[num-1]->skybox_scaley = mapheaderinfo[num-1]->skybox_scalez = (INT16)i; - else if (fastcmp(word, "SKYBOXSCALEX")) - mapheaderinfo[num-1]->skybox_scalex = (INT16)i; - else if (fastcmp(word, "SKYBOXSCALEY")) - mapheaderinfo[num-1]->skybox_scaley = (INT16)i; - else if (fastcmp(word, "SKYBOXSCALEZ")) - mapheaderinfo[num-1]->skybox_scalez = (INT16)i; - - else if (fastcmp(word, "BONUSTYPE")) - { - if (fastcmp(word2, "NONE")) i = -1; - else if (fastcmp(word2, "NORMAL")) i = 0; - else if (fastcmp(word2, "BOSS")) i = 1; - else if (fastcmp(word2, "ERZ3")) i = 2; - else if (fastcmp(word2, "NIGHTS")) i = 3; - else if (fastcmp(word2, "NIGHTSLINK")) i = 4; - - if (i >= -1 && i <= 4) // -1 for no bonus. Max is 4. - mapheaderinfo[num-1]->bonustype = (SINT8)i; - else - deh_warning("Level header %d: invalid bonus type number %d", num, i); - } - - // Title card - else if (fastcmp(word, "TITLECARDZIGZAG")) - { - deh_strlcpy(mapheaderinfo[num-1]->ltzzpatch, word2, - sizeof(mapheaderinfo[num-1]->ltzzpatch), va("Level header %d: title card zigzag patch name", num)); - } - else if (fastcmp(word, "TITLECARDZIGZAGTEXT")) - { - deh_strlcpy(mapheaderinfo[num-1]->ltzztext, word2, - sizeof(mapheaderinfo[num-1]->ltzztext), va("Level header %d: title card zigzag text patch name", num)); - } - else if (fastcmp(word, "TITLECARDACTDIAMOND")) - { - deh_strlcpy(mapheaderinfo[num-1]->ltactdiamond, word2, - sizeof(mapheaderinfo[num-1]->ltactdiamond), va("Level header %d: title card act diamond patch name", num)); - } - - else if (fastcmp(word, "MAXBONUSLIVES")) - mapheaderinfo[num-1]->maxbonuslives = (SINT8)i; - else if (fastcmp(word, "LEVELFLAGS")) - mapheaderinfo[num-1]->levelflags = (UINT16)i; - else if (fastcmp(word, "MENUFLAGS")) - mapheaderinfo[num-1]->menuflags = (UINT8)i; - - // Individual triggers for level flags, for ease of use (and 2.0 compatibility) - else if (fastcmp(word, "SCRIPTISFILE")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_SCRIPTISFILE; - else - mapheaderinfo[num-1]->levelflags &= ~LF_SCRIPTISFILE; - } - else if (fastcmp(word, "SPEEDMUSIC")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_SPEEDMUSIC; - else - mapheaderinfo[num-1]->levelflags &= ~LF_SPEEDMUSIC; - } - else if (fastcmp(word, "NOSSMUSIC")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_NOSSMUSIC; - else - mapheaderinfo[num-1]->levelflags &= ~LF_NOSSMUSIC; - } - else if (fastcmp(word, "NORELOAD")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_NORELOAD; - else - mapheaderinfo[num-1]->levelflags &= ~LF_NORELOAD; - } - else if (fastcmp(word, "NOZONE")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_NOZONE; - else - mapheaderinfo[num-1]->levelflags &= ~LF_NOZONE; - } - else if (fastcmp(word, "SAVEGAME")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_SAVEGAME; - else - mapheaderinfo[num-1]->levelflags &= ~LF_SAVEGAME; - } - else if (fastcmp(word, "MIXNIGHTSCOUNTDOWN")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_MIXNIGHTSCOUNTDOWN; - else - mapheaderinfo[num-1]->levelflags &= ~LF_MIXNIGHTSCOUNTDOWN; - } - else if (fastcmp(word, "WARNINGTITLE")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_WARNINGTITLE; - else - mapheaderinfo[num-1]->levelflags &= ~LF_WARNINGTITLE; - } - else if (fastcmp(word, "NOTITLECARD")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_NOTITLECARD; - else - mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARD; - } - else if (fastcmp(word, "SHOWTITLECARDFOR")) - { - mapheaderinfo[num-1]->levelflags |= LF_NOTITLECARD; - tmp = strtok(word2,","); - do { - if (fastcmp(tmp, "FIRST")) - mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARDFIRST; - else if (fastcmp(tmp, "RESPAWN")) - mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARDRESPAWN; - else if (fastcmp(tmp, "RECORDATTACK")) - mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARDRECORDATTACK; - else if (fastcmp(tmp, "ALL")) - mapheaderinfo[num-1]->levelflags &= ~LF_NOTITLECARD; - else if (!fastcmp(tmp, "NONE")) - deh_warning("Level header %d: unknown titlecard show option %s\n", num, tmp); - - } while((tmp = strtok(NULL,",")) != NULL); - } - - // Individual triggers for menu flags - else if (fastcmp(word, "HIDDEN")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->menuflags |= LF2_HIDEINMENU; - else - mapheaderinfo[num-1]->menuflags &= ~LF2_HIDEINMENU; - } - else if (fastcmp(word, "HIDEINSTATS")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->menuflags |= LF2_HIDEINSTATS; - else - mapheaderinfo[num-1]->menuflags &= ~LF2_HIDEINSTATS; - } - else if (fastcmp(word, "RECORDATTACK") || fastcmp(word, "TIMEATTACK")) - { // TIMEATTACK is an accepted alias - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->menuflags |= LF2_RECORDATTACK; - else - mapheaderinfo[num-1]->menuflags &= ~LF2_RECORDATTACK; - } - else if (fastcmp(word, "NIGHTSATTACK")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->menuflags |= LF2_NIGHTSATTACK; - else - mapheaderinfo[num-1]->menuflags &= LF2_NIGHTSATTACK; - } - else if (fastcmp(word, "NOVISITNEEDED")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->menuflags |= LF2_NOVISITNEEDED; - else - mapheaderinfo[num-1]->menuflags &= ~LF2_NOVISITNEEDED; - } - else if (fastcmp(word, "WIDEICON")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->menuflags |= LF2_WIDEICON; - else - mapheaderinfo[num-1]->menuflags &= ~LF2_WIDEICON; - } - else if (fastcmp(word, "STARTRINGS")) - mapheaderinfo[num-1]->startrings = (UINT16)i; - else if (fastcmp(word, "SPECIALSTAGETIME")) - mapheaderinfo[num-1]->sstimer = i; - else if (fastcmp(word, "SPECIALSTAGESPHERES")) - mapheaderinfo[num-1]->ssspheres = i; - else if (fastcmp(word, "GRAVITY")) - mapheaderinfo[num-1]->gravity = FLOAT_TO_FIXED(atof(word2)); - else - deh_warning("Level header %d: unknown word '%s'", num, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -#undef MAXFLICKIES - -static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) -{ - char *s = Z_Calloc(MAXLINELEN, PU_STATIC, NULL); - char *word; - char *word2; - INT32 i; - UINT16 usi; - UINT8 picid; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - if (fastcmp(word, "SCENETEXT")) - { - char *scenetext = NULL; - char *buffer; - const int bufferlen = 4096; - - for (i = 0; i < MAXLINELEN; i++) - { - if (s[i] == '=') - { - scenetext = &s[i+2]; - break; - } - } - - if (!scenetext) - { - Z_Free(cutscenes[num]->scene[scenenum].text); - cutscenes[num]->scene[scenenum].text = NULL; - continue; - } - - for (i = 0; i < MAXLINELEN; i++) - { - if (s[i] == '\0') { - s[i] = '\n'; - s[i+1] = '\0'; - break; - } - } - - buffer = Z_Malloc(4096, PU_STATIC, NULL); - strcpy(buffer, scenetext); - - strcat(buffer, - myhashfgets(scenetext, bufferlen - - strlen(buffer) - 1, f)); - - // A cutscene overwriting another one... - Z_Free(cutscenes[num]->scene[scenenum].text); - - cutscenes[num]->scene[scenenum].text = Z_StrDup(buffer); - - Z_Free(buffer); - - continue; - } - - word2 = strtok(NULL, " = "); - if (word2) - strupr(word2); - else - break; - - if (word2[strlen(word2)-1] == '\n') - word2[strlen(word2)-1] = '\0'; - i = atoi(word2); - usi = (UINT16)i; - - - if (fastcmp(word, "NUMBEROFPICS")) - { - cutscenes[num]->scene[scenenum].numpics = (UINT8)i; - } - else if (fastncmp(word, "PIC", 3)) - { - picid = (UINT8)atoi(word + 3); - if (picid > 8 || picid == 0) - { - deh_warning("CutSceneScene %d: unknown word '%s'", num, word); - continue; - } - --picid; - - if (fastcmp(word+4, "NAME")) - { - strncpy(cutscenes[num]->scene[scenenum].picname[picid], word2, 8); - } - else if (fastcmp(word+4, "HIRES")) - { - cutscenes[num]->scene[scenenum].pichires[picid] = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); - } - else if (fastcmp(word+4, "DURATION")) - { - cutscenes[num]->scene[scenenum].picduration[picid] = usi; - } - else if (fastcmp(word+4, "XCOORD")) - { - cutscenes[num]->scene[scenenum].xcoord[picid] = usi; - } - else if (fastcmp(word+4, "YCOORD")) - { - cutscenes[num]->scene[scenenum].ycoord[picid] = usi; - } - else - deh_warning("CutSceneScene %d: unknown word '%s'", num, word); - } - else if (fastcmp(word, "MUSIC")) - { - strncpy(cutscenes[num]->scene[scenenum].musswitch, word2, 7); - cutscenes[num]->scene[scenenum].musswitch[6] = 0; - } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - i = get_mus(word2, true); - if (i && i <= 1035) - snprintf(cutscenes[num]->scene[scenenum].musswitch, 7, "%sM", G_BuildMapName(i)); - else if (i && i <= 1050) - strncpy(cutscenes[num]->scene[scenenum].musswitch, compat_special_music_slots[i - 1036], 7); - else - cutscenes[num]->scene[scenenum].musswitch[0] = 0; // becomes empty string - cutscenes[num]->scene[scenenum].musswitch[6] = 0; - } -#endif - else if (fastcmp(word, "MUSICTRACK")) - { - cutscenes[num]->scene[scenenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; - } - else if (fastcmp(word, "MUSICPOS")) - { - cutscenes[num]->scene[scenenum].musswitchposition = (UINT32)get_number(word2); - } - else if (fastcmp(word, "MUSICLOOP")) - { - cutscenes[num]->scene[scenenum].musicloop = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); - } - else if (fastcmp(word, "TEXTXPOS")) - { - cutscenes[num]->scene[scenenum].textxpos = usi; - } - else if (fastcmp(word, "TEXTYPOS")) - { - cutscenes[num]->scene[scenenum].textypos = usi; - } - else if (fastcmp(word, "FADEINID")) - { - cutscenes[num]->scene[scenenum].fadeinid = (UINT8)i; - } - else if (fastcmp(word, "FADEOUTID")) - { - cutscenes[num]->scene[scenenum].fadeoutid = (UINT8)i; - } - else if (fastcmp(word, "FADECOLOR")) - { - cutscenes[num]->scene[scenenum].fadecolor = (UINT8)i; - } - else - deh_warning("CutSceneScene %d: unknown word '%s'", num, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -static void readcutscene(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word; - char *word2; - char *tmp; - INT32 value; - - // Allocate memory for this cutscene if we don't yet have any - if (!cutscenes[num]) - cutscenes[num] = Z_Calloc(sizeof (cutscene_t), PU_STATIC, NULL); - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - word2 = strtok(NULL, " "); - if (word2) - value = atoi(word2); - else - { - deh_warning("No value for token %s", word); - continue; - } - - if (fastcmp(word, "NUMSCENES")) - { - cutscenes[num]->numscenes = value; - } - else if (fastcmp(word, "SCENE")) - { - if (1 <= value && value <= 128) - { - readcutscenescene(f, num, value - 1); - } - else - deh_warning("Scene number %d out of range (1 - 128)", value); - - } - else - deh_warning("Cutscene %d: unknown word '%s', Scene <num> expected.", num, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) -{ - char *s = Z_Calloc(MAXLINELEN, PU_STATIC, NULL); - char *word; - char *word2; - INT32 i; - UINT16 usi; - UINT8 picid; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - if (fastcmp(word, "PAGETEXT")) - { - char *pagetext = NULL; - char *buffer; - const int bufferlen = 4096; - - for (i = 0; i < MAXLINELEN; i++) - { - if (s[i] == '=') - { - pagetext = &s[i+2]; - break; - } - } - - if (!pagetext) - { - Z_Free(textprompts[num]->page[pagenum].text); - textprompts[num]->page[pagenum].text = NULL; - continue; - } - - for (i = 0; i < MAXLINELEN; i++) - { - if (s[i] == '\0') - { - s[i] = '\n'; - s[i+1] = '\0'; - break; - } - } - - buffer = Z_Malloc(4096, PU_STATIC, NULL); - strcpy(buffer, pagetext); - - // \todo trim trailing whitespace before the # - // and also support # at the end of a PAGETEXT with no line break - - strcat(buffer, - myhashfgets(pagetext, bufferlen - - strlen(buffer) - 1, f)); - - // A text prompt overwriting another one... - Z_Free(textprompts[num]->page[pagenum].text); - - textprompts[num]->page[pagenum].text = Z_StrDup(buffer); - - Z_Free(buffer); - - continue; - } - - word2 = strtok(NULL, " = "); - if (word2) - strupr(word2); - else - break; - - if (word2[strlen(word2)-1] == '\n') - word2[strlen(word2)-1] = '\0'; - i = atoi(word2); - usi = (UINT16)i; - - // copypasta from readcutscenescene - if (fastcmp(word, "NUMBEROFPICS")) - { - textprompts[num]->page[pagenum].numpics = (UINT8)i; - } - else if (fastcmp(word, "PICMODE")) - { - UINT8 picmode = 0; // PROMPT_PIC_PERSIST - if (usi == 1 || word2[0] == 'L') picmode = PROMPT_PIC_LOOP; - else if (usi == 2 || word2[0] == 'D' || word2[0] == 'H') picmode = PROMPT_PIC_DESTROY; - textprompts[num]->page[pagenum].picmode = picmode; - } - else if (fastcmp(word, "PICTOLOOP")) - textprompts[num]->page[pagenum].pictoloop = (UINT8)i; - else if (fastcmp(word, "PICTOSTART")) - textprompts[num]->page[pagenum].pictostart = (UINT8)i; - else if (fastcmp(word, "PICSMETAPAGE")) - { - if (usi && usi <= textprompts[num]->numpages) - { - UINT8 metapagenum = usi - 1; - - textprompts[num]->page[pagenum].numpics = textprompts[num]->page[metapagenum].numpics; - textprompts[num]->page[pagenum].picmode = textprompts[num]->page[metapagenum].picmode; - textprompts[num]->page[pagenum].pictoloop = textprompts[num]->page[metapagenum].pictoloop; - textprompts[num]->page[pagenum].pictostart = textprompts[num]->page[metapagenum].pictostart; - - for (picid = 0; picid < MAX_PROMPT_PICS; picid++) - { - strncpy(textprompts[num]->page[pagenum].picname[picid], textprompts[num]->page[metapagenum].picname[picid], 8); - textprompts[num]->page[pagenum].pichires[picid] = textprompts[num]->page[metapagenum].pichires[picid]; - textprompts[num]->page[pagenum].picduration[picid] = textprompts[num]->page[metapagenum].picduration[picid]; - textprompts[num]->page[pagenum].xcoord[picid] = textprompts[num]->page[metapagenum].xcoord[picid]; - textprompts[num]->page[pagenum].ycoord[picid] = textprompts[num]->page[metapagenum].ycoord[picid]; - } - } - } - else if (fastncmp(word, "PIC", 3)) - { - picid = (UINT8)atoi(word + 3); - if (picid > MAX_PROMPT_PICS || picid == 0) - { - deh_warning("textpromptscene %d: unknown word '%s'", num, word); - continue; - } - --picid; - - if (fastcmp(word+4, "NAME")) - { - strncpy(textprompts[num]->page[pagenum].picname[picid], word2, 8); - } - else if (fastcmp(word+4, "HIRES")) - { - textprompts[num]->page[pagenum].pichires[picid] = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); - } - else if (fastcmp(word+4, "DURATION")) - { - textprompts[num]->page[pagenum].picduration[picid] = usi; - } - else if (fastcmp(word+4, "XCOORD")) - { - textprompts[num]->page[pagenum].xcoord[picid] = usi; - } - else if (fastcmp(word+4, "YCOORD")) - { - textprompts[num]->page[pagenum].ycoord[picid] = usi; - } - else - deh_warning("textpromptscene %d: unknown word '%s'", num, word); - } - else if (fastcmp(word, "MUSIC")) - { - strncpy(textprompts[num]->page[pagenum].musswitch, word2, 7); - textprompts[num]->page[pagenum].musswitch[6] = 0; - } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - i = get_mus(word2, true); - if (i && i <= 1035) - snprintf(textprompts[num]->page[pagenum].musswitch, 7, "%sM", G_BuildMapName(i)); - else if (i && i <= 1050) - strncpy(textprompts[num]->page[pagenum].musswitch, compat_special_music_slots[i - 1036], 7); - else - textprompts[num]->page[pagenum].musswitch[0] = 0; // becomes empty string - textprompts[num]->page[pagenum].musswitch[6] = 0; - } -#endif - else if (fastcmp(word, "MUSICTRACK")) - { - textprompts[num]->page[pagenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; - } - else if (fastcmp(word, "MUSICLOOP")) - { - textprompts[num]->page[pagenum].musicloop = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); - } - // end copypasta from readcutscenescene - else if (fastcmp(word, "NAME")) - { - if (*word2 != '\0') - { - INT32 j; - - // HACK: Add yellow control char now - // so the drawing function doesn't call it repeatedly - char name[34]; - name[0] = '\x82'; // color yellow - name[1] = 0; - strncat(name, word2, 33); - name[33] = 0; - - // Replace _ with ' ' - for (j = 0; j < 32 && name[j]; j++) - { - if (name[j] == '_') - name[j] = ' '; - } - - strncpy(textprompts[num]->page[pagenum].name, name, 32); - } - else - *textprompts[num]->page[pagenum].name = '\0'; - } - else if (fastcmp(word, "ICON")) - strncpy(textprompts[num]->page[pagenum].iconname, word2, 8); - else if (fastcmp(word, "ICONALIGN")) - textprompts[num]->page[pagenum].rightside = (i || word2[0] == 'R'); - else if (fastcmp(word, "ICONFLIP")) - textprompts[num]->page[pagenum].iconflip = (i || word2[0] == 'T' || word2[0] == 'Y'); - else if (fastcmp(word, "LINES")) - textprompts[num]->page[pagenum].lines = usi; - else if (fastcmp(word, "BACKCOLOR")) - { - INT32 backcolor; - if (i == 0 || fastcmp(word2, "WHITE")) backcolor = 0; - else if (i == 1 || fastcmp(word2, "GRAY") || fastcmp(word2, "GREY") || - fastcmp(word2, "BLACK")) backcolor = 1; - else if (i == 2 || fastcmp(word2, "SEPIA")) backcolor = 2; - else if (i == 3 || fastcmp(word2, "BROWN")) backcolor = 3; - else if (i == 4 || fastcmp(word2, "PINK")) backcolor = 4; - else if (i == 5 || fastcmp(word2, "RASPBERRY")) backcolor = 5; - else if (i == 6 || fastcmp(word2, "RED")) backcolor = 6; - else if (i == 7 || fastcmp(word2, "CREAMSICLE")) backcolor = 7; - else if (i == 8 || fastcmp(word2, "ORANGE")) backcolor = 8; - else if (i == 9 || fastcmp(word2, "GOLD")) backcolor = 9; - else if (i == 10 || fastcmp(word2, "YELLOW")) backcolor = 10; - else if (i == 11 || fastcmp(word2, "EMERALD")) backcolor = 11; - else if (i == 12 || fastcmp(word2, "GREEN")) backcolor = 12; - else if (i == 13 || fastcmp(word2, "CYAN") || fastcmp(word2, "AQUA")) backcolor = 13; - else if (i == 14 || fastcmp(word2, "STEEL")) backcolor = 14; - else if (i == 15 || fastcmp(word2, "PERIWINKLE")) backcolor = 15; - else if (i == 16 || fastcmp(word2, "BLUE")) backcolor = 16; - else if (i == 17 || fastcmp(word2, "PURPLE")) backcolor = 17; - else if (i == 18 || fastcmp(word2, "LAVENDER")) backcolor = 18; - else if (i >= 256 && i < 512) backcolor = i; // non-transparent palette index - else if (i < 0) backcolor = INT32_MAX; // CONS_BACKCOLOR user-configured - else backcolor = 1; // default gray - textprompts[num]->page[pagenum].backcolor = backcolor; - } - else if (fastcmp(word, "ALIGN")) - { - UINT8 align = 0; // left - if (usi == 1 || word2[0] == 'R') align = 1; - else if (usi == 2 || word2[0] == 'C' || word2[0] == 'M') align = 2; - textprompts[num]->page[pagenum].align = align; - } - else if (fastcmp(word, "VERTICALALIGN")) - { - UINT8 align = 0; // top - if (usi == 1 || word2[0] == 'B') align = 1; - else if (usi == 2 || word2[0] == 'C' || word2[0] == 'M') align = 2; - textprompts[num]->page[pagenum].verticalalign = align; - } - else if (fastcmp(word, "TEXTSPEED")) - textprompts[num]->page[pagenum].textspeed = get_number(word2); - else if (fastcmp(word, "TEXTSFX")) - textprompts[num]->page[pagenum].textsfx = get_number(word2); - else if (fastcmp(word, "HIDEHUD")) - { - UINT8 hidehud = 0; - if ((word2[0] == 'F' && (word2[1] == 'A' || !word2[1])) || word2[0] == 'N') hidehud = 0; // false - else if (usi == 1 || word2[0] == 'T' || word2[0] == 'Y') hidehud = 1; // true (hide appropriate HUD elements) - else if (usi == 2 || word2[0] == 'A' || (word2[0] == 'F' && word2[1] == 'O')) hidehud = 2; // force (hide all HUD elements) - textprompts[num]->page[pagenum].hidehud = hidehud; - } - else if (fastcmp(word, "METAPAGE")) - { - if (usi && usi <= textprompts[num]->numpages) - { - UINT8 metapagenum = usi - 1; - - strncpy(textprompts[num]->page[pagenum].name, textprompts[num]->page[metapagenum].name, 32); - strncpy(textprompts[num]->page[pagenum].iconname, textprompts[num]->page[metapagenum].iconname, 8); - textprompts[num]->page[pagenum].rightside = textprompts[num]->page[metapagenum].rightside; - textprompts[num]->page[pagenum].iconflip = textprompts[num]->page[metapagenum].iconflip; - textprompts[num]->page[pagenum].lines = textprompts[num]->page[metapagenum].lines; - textprompts[num]->page[pagenum].backcolor = textprompts[num]->page[metapagenum].backcolor; - textprompts[num]->page[pagenum].align = textprompts[num]->page[metapagenum].align; - textprompts[num]->page[pagenum].verticalalign = textprompts[num]->page[metapagenum].verticalalign; - textprompts[num]->page[pagenum].textspeed = textprompts[num]->page[metapagenum].textspeed; - textprompts[num]->page[pagenum].textsfx = textprompts[num]->page[metapagenum].textsfx; - textprompts[num]->page[pagenum].hidehud = textprompts[num]->page[metapagenum].hidehud; - - // music: don't copy, else each page change may reset the music - } - } - else if (fastcmp(word, "TAG")) - strncpy(textprompts[num]->page[pagenum].tag, word2, 33); - else if (fastcmp(word, "NEXTPROMPT")) - textprompts[num]->page[pagenum].nextprompt = usi; - else if (fastcmp(word, "NEXTPAGE")) - textprompts[num]->page[pagenum].nextpage = usi; - else if (fastcmp(word, "NEXTTAG")) - strncpy(textprompts[num]->page[pagenum].nexttag, word2, 33); - else if (fastcmp(word, "TIMETONEXT")) - textprompts[num]->page[pagenum].timetonext = get_number(word2); - else - deh_warning("PromptPage %d: unknown word '%s'", num, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -static void readtextprompt(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word; - char *word2; - char *tmp; - INT32 value; - - // Allocate memory for this prompt if we don't yet have any - if (!textprompts[num]) - textprompts[num] = Z_Calloc(sizeof (textprompt_t), PU_STATIC, NULL); - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - word2 = strtok(NULL, " "); - if (word2) - value = atoi(word2); - else - { - deh_warning("No value for token %s", word); - continue; - } - - if (fastcmp(word, "NUMPAGES")) - { - textprompts[num]->numpages = min(max(value, 0), MAX_PAGES); - } - else if (fastcmp(word, "PAGE")) - { - if (1 <= value && value <= MAX_PAGES) - { - textprompts[num]->page[value - 1].backcolor = 1; // default to gray - textprompts[num]->page[value - 1].hidehud = 1; // hide appropriate HUD elements - readtextpromptpage(f, num, value - 1); - } - else - deh_warning("Page number %d out of range (1 - %d)", value, MAX_PAGES); - - } - else - deh_warning("Prompt %d: unknown word '%s', Page <num> expected.", num, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -static void readmenu(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word = s; - char *word2; - char *tmp; - INT32 value; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - *(tmp-1) = '\0'; - else - break; - strupr(word); - - // Now get the part after - word2 = (tmp += 2); - strupr(word2); - - value = atoi(word2); // used for numerical settings - - if (fastcmp(word, "BACKGROUNDNAME")) - { - strncpy(menupres[num].bgname, word2, 8); - titlechanged = true; - } - else if (fastcmp(word, "HIDEBACKGROUND")) - { - menupres[num].bghide = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); - titlechanged = true; - } - else if (fastcmp(word, "BACKGROUNDCOLOR")) - { - menupres[num].bgcolor = get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "HIDEPICS") || fastcmp(word, "TITLEPICSHIDE")) - { - // true by default, except MM_MAIN - menupres[num].hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSMODE")) - { - if (fastcmp(word2, "USER")) - menupres[num].ttmode = TTMODE_USER; - else if (fastcmp(word2, "ALACROIX")) - menupres[num].ttmode = TTMODE_ALACROIX; - else if (fastcmp(word2, "HIDE") || fastcmp(word2, "HIDDEN") || fastcmp(word2, "NONE")) - { - menupres[num].ttmode = TTMODE_USER; - menupres[num].ttname[0] = 0; - menupres[num].hidetitlepics = true; - } - else // if (fastcmp(word2, "OLD") || fastcmp(word2, "SSNTAILS")) - menupres[num].ttmode = TTMODE_OLD; - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSSCALE")) - { - // Don't handle Alacroix special case here; see Maincfg section. - menupres[num].ttscale = max(1, min(8, (UINT8)get_number(word2))); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSNAME")) - { - strncpy(menupres[num].ttname, word2, 9); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSX")) - { - menupres[num].ttx = (INT16)get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSY")) - { - menupres[num].tty = (INT16)get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSLOOP")) - { - menupres[num].ttloop = (INT16)get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSTICS")) - { - menupres[num].tttics = (UINT16)get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "TITLESCROLLSPEED") || fastcmp(word, "TITLESCROLLXSPEED") - || fastcmp(word, "SCROLLSPEED") || fastcmp(word, "SCROLLXSPEED")) - { - menupres[num].titlescrollxspeed = get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "TITLESCROLLYSPEED") || fastcmp(word, "SCROLLYSPEED")) - { - menupres[num].titlescrollyspeed = get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "MUSIC")) - { - strncpy(menupres[num].musname, word2, 7); - menupres[num].musname[6] = 0; - titlechanged = true; - } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - value = get_mus(word2, true); - if (value && value <= 1035) - snprintf(menupres[num].musname, 7, "%sM", G_BuildMapName(value)); - else if (value && value <= 1050) - strncpy(menupres[num].musname, compat_special_music_slots[value - 1036], 7); - else - menupres[num].musname[0] = 0; // becomes empty string - menupres[num].musname[6] = 0; - titlechanged = true; - } -#endif - else if (fastcmp(word, "MUSICTRACK")) - { - menupres[num].mustrack = ((UINT16)value - 1); - titlechanged = true; - } - else if (fastcmp(word, "MUSICLOOP")) - { - // true by default except MM_MAIN - menupres[num].muslooping = (value || word2[0] == 'T' || word2[0] == 'Y'); - titlechanged = true; - } - else if (fastcmp(word, "NOMUSIC")) - { - menupres[num].musstop = (value || word2[0] == 'T' || word2[0] == 'Y'); - titlechanged = true; - } - else if (fastcmp(word, "IGNOREMUSIC")) - { - menupres[num].musignore = (value || word2[0] == 'T' || word2[0] == 'Y'); - titlechanged = true; - } - else if (fastcmp(word, "FADESTRENGTH")) - { - // one-based, <= 0 means use default value. 1-32 - menupres[num].fadestrength = get_number(word2)-1; - titlechanged = true; - } - else if (fastcmp(word, "NOENTERBUBBLE")) - { - menupres[num].enterbubble = !(value || word2[0] == 'T' || word2[0] == 'Y'); - titlechanged = true; - } - else if (fastcmp(word, "NOEXITBUBBLE")) - { - menupres[num].exitbubble = !(value || word2[0] == 'T' || word2[0] == 'Y'); - titlechanged = true; - } - else if (fastcmp(word, "ENTERTAG")) - { - menupres[num].entertag = get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "EXITTAG")) - { - menupres[num].exittag = get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "ENTERWIPE")) - { - menupres[num].enterwipe = get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "EXITWIPE")) - { - menupres[num].exitwipe = get_number(word2); - titlechanged = true; - } - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -static void readhuditem(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word = s; - char *word2; - char *tmp; - INT32 i; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - *(tmp-1) = '\0'; - else - break; - strupr(word); - - // Now get the part after - word2 = tmp += 2; - strupr(word2); - - i = atoi(word2); // used for numerical settings - - if (fastcmp(word, "X")) - { - hudinfo[num].x = i; - } - else if (fastcmp(word, "Y")) - { - hudinfo[num].y = i; - } - else if (fastcmp(word, "F")) - { - hudinfo[num].f = i; - } - else - deh_warning("Level header %d: unknown word '%s'", num, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -/* -Sprite number = 10 -Sprite subnumber = 32968 -Duration = 200 -Next frame = 200 -*/ - -/** Action pointer for reading actions from Dehacked lumps. - */ -typedef struct -{ - actionf_t action; ///< Function pointer corresponding to the actual action. - const char *name; ///< Name of the action in ALL CAPS. -} actionpointer_t; - -/** Array mapping action names to action functions. - * Names must be in ALL CAPS for case insensitive comparisons. - */ -static actionpointer_t actionpointers[] = -{ - {{A_Explode}, "A_EXPLODE"}, - {{A_Pain}, "A_PAIN"}, - {{A_Fall}, "A_FALL"}, - {{A_MonitorPop}, "A_MONITORPOP"}, - {{A_GoldMonitorPop}, "A_GOLDMONITORPOP"}, - {{A_GoldMonitorRestore}, "A_GOLDMONITORRESTORE"}, - {{A_GoldMonitorSparkle}, "A_GOLDMONITORSPARKLE"}, - {{A_Look}, "A_LOOK"}, - {{A_Chase}, "A_CHASE"}, - {{A_FaceStabChase}, "A_FACESTABCHASE"}, - {{A_FaceStabRev}, "A_FACESTABREV"}, - {{A_FaceStabHurl}, "A_FACESTABHURL"}, - {{A_FaceStabMiss}, "A_FACESTABMISS"}, - {{A_StatueBurst}, "A_STATUEBURST"}, - {{A_FaceTarget}, "A_FACETARGET"}, - {{A_FaceTracer}, "A_FACETRACER"}, - {{A_Scream}, "A_SCREAM"}, - {{A_BossDeath}, "A_BOSSDEATH"}, - {{A_CustomPower}, "A_CUSTOMPOWER"}, - {{A_GiveWeapon}, "A_GIVEWEAPON"}, - {{A_RingBox}, "A_RINGBOX"}, - {{A_Invincibility}, "A_INVINCIBILITY"}, - {{A_SuperSneakers}, "A_SUPERSNEAKERS"}, - {{A_BunnyHop}, "A_BUNNYHOP"}, - {{A_BubbleSpawn}, "A_BUBBLESPAWN"}, - {{A_FanBubbleSpawn}, "A_FANBUBBLESPAWN"}, - {{A_BubbleRise}, "A_BUBBLERISE"}, - {{A_BubbleCheck}, "A_BUBBLECHECK"}, - {{A_AwardScore}, "A_AWARDSCORE"}, - {{A_ExtraLife}, "A_EXTRALIFE"}, - {{A_GiveShield}, "A_GIVESHIELD"}, - {{A_GravityBox}, "A_GRAVITYBOX"}, - {{A_ScoreRise}, "A_SCORERISE"}, - {{A_AttractChase}, "A_ATTRACTCHASE"}, - {{A_DropMine}, "A_DROPMINE"}, - {{A_FishJump}, "A_FISHJUMP"}, - {{A_ThrownRing}, "A_THROWNRING"}, - {{A_SetSolidSteam}, "A_SETSOLIDSTEAM"}, - {{A_UnsetSolidSteam}, "A_UNSETSOLIDSTEAM"}, - {{A_SignSpin}, "A_SIGNSPIN"}, - {{A_SignPlayer}, "A_SIGNPLAYER"}, - {{A_OverlayThink}, "A_OVERLAYTHINK"}, - {{A_JetChase}, "A_JETCHASE"}, - {{A_JetbThink}, "A_JETBTHINK"}, - {{A_JetgThink}, "A_JETGTHINK"}, - {{A_JetgShoot}, "A_JETGSHOOT"}, - {{A_ShootBullet}, "A_SHOOTBULLET"}, - {{A_MinusDigging}, "A_MINUSDIGGING"}, - {{A_MinusPopup}, "A_MINUSPOPUP"}, - {{A_MinusCheck}, "A_MINUSCHECK"}, - {{A_ChickenCheck}, "A_CHICKENCHECK"}, - {{A_MouseThink}, "A_MOUSETHINK"}, - {{A_DetonChase}, "A_DETONCHASE"}, - {{A_CapeChase}, "A_CAPECHASE"}, - {{A_RotateSpikeBall}, "A_ROTATESPIKEBALL"}, - {{A_SlingAppear}, "A_SLINGAPPEAR"}, - {{A_UnidusBall}, "A_UNIDUSBALL"}, - {{A_RockSpawn}, "A_ROCKSPAWN"}, - {{A_SetFuse}, "A_SETFUSE"}, - {{A_CrawlaCommanderThink}, "A_CRAWLACOMMANDERTHINK"}, - {{A_SmokeTrailer}, "A_SMOKETRAILER"}, - {{A_RingExplode}, "A_RINGEXPLODE"}, - {{A_OldRingExplode}, "A_OLDRINGEXPLODE"}, - {{A_MixUp}, "A_MIXUP"}, - {{A_RecyclePowers}, "A_RECYCLEPOWERS"}, - {{A_Boss1Chase}, "A_BOSS1CHASE"}, - {{A_FocusTarget}, "A_FOCUSTARGET"}, - {{A_Boss2Chase}, "A_BOSS2CHASE"}, - {{A_Boss2Pogo}, "A_BOSS2POGO"}, - {{A_BossZoom}, "A_BOSSZOOM"}, - {{A_BossScream}, "A_BOSSSCREAM"}, - {{A_Boss2TakeDamage}, "A_BOSS2TAKEDAMAGE"}, - {{A_Boss7Chase}, "A_BOSS7CHASE"}, - {{A_GoopSplat}, "A_GOOPSPLAT"}, - {{A_Boss2PogoSFX}, "A_BOSS2POGOSFX"}, - {{A_Boss2PogoTarget}, "A_BOSS2POGOTARGET"}, - {{A_BossJetFume}, "A_BOSSJETFUME"}, - {{A_EggmanBox}, "A_EGGMANBOX"}, - {{A_TurretFire}, "A_TURRETFIRE"}, - {{A_SuperTurretFire}, "A_SUPERTURRETFIRE"}, - {{A_TurretStop}, "A_TURRETSTOP"}, - {{A_JetJawRoam}, "A_JETJAWROAM"}, - {{A_JetJawChomp}, "A_JETJAWCHOMP"}, - {{A_PointyThink}, "A_POINTYTHINK"}, - {{A_CheckBuddy}, "A_CHECKBUDDY"}, - {{A_HoodFire}, "A_HOODFIRE"}, - {{A_HoodThink}, "A_HOODTHINK"}, - {{A_HoodFall}, "A_HOODFALL"}, - {{A_ArrowBonks}, "A_ARROWBONKS"}, - {{A_SnailerThink}, "A_SNAILERTHINK"}, - {{A_SharpChase}, "A_SHARPCHASE"}, - {{A_SharpSpin}, "A_SHARPSPIN"}, - {{A_SharpDecel}, "A_SHARPDECEL"}, - {{A_CrushstaceanWalk}, "A_CRUSHSTACEANWALK"}, - {{A_CrushstaceanPunch}, "A_CRUSHSTACEANPUNCH"}, - {{A_CrushclawAim}, "A_CRUSHCLAWAIM"}, - {{A_CrushclawLaunch}, "A_CRUSHCLAWLAUNCH"}, - {{A_VultureVtol}, "A_VULTUREVTOL"}, - {{A_VultureCheck}, "A_VULTURECHECK"}, - {{A_VultureHover}, "A_VULTUREHOVER"}, - {{A_VultureBlast}, "A_VULTUREBLAST"}, - {{A_VultureFly}, "A_VULTUREFLY"}, - {{A_SkimChase}, "A_SKIMCHASE"}, - {{A_1upThinker}, "A_1UPTHINKER"}, - {{A_SkullAttack}, "A_SKULLATTACK"}, - {{A_LobShot}, "A_LOBSHOT"}, - {{A_FireShot}, "A_FIRESHOT"}, - {{A_SuperFireShot}, "A_SUPERFIRESHOT"}, - {{A_BossFireShot}, "A_BOSSFIRESHOT"}, - {{A_Boss7FireMissiles}, "A_BOSS7FIREMISSILES"}, - {{A_Boss1Laser}, "A_BOSS1LASER"}, - {{A_Boss4Reverse}, "A_BOSS4REVERSE"}, - {{A_Boss4SpeedUp}, "A_BOSS4SPEEDUP"}, - {{A_Boss4Raise}, "A_BOSS4RAISE"}, - {{A_SparkFollow}, "A_SPARKFOLLOW"}, - {{A_BuzzFly}, "A_BUZZFLY"}, - {{A_GuardChase}, "A_GUARDCHASE"}, - {{A_EggShield}, "A_EGGSHIELD"}, - {{A_SetReactionTime}, "A_SETREACTIONTIME"}, - {{A_Boss1Spikeballs}, "A_BOSS1SPIKEBALLS"}, - {{A_Boss3TakeDamage}, "A_BOSS3TAKEDAMAGE"}, - {{A_Boss3Path}, "A_BOSS3PATH"}, - {{A_Boss3ShockThink}, "A_BOSS3SHOCKTHINK"}, - {{A_LinedefExecute}, "A_LINEDEFEXECUTE"}, - {{A_PlaySeeSound}, "A_PLAYSEESOUND"}, - {{A_PlayAttackSound}, "A_PLAYATTACKSOUND"}, - {{A_PlayActiveSound}, "A_PLAYACTIVESOUND"}, - {{A_SpawnObjectAbsolute}, "A_SPAWNOBJECTABSOLUTE"}, - {{A_SpawnObjectRelative}, "A_SPAWNOBJECTRELATIVE"}, - {{A_ChangeAngleRelative}, "A_CHANGEANGLERELATIVE"}, - {{A_ChangeAngleAbsolute}, "A_CHANGEANGLEABSOLUTE"}, - {{A_RollAngle}, "A_ROLLANGLE"}, - {{A_ChangeRollAngleRelative},"A_CHANGEROLLANGLERELATIVE"}, - {{A_ChangeRollAngleAbsolute},"A_CHANGEROLLANGLEABSOLUTE"}, - {{A_PlaySound}, "A_PLAYSOUND"}, - {{A_FindTarget}, "A_FINDTARGET"}, - {{A_FindTracer}, "A_FINDTRACER"}, - {{A_SetTics}, "A_SETTICS"}, - {{A_SetRandomTics}, "A_SETRANDOMTICS"}, - {{A_ChangeColorRelative}, "A_CHANGECOLORRELATIVE"}, - {{A_ChangeColorAbsolute}, "A_CHANGECOLORABSOLUTE"}, - {{A_Dye}, "A_DYE"}, - {{A_MoveRelative}, "A_MOVERELATIVE"}, - {{A_MoveAbsolute}, "A_MOVEABSOLUTE"}, - {{A_Thrust}, "A_THRUST"}, - {{A_ZThrust}, "A_ZTHRUST"}, - {{A_SetTargetsTarget}, "A_SETTARGETSTARGET"}, - {{A_SetObjectFlags}, "A_SETOBJECTFLAGS"}, - {{A_SetObjectFlags2}, "A_SETOBJECTFLAGS2"}, - {{A_RandomState}, "A_RANDOMSTATE"}, - {{A_RandomStateRange}, "A_RANDOMSTATERANGE"}, - {{A_DualAction}, "A_DUALACTION"}, - {{A_RemoteAction}, "A_REMOTEACTION"}, - {{A_ToggleFlameJet}, "A_TOGGLEFLAMEJET"}, - {{A_OrbitNights}, "A_ORBITNIGHTS"}, - {{A_GhostMe}, "A_GHOSTME"}, - {{A_SetObjectState}, "A_SETOBJECTSTATE"}, - {{A_SetObjectTypeState}, "A_SETOBJECTTYPESTATE"}, - {{A_KnockBack}, "A_KNOCKBACK"}, - {{A_PushAway}, "A_PUSHAWAY"}, - {{A_RingDrain}, "A_RINGDRAIN"}, - {{A_SplitShot}, "A_SPLITSHOT"}, - {{A_MissileSplit}, "A_MISSILESPLIT"}, - {{A_MultiShot}, "A_MULTISHOT"}, - {{A_InstaLoop}, "A_INSTALOOP"}, - {{A_Custom3DRotate}, "A_CUSTOM3DROTATE"}, - {{A_SearchForPlayers}, "A_SEARCHFORPLAYERS"}, - {{A_CheckRandom}, "A_CHECKRANDOM"}, - {{A_CheckTargetRings}, "A_CHECKTARGETRINGS"}, - {{A_CheckRings}, "A_CHECKRINGS"}, - {{A_CheckTotalRings}, "A_CHECKTOTALRINGS"}, - {{A_CheckHealth}, "A_CHECKHEALTH"}, - {{A_CheckRange}, "A_CHECKRANGE"}, - {{A_CheckHeight}, "A_CHECKHEIGHT"}, - {{A_CheckTrueRange}, "A_CHECKTRUERANGE"}, - {{A_CheckThingCount}, "A_CHECKTHINGCOUNT"}, - {{A_CheckAmbush}, "A_CHECKAMBUSH"}, - {{A_CheckCustomValue}, "A_CHECKCUSTOMVALUE"}, - {{A_CheckCusValMemo}, "A_CHECKCUSVALMEMO"}, - {{A_SetCustomValue}, "A_SETCUSTOMVALUE"}, - {{A_UseCusValMemo}, "A_USECUSVALMEMO"}, - {{A_RelayCustomValue}, "A_RELAYCUSTOMVALUE"}, - {{A_CusValAction}, "A_CUSVALACTION"}, - {{A_ForceStop}, "A_FORCESTOP"}, - {{A_ForceWin}, "A_FORCEWIN"}, - {{A_SpikeRetract}, "A_SPIKERETRACT"}, - {{A_InfoState}, "A_INFOSTATE"}, - {{A_Repeat}, "A_REPEAT"}, - {{A_SetScale}, "A_SETSCALE"}, - {{A_RemoteDamage}, "A_REMOTEDAMAGE"}, - {{A_HomingChase}, "A_HOMINGCHASE"}, - {{A_TrapShot}, "A_TRAPSHOT"}, - {{A_VileTarget}, "A_VILETARGET"}, - {{A_VileAttack}, "A_VILEATTACK"}, - {{A_VileFire}, "A_VILEFIRE"}, - {{A_BrakChase}, "A_BRAKCHASE"}, - {{A_BrakFireShot}, "A_BRAKFIRESHOT"}, - {{A_BrakLobShot}, "A_BRAKLOBSHOT"}, - {{A_NapalmScatter}, "A_NAPALMSCATTER"}, - {{A_SpawnFreshCopy}, "A_SPAWNFRESHCOPY"}, - {{A_FlickySpawn}, "A_FLICKYSPAWN"}, - {{A_FlickyCenter}, "A_FLICKYCENTER"}, - {{A_FlickyAim}, "A_FLICKYAIM"}, - {{A_FlickyFly}, "A_FLICKYFLY"}, - {{A_FlickySoar}, "A_FLICKYSOAR"}, - {{A_FlickyCoast}, "A_FLICKYCOAST"}, - {{A_FlickyHop}, "A_FLICKYHOP"}, - {{A_FlickyFlounder}, "A_FLICKYFLOUNDER"}, - {{A_FlickyCheck}, "A_FLICKYCHECK"}, - {{A_FlickyHeightCheck}, "A_FLICKYHEIGHTCHECK"}, - {{A_FlickyFlutter}, "A_FLICKYFLUTTER"}, - {{A_FlameParticle}, "A_FLAMEPARTICLE"}, - {{A_FadeOverlay}, "A_FADEOVERLAY"}, - {{A_Boss5Jump}, "A_BOSS5JUMP"}, - {{A_LightBeamReset}, "A_LIGHTBEAMRESET"}, - {{A_MineExplode}, "A_MINEEXPLODE"}, - {{A_MineRange}, "A_MINERANGE"}, - {{A_ConnectToGround}, "A_CONNECTTOGROUND"}, - {{A_SpawnParticleRelative}, "A_SPAWNPARTICLERELATIVE"}, - {{A_MultiShotDist}, "A_MULTISHOTDIST"}, - {{A_WhoCaresIfYourSonIsABee},"A_WHOCARESIFYOURSONISABEE"}, - {{A_ParentTriesToSleep}, "A_PARENTTRIESTOSLEEP"}, - {{A_CryingToMomma}, "A_CRYINGTOMOMMA"}, - {{A_CheckFlags2}, "A_CHECKFLAGS2"}, - {{A_Boss5FindWaypoint}, "A_BOSS5FINDWAYPOINT"}, - {{A_DoNPCSkid}, "A_DONPCSKID"}, - {{A_DoNPCPain}, "A_DONPCPAIN"}, - {{A_PrepareRepeat}, "A_PREPAREREPEAT"}, - {{A_Boss5ExtraRepeat}, "A_BOSS5EXTRAREPEAT"}, - {{A_Boss5Calm}, "A_BOSS5CALM"}, - {{A_Boss5CheckOnGround}, "A_BOSS5CHECKONGROUND"}, - {{A_Boss5CheckFalling}, "A_BOSS5CHECKFALLING"}, - {{A_Boss5PinchShot}, "A_BOSS5PINCHSHOT"}, - {{A_Boss5MakeItRain}, "A_BOSS5MAKEITRAIN"}, - {{A_Boss5MakeJunk}, "A_BOSS5MAKEJUNK"}, - {{A_LookForBetter}, "A_LOOKFORBETTER"}, - {{A_Boss5BombExplode}, "A_BOSS5BOMBEXPLODE"}, - {{A_DustDevilThink}, "A_DUSTDEVILTHINK"}, - {{A_TNTExplode}, "A_TNTEXPLODE"}, - {{A_DebrisRandom}, "A_DEBRISRANDOM"}, - {{A_TrainCameo}, "A_TRAINCAMEO"}, - {{A_TrainCameo2}, "A_TRAINCAMEO2"}, - {{A_CanarivoreGas}, "A_CANARIVOREGAS"}, - {{A_KillSegments}, "A_KILLSEGMENTS"}, - {{A_SnapperSpawn}, "A_SNAPPERSPAWN"}, - {{A_SnapperThinker}, "A_SNAPPERTHINKER"}, - {{A_SaloonDoorSpawn}, "A_SALOONDOORSPAWN"}, - {{A_MinecartSparkThink}, "A_MINECARTSPARKTHINK"}, - {{A_ModuloToState}, "A_MODULOTOSTATE"}, - {{A_LavafallRocks}, "A_LAVAFALLROCKS"}, - {{A_LavafallLava}, "A_LAVAFALLLAVA"}, - {{A_FallingLavaCheck}, "A_FALLINGLAVACHECK"}, - {{A_FireShrink}, "A_FIRESHRINK"}, - {{A_SpawnPterabytes}, "A_SPAWNPTERABYTES"}, - {{A_PterabyteHover}, "A_PTERABYTEHOVER"}, - {{A_RolloutSpawn}, "A_ROLLOUTSPAWN"}, - {{A_RolloutRock}, "A_ROLLOUTROCK"}, - {{A_DragonbomberSpawn}, "A_DRAGONBOMERSPAWN"}, - {{A_DragonWing}, "A_DRAGONWING"}, - {{A_DragonSegment}, "A_DRAGONSEGMENT"}, - {{A_ChangeHeight}, "A_CHANGEHEIGHT"}, - {{NULL}, "NONE"}, - - // This NULL entry must be the last in the list - {{NULL}, NULL}, -}; - -static void readframe(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word1; - char *word2 = NULL; - char *tmp; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - word1 = strtok(s, " "); - if (word1) - strupr(word1); - else - break; - - word2 = strtok(NULL, " = "); - if (word2) - strupr(word2); - else - break; - if (word2[strlen(word2)-1] == '\n') - word2[strlen(word2)-1] = '\0'; - - if (fastcmp(word1, "SPRITENUMBER") || fastcmp(word1, "SPRITENAME")) - { - states[num].sprite = get_sprite(word2); - } - else if (fastcmp(word1, "SPRITESUBNUMBER") || fastcmp(word1, "SPRITEFRAME")) - { - states[num].frame = (INT32)get_number(word2); // So the FF_ flags get calculated - } - else if (fastcmp(word1, "DURATION")) - { - states[num].tics = (INT32)get_number(word2); // So TICRATE can be used - } - else if (fastcmp(word1, "NEXT")) - { - states[num].nextstate = get_state(word2); - } - else if (fastcmp(word1, "VAR1")) - { - states[num].var1 = (INT32)get_number(word2); - } - else if (fastcmp(word1, "VAR2")) - { - states[num].var2 = (INT32)get_number(word2); - } - else if (fastcmp(word1, "ACTION")) - { - size_t z; - boolean found = false; - char actiontocompare[32]; - - memset(actiontocompare, 0x00, sizeof(actiontocompare)); - strlcpy(actiontocompare, word2, sizeof (actiontocompare)); - strupr(actiontocompare); - - for (z = 0; z < 32; z++) - { - if (actiontocompare[z] == '\n' || actiontocompare[z] == '\r') - { - actiontocompare[z] = '\0'; - break; - } - } - - for (z = 0; actionpointers[z].name; z++) - { - if (actionpointers[z].action.acv == states[num].action.acv) - break; - } - - z = 0; - found = LUA_SetLuaAction(&states[num], actiontocompare); - if (!found) - while (actionpointers[z].name) - { - if (fastcmp(actiontocompare, actionpointers[z].name)) - { - states[num].action = actionpointers[z].action; - states[num].action.acv = actionpointers[z].action.acv; // assign - states[num].action.acp1 = actionpointers[z].action.acp1; - found = true; - break; - } - z++; - } - - if (!found) - deh_warning("Unknown action %s", actiontocompare); - } - else - deh_warning("Frame %d: unknown word '%s'", num, word1); - } - } while (!myfeof(f)); - - Z_Free(s); -} - -static void readsound(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word; - char *word2; - char *tmp; - INT32 value; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - word = strtok(s, " "); - if (word) - strupr(word); - else - break; - - word2 = strtok(NULL, " "); - if (word2) - value = atoi(word2); - else - { - deh_warning("No value for token %s", word); - continue; - } - - if (fastcmp(word, "SINGULAR")) - { - S_sfx[num].singularity = value; - } - else if (fastcmp(word, "PRIORITY")) - { - S_sfx[num].priority = value; - } - else if (fastcmp(word, "FLAGS")) - { - S_sfx[num].pitch = value; - } - else if (fastcmp(word, "CAPTION") || fastcmp(word, "DESCRIPTION")) - { - deh_strlcpy(S_sfx[num].caption, word2, - sizeof(S_sfx[num].caption), va("Sound effect %d: caption", num)); - } - else - deh_warning("Sound %d : unknown word '%s'",num,word); - } - } while (!myfeof(f)); - - Z_Free(s); -} - -/** Checks if a game data file name for a mod is good. - * "Good" means that it contains only alphanumerics, _, and -; - * ends in ".dat"; has at least one character before the ".dat"; - * and is not "gamedata.dat" (tested case-insensitively). - * - * Assumption: that gamedata.dat is the only .dat file that will - * ever be treated specially by the game. - * - * Note: Check for the tail ".dat" case-insensitively since at - * present, we get passed the filename in all uppercase. - * - * \param s Filename string to check. - * \return True if the filename is good. - * \sa readmaincfg() - * \author Graue <graue@oceanbase.org> - */ -static boolean GoodDataFileName(const char *s) -{ - const char *p; - const char *tail = ".dat"; - - for (p = s; *p != '\0'; p++) - if (!isalnum(*p) && *p != '_' && *p != '-' && *p != '.') - return false; - - p = s + strlen(s) - strlen(tail); - if (p <= s) return false; // too short - if (!fasticmp(p, tail)) return false; // doesn't end in .dat - if (fasticmp(s, "gamedata.dat")) return false; - - return true; -} - -static void reademblemdata(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word = s; - char *word2; - char *tmp; - INT32 value; - - memset(&emblemlocations[num-1], 0, sizeof(emblem_t)); - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - *(tmp-1) = '\0'; - else - break; - strupr(word); - - // Now get the part after - word2 = tmp += 2; - value = atoi(word2); // used for numerical settings - - // Up here to allow lowercase in hints - if (fastcmp(word, "HINT")) - { - while ((tmp = strchr(word2, '\\'))) - *tmp = '\n'; - deh_strlcpy(emblemlocations[num-1].hint, word2, sizeof (emblemlocations[num-1].hint), va("Emblem %d: hint", num)); - continue; - } - strupr(word2); - - if (fastcmp(word, "TYPE")) - { - if (fastcmp(word2, "GLOBAL")) - emblemlocations[num-1].type = ET_GLOBAL; - else if (fastcmp(word2, "SKIN")) - emblemlocations[num-1].type = ET_SKIN; - else if (fastcmp(word2, "SCORE")) - emblemlocations[num-1].type = ET_SCORE; - else if (fastcmp(word2, "TIME")) - emblemlocations[num-1].type = ET_TIME; - else if (fastcmp(word2, "RINGS")) - emblemlocations[num-1].type = ET_RINGS; - else if (fastcmp(word2, "MAP")) - emblemlocations[num-1].type = ET_MAP; - else if (fastcmp(word2, "NGRADE")) - emblemlocations[num-1].type = ET_NGRADE; - else if (fastcmp(word2, "NTIME")) - emblemlocations[num-1].type = ET_NTIME; - else - emblemlocations[num-1].type = (UINT8)value; - } - else if (fastcmp(word, "TAG")) - emblemlocations[num-1].tag = (INT16)value; - else if (fastcmp(word, "MAPNUM")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - - emblemlocations[num-1].level = (INT16)value; - } - else if (fastcmp(word, "SPRITE")) - { - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = word2[0]; - else - value += 'A'-1; - - if (value < 'A' || value > 'Z') - deh_warning("Emblem %d: sprite must be from A - Z (1 - 26)", num); - else - emblemlocations[num-1].sprite = (UINT8)value; - } - else if (fastcmp(word, "COLOR")) - emblemlocations[num-1].color = get_number(word2); - else if (fastcmp(word, "VAR")) - emblemlocations[num-1].var = get_number(word2); - else - deh_warning("Emblem %d: unknown word '%s'", num, word); - } - } while (!myfeof(f)); - - // Default sprite and color definitions for lazy people like me - if (!emblemlocations[num-1].sprite) switch (emblemlocations[num-1].type) - { - case ET_RINGS: - emblemlocations[num-1].sprite = 'R'; break; - case ET_SCORE: case ET_NGRADE: - emblemlocations[num-1].sprite = 'S'; break; - case ET_TIME: case ET_NTIME: - emblemlocations[num-1].sprite = 'T'; break; - default: - emblemlocations[num-1].sprite = 'A'; break; - } - if (!emblemlocations[num-1].color) switch (emblemlocations[num-1].type) - { - case ET_RINGS: - emblemlocations[num-1].color = SKINCOLOR_GOLD; break; - case ET_SCORE: - emblemlocations[num-1].color = SKINCOLOR_BROWN; break; - case ET_NGRADE: - emblemlocations[num-1].color = SKINCOLOR_TEAL; break; - case ET_TIME: case ET_NTIME: - emblemlocations[num-1].color = SKINCOLOR_GREY; break; - default: - emblemlocations[num-1].color = SKINCOLOR_BLUE; break; - } - - Z_Free(s); -} - -static void readextraemblemdata(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word = s; - char *word2; - char *tmp; - INT32 value; - - memset(&extraemblems[num-1], 0, sizeof(extraemblem_t)); - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - *(tmp-1) = '\0'; - else - break; - strupr(word); - - // Now get the part after - word2 = tmp += 2; - - value = atoi(word2); // used for numerical settings - - if (fastcmp(word, "NAME")) - deh_strlcpy(extraemblems[num-1].name, word2, - sizeof (extraemblems[num-1].name), va("Extra emblem %d: name", num)); - else if (fastcmp(word, "OBJECTIVE")) - deh_strlcpy(extraemblems[num-1].description, word2, - sizeof (extraemblems[num-1].description), va("Extra emblem %d: objective", num)); - else if (fastcmp(word, "CONDITIONSET")) - extraemblems[num-1].conditionset = (UINT8)value; - else if (fastcmp(word, "SHOWCONDITIONSET")) - extraemblems[num-1].showconditionset = (UINT8)value; - else - { - strupr(word2); - if (fastcmp(word, "SPRITE")) - { - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = word2[0]; - else - value += 'A'-1; - - if (value < 'A' || value > 'Z') - deh_warning("Emblem %d: sprite must be from A - Z (1 - 26)", num); - else - extraemblems[num-1].sprite = (UINT8)value; - } - else if (fastcmp(word, "COLOR")) - extraemblems[num-1].color = get_number(word2); - else - deh_warning("Extra emblem %d: unknown word '%s'", num, word); - } - } - } while (!myfeof(f)); - - if (!extraemblems[num-1].sprite) - extraemblems[num-1].sprite = 'X'; - if (!extraemblems[num-1].color) - extraemblems[num-1].color = SKINCOLOR_BLUE; - - Z_Free(s); -} - -static void readunlockable(MYFILE *f, INT32 num) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word = s; - char *word2; - char *tmp; - INT32 i; - - memset(&unlockables[num], 0, sizeof(unlockable_t)); - unlockables[num].objective[0] = '/'; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - *(tmp-1) = '\0'; - else - break; - strupr(word); - - // Now get the part after - word2 = tmp += 2; - - i = atoi(word2); // used for numerical settings - - if (fastcmp(word, "NAME")) - deh_strlcpy(unlockables[num].name, word2, - sizeof (unlockables[num].name), va("Unlockable %d: name", num)); - else if (fastcmp(word, "OBJECTIVE")) - deh_strlcpy(unlockables[num].objective, word2, - sizeof (unlockables[num].objective), va("Unlockable %d: objective", num)); - else - { - strupr(word2); - if (fastcmp(word, "HEIGHT")) - unlockables[num].height = (UINT16)i; - else if (fastcmp(word, "CONDITIONSET")) - unlockables[num].conditionset = (UINT8)i; - else if (fastcmp(word, "SHOWCONDITIONSET")) - unlockables[num].showconditionset = (UINT8)i; - else if (fastcmp(word, "NOCECHO")) - unlockables[num].nocecho = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); - else if (fastcmp(word, "NOCHECKLIST")) - unlockables[num].nochecklist = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); - else if (fastcmp(word, "TYPE")) - { - if (fastcmp(word2, "NONE")) - unlockables[num].type = SECRET_NONE; - else if (fastcmp(word2, "ITEMFINDER")) - unlockables[num].type = SECRET_ITEMFINDER; - else if (fastcmp(word2, "EMBLEMHINTS")) - unlockables[num].type = SECRET_EMBLEMHINTS; - else if (fastcmp(word2, "PANDORA")) - unlockables[num].type = SECRET_PANDORA; - else if (fastcmp(word2, "CREDITS")) - unlockables[num].type = SECRET_CREDITS; - else if (fastcmp(word2, "RECORDATTACK")) - unlockables[num].type = SECRET_RECORDATTACK; - else if (fastcmp(word2, "NIGHTSMODE")) - unlockables[num].type = SECRET_NIGHTSMODE; - else if (fastcmp(word2, "HEADER")) - unlockables[num].type = SECRET_HEADER; - else if (fastcmp(word2, "LEVELSELECT")) - unlockables[num].type = SECRET_LEVELSELECT; - else if (fastcmp(word2, "WARP")) - unlockables[num].type = SECRET_WARP; - else if (fastcmp(word2, "SOUNDTEST")) - unlockables[num].type = SECRET_SOUNDTEST; - else - unlockables[num].type = (INT16)i; - } - else if (fastcmp(word, "VAR")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - i = M_MapNumber(word2[0], word2[1]); - - unlockables[num].variable = (INT16)i; - } - else - deh_warning("Unlockable %d: unknown word '%s'", num+1, word); - } - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -static const char NIGHTSGRADE_LIST[] = { - 'F', // GRADE_F - 'E', // GRADE_E - 'D', // GRADE_D - 'C', // GRADE_C - 'B', // GRADE_B - 'A', // GRADE_A - 'S', // GRADE_S - '\0' -}; - -#define PARAMCHECK(n) do { if (!params[n]) { deh_warning("Too few parameters, need %d", n); return; }} while (0) -static void readcondition(UINT8 set, UINT32 id, char *word2) -{ - INT32 i; - char *params[4]; // condition, requirement, extra info, extra info - char *spos; - - conditiontype_t ty; - INT32 re; - INT16 x1 = 0, x2 = 0; - - INT32 offset = 0; - - spos = strtok(word2, " "); - - for (i = 0; i < 4; ++i) - { - if (spos != NULL) - { - params[i] = spos; - spos = strtok(NULL, " "); - } - else - params[i] = NULL; - } - - if (!params[0]) - { - deh_warning("condition line is empty"); - return; - } - - if (fastcmp(params[0], "PLAYTIME")) - { - PARAMCHECK(1); - ty = UC_PLAYTIME; - re = atoi(params[1]); - } - else if (fastcmp(params[0], "GAMECLEAR") - || (++offset && fastcmp(params[0], "ALLEMERALDS")) - || (++offset && fastcmp(params[0], "ULTIMATECLEAR"))) - { - ty = UC_GAMECLEAR + offset; - re = (params[1]) ? atoi(params[1]) : 1; - } - else if ((offset=0) || fastcmp(params[0], "OVERALLSCORE") - || (++offset && fastcmp(params[0], "OVERALLTIME")) - || (++offset && fastcmp(params[0], "OVERALLRINGS"))) - { - PARAMCHECK(1); - ty = UC_OVERALLSCORE + offset; - re = atoi(params[1]); - } - else if ((offset=0) || fastcmp(params[0], "MAPVISITED") - || (++offset && fastcmp(params[0], "MAPBEATEN")) - || (++offset && fastcmp(params[0], "MAPALLEMERALDS")) - || (++offset && fastcmp(params[0], "MAPULTIMATE")) - || (++offset && fastcmp(params[0], "MAPPERFECT"))) - { - PARAMCHECK(1); - ty = UC_MAPVISITED + offset; - - // Convert to map number if it appears to be one - if (params[1][0] >= 'A' && params[1][0] <= 'Z') - re = M_MapNumber(params[1][0], params[1][1]); - else - re = atoi(params[1]); - - if (re < 0 || re >= NUMMAPS) - { - deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); - return; - } - } - else if ((offset=0) || fastcmp(params[0], "MAPSCORE") - || (++offset && fastcmp(params[0], "MAPTIME")) - || (++offset && fastcmp(params[0], "MAPRINGS"))) - { - PARAMCHECK(2); - ty = UC_MAPSCORE + offset; - re = atoi(params[2]); - - // Convert to map number if it appears to be one - if (params[1][0] >= 'A' && params[1][0] <= 'Z') - x1 = (INT16)M_MapNumber(params[1][0], params[1][1]); - else - x1 = (INT16)atoi(params[1]); - - if (x1 < 0 || x1 >= NUMMAPS) - { - deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); - return; - } - } - else if ((offset=0) || fastcmp(params[0], "NIGHTSSCORE") - || (++offset && fastcmp(params[0], "NIGHTSTIME")) - || (++offset && fastcmp(params[0], "NIGHTSGRADE"))) - { - PARAMCHECK(2); // one optional one - - ty = UC_NIGHTSSCORE + offset; - i = (params[3] ? 3 : 2); - if (fastncmp("GRADE_",params[i],6)) - { - char *p = params[i]+6; - for (re = 0; NIGHTSGRADE_LIST[re]; re++) - if (*p == NIGHTSGRADE_LIST[re]) - break; - if (!NIGHTSGRADE_LIST[re]) - { - deh_warning("Invalid NiGHTS grade %s\n", params[i]); - return; - } - } - else - re = atoi(params[i]); - - // Convert to map number if it appears to be one - if (params[1][0] >= 'A' && params[1][0] <= 'Z') - x1 = (INT16)M_MapNumber(params[1][0], params[1][1]); - else - x1 = (INT16)atoi(params[1]); - - if (x1 < 0 || x1 >= NUMMAPS) - { - deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); - return; - } - - // Mare number (0 for overall) - if (params[3]) // Only if we actually got 3 params (so the second one == mare and not requirement) - x2 = (INT16)atoi(params[2]); - else - x2 = 0; - - } - else if (fastcmp(params[0], "TRIGGER")) - { - PARAMCHECK(1); - ty = UC_TRIGGER; - re = atoi(params[1]); - - // constrained by 32 bits - if (re < 0 || re > 31) - { - deh_warning("Trigger ID %d out of range (0 - 31)", re); - return; - } - } - else if (fastcmp(params[0], "TOTALEMBLEMS")) - { - PARAMCHECK(1); - ty = UC_TOTALEMBLEMS; - re = atoi(params[1]); - } - else if (fastcmp(params[0], "EMBLEM")) - { - PARAMCHECK(1); - ty = UC_EMBLEM; - re = atoi(params[1]); - - if (re <= 0 || re > MAXEMBLEMS) - { - deh_warning("Emblem %d out of range (1 - %d)", re, MAXEMBLEMS); - return; - } - } - else if (fastcmp(params[0], "EXTRAEMBLEM")) - { - PARAMCHECK(1); - ty = UC_EXTRAEMBLEM; - re = atoi(params[1]); - - if (re <= 0 || re > MAXEXTRAEMBLEMS) - { - deh_warning("Extra emblem %d out of range (1 - %d)", re, MAXEXTRAEMBLEMS); - return; - } - } - else if (fastcmp(params[0], "CONDITIONSET")) - { - PARAMCHECK(1); - ty = UC_CONDITIONSET; - re = atoi(params[1]); - - if (re <= 0 || re > MAXCONDITIONSETS) - { - deh_warning("Condition set %d out of range (1 - %d)", re, MAXCONDITIONSETS); - return; - } - } - else - { - deh_warning("Invalid condition name %s", params[0]); - return; - } - - M_AddRawCondition(set, (UINT8)id, ty, re, x1, x2); -} -#undef PARAMCHECK - -static void readconditionset(MYFILE *f, UINT8 setnum) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word = s; - char *word2; - char *tmp; - UINT8 id; - UINT8 previd = 0; - - M_ClearConditionSet(setnum); - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - *(tmp-1) = '\0'; - else - break; - strupr(word); - - // Now get the part after - word2 = tmp += 2; - strupr(word2); - - if (fastncmp(word, "CONDITION", 9)) - { - id = (UINT8)atoi(word + 9); - if (id == 0) - { - deh_warning("Condition set %d: unknown word '%s'", setnum, word); - continue; - } - else if (previd > id) - { - // out of order conditions can cause problems, so enforce proper order - deh_warning("Condition set %d: conditions are out of order, ignoring this line", setnum); - continue; - } - previd = id; - - readcondition(setnum, id, word2); - } - else - deh_warning("Condition set %d: unknown word '%s'", setnum, word); - } - } while (!myfeof(f)); // finish when the line is empty - - Z_Free(s); -} - -static void readmaincfg(MYFILE *f) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word = s; - char *word2; - char *tmp; - INT32 value; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - *(tmp-1) = '\0'; - else - break; - strupr(word); - - // Now get the part after - word2 = tmp += 2; - strupr(word2); - - value = atoi(word2); // used for numerical settings - - if (fastcmp(word, "EXECCFG")) - { - if (strchr(word2, '.')) - COM_BufAddText(va("exec %s\n", word2)); - else - { - lumpnum_t lumpnum; - char newname[9]; - - strncpy(newname, word2, 8); - - newname[8] = '\0'; - - lumpnum = W_CheckNumForName(newname); - - if (lumpnum == LUMPERROR || W_LumpLength(lumpnum) == 0) - CONS_Debug(DBG_SETUP, "SOC Error: script lump %s not found/not valid.\n", newname); - else - COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE)); - } - } - - else if (fastcmp(word, "SPSTAGE_START")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); - - spstage_start = spmarathon_start = (INT16)value; - } - else if (fastcmp(word, "SPMARATHON_START")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); - - spmarathon_start = (INT16)value; - } - else if (fastcmp(word, "SSTAGE_START")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); - - sstage_start = (INT16)value; - sstage_end = (INT16)(sstage_start+7); // 7 special stages total plus one weirdo - } - else if (fastcmp(word, "SMPSTAGE_START")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); - - smpstage_start = (INT16)value; - smpstage_end = (INT16)(smpstage_start+6); // 7 special stages total - } - else if (fastcmp(word, "REDTEAM")) - { - skincolor_redteam = (UINT16)get_number(word2); - } - else if (fastcmp(word, "BLUETEAM")) - { - skincolor_blueteam = (UINT16)get_number(word2); - } - else if (fastcmp(word, "REDRING")) - { - skincolor_redring = (UINT16)get_number(word2); - } - else if (fastcmp(word, "BLUERING")) - { - skincolor_bluering = (UINT16)get_number(word2); - } - else if (fastcmp(word, "INVULNTICS")) - { - invulntics = (UINT16)get_number(word2); - } - else if (fastcmp(word, "SNEAKERTICS")) - { - sneakertics = (UINT16)get_number(word2); - } - else if (fastcmp(word, "FLASHINGTICS")) - { - flashingtics = (UINT16)get_number(word2); - } - else if (fastcmp(word, "TAILSFLYTICS")) - { - tailsflytics = (UINT16)get_number(word2); - } - else if (fastcmp(word, "UNDERWATERTICS")) - { - underwatertics = (UINT16)get_number(word2); - } - else if (fastcmp(word, "SPACETIMETICS")) - { - spacetimetics = (UINT16)get_number(word2); - } - else if (fastcmp(word, "EXTRALIFETICS")) - { - extralifetics = (UINT16)get_number(word2); - } - else if (fastcmp(word, "NIGHTSLINKTICS")) - { - nightslinktics = (UINT16)get_number(word2); - } - else if (fastcmp(word, "GAMEOVERTICS")) - { - gameovertics = get_number(word2); - } - else if (fastcmp(word, "AMMOREMOVALTICS")) - { - ammoremovaltics = get_number(word2); - } - else if (fastcmp(word, "INTROTOPLAY")) - { - introtoplay = (UINT8)get_number(word2); - // range check, you morons. - if (introtoplay > 128) - introtoplay = 128; - introchanged = true; - } - else if (fastcmp(word, "CREDITSCUTSCENE")) - { - creditscutscene = (UINT8)get_number(word2); - // range check, you morons. - if (creditscutscene > 128) - creditscutscene = 128; - } - else if (fastcmp(word, "USEBLACKROCK")) - { - useBlackRock = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); - } - else if (fastcmp(word, "LOOPTITLE")) - { - looptitle = (value || word2[0] == 'T' || word2[0] == 'Y'); - titlechanged = true; - } - else if (fastcmp(word, "TITLEMAP")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); - - titlemap = (INT16)value; - titlechanged = true; - } - else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "TITLEPICSHIDE")) - { - hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSMODE")) - { - if (fastcmp(word2, "USER")) - ttmode = TTMODE_USER; - else if (fastcmp(word2, "ALACROIX")) - ttmode = TTMODE_ALACROIX; - else if (fastcmp(word2, "HIDE") || fastcmp(word2, "HIDDEN") || fastcmp(word2, "NONE")) - { - ttmode = TTMODE_USER; - ttname[0] = 0; - hidetitlepics = true; - } - else // if (fastcmp(word2, "OLD") || fastcmp(word2, "SSNTAILS")) - ttmode = TTMODE_OLD; - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSSCALE")) - { - ttscale = max(1, min(8, (UINT8)get_number(word2))); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSSCALESAVAILABLE")) - { - // SPECIAL CASE for Alacroix: Comma-separated list of resolutions that are available - // for gfx loading. - ttavailable[0] = ttavailable[1] = ttavailable[2] = ttavailable[3] =\ - ttavailable[4] = ttavailable[5] = false; - - if (strstr(word2, "1") != NULL) - ttavailable[0] = true; - if (strstr(word2, "2") != NULL) - ttavailable[1] = true; - if (strstr(word2, "3") != NULL) - ttavailable[2] = true; - if (strstr(word2, "4") != NULL) - ttavailable[3] = true; - if (strstr(word2, "5") != NULL) - ttavailable[4] = true; - if (strstr(word2, "6") != NULL) - ttavailable[5] = true; - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSNAME")) - { - strncpy(ttname, word2, 9); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSX")) - { - ttx = (INT16)get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSY")) - { - tty = (INT16)get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSLOOP")) - { - ttloop = (INT16)get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "TITLEPICSTICS")) - { - tttics = (UINT16)get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "TITLESCROLLSPEED") || fastcmp(word, "TITLESCROLLXSPEED")) - { - titlescrollxspeed = get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "TITLESCROLLYSPEED")) - { - titlescrollyspeed = get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "DISABLESPEEDADJUST")) - { - disableSpeedAdjust = (value || word2[0] == 'T' || word2[0] == 'Y'); - } - else if (fastcmp(word, "NUMDEMOS")) - { - numDemos = (UINT8)get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "DEMODELAYTIME")) - { - demoDelayTime = get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "DEMOIDLETIME")) - { - demoIdleTime = get_number(word2); - titlechanged = true; - } - else if (fastcmp(word, "USE1UPSOUND")) - { - use1upSound = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); - } - else if (fastcmp(word, "MAXXTRALIFE")) - { - maxXtraLife = (UINT8)get_number(word2); - } - else if (fastcmp(word, "USECONTINUES")) - { - useContinues = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); - } - - else if (fastcmp(word, "GAMEDATA")) - { - size_t filenamelen; - - // Check the data filename so that mods - // can't write arbitrary files. - if (!GoodDataFileName(word2)) - I_Error("Maincfg: bad data file name '%s'\n", word2); - - G_SaveGameData(); - strlcpy(gamedatafilename, word2, sizeof (gamedatafilename)); - strlwr(gamedatafilename); - savemoddata = true; - - // Also save a time attack folder - filenamelen = strlen(gamedatafilename)-4; // Strip off the extension - strncpy(timeattackfolder, gamedatafilename, min(filenamelen, sizeof (timeattackfolder))); - timeattackfolder[min(filenamelen, sizeof (timeattackfolder) - 1)] = '\0'; - - strcpy(savegamename, timeattackfolder); - strlcat(savegamename, "%u.ssg", sizeof(savegamename)); - // can't use sprintf since there is %u in savegamename - strcatbf(savegamename, srb2home, PATHSEP); - - strcpy(liveeventbackup, va("live%s.bkp", timeattackfolder)); - strcatbf(liveeventbackup, srb2home, PATHSEP); - - gamedataadded = true; - titlechanged = true; - } - else if (fastcmp(word, "RESETDATA")) - { - P_ResetData(value); - titlechanged = true; - } - else if (fastcmp(word, "CUSTOMVERSION")) - { - strlcpy(customversionstring, word2, sizeof (customversionstring)); - //titlechanged = true; - } - else if (fastcmp(word, "BOOTMAP")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); - - bootmap = (INT16)value; - //titlechanged = true; - } - else if (fastcmp(word, "STARTCHAR")) - { - startchar = (INT16)value; - char_on = -1; - } - else if (fastcmp(word, "TUTORIALMAP")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); - - tutorialmap = (INT16)value; - } - else - deh_warning("Maincfg: unknown word '%s'", word); - } - } while (!myfeof(f)); - - Z_Free(s); -} - -static void readwipes(MYFILE *f) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char *word = s; - char *pword = word; - char *word2; - char *tmp; - INT32 value; - INT32 wipeoffset; - - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - - // First remove trailing newline, if there is one - tmp = strchr(s, '\n'); - if (tmp) - *tmp = '\0'; - - tmp = strchr(s, '#'); - if (tmp) - *tmp = '\0'; - if (s == tmp) - continue; // Skip comment lines, but don't break. - - // Get the part before the " = " - tmp = strchr(s, '='); - if (tmp) - *(tmp-1) = '\0'; - else - break; - strupr(word); - - // Now get the part after - word2 = tmp += 2; - value = atoi(word2); // used for numerical settings - - if (value < -1 || value > 99) - { - deh_warning("Wipes: bad value '%s'", word2); - continue; - } - else if (value == -1) - value = UINT8_MAX; - - // error catching - wipeoffset = -1; - - if (fastncmp(word, "LEVEL_", 6)) - { - pword = word + 6; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_level_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_level_final; - } - else if (fastncmp(word, "INTERMISSION_", 13)) - { - pword = word + 13; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_intermission_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_intermission_final; - } - else if (fastncmp(word, "SPECINTER_", 10)) - { - pword = word + 10; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_specinter_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_specinter_final; - } - else if (fastncmp(word, "MULTINTER_", 10)) - { - pword = word + 10; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_multinter_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_multinter_final; - } - else if (fastncmp(word, "CONTINUING_", 11)) - { - pword = word + 11; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_continuing_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_continuing_final; - } - else if (fastncmp(word, "TITLESCREEN_", 12)) - { - pword = word + 12; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_titlescreen_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_titlescreen_final; - } - else if (fastncmp(word, "TIMEATTACK_", 11)) - { - pword = word + 11; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_timeattack_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_timeattack_final; - } - else if (fastncmp(word, "CREDITS_", 8)) - { - pword = word + 8; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_credits_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_credits_final; - else if (fastcmp(pword, "INTERMEDIATE")) - wipeoffset = wipe_credits_intermediate; - } - else if (fastncmp(word, "EVALUATION_", 11)) - { - pword = word + 11; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_evaluation_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_evaluation_final; - } - else if (fastncmp(word, "GAMEEND_", 8)) - { - pword = word + 8; - if (fastcmp(pword, "TOBLACK")) - wipeoffset = wipe_gameend_toblack; - else if (fastcmp(pword, "FINAL")) - wipeoffset = wipe_gameend_final; - } - else if (fastncmp(word, "SPECLEVEL_", 10)) - { - pword = word + 10; - if (fastcmp(pword, "TOWHITE")) - wipeoffset = wipe_speclevel_towhite; - } - - if (wipeoffset < 0) - { - deh_warning("Wipes: unknown word '%s'", word); - continue; - } - - if (value == UINT8_MAX - && (wipeoffset <= wipe_level_toblack || wipeoffset >= wipe_speclevel_towhite)) - { - // Cannot disable non-toblack wipes - // (or the level toblack wipe, or the special towhite wipe) - deh_warning("Wipes: can't disable wipe of type '%s'", word); - continue; - } - - wipedefs[wipeoffset] = (UINT8)value; - } - } while (!myfeof(f)); - - Z_Free(s); -} - -// Used when you do something invalid like read a bad item number -// to prevent extra unnecessary errors -static void ignorelines(MYFILE *f) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - do - { - if (myfgets(s, MAXLINELEN, f)) - { - if (s[0] == '\n') - break; - } - } while (!myfeof(f)); - Z_Free(s); -} - -static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) -{ - char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - char textline[MAXLINELEN]; - char *word; - char *word2; - INT32 i; - - if (!deh_loaded) - initfreeslots(); - - deh_num_warning = 0; - - gamedataadded = titlechanged = introchanged = false; - - // it doesn't test the version of SRB2 and version of dehacked file - dbg_line = -1; // start at -1 so the first line is 0. - while (!myfeof(f)) - { - char origpos[128]; - INT32 size = 0; - char *traverse; - - myfgets(s, MAXLINELEN, f); - memcpy(textline, s, MAXLINELEN); - if (s[0] == '\n' || s[0] == '#') - continue; - - traverse = s; - - while (traverse[0] != '\n') - { - traverse++; - size++; - } - - strncpy(origpos, s, size); - origpos[size] = '\0'; - - if (NULL != (word = strtok(s, " "))) { - strupr(word); - if (word[strlen(word)-1] == '\n') - word[strlen(word)-1] = '\0'; - } - if (word) - { - if (fastcmp(word, "FREESLOT")) - { - readfreeslots(f); - continue; - } - else if (fastcmp(word, "MAINCFG")) - { - readmaincfg(f); - continue; - } - else if (fastcmp(word, "WIPES")) - { - readwipes(f); - continue; - } - word2 = strtok(NULL, " "); - if (word2) { - strupr(word2); - if (word2[strlen(word2) - 1] == '\n') - word2[strlen(word2) - 1] = '\0'; - i = atoi(word2); - } - else - i = 0; - if (fastcmp(word, "CHARACTER")) - { - if (i >= 0 && i < 32) - readPlayer(f, i); - else - { - deh_warning("Character %d out of range (0 - 31)", i); - ignorelines(f); - } - continue; - } - else if (fastcmp(word, "EMBLEM")) - { - if (!mainfile && !gamedataadded) - { - deh_warning("You must define a custom gamedata to use \"%s\"", word); - ignorelines(f); - } - else - { - if (!word2) - i = numemblems + 1; - - if (i > 0 && i <= MAXEMBLEMS) - { - if (numemblems < i) - numemblems = i; - reademblemdata(f, i); - } - else - { - deh_warning("Emblem number %d out of range (1 - %d)", i, MAXEMBLEMS); - ignorelines(f); - } - } - continue; - } - else if (fastcmp(word, "EXTRAEMBLEM")) - { - if (!mainfile && !gamedataadded) - { - deh_warning("You must define a custom gamedata to use \"%s\"", word); - ignorelines(f); - } - else - { - if (!word2) - i = numextraemblems + 1; - - if (i > 0 && i <= MAXEXTRAEMBLEMS) - { - if (numextraemblems < i) - numextraemblems = i; - readextraemblemdata(f, i); - } - else - { - deh_warning("Extra emblem number %d out of range (1 - %d)", i, MAXEXTRAEMBLEMS); - ignorelines(f); - } - } - continue; - } - if (word2) - { - if (fastcmp(word, "THING") || fastcmp(word, "MOBJ") || fastcmp(word, "OBJECT")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_mobjtype(word2); // find a thing by name - if (i < NUMMOBJTYPES && i > 0) - readthing(f, i); - else - { - deh_warning("Thing %d out of range (1 - %d)", i, NUMMOBJTYPES-1); - ignorelines(f); - } - } - else if (fastcmp(word, "SKINCOLOR") || fastcmp(word, "COLOR")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_skincolor(word2); // find a skincolor by name - if (i && i < numskincolors) - readskincolor(f, i); - else - { - deh_warning("Skincolor %d out of range (1 - %d)", i, numskincolors-1); - ignorelines(f); - } - } - else if (fastcmp(word, "SPRITE2")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_sprite2(word2); // find a sprite by name - if (i < (INT32)free_spr2 && i >= (INT32)SPR2_FIRSTFREESLOT) - readsprite2(f, i); - else - { - deh_warning("Sprite2 number %d out of range (%d - %d)", i, SPR2_FIRSTFREESLOT, free_spr2-1); - ignorelines(f); - } - } -#ifdef HWRENDER - else if (fastcmp(word, "LIGHT")) - { - // TODO: Read lights by name - if (i > 0 && i < NUMLIGHTS) - readlight(f, i); - else - { - deh_warning("Light number %d out of range (1 - %d)", i, NUMLIGHTS-1); - ignorelines(f); - } - } -#endif - else if (fastcmp(word, "SPRITE") || fastcmp(word, "SPRITEINFO")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_sprite(word2); // find a sprite by name - if (i < NUMSPRITES && i > 0) - readspriteinfo(f, i, false); - else - { - deh_warning("Sprite number %d out of range (0 - %d)", i, NUMSPRITES-1); - ignorelines(f); - } - } - else if (fastcmp(word, "SPRITE2INFO")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_sprite2(word2); // find a sprite by name - if (i < NUMPLAYERSPRITES && i >= 0) - readspriteinfo(f, i, true); - else - { - deh_warning("Sprite2 number %d out of range (0 - %d)", i, NUMPLAYERSPRITES-1); - ignorelines(f); - } - } - else if (fastcmp(word, "LEVEL")) - { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - i = M_MapNumber(word2[0], word2[1]); - - if (i > 0 && i <= NUMMAPS) - readlevelheader(f, i); - else - { - deh_warning("Level number %d out of range (1 - %d)", i, NUMMAPS); - ignorelines(f); - } - } - else if (fastcmp(word, "GAMETYPE")) - { - // Get the gametype name from textline - // instead of word2, so that gametype names - // aren't allcaps - INT32 c; - for (c = 0; c < MAXLINELEN; c++) - { - if (textline[c] == '\0') - break; - if (textline[c] == ' ') - { - char *gtname = (textline+c+1); - if (gtname) - { - // remove funny characters - INT32 j; - for (j = 0; j < (MAXLINELEN - c); j++) - { - if (gtname[j] == '\0') - break; - if (gtname[j] < 32) - gtname[j] = '\0'; - } - readgametype(f, gtname); - } - break; - } - } - } - else if (fastcmp(word, "CUTSCENE")) - { - if (i > 0 && i < 129) - readcutscene(f, i - 1); - else - { - deh_warning("Cutscene number %d out of range (1 - 128)", i); - ignorelines(f); - } - } - else if (fastcmp(word, "PROMPT")) - { - if (i > 0 && i < MAX_PROMPTS) - readtextprompt(f, i - 1); - else - { - deh_warning("Prompt number %d out of range (1 - %d)", i, MAX_PROMPTS); - ignorelines(f); - } - } - else if (fastcmp(word, "FRAME") || fastcmp(word, "STATE")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_state(word2); // find a state by name - if (i < NUMSTATES && i >= 0) - readframe(f, i); - else - { - deh_warning("Frame %d out of range (0 - %d)", i, NUMSTATES-1); - ignorelines(f); - } - } - else if (fastcmp(word, "SOUND")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_sfx(word2); // find a sound by name - if (i < NUMSFX && i > 0) - readsound(f, i); - else - { - deh_warning("Sound %d out of range (1 - %d)", i, NUMSFX-1); - ignorelines(f); - } - } - else if (fastcmp(word, "HUDITEM")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_huditem(word2); // find a huditem by name - if (i >= 0 && i < NUMHUDITEMS) - readhuditem(f, i); - else - { - deh_warning("HUD item number %d out of range (0 - %d)", i, NUMHUDITEMS-1); - ignorelines(f); - } - } - else if (fastcmp(word, "MENU")) - { - if (i == 0 && word2[0] != '0') // If word2 isn't a number - i = get_menutype(word2); // find a huditem by name - if (i >= 1 && i < NUMMENUTYPES) - readmenu(f, i); - else - { - // zero-based, but let's start at 1 - deh_warning("Menu number %d out of range (1 - %d)", i, NUMMENUTYPES-1); - ignorelines(f); - } - } - else if (fastcmp(word, "UNLOCKABLE")) - { - if (!mainfile && !gamedataadded) - { - deh_warning("You must define a custom gamedata to use \"%s\"", word); - ignorelines(f); - } - else if (i > 0 && i <= MAXUNLOCKABLES) - readunlockable(f, i - 1); - else - { - deh_warning("Unlockable number %d out of range (1 - %d)", i, MAXUNLOCKABLES); - ignorelines(f); - } - } - else if (fastcmp(word, "CONDITIONSET")) - { - if (!mainfile && !gamedataadded) - { - deh_warning("You must define a custom gamedata to use \"%s\"", word); - ignorelines(f); - } - else if (i > 0 && i <= MAXCONDITIONSETS) - readconditionset(f, (UINT8)i); - else - { - deh_warning("Condition set number %d out of range (1 - %d)", i, MAXCONDITIONSETS); - ignorelines(f); - } - } - else if (fastcmp(word, "SRB2")) - { - if (isdigit(word2[0])) - { - i = atoi(word2); - if (i != PATCHVERSION) - { - deh_warning( - "Patch is for SRB2 version %d, " - "only version %d is supported", - i, - PATCHVERSION - ); - } - } - else - { - deh_warning( - "SRB2 version definition has incorrect format, " - "use \"SRB2 %d\"", - PATCHVERSION - ); - } - } - // Clear all data in certain locations (mostly for unlocks) - // Unless you REALLY want to piss people off, - // define a custom gamedata /before/ doing this!! - // (then again, modifiedgame will prevent game data saving anyway) - else if (fastcmp(word, "CLEAR")) - { - boolean clearall = (fastcmp(word2, "ALL")); - - if (!mainfile && !gamedataadded) - { - deh_warning("You must define a custom gamedata to use \"%s\"", word); - continue; - } - - if (clearall || fastcmp(word2, "UNLOCKABLES")) - memset(&unlockables, 0, sizeof(unlockables)); - - if (clearall || fastcmp(word2, "EMBLEMS")) - { - memset(&emblemlocations, 0, sizeof(emblemlocations)); - numemblems = 0; - } - - if (clearall || fastcmp(word2, "EXTRAEMBLEMS")) - { - memset(&extraemblems, 0, sizeof(extraemblems)); - numextraemblems = 0; - } - - if (clearall || fastcmp(word2, "CONDITIONSETS")) - clear_conditionsets(); - - if (clearall || fastcmp(word2, "LEVELS")) - clear_levels(); - } - else - deh_warning("Unknown word: %s", word); - } - else - deh_warning("missing argument for '%s'", word); - } - else - deh_warning("No word in this line: %s", s); - } // end while - - if (gamedataadded) - G_LoadGameData(); - - if (gamestate == GS_TITLESCREEN) - { - if (introchanged) - { - menuactive = false; - I_UpdateMouseGrab(); - COM_BufAddText("playintro"); - } - else if (titlechanged) - { - menuactive = false; - I_UpdateMouseGrab(); - COM_BufAddText("exitgame"); // Command_ExitGame_f() but delayed - } - } - - dbg_line = -1; - if (deh_num_warning) - { - CONS_Printf(M_GetText("%d warning%s in the SOC lump\n"), deh_num_warning, deh_num_warning == 1 ? "" : "s"); - if (devparm) { - I_Error("%s%s",va(M_GetText("%d warning%s in the SOC lump\n"), deh_num_warning, deh_num_warning == 1 ? "" : "s"), M_GetText("See log.txt for details.\n")); - //while (!I_GetKey()) - //I_OsPolling(); - } - } - - deh_loaded = true; - Z_Free(s); -} - -// read dehacked lump in a wad (there is special trick for for deh -// file that are converted to wad in w_wad.c) -void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump, boolean mainfile) -{ - MYFILE f; - f.wad = wad; - f.size = W_LumpLengthPwad(wad, lump); - f.data = Z_Malloc(f.size + 1, PU_STATIC, NULL); - W_ReadLumpPwad(wad, lump, f.data); - f.curpos = f.data; - f.data[f.size] = 0; - DEH_LoadDehackedFile(&f, mainfile); - Z_Free(f.data); -} - -void DEH_LoadDehackedLump(lumpnum_t lumpnum) -{ - DEH_LoadDehackedLumpPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum), false); -} - -//////////////////////////////////////////////////////////////////////////////// -// CRAZY LIST OF STATE NAMES AND ALL FROM HERE DOWN -// TODO: Make this all a seperate file or something, like part of info.c?? -// TODO: Read the list from a text lump in a WAD as necessary instead -// or something, don't just keep it all in memory like this. -// TODO: Make the lists public so we can start using actual mobj -// and state names in warning and error messages! :D - -// RegEx to generate this from info.h: ^\tS_([^,]+), --> \t"S_\1", -// I am leaving the prefixes solely for clarity to programmers, -// because sadly no one remembers this place while searching for full state names. -static const char *const STATE_LIST[] = { // array length left dynamic for sanity testing later. - "S_NULL", - "S_UNKNOWN", - "S_INVISIBLE", // state for invisible sprite - - "S_SPAWNSTATE", - "S_SEESTATE", - "S_MELEESTATE", - "S_MISSILESTATE", - "S_DEATHSTATE", - "S_XDEATHSTATE", - "S_RAISESTATE", - - // Thok - "S_THOK", - - // Player - "S_PLAY_STND", - "S_PLAY_WAIT", - "S_PLAY_WALK", - "S_PLAY_SKID", - "S_PLAY_RUN", - "S_PLAY_DASH", - "S_PLAY_PAIN", - "S_PLAY_STUN", - "S_PLAY_DEAD", - "S_PLAY_DRWN", - "S_PLAY_ROLL", - "S_PLAY_GASP", - "S_PLAY_JUMP", - "S_PLAY_SPRING", - "S_PLAY_FALL", - "S_PLAY_EDGE", - "S_PLAY_RIDE", - - // CA2_SPINDASH - "S_PLAY_SPINDASH", - - // CA_FLY/SWIM - "S_PLAY_FLY", - "S_PLAY_SWIM", - "S_PLAY_FLY_TIRED", - - // CA_GLIDEANDCLIMB - "S_PLAY_GLIDE", - "S_PLAY_GLIDE_LANDING", - "S_PLAY_CLING", - "S_PLAY_CLIMB", - - // CA_FLOAT/CA_SLOWFALL - "S_PLAY_FLOAT", - "S_PLAY_FLOAT_RUN", - - // CA_BOUNCE - "S_PLAY_BOUNCE", - "S_PLAY_BOUNCE_LANDING", - - // CA2_GUNSLINGER - "S_PLAY_FIRE", - "S_PLAY_FIRE_FINISH", - - // CA_TWINSPIN - "S_PLAY_TWINSPIN", - - // CA2_MELEE - "S_PLAY_MELEE", - "S_PLAY_MELEE_FINISH", - "S_PLAY_MELEE_LANDING", - - // SF_SUPER - "S_PLAY_SUPER_TRANS1", - "S_PLAY_SUPER_TRANS2", - "S_PLAY_SUPER_TRANS3", - "S_PLAY_SUPER_TRANS4", - "S_PLAY_SUPER_TRANS5", - "S_PLAY_SUPER_TRANS6", - - // technically the player goes here but it's an infinite tic state - "S_OBJPLACE_DUMMY", - - // 1-Up Box Sprites overlay (uses player sprite) - "S_PLAY_BOX1", - "S_PLAY_BOX2", - "S_PLAY_ICON1", - "S_PLAY_ICON2", - "S_PLAY_ICON3", - - // Level end sign overlay (uses player sprite) - "S_PLAY_SIGN", - - // NiGHTS character (uses player sprite) - "S_PLAY_NIGHTS_TRANS1", - "S_PLAY_NIGHTS_TRANS2", - "S_PLAY_NIGHTS_TRANS3", - "S_PLAY_NIGHTS_TRANS4", - "S_PLAY_NIGHTS_TRANS5", - "S_PLAY_NIGHTS_TRANS6", - "S_PLAY_NIGHTS_STAND", - "S_PLAY_NIGHTS_FLOAT", - "S_PLAY_NIGHTS_FLY", - "S_PLAY_NIGHTS_DRILL", - "S_PLAY_NIGHTS_STUN", - "S_PLAY_NIGHTS_PULL", - "S_PLAY_NIGHTS_ATTACK", - - // c: - "S_TAILSOVERLAY_STAND", - "S_TAILSOVERLAY_0DEGREES", - "S_TAILSOVERLAY_PLUS30DEGREES", - "S_TAILSOVERLAY_PLUS60DEGREES", - "S_TAILSOVERLAY_MINUS30DEGREES", - "S_TAILSOVERLAY_MINUS60DEGREES", - "S_TAILSOVERLAY_RUN", - "S_TAILSOVERLAY_FLY", - "S_TAILSOVERLAY_TIRE", - "S_TAILSOVERLAY_PAIN", - "S_TAILSOVERLAY_GASP", - "S_TAILSOVERLAY_EDGE", - "S_TAILSOVERLAY_DASH", - - // [: - "S_JETFUMEFLASH", - - // Blue Crawla - "S_POSS_STND", - "S_POSS_RUN1", - "S_POSS_RUN2", - "S_POSS_RUN3", - "S_POSS_RUN4", - "S_POSS_RUN5", - "S_POSS_RUN6", - - // Red Crawla - "S_SPOS_STND", - "S_SPOS_RUN1", - "S_SPOS_RUN2", - "S_SPOS_RUN3", - "S_SPOS_RUN4", - "S_SPOS_RUN5", - "S_SPOS_RUN6", - - // Greenflower Fish - "S_FISH1", - "S_FISH2", - "S_FISH3", - "S_FISH4", - - // Buzz (Gold) - "S_BUZZLOOK1", - "S_BUZZLOOK2", - "S_BUZZFLY1", - "S_BUZZFLY2", - - // Buzz (Red) - "S_RBUZZLOOK1", - "S_RBUZZLOOK2", - "S_RBUZZFLY1", - "S_RBUZZFLY2", - - // Jetty-Syn Bomber - "S_JETBLOOK1", - "S_JETBLOOK2", - "S_JETBZOOM1", - "S_JETBZOOM2", - - // Jetty-Syn Gunner - "S_JETGLOOK1", - "S_JETGLOOK2", - "S_JETGZOOM1", - "S_JETGZOOM2", - "S_JETGSHOOT1", - "S_JETGSHOOT2", - - // Crawla Commander - "S_CCOMMAND1", - "S_CCOMMAND2", - "S_CCOMMAND3", - "S_CCOMMAND4", - - // Deton - "S_DETON1", - "S_DETON2", - "S_DETON3", - "S_DETON4", - "S_DETON5", - "S_DETON6", - "S_DETON7", - "S_DETON8", - "S_DETON9", - "S_DETON10", - "S_DETON11", - "S_DETON12", - "S_DETON13", - "S_DETON14", - "S_DETON15", - - // Skim Mine Dropper - "S_SKIM1", - "S_SKIM2", - "S_SKIM3", - "S_SKIM4", - - // THZ Turret - "S_TURRET", - "S_TURRETFIRE", - "S_TURRETSHOCK1", - "S_TURRETSHOCK2", - "S_TURRETSHOCK3", - "S_TURRETSHOCK4", - "S_TURRETSHOCK5", - "S_TURRETSHOCK6", - "S_TURRETSHOCK7", - "S_TURRETSHOCK8", - "S_TURRETSHOCK9", - - // Popup Turret - "S_TURRETLOOK", - "S_TURRETSEE", - "S_TURRETPOPUP1", - "S_TURRETPOPUP2", - "S_TURRETPOPUP3", - "S_TURRETPOPUP4", - "S_TURRETPOPUP5", - "S_TURRETPOPUP6", - "S_TURRETPOPUP7", - "S_TURRETPOPUP8", - "S_TURRETSHOOT", - "S_TURRETPOPDOWN1", - "S_TURRETPOPDOWN2", - "S_TURRETPOPDOWN3", - "S_TURRETPOPDOWN4", - "S_TURRETPOPDOWN5", - "S_TURRETPOPDOWN6", - "S_TURRETPOPDOWN7", - "S_TURRETPOPDOWN8", - - // Spincushion - "S_SPINCUSHION_LOOK", - "S_SPINCUSHION_CHASE1", - "S_SPINCUSHION_CHASE2", - "S_SPINCUSHION_CHASE3", - "S_SPINCUSHION_CHASE4", - "S_SPINCUSHION_AIM1", - "S_SPINCUSHION_AIM2", - "S_SPINCUSHION_AIM3", - "S_SPINCUSHION_AIM4", - "S_SPINCUSHION_AIM5", - "S_SPINCUSHION_SPIN1", - "S_SPINCUSHION_SPIN2", - "S_SPINCUSHION_SPIN3", - "S_SPINCUSHION_SPIN4", - "S_SPINCUSHION_STOP1", - "S_SPINCUSHION_STOP2", - "S_SPINCUSHION_STOP3", - "S_SPINCUSHION_STOP4", - - // Crushstacean - "S_CRUSHSTACEAN_ROAM1", - "S_CRUSHSTACEAN_ROAM2", - "S_CRUSHSTACEAN_ROAM3", - "S_CRUSHSTACEAN_ROAM4", - "S_CRUSHSTACEAN_ROAMPAUSE", - "S_CRUSHSTACEAN_PUNCH1", - "S_CRUSHSTACEAN_PUNCH2", - "S_CRUSHCLAW_AIM", - "S_CRUSHCLAW_OUT", - "S_CRUSHCLAW_STAY", - "S_CRUSHCLAW_IN", - "S_CRUSHCLAW_WAIT", - "S_CRUSHCHAIN", - - // Banpyura - "S_BANPYURA_ROAM1", - "S_BANPYURA_ROAM2", - "S_BANPYURA_ROAM3", - "S_BANPYURA_ROAM4", - "S_BANPYURA_ROAMPAUSE", - "S_CDIAG1", - "S_CDIAG2", - "S_CDIAG3", - "S_CDIAG4", - "S_CDIAG5", - "S_CDIAG6", - "S_CDIAG7", - "S_CDIAG8", - - // Jet Jaw - "S_JETJAW_ROAM1", - "S_JETJAW_ROAM2", - "S_JETJAW_ROAM3", - "S_JETJAW_ROAM4", - "S_JETJAW_ROAM5", - "S_JETJAW_ROAM6", - "S_JETJAW_ROAM7", - "S_JETJAW_ROAM8", - "S_JETJAW_CHOMP1", - "S_JETJAW_CHOMP2", - "S_JETJAW_CHOMP3", - "S_JETJAW_CHOMP4", - "S_JETJAW_CHOMP5", - "S_JETJAW_CHOMP6", - "S_JETJAW_CHOMP7", - "S_JETJAW_CHOMP8", - "S_JETJAW_CHOMP9", - "S_JETJAW_CHOMP10", - "S_JETJAW_CHOMP11", - "S_JETJAW_CHOMP12", - "S_JETJAW_CHOMP13", - "S_JETJAW_CHOMP14", - "S_JETJAW_CHOMP15", - "S_JETJAW_CHOMP16", - "S_JETJAW_SOUND", - - // Snailer - "S_SNAILER1", - "S_SNAILER_FLICKY", - - // Vulture - "S_VULTURE_STND", - "S_VULTURE_DRIFT", - "S_VULTURE_ZOOM1", - "S_VULTURE_ZOOM2", - "S_VULTURE_STUNNED", - - // Pointy - "S_POINTY1", - "S_POINTYBALL1", - - // Robo-Hood - "S_ROBOHOOD_LOOK", - "S_ROBOHOOD_STAND", - "S_ROBOHOOD_FIRE1", - "S_ROBOHOOD_FIRE2", - "S_ROBOHOOD_JUMP1", - "S_ROBOHOOD_JUMP2", - "S_ROBOHOOD_JUMP3", - - // Castlebot Facestabber - "S_FACESTABBER_STND1", - "S_FACESTABBER_STND2", - "S_FACESTABBER_STND3", - "S_FACESTABBER_STND4", - "S_FACESTABBER_STND5", - "S_FACESTABBER_STND6", - "S_FACESTABBER_CHARGE1", - "S_FACESTABBER_CHARGE2", - "S_FACESTABBER_CHARGE3", - "S_FACESTABBER_CHARGE4", - "S_FACESTABBER_PAIN", - "S_FACESTABBER_DIE1", - "S_FACESTABBER_DIE2", - "S_FACESTABBER_DIE3", - "S_FACESTABBERSPEAR", - - // Egg Guard - "S_EGGGUARD_STND", - "S_EGGGUARD_WALK1", - "S_EGGGUARD_WALK2", - "S_EGGGUARD_WALK3", - "S_EGGGUARD_WALK4", - "S_EGGGUARD_MAD1", - "S_EGGGUARD_MAD2", - "S_EGGGUARD_MAD3", - "S_EGGGUARD_RUN1", - "S_EGGGUARD_RUN2", - "S_EGGGUARD_RUN3", - "S_EGGGUARD_RUN4", - - // Egg Shield for Egg Guard - "S_EGGSHIELD", - "S_EGGSHIELDBREAK", - - // Green Snapper - "S_SNAPPER_SPAWN", - "S_SNAPPER_SPAWN2", - "S_GSNAPPER_STND", - "S_GSNAPPER1", - "S_GSNAPPER2", - "S_GSNAPPER3", - "S_GSNAPPER4", - "S_SNAPPER_XPLD", - "S_SNAPPER_LEG", - "S_SNAPPER_LEGRAISE", - "S_SNAPPER_HEAD", - - // Minus - "S_MINUS_INIT", - "S_MINUS_STND", - "S_MINUS_DIGGING1", - "S_MINUS_DIGGING2", - "S_MINUS_DIGGING3", - "S_MINUS_DIGGING4", - "S_MINUS_BURST0", - "S_MINUS_BURST1", - "S_MINUS_BURST2", - "S_MINUS_BURST3", - "S_MINUS_BURST4", - "S_MINUS_BURST5", - "S_MINUS_POPUP", - "S_MINUS_AERIAL1", - "S_MINUS_AERIAL2", - "S_MINUS_AERIAL3", - "S_MINUS_AERIAL4", - - // Minus dirt - "S_MINUSDIRT1", - "S_MINUSDIRT2", - "S_MINUSDIRT3", - "S_MINUSDIRT4", - "S_MINUSDIRT5", - "S_MINUSDIRT6", - "S_MINUSDIRT7", - - // Spring Shell - "S_SSHELL_STND", - "S_SSHELL_RUN1", - "S_SSHELL_RUN2", - "S_SSHELL_RUN3", - "S_SSHELL_RUN4", - "S_SSHELL_SPRING1", - "S_SSHELL_SPRING2", - "S_SSHELL_SPRING3", - "S_SSHELL_SPRING4", - - // Spring Shell (yellow) - "S_YSHELL_STND", - "S_YSHELL_RUN1", - "S_YSHELL_RUN2", - "S_YSHELL_RUN3", - "S_YSHELL_RUN4", - "S_YSHELL_SPRING1", - "S_YSHELL_SPRING2", - "S_YSHELL_SPRING3", - "S_YSHELL_SPRING4", - - // Unidus - "S_UNIDUS_STND", - "S_UNIDUS_RUN", - "S_UNIDUS_BALL", - - // Canarivore - "S_CANARIVORE_LOOK", - "S_CANARIVORE_AWAKEN1", - "S_CANARIVORE_AWAKEN2", - "S_CANARIVORE_AWAKEN3", - "S_CANARIVORE_GAS1", - "S_CANARIVORE_GAS2", - "S_CANARIVORE_GAS3", - "S_CANARIVORE_GAS4", - "S_CANARIVORE_GAS5", - "S_CANARIVORE_GASREPEAT", - "S_CANARIVORE_CLOSE1", - "S_CANARIVORE_CLOSE2", - "S_CANARIVOREGAS_1", - "S_CANARIVOREGAS_2", - "S_CANARIVOREGAS_3", - "S_CANARIVOREGAS_4", - "S_CANARIVOREGAS_5", - "S_CANARIVOREGAS_6", - "S_CANARIVOREGAS_7", - "S_CANARIVOREGAS_8", - - // Pyre Fly - "S_PYREFLY_FLY", - "S_PYREFLY_BURN", - "S_PYREFIRE1", - "S_PYREFIRE2", - - // Pterabyte - "S_PTERABYTESPAWNER", - "S_PTERABYTEWAYPOINT", - "S_PTERABYTE_FLY1", - "S_PTERABYTE_FLY2", - "S_PTERABYTE_FLY3", - "S_PTERABYTE_FLY4", - "S_PTERABYTE_SWOOPDOWN", - "S_PTERABYTE_SWOOPUP", - - // Dragonbomber - "S_DRAGONBOMBER", - "S_DRAGONWING1", - "S_DRAGONWING2", - "S_DRAGONWING3", - "S_DRAGONWING4", - "S_DRAGONTAIL_LOADED", - "S_DRAGONTAIL_EMPTY", - "S_DRAGONTAIL_EMPTYLOOP", - "S_DRAGONTAIL_RELOAD", - "S_DRAGONMINE", - "S_DRAGONMINE_LAND1", - "S_DRAGONMINE_LAND2", - "S_DRAGONMINE_SLOWFLASH1", - "S_DRAGONMINE_SLOWFLASH2", - "S_DRAGONMINE_SLOWLOOP", - "S_DRAGONMINE_FASTFLASH1", - "S_DRAGONMINE_FASTFLASH2", - "S_DRAGONMINE_FASTLOOP", - - // Boss Explosion - "S_BOSSEXPLODE", - - // S3&K Boss Explosion - "S_SONIC3KBOSSEXPLOSION1", - "S_SONIC3KBOSSEXPLOSION2", - "S_SONIC3KBOSSEXPLOSION3", - "S_SONIC3KBOSSEXPLOSION4", - "S_SONIC3KBOSSEXPLOSION5", - "S_SONIC3KBOSSEXPLOSION6", - - "S_JETFUME1", - - // Boss 1 - "S_EGGMOBILE_STND", - "S_EGGMOBILE_ROFL", - "S_EGGMOBILE_LATK1", - "S_EGGMOBILE_LATK2", - "S_EGGMOBILE_LATK3", - "S_EGGMOBILE_LATK4", - "S_EGGMOBILE_LATK5", - "S_EGGMOBILE_LATK6", - "S_EGGMOBILE_LATK7", - "S_EGGMOBILE_LATK8", - "S_EGGMOBILE_LATK9", - "S_EGGMOBILE_RATK1", - "S_EGGMOBILE_RATK2", - "S_EGGMOBILE_RATK3", - "S_EGGMOBILE_RATK4", - "S_EGGMOBILE_RATK5", - "S_EGGMOBILE_RATK6", - "S_EGGMOBILE_RATK7", - "S_EGGMOBILE_RATK8", - "S_EGGMOBILE_RATK9", - "S_EGGMOBILE_PANIC1", - "S_EGGMOBILE_PANIC2", - "S_EGGMOBILE_PANIC3", - "S_EGGMOBILE_PANIC4", - "S_EGGMOBILE_PANIC5", - "S_EGGMOBILE_PANIC6", - "S_EGGMOBILE_PANIC7", - "S_EGGMOBILE_PANIC8", - "S_EGGMOBILE_PANIC9", - "S_EGGMOBILE_PANIC10", - "S_EGGMOBILE_PANIC11", - "S_EGGMOBILE_PANIC12", - "S_EGGMOBILE_PANIC13", - "S_EGGMOBILE_PANIC14", - "S_EGGMOBILE_PANIC15", - "S_EGGMOBILE_PAIN", - "S_EGGMOBILE_PAIN2", - "S_EGGMOBILE_DIE1", - "S_EGGMOBILE_DIE2", - "S_EGGMOBILE_DIE3", - "S_EGGMOBILE_DIE4", - "S_EGGMOBILE_FLEE1", - "S_EGGMOBILE_FLEE2", - "S_EGGMOBILE_BALL", - "S_EGGMOBILE_TARGET", - - "S_BOSSEGLZ1", - "S_BOSSEGLZ2", - - // Boss 2 - "S_EGGMOBILE2_STND", - "S_EGGMOBILE2_POGO1", - "S_EGGMOBILE2_POGO2", - "S_EGGMOBILE2_POGO3", - "S_EGGMOBILE2_POGO4", - "S_EGGMOBILE2_POGO5", - "S_EGGMOBILE2_POGO6", - "S_EGGMOBILE2_POGO7", - "S_EGGMOBILE2_PAIN", - "S_EGGMOBILE2_PAIN2", - "S_EGGMOBILE2_DIE1", - "S_EGGMOBILE2_DIE2", - "S_EGGMOBILE2_DIE3", - "S_EGGMOBILE2_DIE4", - "S_EGGMOBILE2_FLEE1", - "S_EGGMOBILE2_FLEE2", - - "S_BOSSTANK1", - "S_BOSSTANK2", - "S_BOSSSPIGOT", - - // Boss 2 Goop - "S_GOOP1", - "S_GOOP2", - "S_GOOP3", - "S_GOOPTRAIL", - - // Boss 3 - "S_EGGMOBILE3_STND", - "S_EGGMOBILE3_SHOCK", - "S_EGGMOBILE3_ATK1", - "S_EGGMOBILE3_ATK2", - "S_EGGMOBILE3_ATK3A", - "S_EGGMOBILE3_ATK3B", - "S_EGGMOBILE3_ATK3C", - "S_EGGMOBILE3_ATK3D", - "S_EGGMOBILE3_ATK4", - "S_EGGMOBILE3_ATK5", - "S_EGGMOBILE3_ROFL", - "S_EGGMOBILE3_PAIN", - "S_EGGMOBILE3_PAIN2", - "S_EGGMOBILE3_DIE1", - "S_EGGMOBILE3_DIE2", - "S_EGGMOBILE3_DIE3", - "S_EGGMOBILE3_DIE4", - "S_EGGMOBILE3_FLEE1", - "S_EGGMOBILE3_FLEE2", - - // Boss 3 Pinch - "S_FAKEMOBILE_INIT", - "S_FAKEMOBILE", - "S_FAKEMOBILE_ATK1", - "S_FAKEMOBILE_ATK2", - "S_FAKEMOBILE_ATK3A", - "S_FAKEMOBILE_ATK3B", - "S_FAKEMOBILE_ATK3C", - "S_FAKEMOBILE_ATK3D", - "S_FAKEMOBILE_DIE1", - "S_FAKEMOBILE_DIE2", - - "S_BOSSSEBH1", - "S_BOSSSEBH2", - - // Boss 3 Shockwave - "S_SHOCKWAVE1", - "S_SHOCKWAVE2", - - // Boss 4 - "S_EGGMOBILE4_STND", - "S_EGGMOBILE4_LATK1", - "S_EGGMOBILE4_LATK2", - "S_EGGMOBILE4_LATK3", - "S_EGGMOBILE4_LATK4", - "S_EGGMOBILE4_LATK5", - "S_EGGMOBILE4_LATK6", - "S_EGGMOBILE4_RATK1", - "S_EGGMOBILE4_RATK2", - "S_EGGMOBILE4_RATK3", - "S_EGGMOBILE4_RATK4", - "S_EGGMOBILE4_RATK5", - "S_EGGMOBILE4_RATK6", - "S_EGGMOBILE4_RAISE1", - "S_EGGMOBILE4_RAISE2", - "S_EGGMOBILE4_PAIN1", - "S_EGGMOBILE4_PAIN2", - "S_EGGMOBILE4_DIE1", - "S_EGGMOBILE4_DIE2", - "S_EGGMOBILE4_DIE3", - "S_EGGMOBILE4_DIE4", - "S_EGGMOBILE4_FLEE1", - "S_EGGMOBILE4_FLEE2", - "S_EGGMOBILE4_MACE", - "S_EGGMOBILE4_MACE_DIE1", - "S_EGGMOBILE4_MACE_DIE2", - "S_EGGMOBILE4_MACE_DIE3", - - // Boss 4 jet flame - "S_JETFLAME", - - // Boss 4 Spectator Eggrobo - "S_EGGROBO1_STND", - "S_EGGROBO1_BSLAP1", - "S_EGGROBO1_BSLAP2", - "S_EGGROBO1_PISSED", - - // Boss 4 Spectator Eggrobo jet flame - "S_EGGROBOJET", - - // Boss 5 - "S_FANG_SETUP", - "S_FANG_INTRO0", - "S_FANG_INTRO1", - "S_FANG_INTRO2", - "S_FANG_INTRO3", - "S_FANG_INTRO4", - "S_FANG_INTRO5", - "S_FANG_INTRO6", - "S_FANG_INTRO7", - "S_FANG_INTRO8", - "S_FANG_INTRO9", - "S_FANG_INTRO10", - "S_FANG_INTRO11", - "S_FANG_INTRO12", - "S_FANG_CLONE1", - "S_FANG_CLONE2", - "S_FANG_CLONE3", - "S_FANG_CLONE4", - "S_FANG_IDLE0", - "S_FANG_IDLE1", - "S_FANG_IDLE2", - "S_FANG_IDLE3", - "S_FANG_IDLE4", - "S_FANG_IDLE5", - "S_FANG_IDLE6", - "S_FANG_IDLE7", - "S_FANG_IDLE8", - "S_FANG_PAIN1", - "S_FANG_PAIN2", - "S_FANG_PATHINGSTART1", - "S_FANG_PATHINGSTART2", - "S_FANG_PATHING", - "S_FANG_BOUNCE1", - "S_FANG_BOUNCE2", - "S_FANG_BOUNCE3", - "S_FANG_BOUNCE4", - "S_FANG_FALL1", - "S_FANG_FALL2", - "S_FANG_CHECKPATH1", - "S_FANG_CHECKPATH2", - "S_FANG_PATHINGCONT1", - "S_FANG_PATHINGCONT2", - "S_FANG_PATHINGCONT3", - "S_FANG_SKID1", - "S_FANG_SKID2", - "S_FANG_SKID3", - "S_FANG_CHOOSEATTACK", - "S_FANG_FIRESTART1", - "S_FANG_FIRESTART2", - "S_FANG_FIRE1", - "S_FANG_FIRE2", - "S_FANG_FIRE3", - "S_FANG_FIRE4", - "S_FANG_FIREREPEAT", - "S_FANG_LOBSHOT0", - "S_FANG_LOBSHOT1", - "S_FANG_LOBSHOT2", - "S_FANG_WAIT1", - "S_FANG_WAIT2", - "S_FANG_WALLHIT", - "S_FANG_PINCHPATHINGSTART1", - "S_FANG_PINCHPATHINGSTART2", - "S_FANG_PINCHPATHING", - "S_FANG_PINCHBOUNCE0", - "S_FANG_PINCHBOUNCE1", - "S_FANG_PINCHBOUNCE2", - "S_FANG_PINCHBOUNCE3", - "S_FANG_PINCHBOUNCE4", - "S_FANG_PINCHFALL0", - "S_FANG_PINCHFALL1", - "S_FANG_PINCHFALL2", - "S_FANG_PINCHSKID1", - "S_FANG_PINCHSKID2", - "S_FANG_PINCHLOBSHOT0", - "S_FANG_PINCHLOBSHOT1", - "S_FANG_PINCHLOBSHOT2", - "S_FANG_PINCHLOBSHOT3", - "S_FANG_PINCHLOBSHOT4", - "S_FANG_DIE1", - "S_FANG_DIE2", - "S_FANG_DIE3", - "S_FANG_DIE4", - "S_FANG_DIE5", - "S_FANG_DIE6", - "S_FANG_DIE7", - "S_FANG_DIE8", - "S_FANG_FLEEPATHING1", - "S_FANG_FLEEPATHING2", - "S_FANG_FLEEBOUNCE1", - "S_FANG_FLEEBOUNCE2", - "S_FANG_KO", - - "S_BROKENROBOTRANDOM", - "S_BROKENROBOTA", - "S_BROKENROBOTB", - "S_BROKENROBOTC", - "S_BROKENROBOTD", - "S_BROKENROBOTE", - "S_BROKENROBOTF", - - "S_ALART1", - "S_ALART2", - - "S_VWREF", - "S_VWREB", - - "S_PROJECTORLIGHT1", - "S_PROJECTORLIGHT2", - "S_PROJECTORLIGHT3", - "S_PROJECTORLIGHT4", - "S_PROJECTORLIGHT5", - - "S_FBOMB1", - "S_FBOMB2", - "S_FBOMB_EXPL1", - "S_FBOMB_EXPL2", - "S_FBOMB_EXPL3", - "S_FBOMB_EXPL4", - "S_FBOMB_EXPL5", - "S_FBOMB_EXPL6", - "S_TNTDUST_1", - "S_TNTDUST_2", - "S_TNTDUST_3", - "S_TNTDUST_4", - "S_TNTDUST_5", - "S_TNTDUST_6", - "S_TNTDUST_7", - "S_TNTDUST_8", - "S_FSGNA", - "S_FSGNB", - "S_FSGNC", - "S_FSGND", - - // Black Eggman (Boss 7) - "S_BLACKEGG_STND", - "S_BLACKEGG_STND2", - "S_BLACKEGG_WALK1", - "S_BLACKEGG_WALK2", - "S_BLACKEGG_WALK3", - "S_BLACKEGG_WALK4", - "S_BLACKEGG_WALK5", - "S_BLACKEGG_WALK6", - "S_BLACKEGG_SHOOT1", - "S_BLACKEGG_SHOOT2", - "S_BLACKEGG_PAIN1", - "S_BLACKEGG_PAIN2", - "S_BLACKEGG_PAIN3", - "S_BLACKEGG_PAIN4", - "S_BLACKEGG_PAIN5", - "S_BLACKEGG_PAIN6", - "S_BLACKEGG_PAIN7", - "S_BLACKEGG_PAIN8", - "S_BLACKEGG_PAIN9", - "S_BLACKEGG_PAIN10", - "S_BLACKEGG_PAIN11", - "S_BLACKEGG_PAIN12", - "S_BLACKEGG_PAIN13", - "S_BLACKEGG_PAIN14", - "S_BLACKEGG_PAIN15", - "S_BLACKEGG_PAIN16", - "S_BLACKEGG_PAIN17", - "S_BLACKEGG_PAIN18", - "S_BLACKEGG_PAIN19", - "S_BLACKEGG_PAIN20", - "S_BLACKEGG_PAIN21", - "S_BLACKEGG_PAIN22", - "S_BLACKEGG_PAIN23", - "S_BLACKEGG_PAIN24", - "S_BLACKEGG_PAIN25", - "S_BLACKEGG_PAIN26", - "S_BLACKEGG_PAIN27", - "S_BLACKEGG_PAIN28", - "S_BLACKEGG_PAIN29", - "S_BLACKEGG_PAIN30", - "S_BLACKEGG_PAIN31", - "S_BLACKEGG_PAIN32", - "S_BLACKEGG_PAIN33", - "S_BLACKEGG_PAIN34", - "S_BLACKEGG_PAIN35", - "S_BLACKEGG_HITFACE1", - "S_BLACKEGG_HITFACE2", - "S_BLACKEGG_HITFACE3", - "S_BLACKEGG_HITFACE4", - "S_BLACKEGG_DIE1", - "S_BLACKEGG_DIE2", - "S_BLACKEGG_DIE3", - "S_BLACKEGG_DIE4", - "S_BLACKEGG_DIE5", - "S_BLACKEGG_MISSILE1", - "S_BLACKEGG_MISSILE2", - "S_BLACKEGG_MISSILE3", - "S_BLACKEGG_GOOP", - "S_BLACKEGG_JUMP1", - "S_BLACKEGG_JUMP2", - "S_BLACKEGG_DESTROYPLAT1", - "S_BLACKEGG_DESTROYPLAT2", - "S_BLACKEGG_DESTROYPLAT3", - - "S_BLACKEGG_HELPER", // Collision helper - - "S_BLACKEGG_GOOP1", - "S_BLACKEGG_GOOP2", - "S_BLACKEGG_GOOP3", - "S_BLACKEGG_GOOP4", - "S_BLACKEGG_GOOP5", - "S_BLACKEGG_GOOP6", - "S_BLACKEGG_GOOP7", - - "S_BLACKEGG_MISSILE", - - // New Very-Last-Minute 2.1 Brak Eggman (Cy-Brak-demon) - "S_CYBRAKDEMON_IDLE", - "S_CYBRAKDEMON_WALK1", - "S_CYBRAKDEMON_WALK2", - "S_CYBRAKDEMON_WALK3", - "S_CYBRAKDEMON_WALK4", - "S_CYBRAKDEMON_WALK5", - "S_CYBRAKDEMON_WALK6", - "S_CYBRAKDEMON_CHOOSE_ATTACK1", - "S_CYBRAKDEMON_MISSILE_ATTACK1", // Aim - "S_CYBRAKDEMON_MISSILE_ATTACK2", // Fire - "S_CYBRAKDEMON_MISSILE_ATTACK3", // Aim - "S_CYBRAKDEMON_MISSILE_ATTACK4", // Fire - "S_CYBRAKDEMON_MISSILE_ATTACK5", // Aim - "S_CYBRAKDEMON_MISSILE_ATTACK6", // Fire - "S_CYBRAKDEMON_FLAME_ATTACK1", // Reset - "S_CYBRAKDEMON_FLAME_ATTACK2", // Aim - "S_CYBRAKDEMON_FLAME_ATTACK3", // Fire - "S_CYBRAKDEMON_FLAME_ATTACK4", // Loop - "S_CYBRAKDEMON_CHOOSE_ATTACK2", - "S_CYBRAKDEMON_VILE_ATTACK1", - "S_CYBRAKDEMON_VILE_ATTACK2", - "S_CYBRAKDEMON_VILE_ATTACK3", - "S_CYBRAKDEMON_VILE_ATTACK4", - "S_CYBRAKDEMON_VILE_ATTACK5", - "S_CYBRAKDEMON_VILE_ATTACK6", - "S_CYBRAKDEMON_NAPALM_ATTACK1", - "S_CYBRAKDEMON_NAPALM_ATTACK2", - "S_CYBRAKDEMON_NAPALM_ATTACK3", - "S_CYBRAKDEMON_FINISH_ATTACK1", // If just attacked, remove MF2_FRET w/out going back to spawnstate - "S_CYBRAKDEMON_FINISH_ATTACK2", // Force a delay between attacks so you don't get bombarded with them back-to-back - "S_CYBRAKDEMON_PAIN1", - "S_CYBRAKDEMON_PAIN2", - "S_CYBRAKDEMON_PAIN3", - "S_CYBRAKDEMON_DIE1", - "S_CYBRAKDEMON_DIE2", - "S_CYBRAKDEMON_DIE3", - "S_CYBRAKDEMON_DIE4", - "S_CYBRAKDEMON_DIE5", - "S_CYBRAKDEMON_DIE6", - "S_CYBRAKDEMON_DIE7", - "S_CYBRAKDEMON_DIE8", - "S_CYBRAKDEMON_DEINVINCIBLERIZE", - "S_CYBRAKDEMON_INVINCIBLERIZE", - - "S_CYBRAKDEMONMISSILE", - "S_CYBRAKDEMONMISSILE_EXPLODE1", - "S_CYBRAKDEMONMISSILE_EXPLODE2", - "S_CYBRAKDEMONMISSILE_EXPLODE3", - - "S_CYBRAKDEMONFLAMESHOT_FLY1", - "S_CYBRAKDEMONFLAMESHOT_FLY2", - "S_CYBRAKDEMONFLAMESHOT_FLY3", - "S_CYBRAKDEMONFLAMESHOT_DIE", - - "S_CYBRAKDEMONFLAMEREST", - - "S_CYBRAKDEMONELECTRICBARRIER_INIT1", - "S_CYBRAKDEMONELECTRICBARRIER_INIT2", - "S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND", - "S_CYBRAKDEMONELECTRICBARRIER1", - "S_CYBRAKDEMONELECTRICBARRIER2", - "S_CYBRAKDEMONELECTRICBARRIER3", - "S_CYBRAKDEMONELECTRICBARRIER4", - "S_CYBRAKDEMONELECTRICBARRIER5", - "S_CYBRAKDEMONELECTRICBARRIER6", - "S_CYBRAKDEMONELECTRICBARRIER7", - "S_CYBRAKDEMONELECTRICBARRIER8", - "S_CYBRAKDEMONELECTRICBARRIER9", - "S_CYBRAKDEMONELECTRICBARRIER10", - "S_CYBRAKDEMONELECTRICBARRIER11", - "S_CYBRAKDEMONELECTRICBARRIER12", - "S_CYBRAKDEMONELECTRICBARRIER13", - "S_CYBRAKDEMONELECTRICBARRIER14", - "S_CYBRAKDEMONELECTRICBARRIER15", - "S_CYBRAKDEMONELECTRICBARRIER16", - "S_CYBRAKDEMONELECTRICBARRIER17", - "S_CYBRAKDEMONELECTRICBARRIER18", - "S_CYBRAKDEMONELECTRICBARRIER19", - "S_CYBRAKDEMONELECTRICBARRIER20", - "S_CYBRAKDEMONELECTRICBARRIER21", - "S_CYBRAKDEMONELECTRICBARRIER22", - "S_CYBRAKDEMONELECTRICBARRIER23", - "S_CYBRAKDEMONELECTRICBARRIER24", - "S_CYBRAKDEMONELECTRICBARRIER_DIE1", - "S_CYBRAKDEMONELECTRICBARRIER_DIE2", - "S_CYBRAKDEMONELECTRICBARRIER_DIE3", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMSUCCESS", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHOOSE", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM1", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM2", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM3", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM4", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM5", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM6", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM7", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM8", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM9", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM10", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM11", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOM12", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMFAIL", - "S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP", - "S_CYBRAKDEMONELECTRICBARRIER_REVIVE1", - "S_CYBRAKDEMONELECTRICBARRIER_REVIVE2", - "S_CYBRAKDEMONELECTRICBARRIER_REVIVE3", - - "S_CYBRAKDEMONTARGETRETICULE1", - "S_CYBRAKDEMONTARGETRETICULE2", - "S_CYBRAKDEMONTARGETRETICULE3", - "S_CYBRAKDEMONTARGETRETICULE4", - "S_CYBRAKDEMONTARGETRETICULE5", - "S_CYBRAKDEMONTARGETRETICULE6", - "S_CYBRAKDEMONTARGETRETICULE7", - "S_CYBRAKDEMONTARGETRETICULE8", - "S_CYBRAKDEMONTARGETRETICULE9", - "S_CYBRAKDEMONTARGETRETICULE10", - "S_CYBRAKDEMONTARGETRETICULE11", - "S_CYBRAKDEMONTARGETRETICULE12", - "S_CYBRAKDEMONTARGETRETICULE13", - "S_CYBRAKDEMONTARGETRETICULE14", - - "S_CYBRAKDEMONTARGETDOT", - - "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1", - "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2", - "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3", - "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4", - "S_CYBRAKDEMONNAPALMBOMBLARGE_DIE1", // Explode - "S_CYBRAKDEMONNAPALMBOMBLARGE_DIE2", // Outer ring - "S_CYBRAKDEMONNAPALMBOMBLARGE_DIE3", // Center - "S_CYBRAKDEMONNAPALMBOMBLARGE_DIE4", // Sound - - "S_CYBRAKDEMONNAPALMBOMBSMALL", - "S_CYBRAKDEMONNAPALMBOMBSMALL_DIE1", // Explode - "S_CYBRAKDEMONNAPALMBOMBSMALL_DIE2", // Outer ring - "S_CYBRAKDEMONNAPALMBOMBSMALL_DIE3", // Inner ring - "S_CYBRAKDEMONNAPALMBOMBSMALL_DIE4", // Center - "S_CYBRAKDEMONNAPALMBOMBSMALL_DIE5", // Sound - - "S_CYBRAKDEMONNAPALMFLAME_FLY1", - "S_CYBRAKDEMONNAPALMFLAME_FLY2", - "S_CYBRAKDEMONNAPALMFLAME_FLY3", - "S_CYBRAKDEMONNAPALMFLAME_FLY4", - "S_CYBRAKDEMONNAPALMFLAME_FLY5", - "S_CYBRAKDEMONNAPALMFLAME_FLY6", - "S_CYBRAKDEMONNAPALMFLAME_DIE", - - "S_CYBRAKDEMONVILEEXPLOSION1", - "S_CYBRAKDEMONVILEEXPLOSION2", - "S_CYBRAKDEMONVILEEXPLOSION3", - - // Metal Sonic (Race) - "S_METALSONIC_RACE", - // Metal Sonic (Battle) - "S_METALSONIC_FLOAT", - "S_METALSONIC_VECTOR", - "S_METALSONIC_STUN", - "S_METALSONIC_RAISE", - "S_METALSONIC_GATHER", - "S_METALSONIC_DASH", - "S_METALSONIC_BOUNCE", - "S_METALSONIC_BADBOUNCE", - "S_METALSONIC_SHOOT", - "S_METALSONIC_PAIN", - "S_METALSONIC_DEATH1", - "S_METALSONIC_DEATH2", - "S_METALSONIC_DEATH3", - "S_METALSONIC_DEATH4", - "S_METALSONIC_FLEE1", - "S_METALSONIC_FLEE2", - - "S_MSSHIELD_F1", - "S_MSSHIELD_F2", - - // Ring - "S_RING", - - // Blue Sphere for special stages - "S_BLUESPHERE", - "S_BLUESPHEREBONUS", - "S_BLUESPHERESPARK", - - // Bomb Sphere - "S_BOMBSPHERE1", - "S_BOMBSPHERE2", - "S_BOMBSPHERE3", - "S_BOMBSPHERE4", - - // NiGHTS Chip - "S_NIGHTSCHIP", - "S_NIGHTSCHIPBONUS", - - // NiGHTS Star - "S_NIGHTSSTAR", - "S_NIGHTSSTARXMAS", - - // Gravity Wells for special stages - "S_GRAVWELLGREEN", - "S_GRAVWELLRED", - - // Individual Team Rings - "S_TEAMRING", - - // Special Stage Token - "S_TOKEN", - - // CTF Flags - "S_REDFLAG", - "S_BLUEFLAG", - - // Emblem - "S_EMBLEM1", - "S_EMBLEM2", - "S_EMBLEM3", - "S_EMBLEM4", - "S_EMBLEM5", - "S_EMBLEM6", - "S_EMBLEM7", - "S_EMBLEM8", - "S_EMBLEM9", - "S_EMBLEM10", - "S_EMBLEM11", - "S_EMBLEM12", - "S_EMBLEM13", - "S_EMBLEM14", - "S_EMBLEM15", - "S_EMBLEM16", - "S_EMBLEM17", - "S_EMBLEM18", - "S_EMBLEM19", - "S_EMBLEM20", - "S_EMBLEM21", - "S_EMBLEM22", - "S_EMBLEM23", - "S_EMBLEM24", - "S_EMBLEM25", - "S_EMBLEM26", - - // Chaos Emeralds - "S_CEMG1", - "S_CEMG2", - "S_CEMG3", - "S_CEMG4", - "S_CEMG5", - "S_CEMG6", - "S_CEMG7", - - // Emerald hunt shards - "S_SHRD1", - "S_SHRD2", - "S_SHRD3", - - // Bubble Source - "S_BUBBLES1", - "S_BUBBLES2", - "S_BUBBLES3", - "S_BUBBLES4", - - // Level End Sign - "S_SIGN", - "S_SIGNSPIN1", - "S_SIGNSPIN2", - "S_SIGNSPIN3", - "S_SIGNSPIN4", - "S_SIGNSPIN5", - "S_SIGNSPIN6", - "S_SIGNPLAYER", - "S_SIGNSLOW", - "S_SIGNSTOP", - "S_SIGNBOARD", - "S_EGGMANSIGN", - "S_CLEARSIGN", - - // Spike Ball - "S_SPIKEBALL1", - "S_SPIKEBALL2", - "S_SPIKEBALL3", - "S_SPIKEBALL4", - "S_SPIKEBALL5", - "S_SPIKEBALL6", - "S_SPIKEBALL7", - "S_SPIKEBALL8", - - // Elemental Shield's Spawn - "S_SPINFIRE1", - "S_SPINFIRE2", - "S_SPINFIRE3", - "S_SPINFIRE4", - "S_SPINFIRE5", - "S_SPINFIRE6", - - // Spikes - "S_SPIKE1", - "S_SPIKE2", - "S_SPIKE3", - "S_SPIKE4", - "S_SPIKE5", - "S_SPIKE6", - "S_SPIKED1", - "S_SPIKED2", - - // Wall spikes - "S_WALLSPIKE1", - "S_WALLSPIKE2", - "S_WALLSPIKE3", - "S_WALLSPIKE4", - "S_WALLSPIKE5", - "S_WALLSPIKE6", - "S_WALLSPIKEBASE", - "S_WALLSPIKED1", - "S_WALLSPIKED2", - - // Starpost - "S_STARPOST_IDLE", - "S_STARPOST_FLASH", - "S_STARPOST_STARTSPIN", - "S_STARPOST_SPIN", - "S_STARPOST_ENDSPIN", - - // Big floating mine - "S_BIGMINE_IDLE", - "S_BIGMINE_ALERT1", - "S_BIGMINE_ALERT2", - "S_BIGMINE_ALERT3", - "S_BIGMINE_SET1", - "S_BIGMINE_SET2", - "S_BIGMINE_SET3", - "S_BIGMINE_BLAST1", - "S_BIGMINE_BLAST2", - "S_BIGMINE_BLAST3", - "S_BIGMINE_BLAST4", - "S_BIGMINE_BLAST5", - - // Cannon Launcher - "S_CANNONLAUNCHER1", - "S_CANNONLAUNCHER2", - "S_CANNONLAUNCHER3", - - // Monitor Miscellany - "S_BOXSPARKLE1", - "S_BOXSPARKLE2", - "S_BOXSPARKLE3", - "S_BOXSPARKLE4", - - "S_BOX_FLICKER", - "S_BOX_POP1", - "S_BOX_POP2", - - "S_GOLDBOX_FLICKER", - "S_GOLDBOX_OFF1", - "S_GOLDBOX_OFF2", - "S_GOLDBOX_OFF3", - "S_GOLDBOX_OFF4", - "S_GOLDBOX_OFF5", - "S_GOLDBOX_OFF6", - "S_GOLDBOX_OFF7", - - // Monitor States (one per box) - "S_MYSTERY_BOX", - "S_RING_BOX", - "S_PITY_BOX", - "S_ATTRACT_BOX", - "S_FORCE_BOX", - "S_ARMAGEDDON_BOX", - "S_WHIRLWIND_BOX", - "S_ELEMENTAL_BOX", - "S_SNEAKERS_BOX", - "S_INVULN_BOX", - "S_1UP_BOX", - "S_EGGMAN_BOX", - "S_MIXUP_BOX", - "S_GRAVITY_BOX", - "S_RECYCLER_BOX", - "S_SCORE1K_BOX", - "S_SCORE10K_BOX", - "S_FLAMEAURA_BOX", - "S_BUBBLEWRAP_BOX", - "S_THUNDERCOIN_BOX", - - // Gold Repeat Monitor States (one per box) - "S_PITY_GOLDBOX", - "S_ATTRACT_GOLDBOX", - "S_FORCE_GOLDBOX", - "S_ARMAGEDDON_GOLDBOX", - "S_WHIRLWIND_GOLDBOX", - "S_ELEMENTAL_GOLDBOX", - "S_SNEAKERS_GOLDBOX", - "S_INVULN_GOLDBOX", - "S_EGGMAN_GOLDBOX", - "S_GRAVITY_GOLDBOX", - "S_FLAMEAURA_GOLDBOX", - "S_BUBBLEWRAP_GOLDBOX", - "S_THUNDERCOIN_GOLDBOX", - - // Team Ring Boxes (these are special) - "S_RING_REDBOX1", - "S_RING_REDBOX2", - "S_REDBOX_POP1", - "S_REDBOX_POP2", - - "S_RING_BLUEBOX1", - "S_RING_BLUEBOX2", - "S_BLUEBOX_POP1", - "S_BLUEBOX_POP2", - - // Box Icons -- 2 states each, animation and action - "S_RING_ICON1", - "S_RING_ICON2", - - "S_PITY_ICON1", - "S_PITY_ICON2", - - "S_ATTRACT_ICON1", - "S_ATTRACT_ICON2", - - "S_FORCE_ICON1", - "S_FORCE_ICON2", - - "S_ARMAGEDDON_ICON1", - "S_ARMAGEDDON_ICON2", - - "S_WHIRLWIND_ICON1", - "S_WHIRLWIND_ICON2", - - "S_ELEMENTAL_ICON1", - "S_ELEMENTAL_ICON2", - - "S_SNEAKERS_ICON1", - "S_SNEAKERS_ICON2", - - "S_INVULN_ICON1", - "S_INVULN_ICON2", - - "S_1UP_ICON1", - "S_1UP_ICON2", - - "S_EGGMAN_ICON1", - "S_EGGMAN_ICON2", - - "S_MIXUP_ICON1", - "S_MIXUP_ICON2", - - "S_GRAVITY_ICON1", - "S_GRAVITY_ICON2", - - "S_RECYCLER_ICON1", - "S_RECYCLER_ICON2", - - "S_SCORE1K_ICON1", - "S_SCORE1K_ICON2", - - "S_SCORE10K_ICON1", - "S_SCORE10K_ICON2", - - "S_FLAMEAURA_ICON1", - "S_FLAMEAURA_ICON2", - - "S_BUBBLEWRAP_ICON1", - "S_BUBBLEWRAP_ICON2", - - "S_THUNDERCOIN_ICON1", - "S_THUNDERCOIN_ICON2", - - // --- - - "S_ROCKET", - - "S_LASER", - "S_LASER2", - "S_LASERFLASH", - - "S_LASERFLAME1", - "S_LASERFLAME2", - "S_LASERFLAME3", - "S_LASERFLAME4", - "S_LASERFLAME5", - - "S_TORPEDO", - - "S_ENERGYBALL1", - "S_ENERGYBALL2", - - // Skim Mine, also used by Jetty-Syn bomber - "S_MINE1", - "S_MINE_BOOM1", - "S_MINE_BOOM2", - "S_MINE_BOOM3", - "S_MINE_BOOM4", - - // Jetty-Syn Bullet - "S_JETBULLET1", - "S_JETBULLET2", - - "S_TURRETLASER", - "S_TURRETLASEREXPLODE1", - "S_TURRETLASEREXPLODE2", - - // Cannonball - "S_CANNONBALL1", - - // Arrow - "S_ARROW", - "S_ARROWBONK", - - // Glaregoyle Demon fire - "S_DEMONFIRE", - - // The letter - "S_LETTER", - - // GFZ flowers - "S_GFZFLOWERA", - "S_GFZFLOWERB", - "S_GFZFLOWERC", - - "S_BLUEBERRYBUSH", - "S_BERRYBUSH", - "S_BUSH", - - // Trees (both GFZ and misc) - "S_GFZTREE", - "S_GFZBERRYTREE", - "S_GFZCHERRYTREE", - "S_CHECKERTREE", - "S_CHECKERSUNSETTREE", - "S_FHZTREE", // Frozen Hillside - "S_FHZPINKTREE", - "S_POLYGONTREE", - "S_BUSHTREE", - "S_BUSHREDTREE", - "S_SPRINGTREE", - - // THZ flowers - "S_THZFLOWERA", // THZ1 Steam flower - "S_THZFLOWERB", // THZ1 Spin flower (red) - "S_THZFLOWERC", // THZ1 Spin flower (yellow) - - // THZ Steam Whistle tree/bush - "S_THZTREE", - "S_THZTREEBRANCH1", - "S_THZTREEBRANCH2", - "S_THZTREEBRANCH3", - "S_THZTREEBRANCH4", - "S_THZTREEBRANCH5", - "S_THZTREEBRANCH6", - "S_THZTREEBRANCH7", - "S_THZTREEBRANCH8", - "S_THZTREEBRANCH9", - "S_THZTREEBRANCH10", - "S_THZTREEBRANCH11", - "S_THZTREEBRANCH12", - "S_THZTREEBRANCH13", - - // THZ Alarm - "S_ALARM1", - - // Deep Sea Gargoyle - "S_GARGOYLE", - "S_BIGGARGOYLE", - - // DSZ Seaweed - "S_SEAWEED1", - "S_SEAWEED2", - "S_SEAWEED3", - "S_SEAWEED4", - "S_SEAWEED5", - "S_SEAWEED6", - - // Dripping Water - "S_DRIPA1", - "S_DRIPA2", - "S_DRIPA3", - "S_DRIPA4", - "S_DRIPB1", - "S_DRIPC1", - "S_DRIPC2", - - // Coral - "S_CORAL1", - "S_CORAL2", - "S_CORAL3", - "S_CORAL4", - "S_CORAL5", - - // Blue Crystal - "S_BLUECRYSTAL1", - - // Kelp, - "S_KELP", - - // Animated algae - "S_ANIMALGAETOP1", - "S_ANIMALGAETOP2", - "S_ANIMALGAESEG", - - // DSZ Stalagmites - "S_DSZSTALAGMITE", - "S_DSZ2STALAGMITE", - - // DSZ Light beam - "S_LIGHTBEAM1", - "S_LIGHTBEAM2", - "S_LIGHTBEAM3", - "S_LIGHTBEAM4", - "S_LIGHTBEAM5", - "S_LIGHTBEAM6", - "S_LIGHTBEAM7", - "S_LIGHTBEAM8", - "S_LIGHTBEAM9", - "S_LIGHTBEAM10", - "S_LIGHTBEAM11", - "S_LIGHTBEAM12", - - // CEZ Chain - "S_CEZCHAIN", - - // Flame - "S_FLAME", - "S_FLAMEPARTICLE", - "S_FLAMEREST", - - // Eggman Statue - "S_EGGSTATUE1", - - // CEZ hidden sling - "S_SLING1", - "S_SLING2", - - // CEZ maces and chains - "S_SMALLMACECHAIN", - "S_BIGMACECHAIN", - "S_SMALLMACE", - "S_BIGMACE", - "S_SMALLGRABCHAIN", - "S_BIGGRABCHAIN", - - // Yellow spring on a ball - "S_YELLOWSPRINGBALL", - "S_YELLOWSPRINGBALL2", - "S_YELLOWSPRINGBALL3", - "S_YELLOWSPRINGBALL4", - "S_YELLOWSPRINGBALL5", - - // Red spring on a ball - "S_REDSPRINGBALL", - "S_REDSPRINGBALL2", - "S_REDSPRINGBALL3", - "S_REDSPRINGBALL4", - "S_REDSPRINGBALL5", - - // Small Firebar - "S_SMALLFIREBAR1", - "S_SMALLFIREBAR2", - "S_SMALLFIREBAR3", - "S_SMALLFIREBAR4", - "S_SMALLFIREBAR5", - "S_SMALLFIREBAR6", - "S_SMALLFIREBAR7", - "S_SMALLFIREBAR8", - "S_SMALLFIREBAR9", - "S_SMALLFIREBAR10", - "S_SMALLFIREBAR11", - "S_SMALLFIREBAR12", - "S_SMALLFIREBAR13", - "S_SMALLFIREBAR14", - "S_SMALLFIREBAR15", - "S_SMALLFIREBAR16", - - // Big Firebar - "S_BIGFIREBAR1", - "S_BIGFIREBAR2", - "S_BIGFIREBAR3", - "S_BIGFIREBAR4", - "S_BIGFIREBAR5", - "S_BIGFIREBAR6", - "S_BIGFIREBAR7", - "S_BIGFIREBAR8", - "S_BIGFIREBAR9", - "S_BIGFIREBAR10", - "S_BIGFIREBAR11", - "S_BIGFIREBAR12", - "S_BIGFIREBAR13", - "S_BIGFIREBAR14", - "S_BIGFIREBAR15", - "S_BIGFIREBAR16", - - "S_CEZFLOWER", - "S_CEZPOLE", - "S_CEZBANNER1", - "S_CEZBANNER2", - "S_PINETREE", - "S_CEZBUSH1", - "S_CEZBUSH2", - "S_CANDLE", - "S_CANDLEPRICKET", - "S_FLAMEHOLDER", - "S_FIRETORCH", - "S_WAVINGFLAG", - "S_WAVINGFLAGSEG1", - "S_WAVINGFLAGSEG2", - "S_CRAWLASTATUE", - "S_FACESTABBERSTATUE", - "S_SUSPICIOUSFACESTABBERSTATUE_WAIT", - "S_SUSPICIOUSFACESTABBERSTATUE_BURST1", - "S_SUSPICIOUSFACESTABBERSTATUE_BURST2", - "S_BRAMBLES", - - // Big Tumbleweed - "S_BIGTUMBLEWEED", - "S_BIGTUMBLEWEED_ROLL1", - "S_BIGTUMBLEWEED_ROLL2", - "S_BIGTUMBLEWEED_ROLL3", - "S_BIGTUMBLEWEED_ROLL4", - "S_BIGTUMBLEWEED_ROLL5", - "S_BIGTUMBLEWEED_ROLL6", - "S_BIGTUMBLEWEED_ROLL7", - "S_BIGTUMBLEWEED_ROLL8", - - // Little Tumbleweed - "S_LITTLETUMBLEWEED", - "S_LITTLETUMBLEWEED_ROLL1", - "S_LITTLETUMBLEWEED_ROLL2", - "S_LITTLETUMBLEWEED_ROLL3", - "S_LITTLETUMBLEWEED_ROLL4", - "S_LITTLETUMBLEWEED_ROLL5", - "S_LITTLETUMBLEWEED_ROLL6", - "S_LITTLETUMBLEWEED_ROLL7", - "S_LITTLETUMBLEWEED_ROLL8", - - // Cacti - "S_CACTI1", - "S_CACTI2", - "S_CACTI3", - "S_CACTI4", - "S_CACTI5", - "S_CACTI6", - "S_CACTI7", - "S_CACTI8", - "S_CACTI9", - "S_CACTI10", - "S_CACTI11", - "S_CACTITINYSEG", - "S_CACTISMALLSEG", - - // Warning signs - "S_ARIDSIGN_CAUTION", - "S_ARIDSIGN_CACTI", - "S_ARIDSIGN_SHARPTURN", - - // Oil lamp - "S_OILLAMP", - "S_OILLAMPFLARE", - - // TNT barrel - "S_TNTBARREL_STND1", - "S_TNTBARREL_EXPL1", - "S_TNTBARREL_EXPL2", - "S_TNTBARREL_EXPL3", - "S_TNTBARREL_EXPL4", - "S_TNTBARREL_EXPL5", - "S_TNTBARREL_EXPL6", - "S_TNTBARREL_EXPL7", - "S_TNTBARREL_FLYING", - - // TNT proximity shell - "S_PROXIMITY_TNT", - "S_PROXIMITY_TNT_TRIGGER1", - "S_PROXIMITY_TNT_TRIGGER2", - "S_PROXIMITY_TNT_TRIGGER3", - "S_PROXIMITY_TNT_TRIGGER4", - "S_PROXIMITY_TNT_TRIGGER5", - "S_PROXIMITY_TNT_TRIGGER6", - "S_PROXIMITY_TNT_TRIGGER7", - "S_PROXIMITY_TNT_TRIGGER8", - "S_PROXIMITY_TNT_TRIGGER9", - "S_PROXIMITY_TNT_TRIGGER10", - "S_PROXIMITY_TNT_TRIGGER11", - "S_PROXIMITY_TNT_TRIGGER12", - "S_PROXIMITY_TNT_TRIGGER13", - "S_PROXIMITY_TNT_TRIGGER14", - "S_PROXIMITY_TNT_TRIGGER15", - "S_PROXIMITY_TNT_TRIGGER16", - "S_PROXIMITY_TNT_TRIGGER17", - "S_PROXIMITY_TNT_TRIGGER18", - "S_PROXIMITY_TNT_TRIGGER19", - "S_PROXIMITY_TNT_TRIGGER20", - "S_PROXIMITY_TNT_TRIGGER21", - "S_PROXIMITY_TNT_TRIGGER22", - "S_PROXIMITY_TNT_TRIGGER23", - - // Dust devil - "S_DUSTDEVIL", - "S_DUSTLAYER1", - "S_DUSTLAYER2", - "S_DUSTLAYER3", - "S_DUSTLAYER4", - "S_DUSTLAYER5", - "S_ARIDDUST1", - "S_ARIDDUST2", - "S_ARIDDUST3", - - // Minecart - "S_MINECART_IDLE", - "S_MINECART_DTH1", - "S_MINECARTEND", - "S_MINECARTSEG_FRONT", - "S_MINECARTSEG_BACK", - "S_MINECARTSEG_LEFT", - "S_MINECARTSEG_RIGHT", - "S_MINECARTSIDEMARK1", - "S_MINECARTSIDEMARK2", - "S_MINECARTSPARK", - - // Saloon door - "S_SALOONDOOR", - "S_SALOONDOORCENTER", - - // Train cameo - "S_TRAINCAMEOSPAWNER_1", - "S_TRAINCAMEOSPAWNER_2", - "S_TRAINCAMEOSPAWNER_3", - "S_TRAINCAMEOSPAWNER_4", - "S_TRAINCAMEOSPAWNER_5", - "S_TRAINPUFFMAKER", - - // Train - "S_TRAINDUST", - "S_TRAINSTEAM", - - // Flame jet - "S_FLAMEJETSTND", - "S_FLAMEJETSTART", - "S_FLAMEJETSTOP", - "S_FLAMEJETFLAME1", - "S_FLAMEJETFLAME2", - "S_FLAMEJETFLAME3", - "S_FLAMEJETFLAME4", - "S_FLAMEJETFLAME5", - "S_FLAMEJETFLAME6", - "S_FLAMEJETFLAME7", - "S_FLAMEJETFLAME8", - "S_FLAMEJETFLAME9", - - // Spinning flame jets - "S_FJSPINAXISA1", // Counter-clockwise - "S_FJSPINAXISA2", - "S_FJSPINAXISB1", // Clockwise - "S_FJSPINAXISB2", - - // Blade's flame - "S_FLAMEJETFLAMEB1", - "S_FLAMEJETFLAMEB2", - "S_FLAMEJETFLAMEB3", - - // Lavafall - "S_LAVAFALL_DORMANT", - "S_LAVAFALL_TELL", - "S_LAVAFALL_SHOOT", - "S_LAVAFALL_LAVA1", - "S_LAVAFALL_LAVA2", - "S_LAVAFALL_LAVA3", - "S_LAVAFALLROCK", - - // Rollout Rock - "S_ROLLOUTSPAWN", - "S_ROLLOUTROCK", - - // RVZ scenery - "S_BIGFERNLEAF", - "S_BIGFERN1", - "S_BIGFERN2", - "S_JUNGLEPALM", - "S_TORCHFLOWER", - "S_WALLVINE_LONG", - "S_WALLVINE_SHORT", - - // Glaregoyles - "S_GLAREGOYLE", - "S_GLAREGOYLE_CHARGE", - "S_GLAREGOYLE_BLINK", - "S_GLAREGOYLE_HOLD", - "S_GLAREGOYLE_FIRE", - "S_GLAREGOYLE_LOOP", - "S_GLAREGOYLE_COOLDOWN", - "S_GLAREGOYLEUP", - "S_GLAREGOYLEUP_CHARGE", - "S_GLAREGOYLEUP_BLINK", - "S_GLAREGOYLEUP_HOLD", - "S_GLAREGOYLEUP_FIRE", - "S_GLAREGOYLEUP_LOOP", - "S_GLAREGOYLEUP_COOLDOWN", - "S_GLAREGOYLEDOWN", - "S_GLAREGOYLEDOWN_CHARGE", - "S_GLAREGOYLEDOWN_BLINK", - "S_GLAREGOYLEDOWN_HOLD", - "S_GLAREGOYLEDOWN_FIRE", - "S_GLAREGOYLEDOWN_LOOP", - "S_GLAREGOYLEDOWN_COOLDOWN", - "S_GLAREGOYLELONG", - "S_GLAREGOYLELONG_CHARGE", - "S_GLAREGOYLELONG_BLINK", - "S_GLAREGOYLELONG_HOLD", - "S_GLAREGOYLELONG_FIRE", - "S_GLAREGOYLELONG_LOOP", - "S_GLAREGOYLELONG_COOLDOWN", - - // ATZ's Red Crystal/Target - "S_TARGET_IDLE", - "S_TARGET_HIT1", - "S_TARGET_HIT2", - "S_TARGET_RESPAWN", - "S_TARGET_ALLDONE", - - // ATZ's green flame - "S_GREENFLAME", - - // ATZ Blue Gargoyle - "S_BLUEGARGOYLE", - - // Stalagmites - "S_STG0", - "S_STG1", - "S_STG2", - "S_STG3", - "S_STG4", - "S_STG5", - "S_STG6", - "S_STG7", - "S_STG8", - "S_STG9", - - // Xmas-specific stuff - "S_XMASPOLE", - "S_CANDYCANE", - "S_SNOWMAN", // normal - "S_SNOWMANHAT", // with hat + scarf - "S_LAMPPOST1", // normal - "S_LAMPPOST2", // with snow - "S_HANGSTAR", - "S_MISTLETOE", - // Xmas GFZ bushes - "S_XMASBLUEBERRYBUSH", - "S_XMASBERRYBUSH", - "S_XMASBUSH", - // FHZ - "S_FHZICE1", - "S_FHZICE2", - "S_ROSY_IDLE1", - "S_ROSY_IDLE2", - "S_ROSY_IDLE3", - "S_ROSY_IDLE4", - "S_ROSY_JUMP", - "S_ROSY_WALK", - "S_ROSY_HUG", - "S_ROSY_PAIN", - "S_ROSY_STND", - "S_ROSY_UNHAPPY", - - // Halloween Scenery - // Pumpkins - "S_JACKO1", - "S_JACKO1OVERLAY_1", - "S_JACKO1OVERLAY_2", - "S_JACKO1OVERLAY_3", - "S_JACKO1OVERLAY_4", - "S_JACKO2", - "S_JACKO2OVERLAY_1", - "S_JACKO2OVERLAY_2", - "S_JACKO2OVERLAY_3", - "S_JACKO2OVERLAY_4", - "S_JACKO3", - "S_JACKO3OVERLAY_1", - "S_JACKO3OVERLAY_2", - "S_JACKO3OVERLAY_3", - "S_JACKO3OVERLAY_4", - // Dr Seuss Trees - "S_HHZTREE_TOP", - "S_HHZTREE_TRUNK", - "S_HHZTREE_LEAF", - // Mushroom - "S_HHZSHROOM_1", - "S_HHZSHROOM_2", - "S_HHZSHROOM_3", - "S_HHZSHROOM_4", - "S_HHZSHROOM_5", - "S_HHZSHROOM_6", - "S_HHZSHROOM_7", - "S_HHZSHROOM_8", - "S_HHZSHROOM_9", - "S_HHZSHROOM_10", - "S_HHZSHROOM_11", - "S_HHZSHROOM_12", - "S_HHZSHROOM_13", - "S_HHZSHROOM_14", - "S_HHZSHROOM_15", - "S_HHZSHROOM_16", - // Misc - "S_HHZGRASS", - "S_HHZTENT1", - "S_HHZTENT2", - "S_HHZSTALAGMITE_TALL", - "S_HHZSTALAGMITE_SHORT", - - // Botanic Serenity's loads of scenery states - "S_BSZTALLFLOWER_RED", - "S_BSZTALLFLOWER_PURPLE", - "S_BSZTALLFLOWER_BLUE", - "S_BSZTALLFLOWER_CYAN", - "S_BSZTALLFLOWER_YELLOW", - "S_BSZTALLFLOWER_ORANGE", - "S_BSZFLOWER_RED", - "S_BSZFLOWER_PURPLE", - "S_BSZFLOWER_BLUE", - "S_BSZFLOWER_CYAN", - "S_BSZFLOWER_YELLOW", - "S_BSZFLOWER_ORANGE", - "S_BSZSHORTFLOWER_RED", - "S_BSZSHORTFLOWER_PURPLE", - "S_BSZSHORTFLOWER_BLUE", - "S_BSZSHORTFLOWER_CYAN", - "S_BSZSHORTFLOWER_YELLOW", - "S_BSZSHORTFLOWER_ORANGE", - "S_BSZTULIP_RED", - "S_BSZTULIP_PURPLE", - "S_BSZTULIP_BLUE", - "S_BSZTULIP_CYAN", - "S_BSZTULIP_YELLOW", - "S_BSZTULIP_ORANGE", - "S_BSZCLUSTER_RED", - "S_BSZCLUSTER_PURPLE", - "S_BSZCLUSTER_BLUE", - "S_BSZCLUSTER_CYAN", - "S_BSZCLUSTER_YELLOW", - "S_BSZCLUSTER_ORANGE", - "S_BSZBUSH_RED", - "S_BSZBUSH_PURPLE", - "S_BSZBUSH_BLUE", - "S_BSZBUSH_CYAN", - "S_BSZBUSH_YELLOW", - "S_BSZBUSH_ORANGE", - "S_BSZVINE_RED", - "S_BSZVINE_PURPLE", - "S_BSZVINE_BLUE", - "S_BSZVINE_CYAN", - "S_BSZVINE_YELLOW", - "S_BSZVINE_ORANGE", - "S_BSZSHRUB", - "S_BSZCLOVER", - "S_BIG_PALMTREE_TRUNK", - "S_BIG_PALMTREE_TOP", - "S_PALMTREE_TRUNK", - "S_PALMTREE_TOP", - - "S_DBALL1", - "S_DBALL2", - "S_DBALL3", - "S_DBALL4", - "S_DBALL5", - "S_DBALL6", - "S_EGGSTATUE2", - - // Shield Orb - "S_ARMA1", - "S_ARMA2", - "S_ARMA3", - "S_ARMA4", - "S_ARMA5", - "S_ARMA6", - "S_ARMA7", - "S_ARMA8", - "S_ARMA9", - "S_ARMA10", - "S_ARMA11", - "S_ARMA12", - "S_ARMA13", - "S_ARMA14", - "S_ARMA15", - "S_ARMA16", - - "S_ARMF1", - "S_ARMF2", - "S_ARMF3", - "S_ARMF4", - "S_ARMF5", - "S_ARMF6", - "S_ARMF7", - "S_ARMF8", - "S_ARMF9", - "S_ARMF10", - "S_ARMF11", - "S_ARMF12", - "S_ARMF13", - "S_ARMF14", - "S_ARMF15", - "S_ARMF16", - "S_ARMF17", - "S_ARMF18", - "S_ARMF19", - "S_ARMF20", - "S_ARMF21", - "S_ARMF22", - "S_ARMF23", - "S_ARMF24", - "S_ARMF25", - "S_ARMF26", - "S_ARMF27", - "S_ARMF28", - "S_ARMF29", - "S_ARMF30", - "S_ARMF31", - "S_ARMF32", - - "S_ARMB1", - "S_ARMB2", - "S_ARMB3", - "S_ARMB4", - "S_ARMB5", - "S_ARMB6", - "S_ARMB7", - "S_ARMB8", - "S_ARMB9", - "S_ARMB10", - "S_ARMB11", - "S_ARMB12", - "S_ARMB13", - "S_ARMB14", - "S_ARMB15", - "S_ARMB16", - "S_ARMB17", - "S_ARMB18", - "S_ARMB19", - "S_ARMB20", - "S_ARMB21", - "S_ARMB22", - "S_ARMB23", - "S_ARMB24", - "S_ARMB25", - "S_ARMB26", - "S_ARMB27", - "S_ARMB28", - "S_ARMB29", - "S_ARMB30", - "S_ARMB31", - "S_ARMB32", - - "S_WIND1", - "S_WIND2", - "S_WIND3", - "S_WIND4", - "S_WIND5", - "S_WIND6", - "S_WIND7", - "S_WIND8", - - "S_MAGN1", - "S_MAGN2", - "S_MAGN3", - "S_MAGN4", - "S_MAGN5", - "S_MAGN6", - "S_MAGN7", - "S_MAGN8", - "S_MAGN9", - "S_MAGN10", - "S_MAGN11", - "S_MAGN12", - "S_MAGN13", - - "S_FORC1", - "S_FORC2", - "S_FORC3", - "S_FORC4", - "S_FORC5", - "S_FORC6", - "S_FORC7", - "S_FORC8", - "S_FORC9", - "S_FORC10", - - "S_FORC11", - "S_FORC12", - "S_FORC13", - "S_FORC14", - "S_FORC15", - "S_FORC16", - "S_FORC17", - "S_FORC18", - "S_FORC19", - "S_FORC20", - - "S_FORC21", - - "S_ELEM1", - "S_ELEM2", - "S_ELEM3", - "S_ELEM4", - "S_ELEM5", - "S_ELEM6", - "S_ELEM7", - "S_ELEM8", - "S_ELEM9", - "S_ELEM10", - "S_ELEM11", - "S_ELEM12", - - "S_ELEM13", - "S_ELEM14", - - "S_ELEMF1", - "S_ELEMF2", - "S_ELEMF3", - "S_ELEMF4", - "S_ELEMF5", - "S_ELEMF6", - "S_ELEMF7", - "S_ELEMF8", - "S_ELEMF9", - "S_ELEMF10", - - "S_PITY1", - "S_PITY2", - "S_PITY3", - "S_PITY4", - "S_PITY5", - "S_PITY6", - "S_PITY7", - "S_PITY8", - "S_PITY9", - "S_PITY10", - "S_PITY11", - "S_PITY12", - - "S_FIRS1", - "S_FIRS2", - "S_FIRS3", - "S_FIRS4", - "S_FIRS5", - "S_FIRS6", - "S_FIRS7", - "S_FIRS8", - "S_FIRS9", - - "S_FIRS10", - "S_FIRS11", - - "S_FIRSB1", - "S_FIRSB2", - "S_FIRSB3", - "S_FIRSB4", - "S_FIRSB5", - "S_FIRSB6", - "S_FIRSB7", - "S_FIRSB8", - "S_FIRSB9", - - "S_FIRSB10", - - "S_BUBS1", - "S_BUBS2", - "S_BUBS3", - "S_BUBS4", - "S_BUBS5", - "S_BUBS6", - "S_BUBS7", - "S_BUBS8", - "S_BUBS9", - - "S_BUBS10", - "S_BUBS11", - - "S_BUBSB1", - "S_BUBSB2", - "S_BUBSB3", - "S_BUBSB4", - - "S_BUBSB5", - "S_BUBSB6", - - "S_ZAPS1", - "S_ZAPS2", - "S_ZAPS3", - "S_ZAPS4", - "S_ZAPS5", - "S_ZAPS6", - "S_ZAPS7", - "S_ZAPS8", - "S_ZAPS9", - "S_ZAPS10", - "S_ZAPS11", - "S_ZAPS12", - "S_ZAPS13", // blank frame - "S_ZAPS14", - "S_ZAPS15", - "S_ZAPS16", - - "S_ZAPSB1", // blank frame - "S_ZAPSB2", - "S_ZAPSB3", - "S_ZAPSB4", - "S_ZAPSB5", - "S_ZAPSB6", - "S_ZAPSB7", - "S_ZAPSB8", - "S_ZAPSB9", - "S_ZAPSB10", - "S_ZAPSB11", // blank frame - - //Thunder spark - "S_THUNDERCOIN_SPARK", - - // Invincibility Sparkles - "S_IVSP", - - // Super Sonic Spark - "S_SSPK1", - "S_SSPK2", - "S_SSPK3", - "S_SSPK4", - "S_SSPK5", - - // Flicky-sized bubble - "S_FLICKY_BUBBLE", - - // Bluebird - "S_FLICKY_01_OUT", - "S_FLICKY_01_FLAP1", - "S_FLICKY_01_FLAP2", - "S_FLICKY_01_FLAP3", - "S_FLICKY_01_STAND", - "S_FLICKY_01_CENTER", - - // Rabbit - "S_FLICKY_02_OUT", - "S_FLICKY_02_AIM", - "S_FLICKY_02_HOP", - "S_FLICKY_02_UP", - "S_FLICKY_02_DOWN", - "S_FLICKY_02_STAND", - "S_FLICKY_02_CENTER", - - // Chicken - "S_FLICKY_03_OUT", - "S_FLICKY_03_AIM", - "S_FLICKY_03_HOP", - "S_FLICKY_03_UP", - "S_FLICKY_03_FLAP1", - "S_FLICKY_03_FLAP2", - "S_FLICKY_03_STAND", - "S_FLICKY_03_CENTER", - - // Seal - "S_FLICKY_04_OUT", - "S_FLICKY_04_AIM", - "S_FLICKY_04_HOP", - "S_FLICKY_04_UP", - "S_FLICKY_04_DOWN", - "S_FLICKY_04_SWIM1", - "S_FLICKY_04_SWIM2", - "S_FLICKY_04_SWIM3", - "S_FLICKY_04_SWIM4", - "S_FLICKY_04_STAND", - "S_FLICKY_04_CENTER", - - // Pig - "S_FLICKY_05_OUT", - "S_FLICKY_05_AIM", - "S_FLICKY_05_HOP", - "S_FLICKY_05_UP", - "S_FLICKY_05_DOWN", - "S_FLICKY_05_STAND", - "S_FLICKY_05_CENTER", - - // Chipmunk - "S_FLICKY_06_OUT", - "S_FLICKY_06_AIM", - "S_FLICKY_06_HOP", - "S_FLICKY_06_UP", - "S_FLICKY_06_DOWN", - "S_FLICKY_06_STAND", - "S_FLICKY_06_CENTER", - - // Penguin - "S_FLICKY_07_OUT", - "S_FLICKY_07_AIML", - "S_FLICKY_07_HOPL", - "S_FLICKY_07_UPL", - "S_FLICKY_07_DOWNL", - "S_FLICKY_07_AIMR", - "S_FLICKY_07_HOPR", - "S_FLICKY_07_UPR", - "S_FLICKY_07_DOWNR", - "S_FLICKY_07_SWIM1", - "S_FLICKY_07_SWIM2", - "S_FLICKY_07_SWIM3", - "S_FLICKY_07_STAND", - "S_FLICKY_07_CENTER", - - // Fish - "S_FLICKY_08_OUT", - "S_FLICKY_08_AIM", - "S_FLICKY_08_HOP", - "S_FLICKY_08_FLAP1", - "S_FLICKY_08_FLAP2", - "S_FLICKY_08_FLAP3", - "S_FLICKY_08_FLAP4", - "S_FLICKY_08_SWIM1", - "S_FLICKY_08_SWIM2", - "S_FLICKY_08_SWIM3", - "S_FLICKY_08_SWIM4", - "S_FLICKY_08_STAND", - "S_FLICKY_08_CENTER", - - // Ram - "S_FLICKY_09_OUT", - "S_FLICKY_09_AIM", - "S_FLICKY_09_HOP", - "S_FLICKY_09_UP", - "S_FLICKY_09_DOWN", - "S_FLICKY_09_STAND", - "S_FLICKY_09_CENTER", - - // Puffin - "S_FLICKY_10_OUT", - "S_FLICKY_10_FLAP1", - "S_FLICKY_10_FLAP2", - "S_FLICKY_10_STAND", - "S_FLICKY_10_CENTER", - - // Cow - "S_FLICKY_11_OUT", - "S_FLICKY_11_AIM", - "S_FLICKY_11_RUN1", - "S_FLICKY_11_RUN2", - "S_FLICKY_11_RUN3", - "S_FLICKY_11_STAND", - "S_FLICKY_11_CENTER", - - // Rat - "S_FLICKY_12_OUT", - "S_FLICKY_12_AIM", - "S_FLICKY_12_RUN1", - "S_FLICKY_12_RUN2", - "S_FLICKY_12_RUN3", - "S_FLICKY_12_STAND", - "S_FLICKY_12_CENTER", - - // Bear - "S_FLICKY_13_OUT", - "S_FLICKY_13_AIM", - "S_FLICKY_13_HOP", - "S_FLICKY_13_UP", - "S_FLICKY_13_DOWN", - "S_FLICKY_13_STAND", - "S_FLICKY_13_CENTER", - - // Dove - "S_FLICKY_14_OUT", - "S_FLICKY_14_FLAP1", - "S_FLICKY_14_FLAP2", - "S_FLICKY_14_FLAP3", - "S_FLICKY_14_STAND", - "S_FLICKY_14_CENTER", - - // Cat - "S_FLICKY_15_OUT", - "S_FLICKY_15_AIM", - "S_FLICKY_15_HOP", - "S_FLICKY_15_UP", - "S_FLICKY_15_DOWN", - "S_FLICKY_15_STAND", - "S_FLICKY_15_CENTER", - - // Canary - "S_FLICKY_16_OUT", - "S_FLICKY_16_FLAP1", - "S_FLICKY_16_FLAP2", - "S_FLICKY_16_FLAP3", - "S_FLICKY_16_STAND", - "S_FLICKY_16_CENTER", - - // Spider - "S_SECRETFLICKY_01_OUT", - "S_SECRETFLICKY_01_AIM", - "S_SECRETFLICKY_01_HOP", - "S_SECRETFLICKY_01_UP", - "S_SECRETFLICKY_01_DOWN", - "S_SECRETFLICKY_01_STAND", - "S_SECRETFLICKY_01_CENTER", - - // Bat - "S_SECRETFLICKY_02_OUT", - "S_SECRETFLICKY_02_FLAP1", - "S_SECRETFLICKY_02_FLAP2", - "S_SECRETFLICKY_02_FLAP3", - "S_SECRETFLICKY_02_STAND", - "S_SECRETFLICKY_02_CENTER", - - // Fan - "S_FAN", - "S_FAN2", - "S_FAN3", - "S_FAN4", - "S_FAN5", - - // Steam Riser - "S_STEAM1", - "S_STEAM2", - "S_STEAM3", - "S_STEAM4", - "S_STEAM5", - "S_STEAM6", - "S_STEAM7", - "S_STEAM8", - - // Bumpers - "S_BUMPER", - "S_BUMPERHIT", - - // Balloons - "S_BALLOON", - "S_BALLOONPOP1", - "S_BALLOONPOP2", - "S_BALLOONPOP3", - "S_BALLOONPOP4", - "S_BALLOONPOP5", - "S_BALLOONPOP6", - - // Yellow Spring - "S_YELLOWSPRING", - "S_YELLOWSPRING2", - "S_YELLOWSPRING3", - "S_YELLOWSPRING4", - "S_YELLOWSPRING5", - - // Red Spring - "S_REDSPRING", - "S_REDSPRING2", - "S_REDSPRING3", - "S_REDSPRING4", - "S_REDSPRING5", - - // Blue Spring - "S_BLUESPRING", - "S_BLUESPRING2", - "S_BLUESPRING3", - "S_BLUESPRING4", - "S_BLUESPRING5", - - // Yellow Diagonal Spring - "S_YDIAG1", - "S_YDIAG2", - "S_YDIAG3", - "S_YDIAG4", - "S_YDIAG5", - "S_YDIAG6", - "S_YDIAG7", - "S_YDIAG8", - - // Red Diagonal Spring - "S_RDIAG1", - "S_RDIAG2", - "S_RDIAG3", - "S_RDIAG4", - "S_RDIAG5", - "S_RDIAG6", - "S_RDIAG7", - "S_RDIAG8", - - // Blue Diagonal Spring - "S_BDIAG1", - "S_BDIAG2", - "S_BDIAG3", - "S_BDIAG4", - "S_BDIAG5", - "S_BDIAG6", - "S_BDIAG7", - "S_BDIAG8", - - // Yellow Side Spring - "S_YHORIZ1", - "S_YHORIZ2", - "S_YHORIZ3", - "S_YHORIZ4", - "S_YHORIZ5", - "S_YHORIZ6", - "S_YHORIZ7", - "S_YHORIZ8", - - // Red Side Spring - "S_RHORIZ1", - "S_RHORIZ2", - "S_RHORIZ3", - "S_RHORIZ4", - "S_RHORIZ5", - "S_RHORIZ6", - "S_RHORIZ7", - "S_RHORIZ8", - - // Blue Side Spring - "S_BHORIZ1", - "S_BHORIZ2", - "S_BHORIZ3", - "S_BHORIZ4", - "S_BHORIZ5", - "S_BHORIZ6", - "S_BHORIZ7", - "S_BHORIZ8", - - // Booster - "S_BOOSTERSOUND", - "S_YELLOWBOOSTERROLLER", - "S_YELLOWBOOSTERSEG_LEFT", - "S_YELLOWBOOSTERSEG_RIGHT", - "S_YELLOWBOOSTERSEG_FACE", - "S_REDBOOSTERROLLER", - "S_REDBOOSTERSEG_LEFT", - "S_REDBOOSTERSEG_RIGHT", - "S_REDBOOSTERSEG_FACE", - - // Rain - "S_RAIN1", - "S_RAINRETURN", - - // Snowflake - "S_SNOW1", - "S_SNOW2", - "S_SNOW3", - - // Water Splish - "S_SPLISH1", - "S_SPLISH2", - "S_SPLISH3", - "S_SPLISH4", - "S_SPLISH5", - "S_SPLISH6", - "S_SPLISH7", - "S_SPLISH8", - "S_SPLISH9", - - // Lava Splish - "S_LAVASPLISH", - - // added water splash - "S_SPLASH1", - "S_SPLASH2", - "S_SPLASH3", - - // lava/slime damage burn smoke - "S_SMOKE1", - "S_SMOKE2", - "S_SMOKE3", - "S_SMOKE4", - "S_SMOKE5", - - // Bubbles - "S_SMALLBUBBLE", - "S_MEDIUMBUBBLE", - "S_LARGEBUBBLE1", - "S_LARGEBUBBLE2", - "S_EXTRALARGEBUBBLE", // breathable - - "S_POP1", // Extra Large bubble goes POP! - - "S_WATERZAP", - - // Spindash dust - "S_SPINDUST1", - "S_SPINDUST2", - "S_SPINDUST3", - "S_SPINDUST4", - "S_SPINDUST_BUBBLE1", - "S_SPINDUST_BUBBLE2", - "S_SPINDUST_BUBBLE3", - "S_SPINDUST_BUBBLE4", - "S_SPINDUST_FIRE1", - "S_SPINDUST_FIRE2", - "S_SPINDUST_FIRE3", - "S_SPINDUST_FIRE4", - - "S_FOG1", - "S_FOG2", - "S_FOG3", - "S_FOG4", - "S_FOG5", - "S_FOG6", - "S_FOG7", - "S_FOG8", - "S_FOG9", - "S_FOG10", - "S_FOG11", - "S_FOG12", - "S_FOG13", - "S_FOG14", - - "S_SEED", - - "S_PARTICLE", - - // Score Logos - "S_SCRA", // 100 - "S_SCRB", // 200 - "S_SCRC", // 500 - "S_SCRD", // 1000 - "S_SCRE", // 10000 - "S_SCRF", // 400 (mario) - "S_SCRG", // 800 (mario) - "S_SCRH", // 2000 (mario) - "S_SCRI", // 4000 (mario) - "S_SCRJ", // 8000 (mario) - "S_SCRK", // 1UP (mario) - "S_SCRL", // 10 - - // Drowning Timer Numbers - "S_ZERO1", - "S_ONE1", - "S_TWO1", - "S_THREE1", - "S_FOUR1", - "S_FIVE1", - - "S_ZERO2", - "S_ONE2", - "S_TWO2", - "S_THREE2", - "S_FOUR2", - "S_FIVE2", - - "S_FLIGHTINDICATOR", - - "S_LOCKON1", - "S_LOCKON2", - "S_LOCKON3", - "S_LOCKON4", - "S_LOCKONINF1", - "S_LOCKONINF2", - "S_LOCKONINF3", - "S_LOCKONINF4", - - // Tag Sign - "S_TTAG", - - // Got Flag Sign - "S_GOTFLAG", - - // Finish flag - "S_FINISHFLAG", - - "S_CORK", - "S_LHRT", - - // Red Ring - "S_RRNG1", - "S_RRNG2", - "S_RRNG3", - "S_RRNG4", - "S_RRNG5", - "S_RRNG6", - "S_RRNG7", - - // Weapon Ring Ammo - "S_BOUNCERINGAMMO", - "S_RAILRINGAMMO", - "S_INFINITYRINGAMMO", - "S_AUTOMATICRINGAMMO", - "S_EXPLOSIONRINGAMMO", - "S_SCATTERRINGAMMO", - "S_GRENADERINGAMMO", - - // Weapon pickup - "S_BOUNCEPICKUP", - "S_BOUNCEPICKUPFADE1", - "S_BOUNCEPICKUPFADE2", - "S_BOUNCEPICKUPFADE3", - "S_BOUNCEPICKUPFADE4", - "S_BOUNCEPICKUPFADE5", - "S_BOUNCEPICKUPFADE6", - "S_BOUNCEPICKUPFADE7", - "S_BOUNCEPICKUPFADE8", - - "S_RAILPICKUP", - "S_RAILPICKUPFADE1", - "S_RAILPICKUPFADE2", - "S_RAILPICKUPFADE3", - "S_RAILPICKUPFADE4", - "S_RAILPICKUPFADE5", - "S_RAILPICKUPFADE6", - "S_RAILPICKUPFADE7", - "S_RAILPICKUPFADE8", - - "S_AUTOPICKUP", - "S_AUTOPICKUPFADE1", - "S_AUTOPICKUPFADE2", - "S_AUTOPICKUPFADE3", - "S_AUTOPICKUPFADE4", - "S_AUTOPICKUPFADE5", - "S_AUTOPICKUPFADE6", - "S_AUTOPICKUPFADE7", - "S_AUTOPICKUPFADE8", - - "S_EXPLODEPICKUP", - "S_EXPLODEPICKUPFADE1", - "S_EXPLODEPICKUPFADE2", - "S_EXPLODEPICKUPFADE3", - "S_EXPLODEPICKUPFADE4", - "S_EXPLODEPICKUPFADE5", - "S_EXPLODEPICKUPFADE6", - "S_EXPLODEPICKUPFADE7", - "S_EXPLODEPICKUPFADE8", - - "S_SCATTERPICKUP", - "S_SCATTERPICKUPFADE1", - "S_SCATTERPICKUPFADE2", - "S_SCATTERPICKUPFADE3", - "S_SCATTERPICKUPFADE4", - "S_SCATTERPICKUPFADE5", - "S_SCATTERPICKUPFADE6", - "S_SCATTERPICKUPFADE7", - "S_SCATTERPICKUPFADE8", - - "S_GRENADEPICKUP", - "S_GRENADEPICKUPFADE1", - "S_GRENADEPICKUPFADE2", - "S_GRENADEPICKUPFADE3", - "S_GRENADEPICKUPFADE4", - "S_GRENADEPICKUPFADE5", - "S_GRENADEPICKUPFADE6", - "S_GRENADEPICKUPFADE7", - "S_GRENADEPICKUPFADE8", - - // Thrown Weapon Rings - "S_THROWNBOUNCE1", - "S_THROWNBOUNCE2", - "S_THROWNBOUNCE3", - "S_THROWNBOUNCE4", - "S_THROWNBOUNCE5", - "S_THROWNBOUNCE6", - "S_THROWNBOUNCE7", - "S_THROWNINFINITY1", - "S_THROWNINFINITY2", - "S_THROWNINFINITY3", - "S_THROWNINFINITY4", - "S_THROWNINFINITY5", - "S_THROWNINFINITY6", - "S_THROWNINFINITY7", - "S_THROWNAUTOMATIC1", - "S_THROWNAUTOMATIC2", - "S_THROWNAUTOMATIC3", - "S_THROWNAUTOMATIC4", - "S_THROWNAUTOMATIC5", - "S_THROWNAUTOMATIC6", - "S_THROWNAUTOMATIC7", - "S_THROWNEXPLOSION1", - "S_THROWNEXPLOSION2", - "S_THROWNEXPLOSION3", - "S_THROWNEXPLOSION4", - "S_THROWNEXPLOSION5", - "S_THROWNEXPLOSION6", - "S_THROWNEXPLOSION7", - "S_THROWNGRENADE1", - "S_THROWNGRENADE2", - "S_THROWNGRENADE3", - "S_THROWNGRENADE4", - "S_THROWNGRENADE5", - "S_THROWNGRENADE6", - "S_THROWNGRENADE7", - "S_THROWNGRENADE8", - "S_THROWNGRENADE9", - "S_THROWNGRENADE10", - "S_THROWNGRENADE11", - "S_THROWNGRENADE12", - "S_THROWNGRENADE13", - "S_THROWNGRENADE14", - "S_THROWNGRENADE15", - "S_THROWNGRENADE16", - "S_THROWNGRENADE17", - "S_THROWNGRENADE18", - "S_THROWNSCATTER", - - "S_RINGEXPLODE", - - "S_COIN1", - "S_COIN2", - "S_COIN3", - "S_COINSPARKLE1", - "S_COINSPARKLE2", - "S_COINSPARKLE3", - "S_COINSPARKLE4", - "S_GOOMBA1", - "S_GOOMBA1B", - "S_GOOMBA2", - "S_GOOMBA3", - "S_GOOMBA4", - "S_GOOMBA5", - "S_GOOMBA6", - "S_GOOMBA7", - "S_GOOMBA8", - "S_GOOMBA9", - "S_GOOMBA_DEAD", - "S_BLUEGOOMBA1", - "S_BLUEGOOMBA1B", - "S_BLUEGOOMBA2", - "S_BLUEGOOMBA3", - "S_BLUEGOOMBA4", - "S_BLUEGOOMBA5", - "S_BLUEGOOMBA6", - "S_BLUEGOOMBA7", - "S_BLUEGOOMBA8", - "S_BLUEGOOMBA9", - "S_BLUEGOOMBA_DEAD", - - // Mario-specific stuff - "S_FIREFLOWER1", - "S_FIREFLOWER2", - "S_FIREFLOWER3", - "S_FIREFLOWER4", - "S_FIREBALL", - "S_FIREBALLTRAIL1", - "S_FIREBALLTRAIL2", - "S_SHELL", - "S_PUMA_START1", - "S_PUMA_START2", - "S_PUMA_UP1", - "S_PUMA_UP2", - "S_PUMA_UP3", - "S_PUMA_DOWN1", - "S_PUMA_DOWN2", - "S_PUMA_DOWN3", - "S_PUMATRAIL1", - "S_PUMATRAIL2", - "S_PUMATRAIL3", - "S_PUMATRAIL4", - "S_HAMMER", - "S_KOOPA1", - "S_KOOPA2", - "S_KOOPAFLAME1", - "S_KOOPAFLAME2", - "S_KOOPAFLAME3", - "S_AXE1", - "S_AXE2", - "S_AXE3", - "S_MARIOBUSH1", - "S_MARIOBUSH2", - "S_TOAD", - - // Nights-specific stuff - "S_NIGHTSDRONE_MAN1", - "S_NIGHTSDRONE_MAN2", - "S_NIGHTSDRONE_SPARKLING1", - "S_NIGHTSDRONE_SPARKLING2", - "S_NIGHTSDRONE_SPARKLING3", - "S_NIGHTSDRONE_SPARKLING4", - "S_NIGHTSDRONE_SPARKLING5", - "S_NIGHTSDRONE_SPARKLING6", - "S_NIGHTSDRONE_SPARKLING7", - "S_NIGHTSDRONE_SPARKLING8", - "S_NIGHTSDRONE_SPARKLING9", - "S_NIGHTSDRONE_SPARKLING10", - "S_NIGHTSDRONE_SPARKLING11", - "S_NIGHTSDRONE_SPARKLING12", - "S_NIGHTSDRONE_SPARKLING13", - "S_NIGHTSDRONE_SPARKLING14", - "S_NIGHTSDRONE_SPARKLING15", - "S_NIGHTSDRONE_SPARKLING16", - "S_NIGHTSDRONE_GOAL1", - "S_NIGHTSDRONE_GOAL2", - "S_NIGHTSDRONE_GOAL3", - "S_NIGHTSDRONE_GOAL4", - - "S_NIGHTSPARKLE1", - "S_NIGHTSPARKLE2", - "S_NIGHTSPARKLE3", - "S_NIGHTSPARKLE4", - "S_NIGHTSPARKLESUPER1", - "S_NIGHTSPARKLESUPER2", - "S_NIGHTSPARKLESUPER3", - "S_NIGHTSPARKLESUPER4", - "S_NIGHTSLOOPHELPER", - - // NiGHTS bumper - "S_NIGHTSBUMPER1", - "S_NIGHTSBUMPER2", - "S_NIGHTSBUMPER3", - "S_NIGHTSBUMPER4", - "S_NIGHTSBUMPER5", - "S_NIGHTSBUMPER6", - "S_NIGHTSBUMPER7", - "S_NIGHTSBUMPER8", - "S_NIGHTSBUMPER9", - "S_NIGHTSBUMPER10", - "S_NIGHTSBUMPER11", - "S_NIGHTSBUMPER12", - - "S_HOOP", - "S_HOOP_XMASA", - "S_HOOP_XMASB", - - "S_NIGHTSCORE10", - "S_NIGHTSCORE20", - "S_NIGHTSCORE30", - "S_NIGHTSCORE40", - "S_NIGHTSCORE50", - "S_NIGHTSCORE60", - "S_NIGHTSCORE70", - "S_NIGHTSCORE80", - "S_NIGHTSCORE90", - "S_NIGHTSCORE100", - "S_NIGHTSCORE10_2", - "S_NIGHTSCORE20_2", - "S_NIGHTSCORE30_2", - "S_NIGHTSCORE40_2", - "S_NIGHTSCORE50_2", - "S_NIGHTSCORE60_2", - "S_NIGHTSCORE70_2", - "S_NIGHTSCORE80_2", - "S_NIGHTSCORE90_2", - "S_NIGHTSCORE100_2", - - // NiGHTS Paraloop Powerups - "S_NIGHTSSUPERLOOP", - "S_NIGHTSDRILLREFILL", - "S_NIGHTSHELPER", - "S_NIGHTSEXTRATIME", - "S_NIGHTSLINKFREEZE", - "S_EGGCAPSULE", - - // Orbiting Chaos Emeralds - "S_ORBITEM1", - "S_ORBITEM2", - "S_ORBITEM3", - "S_ORBITEM4", - "S_ORBITEM5", - "S_ORBITEM6", - "S_ORBITEM7", - "S_ORBITEM8", - "S_ORBIDYA1", - "S_ORBIDYA2", - "S_ORBIDYA3", - "S_ORBIDYA4", - "S_ORBIDYA5", - - // "Flicky" helper - "S_NIGHTOPIANHELPER1", - "S_NIGHTOPIANHELPER2", - "S_NIGHTOPIANHELPER3", - "S_NIGHTOPIANHELPER4", - "S_NIGHTOPIANHELPER5", - "S_NIGHTOPIANHELPER6", - "S_NIGHTOPIANHELPER7", - "S_NIGHTOPIANHELPER8", - "S_NIGHTOPIANHELPER9", - - // Nightopian - "S_PIAN0", - "S_PIAN1", - "S_PIAN2", - "S_PIAN3", - "S_PIAN4", - "S_PIAN5", - "S_PIAN6", - "S_PIANSING", - - // Shleep - "S_SHLEEP1", - "S_SHLEEP2", - "S_SHLEEP3", - "S_SHLEEP4", - "S_SHLEEPBOUNCE1", - "S_SHLEEPBOUNCE2", - "S_SHLEEPBOUNCE3", - - // Secret badniks and hazards, shhhh - "S_PENGUINATOR_LOOK", - "S_PENGUINATOR_WADDLE1", - "S_PENGUINATOR_WADDLE2", - "S_PENGUINATOR_WADDLE3", - "S_PENGUINATOR_WADDLE4", - "S_PENGUINATOR_SLIDE1", - "S_PENGUINATOR_SLIDE2", - "S_PENGUINATOR_SLIDE3", - "S_PENGUINATOR_SLIDE4", - "S_PENGUINATOR_SLIDE5", - - "S_POPHAT_LOOK", - "S_POPHAT_SHOOT1", - "S_POPHAT_SHOOT2", - "S_POPHAT_SHOOT3", - "S_POPHAT_SHOOT4", - "S_POPSHOT", - "S_POPSHOT_TRAIL", - - "S_HIVEELEMENTAL_LOOK", - "S_HIVEELEMENTAL_PREPARE1", - "S_HIVEELEMENTAL_PREPARE2", - "S_HIVEELEMENTAL_SHOOT1", - "S_HIVEELEMENTAL_SHOOT2", - "S_HIVEELEMENTAL_DORMANT", - "S_HIVEELEMENTAL_PAIN", - "S_HIVEELEMENTAL_DIE1", - "S_HIVEELEMENTAL_DIE2", - "S_HIVEELEMENTAL_DIE3", - - "S_BUMBLEBORE_SPAWN", - "S_BUMBLEBORE_LOOK1", - "S_BUMBLEBORE_LOOK2", - "S_BUMBLEBORE_FLY1", - "S_BUMBLEBORE_FLY2", - "S_BUMBLEBORE_RAISE", - "S_BUMBLEBORE_FALL1", - "S_BUMBLEBORE_FALL2", - "S_BUMBLEBORE_STUCK1", - "S_BUMBLEBORE_STUCK2", - "S_BUMBLEBORE_DIE", - - "S_BUGGLEIDLE", - "S_BUGGLEFLY", - - "S_SMASHSPIKE_FLOAT", - "S_SMASHSPIKE_EASE1", - "S_SMASHSPIKE_EASE2", - "S_SMASHSPIKE_FALL", - "S_SMASHSPIKE_STOMP1", - "S_SMASHSPIKE_STOMP2", - "S_SMASHSPIKE_RISE1", - "S_SMASHSPIKE_RISE2", - - "S_CACO_LOOK", - "S_CACO_WAKE1", - "S_CACO_WAKE2", - "S_CACO_WAKE3", - "S_CACO_WAKE4", - "S_CACO_ROAR", - "S_CACO_CHASE", - "S_CACO_CHASE_REPEAT", - "S_CACO_RANDOM", - "S_CACO_PREPARE_SOUND", - "S_CACO_PREPARE1", - "S_CACO_PREPARE2", - "S_CACO_PREPARE3", - "S_CACO_SHOOT_SOUND", - "S_CACO_SHOOT1", - "S_CACO_SHOOT2", - "S_CACO_CLOSE", - "S_CACO_DIE_FLAGS", - "S_CACO_DIE_GIB1", - "S_CACO_DIE_GIB2", - "S_CACO_DIE_SCREAM", - "S_CACO_DIE_SHATTER", - "S_CACO_DIE_FALL", - "S_CACOSHARD_RANDOMIZE", - "S_CACOSHARD1_1", - "S_CACOSHARD1_2", - "S_CACOSHARD2_1", - "S_CACOSHARD2_2", - "S_CACOFIRE1", - "S_CACOFIRE2", - "S_CACOFIRE3", - "S_CACOFIRE_EXPLODE1", - "S_CACOFIRE_EXPLODE2", - "S_CACOFIRE_EXPLODE3", - "S_CACOFIRE_EXPLODE4", - - "S_SPINBOBERT_MOVE_FLIPUP", - "S_SPINBOBERT_MOVE_UP", - "S_SPINBOBERT_MOVE_FLIPDOWN", - "S_SPINBOBERT_MOVE_DOWN", - "S_SPINBOBERT_FIRE_MOVE", - "S_SPINBOBERT_FIRE_GHOST", - "S_SPINBOBERT_FIRE_TRAIL1", - "S_SPINBOBERT_FIRE_TRAIL2", - "S_SPINBOBERT_FIRE_TRAIL3", - - "S_HANGSTER_LOOK", - "S_HANGSTER_SWOOP1", - "S_HANGSTER_SWOOP2", - "S_HANGSTER_ARC1", - "S_HANGSTER_ARC2", - "S_HANGSTER_ARC3", - "S_HANGSTER_FLY1", - "S_HANGSTER_FLY2", - "S_HANGSTER_FLY3", - "S_HANGSTER_FLY4", - "S_HANGSTER_FLYREPEAT", - "S_HANGSTER_ARCUP1", - "S_HANGSTER_ARCUP2", - "S_HANGSTER_ARCUP3", - "S_HANGSTER_RETURN1", - "S_HANGSTER_RETURN2", - "S_HANGSTER_RETURN3", - - "S_CRUMBLE1", - "S_CRUMBLE2", - - // Spark - "S_SPRK1", - "S_SPRK2", - "S_SPRK3", - - // Robot Explosion - "S_XPLD_FLICKY", - "S_XPLD1", - "S_XPLD2", - "S_XPLD3", - "S_XPLD4", - "S_XPLD5", - "S_XPLD6", - "S_XPLD_EGGTRAP", - - // Underwater Explosion - "S_WPLD1", - "S_WPLD2", - "S_WPLD3", - "S_WPLD4", - "S_WPLD5", - "S_WPLD6", - - "S_DUST1", - "S_DUST2", - "S_DUST3", - "S_DUST4", - - "S_ROCKSPAWN", - - "S_ROCKCRUMBLEA", - "S_ROCKCRUMBLEB", - "S_ROCKCRUMBLEC", - "S_ROCKCRUMBLED", - "S_ROCKCRUMBLEE", - "S_ROCKCRUMBLEF", - "S_ROCKCRUMBLEG", - "S_ROCKCRUMBLEH", - "S_ROCKCRUMBLEI", - "S_ROCKCRUMBLEJ", - "S_ROCKCRUMBLEK", - "S_ROCKCRUMBLEL", - "S_ROCKCRUMBLEM", - "S_ROCKCRUMBLEN", - "S_ROCKCRUMBLEO", - "S_ROCKCRUMBLEP", - - // Level debris - "S_GFZDEBRIS", - "S_BRICKDEBRIS", - "S_WOODDEBRIS", - "S_REDBRICKDEBRIS", - "S_BLUEBRICKDEBRIS", - "S_YELLOWBRICKDEBRIS", - -#ifdef SEENAMES - "S_NAMECHECK", -#endif -}; - -// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", -// I am leaving the prefixes solely for clarity to programmers, -// because sadly no one remembers this place while searching for full state names. -static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity testing later. - "MT_NULL", - "MT_UNKNOWN", - - "MT_THOK", // Thok! mobj - "MT_PLAYER", - "MT_TAILSOVERLAY", // c: - "MT_METALJETFUME", - - // Enemies - "MT_BLUECRAWLA", // Crawla (Blue) - "MT_REDCRAWLA", // Crawla (Red) - "MT_GFZFISH", // SDURF - "MT_GOLDBUZZ", // Buzz (Gold) - "MT_REDBUZZ", // Buzz (Red) - "MT_JETTBOMBER", // Jetty-Syn Bomber - "MT_JETTGUNNER", // Jetty-Syn Gunner - "MT_CRAWLACOMMANDER", // Crawla Commander - "MT_DETON", // Deton - "MT_SKIM", // Skim mine dropper - "MT_TURRET", // Industrial Turret - "MT_POPUPTURRET", // Pop-Up Turret - "MT_SPINCUSHION", // Spincushion - "MT_CRUSHSTACEAN", // Crushstacean - "MT_CRUSHCLAW", // Big meaty claw - "MT_CRUSHCHAIN", // Chain - "MT_BANPYURA", // Banpyura - "MT_BANPSPRING", // Banpyura spring - "MT_JETJAW", // Jet Jaw - "MT_SNAILER", // Snailer - "MT_VULTURE", // BASH - "MT_POINTY", // Pointy - "MT_POINTYBALL", // Pointy Ball - "MT_ROBOHOOD", // Robo-Hood - "MT_FACESTABBER", // Castlebot Facestabber - "MT_FACESTABBERSPEAR", // Castlebot Facestabber spear aura - "MT_EGGGUARD", // Egg Guard - "MT_EGGSHIELD", // Egg Guard's shield - "MT_GSNAPPER", // Green Snapper - "MT_SNAPPER_LEG", // Green Snapper leg - "MT_SNAPPER_HEAD", // Green Snapper head - "MT_MINUS", // Minus - "MT_MINUSDIRT", // Minus dirt - "MT_SPRINGSHELL", // Spring Shell - "MT_YELLOWSHELL", // Spring Shell (yellow) - "MT_UNIDUS", // Unidus - "MT_UNIBALL", // Unidus Ball - "MT_CANARIVORE", // Canarivore - "MT_CANARIVORE_GAS", // Canarivore gas - "MT_PYREFLY", // Pyre Fly - "MT_PYREFLY_FIRE", // Pyre Fly fire - "MT_PTERABYTESPAWNER", // Pterabyte spawner - "MT_PTERABYTEWAYPOINT", // Pterabyte waypoint - "MT_PTERABYTE", // Pterabyte - "MT_DRAGONBOMBER", // Dragonbomber - "MT_DRAGONWING", // Dragonbomber wing - "MT_DRAGONTAIL", // Dragonbomber tail segment - "MT_DRAGONMINE", // Dragonbomber mine - - // Generic Boss Items - "MT_BOSSEXPLODE", - "MT_SONIC3KBOSSEXPLODE", - "MT_BOSSFLYPOINT", - "MT_EGGTRAP", - "MT_BOSS3WAYPOINT", - "MT_BOSS9GATHERPOINT", - "MT_BOSSJUNK", - - // Boss 1 - "MT_EGGMOBILE", - "MT_JETFUME1", - "MT_EGGMOBILE_BALL", - "MT_EGGMOBILE_TARGET", - "MT_EGGMOBILE_FIRE", - - // Boss 2 - "MT_EGGMOBILE2", - "MT_EGGMOBILE2_POGO", - "MT_GOOP", - "MT_GOOPTRAIL", - - // Boss 3 - "MT_EGGMOBILE3", - "MT_FAKEMOBILE", - "MT_SHOCKWAVE", - - // Boss 4 - "MT_EGGMOBILE4", - "MT_EGGMOBILE4_MACE", - "MT_JETFLAME", - "MT_EGGROBO1", - "MT_EGGROBO1JET", - - // Boss 5 - "MT_FANG", - "MT_BROKENROBOT", - "MT_VWREF", - "MT_VWREB", - "MT_PROJECTORLIGHT", - "MT_FBOMB", - "MT_TNTDUST", // also used by barrel - "MT_FSGNA", - "MT_FSGNB", - "MT_FANGWAYPOINT", - - // Black Eggman (Boss 7) - "MT_BLACKEGGMAN", - "MT_BLACKEGGMAN_HELPER", - "MT_BLACKEGGMAN_GOOPFIRE", - "MT_BLACKEGGMAN_MISSILE", - - // New Very-Last-Minute 2.1 Brak Eggman (Cy-Brak-demon) - "MT_CYBRAKDEMON", - "MT_CYBRAKDEMON_ELECTRIC_BARRIER", - "MT_CYBRAKDEMON_MISSILE", - "MT_CYBRAKDEMON_FLAMESHOT", - "MT_CYBRAKDEMON_FLAMEREST", - "MT_CYBRAKDEMON_TARGET_RETICULE", - "MT_CYBRAKDEMON_TARGET_DOT", - "MT_CYBRAKDEMON_NAPALM_BOMB_LARGE", - "MT_CYBRAKDEMON_NAPALM_BOMB_SMALL", - "MT_CYBRAKDEMON_NAPALM_FLAMES", - "MT_CYBRAKDEMON_VILE_EXPLOSION", - - // Metal Sonic (Boss 9) - "MT_METALSONIC_RACE", - "MT_METALSONIC_BATTLE", - "MT_MSSHIELD_FRONT", - "MT_MSGATHER", - - // Collectible Items - "MT_RING", - "MT_FLINGRING", // Lost ring - "MT_BLUESPHERE", // Blue sphere for special stages - "MT_FLINGBLUESPHERE", // Lost blue sphere - "MT_BOMBSPHERE", - "MT_REDTEAMRING", //Rings collectable by red team. - "MT_BLUETEAMRING", //Rings collectable by blue team. - "MT_TOKEN", // Special Stage token for special stage - "MT_REDFLAG", // Red CTF Flag - "MT_BLUEFLAG", // Blue CTF Flag - "MT_EMBLEM", - "MT_EMERALD1", - "MT_EMERALD2", - "MT_EMERALD3", - "MT_EMERALD4", - "MT_EMERALD5", - "MT_EMERALD6", - "MT_EMERALD7", - "MT_EMERHUNT", // Emerald Hunt - "MT_EMERALDSPAWN", // Emerald spawner w/ delay - "MT_FLINGEMERALD", // Lost emerald - - // Springs and others - "MT_FAN", - "MT_STEAM", - "MT_BUMPER", - "MT_BALLOON", - - "MT_YELLOWSPRING", - "MT_REDSPRING", - "MT_BLUESPRING", - "MT_YELLOWDIAG", - "MT_REDDIAG", - "MT_BLUEDIAG", - "MT_YELLOWHORIZ", - "MT_REDHORIZ", - "MT_BLUEHORIZ", - - "MT_BOOSTERSEG", - "MT_BOOSTERROLLER", - "MT_YELLOWBOOSTER", - "MT_REDBOOSTER", - - // Interactive Objects - "MT_BUBBLES", // Bubble source - "MT_SIGN", // Level end sign - "MT_SPIKEBALL", // Spike Ball - "MT_SPINFIRE", - "MT_SPIKE", - "MT_WALLSPIKE", - "MT_WALLSPIKEBASE", - "MT_STARPOST", - "MT_BIGMINE", - "MT_BLASTEXECUTOR", - "MT_CANNONLAUNCHER", - - // Monitor miscellany - "MT_BOXSPARKLE", - - // Monitor boxes -- regular - "MT_RING_BOX", - "MT_PITY_BOX", - "MT_ATTRACT_BOX", - "MT_FORCE_BOX", - "MT_ARMAGEDDON_BOX", - "MT_WHIRLWIND_BOX", - "MT_ELEMENTAL_BOX", - "MT_SNEAKERS_BOX", - "MT_INVULN_BOX", - "MT_1UP_BOX", - "MT_EGGMAN_BOX", - "MT_MIXUP_BOX", - "MT_MYSTERY_BOX", - "MT_GRAVITY_BOX", - "MT_RECYCLER_BOX", - "MT_SCORE1K_BOX", - "MT_SCORE10K_BOX", - "MT_FLAMEAURA_BOX", - "MT_BUBBLEWRAP_BOX", - "MT_THUNDERCOIN_BOX", - - // Monitor boxes -- repeating (big) boxes - "MT_PITY_GOLDBOX", - "MT_ATTRACT_GOLDBOX", - "MT_FORCE_GOLDBOX", - "MT_ARMAGEDDON_GOLDBOX", - "MT_WHIRLWIND_GOLDBOX", - "MT_ELEMENTAL_GOLDBOX", - "MT_SNEAKERS_GOLDBOX", - "MT_INVULN_GOLDBOX", - "MT_EGGMAN_GOLDBOX", - "MT_GRAVITY_GOLDBOX", - "MT_FLAMEAURA_GOLDBOX", - "MT_BUBBLEWRAP_GOLDBOX", - "MT_THUNDERCOIN_GOLDBOX", - - // Monitor boxes -- special - "MT_RING_REDBOX", - "MT_RING_BLUEBOX", - - // Monitor icons - "MT_RING_ICON", - "MT_PITY_ICON", - "MT_ATTRACT_ICON", - "MT_FORCE_ICON", - "MT_ARMAGEDDON_ICON", - "MT_WHIRLWIND_ICON", - "MT_ELEMENTAL_ICON", - "MT_SNEAKERS_ICON", - "MT_INVULN_ICON", - "MT_1UP_ICON", - "MT_EGGMAN_ICON", - "MT_MIXUP_ICON", - "MT_GRAVITY_ICON", - "MT_RECYCLER_ICON", - "MT_SCORE1K_ICON", - "MT_SCORE10K_ICON", - "MT_FLAMEAURA_ICON", - "MT_BUBBLEWRAP_ICON", - "MT_THUNDERCOIN_ICON", - - // Projectiles - "MT_ROCKET", - "MT_LASER", - "MT_TORPEDO", - "MT_TORPEDO2", // silent - "MT_ENERGYBALL", - "MT_MINE", // Skim/Jetty-Syn mine - "MT_JETTBULLET", // Jetty-Syn Bullet - "MT_TURRETLASER", - "MT_CANNONBALL", // Cannonball - "MT_CANNONBALLDECOR", // Decorative/still cannonball - "MT_ARROW", // Arrow - "MT_DEMONFIRE", // Glaregoyle fire - - // The letter - "MT_LETTER", - - // Greenflower Scenery - "MT_GFZFLOWER1", - "MT_GFZFLOWER2", - "MT_GFZFLOWER3", - - "MT_BLUEBERRYBUSH", - "MT_BERRYBUSH", - "MT_BUSH", - - // Trees (both GFZ and misc) - "MT_GFZTREE", - "MT_GFZBERRYTREE", - "MT_GFZCHERRYTREE", - "MT_CHECKERTREE", - "MT_CHECKERSUNSETTREE", - "MT_FHZTREE", // Frozen Hillside - "MT_FHZPINKTREE", - "MT_POLYGONTREE", - "MT_BUSHTREE", - "MT_BUSHREDTREE", - "MT_SPRINGTREE", - - // Techno Hill Scenery - "MT_THZFLOWER1", - "MT_THZFLOWER2", - "MT_THZFLOWER3", - "MT_THZTREE", // Steam whistle tree/bush - "MT_THZTREEBRANCH", // branch of said tree - "MT_ALARM", - - // Deep Sea Scenery - "MT_GARGOYLE", // Deep Sea Gargoyle - "MT_BIGGARGOYLE", // Deep Sea Gargoyle (Big) - "MT_SEAWEED", // DSZ Seaweed - "MT_WATERDRIP", // Dripping Water source - "MT_WATERDROP", // Water drop from dripping water - "MT_CORAL1", // Coral - "MT_CORAL2", - "MT_CORAL3", - "MT_CORAL4", - "MT_CORAL5", - "MT_BLUECRYSTAL", // Blue Crystal - "MT_KELP", // Kelp - "MT_ANIMALGAETOP", // Animated algae top - "MT_ANIMALGAESEG", // Animated algae segment - "MT_DSZSTALAGMITE", // Deep Sea 1 Stalagmite - "MT_DSZ2STALAGMITE", // Deep Sea 2 Stalagmite - "MT_LIGHTBEAM", // DSZ Light beam - - // Castle Eggman Scenery - "MT_CHAIN", // CEZ Chain - "MT_FLAME", // Flame (has corona) - "MT_FLAMEPARTICLE", - "MT_EGGSTATUE", // Eggman Statue - "MT_MACEPOINT", // Mace rotation point - "MT_CHAINMACEPOINT", // Combination of chains and maces point - "MT_SPRINGBALLPOINT", // Spring ball point - "MT_CHAINPOINT", // Mace chain - "MT_HIDDEN_SLING", // Spin mace chain (activatable) - "MT_FIREBARPOINT", // Firebar - "MT_CUSTOMMACEPOINT", // Custom mace - "MT_SMALLMACECHAIN", // Small Mace Chain - "MT_BIGMACECHAIN", // Big Mace Chain - "MT_SMALLMACE", // Small Mace - "MT_BIGMACE", // Big Mace - "MT_SMALLGRABCHAIN", // Small Grab Chain - "MT_BIGGRABCHAIN", // Big Grab Chain - "MT_YELLOWSPRINGBALL", // Yellow spring on a ball - "MT_REDSPRINGBALL", // Red spring on a ball - "MT_SMALLFIREBAR", // Small Firebar - "MT_BIGFIREBAR", // Big Firebar - "MT_CEZFLOWER", // Flower - "MT_CEZPOLE1", // Pole (with red banner) - "MT_CEZPOLE2", // Pole (with blue banner) - "MT_CEZBANNER1", // Banner (red) - "MT_CEZBANNER2", // Banner (blue) - "MT_PINETREE", // Pine Tree - "MT_CEZBUSH1", // Bush 1 - "MT_CEZBUSH2", // Bush 2 - "MT_CANDLE", // Candle - "MT_CANDLEPRICKET", // Candle pricket - "MT_FLAMEHOLDER", // Flame holder - "MT_FIRETORCH", // Fire torch - "MT_WAVINGFLAG1", // Waving flag (red) - "MT_WAVINGFLAG2", // Waving flag (blue) - "MT_WAVINGFLAGSEG1", // Waving flag segment (red) - "MT_WAVINGFLAGSEG2", // Waving flag segment (blue) - "MT_CRAWLASTATUE", // Crawla statue - "MT_FACESTABBERSTATUE", // Facestabber statue - "MT_SUSPICIOUSFACESTABBERSTATUE", // :eggthinking: - "MT_BRAMBLES", // Brambles - - // Arid Canyon Scenery - "MT_BIGTUMBLEWEED", - "MT_LITTLETUMBLEWEED", - "MT_CACTI1", // Tiny Red Flower Cactus - "MT_CACTI2", // Small Red Flower Cactus - "MT_CACTI3", // Tiny Blue Flower Cactus - "MT_CACTI4", // Small Blue Flower Cactus - "MT_CACTI5", // Prickly Pear - "MT_CACTI6", // Barrel Cactus - "MT_CACTI7", // Tall Barrel Cactus - "MT_CACTI8", // Armed Cactus - "MT_CACTI9", // Ball Cactus - "MT_CACTI10", // Tiny Cactus - "MT_CACTI11", // Small Cactus - "MT_CACTITINYSEG", // Tiny Cactus Segment - "MT_CACTISMALLSEG", // Small Cactus Segment - "MT_ARIDSIGN_CAUTION", // Caution Sign - "MT_ARIDSIGN_CACTI", // Cacti Sign - "MT_ARIDSIGN_SHARPTURN", // Sharp Turn Sign - "MT_OILLAMP", - "MT_TNTBARREL", - "MT_PROXIMITYTNT", - "MT_DUSTDEVIL", - "MT_DUSTLAYER", - "MT_ARIDDUST", - "MT_MINECART", - "MT_MINECARTSEG", - "MT_MINECARTSPAWNER", - "MT_MINECARTEND", - "MT_MINECARTENDSOLID", - "MT_MINECARTSIDEMARK", - "MT_MINECARTSPARK", - "MT_SALOONDOOR", - "MT_SALOONDOORCENTER", - "MT_TRAINCAMEOSPAWNER", - "MT_TRAINSEG", - "MT_TRAINDUSTSPAWNER", - "MT_TRAINSTEAMSPAWNER", - "MT_MINECARTSWITCHPOINT", - - // Red Volcano Scenery - "MT_FLAMEJET", - "MT_VERTICALFLAMEJET", - "MT_FLAMEJETFLAME", - - "MT_FJSPINAXISA", // Counter-clockwise - "MT_FJSPINAXISB", // Clockwise - - "MT_FLAMEJETFLAMEB", // Blade's flame - - "MT_LAVAFALL", - "MT_LAVAFALL_LAVA", - "MT_LAVAFALLROCK", - - "MT_ROLLOUTSPAWN", - "MT_ROLLOUTROCK", - - "MT_BIGFERNLEAF", - "MT_BIGFERN", - "MT_JUNGLEPALM", - "MT_TORCHFLOWER", - "MT_WALLVINE_LONG", - "MT_WALLVINE_SHORT", - - // Dark City Scenery - - // Egg Rock Scenery - - // Azure Temple Scenery - "MT_GLAREGOYLE", - "MT_GLAREGOYLEUP", - "MT_GLAREGOYLEDOWN", - "MT_GLAREGOYLELONG", - "MT_TARGET", // AKA Red Crystal - "MT_GREENFLAME", - "MT_BLUEGARGOYLE", - - // Stalagmites - "MT_STALAGMITE0", - "MT_STALAGMITE1", - "MT_STALAGMITE2", - "MT_STALAGMITE3", - "MT_STALAGMITE4", - "MT_STALAGMITE5", - "MT_STALAGMITE6", - "MT_STALAGMITE7", - "MT_STALAGMITE8", - "MT_STALAGMITE9", - - // Christmas Scenery - "MT_XMASPOLE", - "MT_CANDYCANE", - "MT_SNOWMAN", // normal - "MT_SNOWMANHAT", // with hat + scarf - "MT_LAMPPOST1", // normal - "MT_LAMPPOST2", // with snow - "MT_HANGSTAR", - "MT_MISTLETOE", - // Xmas GFZ bushes - "MT_XMASBLUEBERRYBUSH", - "MT_XMASBERRYBUSH", - "MT_XMASBUSH", - // FHZ - "MT_FHZICE1", - "MT_FHZICE2", - "MT_ROSY", - "MT_CDLHRT", - - // Halloween Scenery - // Pumpkins - "MT_JACKO1", - "MT_JACKO2", - "MT_JACKO3", - // Dr Seuss Trees - "MT_HHZTREE_TOP", - "MT_HHZTREE_PART", - // Misc - "MT_HHZSHROOM", - "MT_HHZGRASS", - "MT_HHZTENTACLE1", - "MT_HHZTENTACLE2", - "MT_HHZSTALAGMITE_TALL", - "MT_HHZSTALAGMITE_SHORT", - - // Botanic Serenity scenery - "MT_BSZTALLFLOWER_RED", - "MT_BSZTALLFLOWER_PURPLE", - "MT_BSZTALLFLOWER_BLUE", - "MT_BSZTALLFLOWER_CYAN", - "MT_BSZTALLFLOWER_YELLOW", - "MT_BSZTALLFLOWER_ORANGE", - "MT_BSZFLOWER_RED", - "MT_BSZFLOWER_PURPLE", - "MT_BSZFLOWER_BLUE", - "MT_BSZFLOWER_CYAN", - "MT_BSZFLOWER_YELLOW", - "MT_BSZFLOWER_ORANGE", - "MT_BSZSHORTFLOWER_RED", - "MT_BSZSHORTFLOWER_PURPLE", - "MT_BSZSHORTFLOWER_BLUE", - "MT_BSZSHORTFLOWER_CYAN", - "MT_BSZSHORTFLOWER_YELLOW", - "MT_BSZSHORTFLOWER_ORANGE", - "MT_BSZTULIP_RED", - "MT_BSZTULIP_PURPLE", - "MT_BSZTULIP_BLUE", - "MT_BSZTULIP_CYAN", - "MT_BSZTULIP_YELLOW", - "MT_BSZTULIP_ORANGE", - "MT_BSZCLUSTER_RED", - "MT_BSZCLUSTER_PURPLE", - "MT_BSZCLUSTER_BLUE", - "MT_BSZCLUSTER_CYAN", - "MT_BSZCLUSTER_YELLOW", - "MT_BSZCLUSTER_ORANGE", - "MT_BSZBUSH_RED", - "MT_BSZBUSH_PURPLE", - "MT_BSZBUSH_BLUE", - "MT_BSZBUSH_CYAN", - "MT_BSZBUSH_YELLOW", - "MT_BSZBUSH_ORANGE", - "MT_BSZVINE_RED", - "MT_BSZVINE_PURPLE", - "MT_BSZVINE_BLUE", - "MT_BSZVINE_CYAN", - "MT_BSZVINE_YELLOW", - "MT_BSZVINE_ORANGE", - "MT_BSZSHRUB", - "MT_BSZCLOVER", - "MT_BIG_PALMTREE_TRUNK", - "MT_BIG_PALMTREE_TOP", - "MT_PALMTREE_TRUNK", - "MT_PALMTREE_TOP", - - // Misc scenery - "MT_DBALL", - "MT_EGGSTATUE2", - - // Powerup Indicators - "MT_ELEMENTAL_ORB", // Elemental shield mobj - "MT_ATTRACT_ORB", // Attract shield mobj - "MT_FORCE_ORB", // Force shield mobj - "MT_ARMAGEDDON_ORB", // Armageddon shield mobj - "MT_WHIRLWIND_ORB", // Whirlwind shield mobj - "MT_PITY_ORB", // Pity shield mobj - "MT_FLAMEAURA_ORB", // Flame shield mobj - "MT_BUBBLEWRAP_ORB", // Bubble shield mobj - "MT_THUNDERCOIN_ORB", // Thunder shield mobj - "MT_THUNDERCOIN_SPARK", // Thunder spark - "MT_IVSP", // Invincibility sparkles - "MT_SUPERSPARK", // Super Sonic Spark - - // Flickies - "MT_FLICKY_01", // Bluebird - "MT_FLICKY_01_CENTER", - "MT_FLICKY_02", // Rabbit - "MT_FLICKY_02_CENTER", - "MT_FLICKY_03", // Chicken - "MT_FLICKY_03_CENTER", - "MT_FLICKY_04", // Seal - "MT_FLICKY_04_CENTER", - "MT_FLICKY_05", // Pig - "MT_FLICKY_05_CENTER", - "MT_FLICKY_06", // Chipmunk - "MT_FLICKY_06_CENTER", - "MT_FLICKY_07", // Penguin - "MT_FLICKY_07_CENTER", - "MT_FLICKY_08", // Fish - "MT_FLICKY_08_CENTER", - "MT_FLICKY_09", // Ram - "MT_FLICKY_09_CENTER", - "MT_FLICKY_10", // Puffin - "MT_FLICKY_10_CENTER", - "MT_FLICKY_11", // Cow - "MT_FLICKY_11_CENTER", - "MT_FLICKY_12", // Rat - "MT_FLICKY_12_CENTER", - "MT_FLICKY_13", // Bear - "MT_FLICKY_13_CENTER", - "MT_FLICKY_14", // Dove - "MT_FLICKY_14_CENTER", - "MT_FLICKY_15", // Cat - "MT_FLICKY_15_CENTER", - "MT_FLICKY_16", // Canary - "MT_FLICKY_16_CENTER", - "MT_SECRETFLICKY_01", // Spider - "MT_SECRETFLICKY_01_CENTER", - "MT_SECRETFLICKY_02", // Bat - "MT_SECRETFLICKY_02_CENTER", - "MT_SEED", - - // Environmental Effects - "MT_RAIN", // Rain - "MT_SNOWFLAKE", // Snowflake - "MT_SPLISH", // Water splish! - "MT_LAVASPLISH", // Lava splish! - "MT_SMOKE", - "MT_SMALLBUBBLE", // small bubble - "MT_MEDIUMBUBBLE", // medium bubble - "MT_EXTRALARGEBUBBLE", // extra large bubble - "MT_WATERZAP", - "MT_SPINDUST", // Spindash dust - "MT_TFOG", - "MT_PARTICLE", - "MT_PARTICLEGEN", // For fans, etc. - - // Game Indicators - "MT_SCORE", // score logo - "MT_DROWNNUMBERS", // Drowning Timer - "MT_GOTEMERALD", // Chaos Emerald (intangible) - "MT_LOCKON", // Target - "MT_LOCKONINF", // In-level Target - "MT_TAG", // Tag Sign - "MT_GOTFLAG", // Got Flag sign - "MT_FINISHFLAG", // Finish flag - - // Ambient Sounds - "MT_AWATERA", // Ambient Water Sound 1 - "MT_AWATERB", // Ambient Water Sound 2 - "MT_AWATERC", // Ambient Water Sound 3 - "MT_AWATERD", // Ambient Water Sound 4 - "MT_AWATERE", // Ambient Water Sound 5 - "MT_AWATERF", // Ambient Water Sound 6 - "MT_AWATERG", // Ambient Water Sound 7 - "MT_AWATERH", // Ambient Water Sound 8 - "MT_RANDOMAMBIENT", - "MT_RANDOMAMBIENT2", - "MT_MACHINEAMBIENCE", - - "MT_CORK", - "MT_LHRT", - - // Ring Weapons - "MT_REDRING", - "MT_BOUNCERING", - "MT_RAILRING", - "MT_INFINITYRING", - "MT_AUTOMATICRING", - "MT_EXPLOSIONRING", - "MT_SCATTERRING", - "MT_GRENADERING", - - "MT_BOUNCEPICKUP", - "MT_RAILPICKUP", - "MT_AUTOPICKUP", - "MT_EXPLODEPICKUP", - "MT_SCATTERPICKUP", - "MT_GRENADEPICKUP", - - "MT_THROWNBOUNCE", - "MT_THROWNINFINITY", - "MT_THROWNAUTOMATIC", - "MT_THROWNSCATTER", - "MT_THROWNEXPLOSION", - "MT_THROWNGRENADE", - - // Mario-specific stuff - "MT_COIN", - "MT_FLINGCOIN", - "MT_GOOMBA", - "MT_BLUEGOOMBA", - "MT_FIREFLOWER", - "MT_FIREBALL", - "MT_FIREBALLTRAIL", - "MT_SHELL", - "MT_PUMA", - "MT_PUMATRAIL", - "MT_HAMMER", - "MT_KOOPA", - "MT_KOOPAFLAME", - "MT_AXE", - "MT_MARIOBUSH1", - "MT_MARIOBUSH2", - "MT_TOAD", - - // NiGHTS Stuff - "MT_AXIS", - "MT_AXISTRANSFER", - "MT_AXISTRANSFERLINE", - "MT_NIGHTSDRONE", - "MT_NIGHTSDRONE_MAN", - "MT_NIGHTSDRONE_SPARKLING", - "MT_NIGHTSDRONE_GOAL", - "MT_NIGHTSPARKLE", - "MT_NIGHTSLOOPHELPER", - "MT_NIGHTSBUMPER", // NiGHTS Bumper - "MT_HOOP", - "MT_HOOPCOLLIDE", // Collision detection for NiGHTS hoops - "MT_HOOPCENTER", // Center of a hoop - "MT_NIGHTSCORE", - "MT_NIGHTSCHIP", // NiGHTS Chip - "MT_FLINGNIGHTSCHIP", // Lost NiGHTS Chip - "MT_NIGHTSSTAR", // NiGHTS Star - "MT_FLINGNIGHTSSTAR", // Lost NiGHTS Star - "MT_NIGHTSSUPERLOOP", - "MT_NIGHTSDRILLREFILL", - "MT_NIGHTSHELPER", - "MT_NIGHTSEXTRATIME", - "MT_NIGHTSLINKFREEZE", - "MT_EGGCAPSULE", - "MT_IDEYAANCHOR", - "MT_NIGHTOPIANHELPER", // the actual helper object that orbits you - "MT_PIAN", // decorative singing friend - "MT_SHLEEP", // almost-decorative sleeping enemy - - // Secret badniks and hazards, shhhh - "MT_PENGUINATOR", - "MT_POPHAT", - "MT_POPSHOT", - "MT_POPSHOT_TRAIL", - - "MT_HIVEELEMENTAL", - "MT_BUMBLEBORE", - - "MT_BUGGLE", - - "MT_SMASHINGSPIKEBALL", - "MT_CACOLANTERN", - "MT_CACOSHARD", - "MT_CACOFIRE", - "MT_SPINBOBERT", - "MT_SPINBOBERT_FIRE1", - "MT_SPINBOBERT_FIRE2", - "MT_HANGSTER", - - // Utility Objects - "MT_TELEPORTMAN", - "MT_ALTVIEWMAN", - "MT_CRUMBLEOBJ", // Sound generator for crumbling platform - "MT_TUBEWAYPOINT", - "MT_PUSH", - "MT_PULL", - "MT_GHOST", - "MT_OVERLAY", - "MT_ANGLEMAN", - "MT_POLYANCHOR", - "MT_POLYSPAWN", - - // Skybox objects - "MT_SKYBOX", - - // Debris - "MT_SPARK", //spark - "MT_EXPLODE", // Robot Explosion - "MT_UWEXPLODE", // Underwater Explosion - "MT_DUST", - "MT_ROCKSPAWNER", - "MT_FALLINGROCK", - "MT_ROCKCRUMBLE1", - "MT_ROCKCRUMBLE2", - "MT_ROCKCRUMBLE3", - "MT_ROCKCRUMBLE4", - "MT_ROCKCRUMBLE5", - "MT_ROCKCRUMBLE6", - "MT_ROCKCRUMBLE7", - "MT_ROCKCRUMBLE8", - "MT_ROCKCRUMBLE9", - "MT_ROCKCRUMBLE10", - "MT_ROCKCRUMBLE11", - "MT_ROCKCRUMBLE12", - "MT_ROCKCRUMBLE13", - "MT_ROCKCRUMBLE14", - "MT_ROCKCRUMBLE15", - "MT_ROCKCRUMBLE16", - - // Level debris - "MT_GFZDEBRIS", - "MT_BRICKDEBRIS", - "MT_WOODDEBRIS", - "MT_REDBRICKDEBRIS", - "MT_BLUEBRICKDEBRIS", - "MT_YELLOWBRICKDEBRIS", - -#ifdef SEENAMES - "MT_NAMECHECK", -#endif -}; - -static const char *const MOBJFLAG_LIST[] = { - "SPECIAL", - "SOLID", - "SHOOTABLE", - "NOSECTOR", - "NOBLOCKMAP", - "PAPERCOLLISION", - "PUSHABLE", - "BOSS", - "SPAWNCEILING", - "NOGRAVITY", - "AMBIENT", - "SLIDEME", - "NOCLIP", - "FLOAT", - "BOXICON", - "MISSILE", - "SPRING", - "BOUNCE", - "MONITOR", - "NOTHINK", - "FIRE", - "NOCLIPHEIGHT", - "ENEMY", - "SCENERY", - "PAIN", - "STICKY", - "NIGHTSITEM", - "NOCLIPTHING", - "GRENADEBOUNCE", - "RUNSPAWNFUNC", - NULL -}; - -// \tMF2_(\S+).*// (.+) --> \t"\1", // \2 -static const char *const MOBJFLAG2_LIST[] = { - "AXIS", // It's a NiGHTS axis! (For faster checking) - "TWOD", // Moves like it's in a 2D level - "DONTRESPAWN", // Don't respawn this object! - "DONTDRAW", // Don't generate a vissprite - "AUTOMATIC", // Thrown ring has automatic properties - "RAILRING", // Thrown ring has rail properties - "BOUNCERING", // Thrown ring has bounce properties - "EXPLOSION", // Thrown ring has explosive properties - "SCATTER", // Thrown ring has scatter properties - "BEYONDTHEGRAVE", // Source of this missile has died and has since respawned. - "SLIDEPUSH", // MF_PUSHABLE that pushes continuously. - "CLASSICPUSH", // Drops straight down when object has negative momz. - "INVERTAIMABLE", // Flips whether it's targetable by A_LookForEnemies (enemies no, decoys yes) - "INFLOAT", // Floating to a height for a move, don't auto float to target's height. - "DEBRIS", // Splash ring from explosion ring - "NIGHTSPULL", // Attracted from a paraloop - "JUSTATTACKED", // can be pushed by other moving mobjs - "FIRING", // turret fire - "SUPERFIRE", // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it. - "SHADOW", // Fuzzy draw, makes targeting harder. - "STRONGBOX", // Flag used for "strong" random monitors. - "OBJECTFLIP", // Flag for objects that always have flipped gravity. - "SKULLFLY", // Special handling: skull in flight. - "FRET", // Flashing from a previous hit - "BOSSNOTRAP", // No Egg Trap after boss - "BOSSFLEE", // Boss is fleeing! - "BOSSDEAD", // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.) - "AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH - "LINKDRAW", // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) - "SHIELD", // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use) - NULL -}; - -static const char *const MOBJEFLAG_LIST[] = { - "ONGROUND", // The mobj stands on solid floor (not on another mobj or in air) - "JUSTHITFLOOR", // The mobj just hit the floor while falling, this is cleared on next frame - "TOUCHWATER", // The mobj stands in a sector with water, and touches the surface - "UNDERWATER", // The mobj stands in a sector with water, and his waist is BELOW the water surface - "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 -}; - -static const char *const MAPTHINGFLAG_LIST[4] = { - "EXTRA", // Extra flag for objects. - "OBJECTFLIP", // Reverse gravity flag for objects. - "OBJECTSPECIAL", // Special flag used with certain objects. - "AMBUSH" // Deaf monsters/do not react to sound. -}; - -static const char *const PLAYERFLAG_LIST[] = { - - // Cvars - "FLIPCAM", // Flip camera angle with gravity flip prefrence. - "ANALOGMODE", // Analog mode? - "DIRECTIONCHAR", // Directional character sprites? - "AUTOBRAKE", // Autobrake? - - // Cheats - "GODMODE", - "NOCLIP", - "INVIS", - - // True if button down last tic. - "ATTACKDOWN", - "SPINDOWN", - "JUMPDOWN", - "WPNDOWN", - - // Unmoving states - "STASIS", // Player is not allowed to move - "JUMPSTASIS", // and that includes jumping. - // (we don't include FULLSTASIS here I guess because it's just those two together...?) - - // Applying autobrake? - "APPLYAUTOBRAKE", - - // Character action status - "STARTJUMP", - "JUMPED", - "NOJUMPDAMAGE", - - "SPINNING", - "STARTDASH", - - "THOKKED", - "SHIELDABILITY", - "GLIDING", - "BOUNCING", - - // Sliding (usually in water) like Labyrinth/Oil Ocean - "SLIDING", - - // NiGHTS stuff - "TRANSFERTOCLOSEST", - "DRILLING", - - // Gametype-specific stuff - "GAMETYPEOVER", // Race time over, or H&S out-of-game - "TAGIT", // The player is it! For Tag Mode - - /*** misc ***/ - "FORCESTRAFE", // Translate turn inputs into strafe inputs - "CANCARRY", // Can carry? - "FINISHED", - - NULL // stop loop here. -}; - -static const char *const GAMETYPERULE_LIST[] = { - "CAMPAIGN", - "RINGSLINGER", - "SPECTATORS", - "LIVES", - "TEAMS", - "FIRSTPERSON", - "POWERSTONES", - "TEAMFLAGS", - "FRIENDLY", - "SPECIALSTAGES", - "EMERALDTOKENS", - "EMERALDHUNT", - "RACE", - "TAG", - "POINTLIMIT", - "TIMELIMIT", - "OVERTIME", - "HURTMESSAGES", - "FRIENDLYFIRE", - "STARTCOUNTDOWN", - "HIDEFROZEN", - "BLINDFOLDED", - "RESPAWNDELAY", - "PITYSHIELD", - "DEATHPENALTY", - "NOSPECTATORSPAWN", - "DEATHMATCHSTARTS", - "SPAWNINVUL", - "SPAWNENEMIES", - "ALLOWEXIT", - "NOTITLECARD", - "CUTSCENES", - NULL -}; - -// Linedef flags -static const char *const ML_LIST[16] = { - "IMPASSIBLE", - "BLOCKMONSTERS", - "TWOSIDED", - "DONTPEGTOP", - "DONTPEGBOTTOM", - "EFFECT1", - "NOCLIMB", - "EFFECT2", - "EFFECT3", - "EFFECT4", - "EFFECT5", - "NOSONIC", - "NOTAILS", - "NOKNUX", - "BOUNCY", - "TFERLINE" -}; - -static const char *COLOR_ENUMS[] = { - "NONE", // SKINCOLOR_NONE, - - // Greyscale ranges - "WHITE", // SKINCOLOR_WHITE, - "BONE", // SKINCOLOR_BONE, - "CLOUDY", // SKINCOLOR_CLOUDY, - "GREY", // SKINCOLOR_GREY, - "SILVER", // SKINCOLOR_SILVER, - "CARBON", // SKINCOLOR_CARBON, - "JET", // SKINCOLOR_JET, - "BLACK", // SKINCOLOR_BLACK, - - // Desaturated - "AETHER", // SKINCOLOR_AETHER, - "SLATE", // SKINCOLOR_SLATE, - "BLUEBELL", // SKINCOLOR_BLUEBELL, - "PINK", // SKINCOLOR_PINK, - "YOGURT", // SKINCOLOR_YOGURT, - "BROWN", // SKINCOLOR_BROWN, - "BRONZE", // SKINCOLOR_BRONZE, - "TAN", // SKINCOLOR_TAN, - "BEIGE", // SKINCOLOR_BEIGE, - "MOSS", // SKINCOLOR_MOSS, - "AZURE", // SKINCOLOR_AZURE, - "LAVENDER", // SKINCOLOR_LAVENDER, - - // Viv's vivid colours (toast 21/07/17) - "RUBY", // SKINCOLOR_RUBY, - "SALMON", // SKINCOLOR_SALMON, - "RED", // SKINCOLOR_RED, - "CRIMSON", // SKINCOLOR_CRIMSON, - "FLAME", // SKINCOLOR_FLAME, - "KETCHUP", // SKINCOLOR_KETCHUP, - "PEACHY", // SKINCOLOR_PEACHY, - "QUAIL", // SKINCOLOR_QUAIL, - "SUNSET", // SKINCOLOR_SUNSET, - "COPPER", // SKINCOLOR_COPPER, - "APRICOT", // SKINCOLOR_APRICOT, - "ORANGE", // SKINCOLOR_ORANGE, - "RUST", // SKINCOLOR_RUST, - "GOLD", // SKINCOLOR_GOLD, - "SANDY", // SKINCOLOR_SANDY, - "YELLOW", // SKINCOLOR_YELLOW, - "OLIVE", // SKINCOLOR_OLIVE, - "LIME", // SKINCOLOR_LIME, - "PERIDOT", // SKINCOLOR_PERIDOT, - "APPLE", // SKINCOLOR_APPLE, - "GREEN", // SKINCOLOR_GREEN, - "FOREST", // SKINCOLOR_FOREST, - "EMERALD", // SKINCOLOR_EMERALD, - "MINT", // SKINCOLOR_MINT, - "SEAFOAM", // SKINCOLOR_SEAFOAM, - "AQUA", // SKINCOLOR_AQUA, - "TEAL", // SKINCOLOR_TEAL, - "WAVE", // SKINCOLOR_WAVE, - "CYAN", // SKINCOLOR_CYAN, - "SKY", // SKINCOLOR_SKY, - "CERULEAN", // SKINCOLOR_CERULEAN, - "ICY", // SKINCOLOR_ICY, - "SAPPHIRE", // SKINCOLOR_SAPPHIRE, - "CORNFLOWER", // SKINCOLOR_CORNFLOWER, - "BLUE", // SKINCOLOR_BLUE, - "COBALT", // SKINCOLOR_COBALT, - "VAPOR", // SKINCOLOR_VAPOR, - "DUSK", // SKINCOLOR_DUSK, - "PASTEL", // SKINCOLOR_PASTEL, - "PURPLE", // SKINCOLOR_PURPLE, - "BUBBLEGUM", // SKINCOLOR_BUBBLEGUM, - "MAGENTA", // SKINCOLOR_MAGENTA, - "NEON", // SKINCOLOR_NEON, - "VIOLET", // SKINCOLOR_VIOLET, - "LILAC", // SKINCOLOR_LILAC, - "PLUM", // SKINCOLOR_PLUM, - "RASPBERRY", // SKINCOLOR_RASPBERRY, - "ROSY", // SKINCOLOR_ROSY, - - // Super special awesome Super flashing colors! - "SUPERSILVER1", // SKINCOLOR_SUPERSILVER1 - "SUPERSILVER2", // SKINCOLOR_SUPERSILVER2, - "SUPERSILVER3", // SKINCOLOR_SUPERSILVER3, - "SUPERSILVER4", // SKINCOLOR_SUPERSILVER4, - "SUPERSILVER5", // SKINCOLOR_SUPERSILVER5, - - "SUPERRED1", // SKINCOLOR_SUPERRED1 - "SUPERRED2", // SKINCOLOR_SUPERRED2, - "SUPERRED3", // SKINCOLOR_SUPERRED3, - "SUPERRED4", // SKINCOLOR_SUPERRED4, - "SUPERRED5", // SKINCOLOR_SUPERRED5, - - "SUPERORANGE1", // SKINCOLOR_SUPERORANGE1 - "SUPERORANGE2", // SKINCOLOR_SUPERORANGE2, - "SUPERORANGE3", // SKINCOLOR_SUPERORANGE3, - "SUPERORANGE4", // SKINCOLOR_SUPERORANGE4, - "SUPERORANGE5", // SKINCOLOR_SUPERORANGE5, - - "SUPERGOLD1", // SKINCOLOR_SUPERGOLD1 - "SUPERGOLD2", // SKINCOLOR_SUPERGOLD2, - "SUPERGOLD3", // SKINCOLOR_SUPERGOLD3, - "SUPERGOLD4", // SKINCOLOR_SUPERGOLD4, - "SUPERGOLD5", // SKINCOLOR_SUPERGOLD5, - - "SUPERPERIDOT1", // SKINCOLOR_SUPERPERIDOT1 - "SUPERPERIDOT2", // SKINCOLOR_SUPERPERIDOT2, - "SUPERPERIDOT3", // SKINCOLOR_SUPERPERIDOT3, - "SUPERPERIDOT4", // SKINCOLOR_SUPERPERIDOT4, - "SUPERPERIDOT5", // SKINCOLOR_SUPERPERIDOT5, - - "SUPERSKY1", // SKINCOLOR_SUPERSKY1 - "SUPERSKY2", // SKINCOLOR_SUPERSKY2, - "SUPERSKY3", // SKINCOLOR_SUPERSKY3, - "SUPERSKY4", // SKINCOLOR_SUPERSKY4, - "SUPERSKY5", // SKINCOLOR_SUPERSKY5, - - "SUPERPURPLE1", // SKINCOLOR_SUPERPURPLE1, - "SUPERPURPLE2", // SKINCOLOR_SUPERPURPLE2, - "SUPERPURPLE3", // SKINCOLOR_SUPERPURPLE3, - "SUPERPURPLE4", // SKINCOLOR_SUPERPURPLE4, - "SUPERPURPLE5", // SKINCOLOR_SUPERPURPLE5, - - "SUPERRUST1", // SKINCOLOR_SUPERRUST1 - "SUPERRUST2", // SKINCOLOR_SUPERRUST2, - "SUPERRUST3", // SKINCOLOR_SUPERRUST3, - "SUPERRUST4", // SKINCOLOR_SUPERRUST4, - "SUPERRUST5", // SKINCOLOR_SUPERRUST5, - - "SUPERTAN1", // SKINCOLOR_SUPERTAN1 - "SUPERTAN2", // SKINCOLOR_SUPERTAN2, - "SUPERTAN3", // SKINCOLOR_SUPERTAN3, - "SUPERTAN4", // SKINCOLOR_SUPERTAN4, - "SUPERTAN5" // SKINCOLOR_SUPERTAN5, -}; - -static const char *const POWERS_LIST[] = { - "INVULNERABILITY", - "SNEAKERS", - "FLASHING", - "SHIELD", - "CARRY", - "TAILSFLY", // tails flying - "UNDERWATER", // underwater timer - "SPACETIME", // In space, no one can hear you spin! - "EXTRALIFE", // Extra Life timer - "PUSHING", - "JUSTSPRUNG", - "NOAUTOBRAKE", - - "SUPER", // Are you super? - "GRAVITYBOOTS", // gravity boots - - // Weapon ammunition - "INFINITYRING", - "AUTOMATICRING", - "BOUNCERING", - "SCATTERRING", - "GRENADERING", - "EXPLOSIONRING", - "RAILRING", - - // Power Stones - "EMERALDS", // stored like global 'emeralds' variable - - // NiGHTS powerups - "NIGHTS_SUPERLOOP", - "NIGHTS_HELPER", - "NIGHTS_LINKFREEZE", - - //for linedef exec 427 - "NOCONTROL", - - //for dyes - "DYE", - - "JUSTLAUNCHED", - - "IGNORELATCH" -}; - -static const char *const HUDITEMS_LIST[] = { - "LIVES", - - "RINGS", - "RINGSNUM", - "RINGSNUMTICS", - - "SCORE", - "SCORENUM", - - "TIME", - "MINUTES", - "TIMECOLON", - "SECONDS", - "TIMETICCOLON", - "TICS", - - "SS_TOTALRINGS", - - "GETRINGS", - "GETRINGSNUM", - "TIMELEFT", - "TIMELEFTNUM", - "TIMEUP", - "HUNTPICS", - "POWERUPS" -}; - -static const char *const MENUTYPES_LIST[] = { - "NONE", - - "MAIN", - - // Single Player - "SP_MAIN", - - "SP_LOAD", - "SP_PLAYER", - - "SP_LEVELSELECT", - "SP_LEVELSTATS", - - "SP_TIMEATTACK", - "SP_TIMEATTACK_LEVELSELECT", - "SP_GUESTREPLAY", - "SP_REPLAY", - "SP_GHOST", - - "SP_NIGHTSATTACK", - "SP_NIGHTS_LEVELSELECT", - "SP_NIGHTS_GUESTREPLAY", - "SP_NIGHTS_REPLAY", - "SP_NIGHTS_GHOST", - - // Multiplayer - "MP_MAIN", - "MP_SPLITSCREEN", // SplitServer - "MP_SERVER", - "MP_CONNECT", - "MP_ROOM", - "MP_PLAYERSETUP", // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET - "MP_SERVER_OPTIONS", - - // Options - "OP_MAIN", - - "OP_P1CONTROLS", - "OP_CHANGECONTROLS", // OP_ChangeControlsDef shared with P2 - "OP_P1MOUSE", - "OP_P1JOYSTICK", - "OP_JOYSTICKSET", // OP_JoystickSetDef shared with P2 - "OP_P1CAMERA", - - "OP_P2CONTROLS", - "OP_P2MOUSE", - "OP_P2JOYSTICK", - "OP_P2CAMERA", - - "OP_PLAYSTYLE", - - "OP_VIDEO", - "OP_VIDEOMODE", - "OP_COLOR", - "OP_OPENGL", - "OP_OPENGL_LIGHTING", - - "OP_SOUND", - - "OP_SERVER", - "OP_MONITORTOGGLE", - - "OP_DATA", - "OP_ADDONS", - "OP_SCREENSHOTS", - "OP_ERASEDATA", - - // Extras - "SR_MAIN", - "SR_PANDORA", - "SR_LEVELSELECT", - "SR_UNLOCKCHECKLIST", - "SR_EMBLEMHINT", - "SR_PLAYER", - "SR_SOUNDTEST", - - // Addons (Part of MISC, but let's make it our own) - "AD_MAIN", - - // MISC - // "MESSAGE", - // "SPAUSE", - - // "MPAUSE", - // "SCRAMBLETEAM", - // "CHANGETEAM", - // "CHANGELEVEL", - - // "MAPAUSE", - // "HELP", - - "SPECIAL" -}; - -struct { - const char *n; - // has to be able to hold both fixed_t and angle_t, so drastic measure!! - lua_Integer v; -} const INT_CONST[] = { - // If a mod removes some variables here, - // please leave the names in-tact and just set - // the value to 0 or something. - - // integer type limits, from doomtype.h - // INT64 and UINT64 limits not included, they're too big for most purposes anyway - // signed - {"INT8_MIN",INT8_MIN}, - {"INT16_MIN",INT16_MIN}, - {"INT32_MIN",INT32_MIN}, - {"INT8_MAX",INT8_MAX}, - {"INT16_MAX",INT16_MAX}, - {"INT32_MAX",INT32_MAX}, - // unsigned - {"UINT8_MAX",UINT8_MAX}, - {"UINT16_MAX",UINT16_MAX}, - {"UINT32_MAX",UINT32_MAX}, - - // fixed_t constants, from m_fixed.h - {"FRACUNIT",FRACUNIT}, - {"FRACBITS",FRACBITS}, - - // doomdef.h constants - {"TICRATE",TICRATE}, - {"MUSICRATE",MUSICRATE}, - {"RING_DIST",RING_DIST}, - {"PUSHACCEL",PUSHACCEL}, - {"MODID",MODID}, // I don't know, I just thought it would be cool for a wad to potentially know what mod it was loaded into. - {"MODVERSION",MODVERSION}, // or what version of the mod this is. - {"CODEBASE",CODEBASE}, // or what release of SRB2 this is. - {"NEWTICRATE",NEWTICRATE}, // TICRATE*NEWTICRATERATIO - {"NEWTICRATERATIO",NEWTICRATERATIO}, - - // Special linedef executor tag numbers! - {"LE_PINCHPHASE",LE_PINCHPHASE}, // A boss entered pinch phase (and, in most cases, is preparing their pinch phase attack!) - {"LE_ALLBOSSESDEAD",LE_ALLBOSSESDEAD}, // All bosses in the map are dead (Egg capsule raise) - {"LE_BOSSDEAD",LE_BOSSDEAD}, // A boss in the map died (Chaos mode boss tally) - {"LE_BOSS4DROP",LE_BOSS4DROP}, // CEZ boss dropped its cage - {"LE_BRAKVILEATACK",LE_BRAKVILEATACK}, // Brak's doing his LOS attack, oh noes - {"LE_TURRET",LE_TURRET}, // THZ turret - {"LE_BRAKPLATFORM",LE_BRAKPLATFORM}, // v2.0 Black Eggman destroys platform - {"LE_CAPSULE2",LE_CAPSULE2}, // Egg Capsule - {"LE_CAPSULE1",LE_CAPSULE1}, // Egg Capsule - {"LE_CAPSULE0",LE_CAPSULE0}, // Egg Capsule - {"LE_KOOPA",LE_KOOPA}, // Distant cousin to Gay Bowser - {"LE_AXE",LE_AXE}, // MKB Axe object - {"LE_PARAMWIDTH",LE_PARAMWIDTH}, // If an object that calls LinedefExecute has a nonzero parameter value, this times the parameter will be subtracted. (Mostly for the purpose of coexisting bosses...) - - /// \todo Get all this stuff into its own sections, maybe. Maybe. - - // Frame settings - {"FF_FRAMEMASK",FF_FRAMEMASK}, - {"FF_SPR2SUPER",FF_SPR2SUPER}, - {"FF_SPR2ENDSTATE",FF_SPR2ENDSTATE}, - {"FF_SPR2MIDSTART",FF_SPR2MIDSTART}, - {"FF_ANIMATE",FF_ANIMATE}, - {"FF_RANDOMANIM",FF_RANDOMANIM}, - {"FF_GLOBALANIM",FF_GLOBALANIM}, - {"FF_FULLBRIGHT",FF_FULLBRIGHT}, - {"FF_VERTICALFLIP",FF_VERTICALFLIP}, - {"FF_HORIZONTALFLIP",FF_HORIZONTALFLIP}, - {"FF_PAPERSPRITE",FF_PAPERSPRITE}, - {"FF_TRANSMASK",FF_TRANSMASK}, - {"FF_TRANSSHIFT",FF_TRANSSHIFT}, - // new preshifted translucency (used in source) - {"FF_TRANS10",FF_TRANS10}, - {"FF_TRANS20",FF_TRANS20}, - {"FF_TRANS30",FF_TRANS30}, - {"FF_TRANS40",FF_TRANS40}, - {"FF_TRANS50",FF_TRANS50}, - {"FF_TRANS60",FF_TRANS60}, - {"FF_TRANS70",FF_TRANS70}, - {"FF_TRANS80",FF_TRANS80}, - {"FF_TRANS90",FF_TRANS90}, - // compatibility - // Transparency for SOCs is pre-shifted - {"TR_TRANS10",tr_trans10<<FF_TRANSSHIFT}, - {"TR_TRANS20",tr_trans20<<FF_TRANSSHIFT}, - {"TR_TRANS30",tr_trans30<<FF_TRANSSHIFT}, - {"TR_TRANS40",tr_trans40<<FF_TRANSSHIFT}, - {"TR_TRANS50",tr_trans50<<FF_TRANSSHIFT}, - {"TR_TRANS60",tr_trans60<<FF_TRANSSHIFT}, - {"TR_TRANS70",tr_trans70<<FF_TRANSSHIFT}, - {"TR_TRANS80",tr_trans80<<FF_TRANSSHIFT}, - {"TR_TRANS90",tr_trans90<<FF_TRANSSHIFT}, - // Transparency for Lua is not, unless capitalized as above. - {"tr_trans10",tr_trans10}, - {"tr_trans20",tr_trans20}, - {"tr_trans30",tr_trans30}, - {"tr_trans40",tr_trans40}, - {"tr_trans50",tr_trans50}, - {"tr_trans60",tr_trans60}, - {"tr_trans70",tr_trans70}, - {"tr_trans80",tr_trans80}, - {"tr_trans90",tr_trans90}, - {"NUMTRANSMAPS",NUMTRANSMAPS}, - - // Level flags - {"LF_SCRIPTISFILE",LF_SCRIPTISFILE}, - {"LF_SPEEDMUSIC",LF_SPEEDMUSIC}, - {"LF_NOSSMUSIC",LF_NOSSMUSIC}, - {"LF_NORELOAD",LF_NORELOAD}, - {"LF_NOZONE",LF_NOZONE}, - {"LF_SAVEGAME",LF_SAVEGAME}, - {"LF_MIXNIGHTSCOUNTDOWN",LF_MIXNIGHTSCOUNTDOWN}, - {"LF_NOTITLECARDFIRST",LF_NOTITLECARDFIRST}, - {"LF_NOTITLECARDRESPAWN",LF_NOTITLECARDRESPAWN}, - {"LF_NOTITLECARDRECORDATTACK",LF_NOTITLECARDRECORDATTACK}, - {"LF_NOTITLECARD",LF_NOTITLECARD}, - {"LF_WARNINGTITLE",LF_WARNINGTITLE}, - // And map flags - {"LF2_HIDEINMENU",LF2_HIDEINMENU}, - {"LF2_HIDEINSTATS",LF2_HIDEINSTATS}, - {"LF2_RECORDATTACK",LF2_RECORDATTACK}, - {"LF2_NIGHTSATTACK",LF2_NIGHTSATTACK}, - {"LF2_NOVISITNEEDED",LF2_NOVISITNEEDED}, - {"LF2_WIDEICON",LF2_WIDEICON}, - - // Emeralds - {"EMERALD1",EMERALD1}, - {"EMERALD2",EMERALD2}, - {"EMERALD3",EMERALD3}, - {"EMERALD4",EMERALD4}, - {"EMERALD5",EMERALD5}, - {"EMERALD6",EMERALD6}, - {"EMERALD7",EMERALD7}, - - // SKINCOLOR_ doesn't include these..! - {"MAXSKINCOLORS",MAXSKINCOLORS}, - {"FIRSTSUPERCOLOR",FIRSTSUPERCOLOR}, - {"NUMSUPERCOLORS",NUMSUPERCOLORS}, - - // Precipitation - {"PRECIP_NONE",PRECIP_NONE}, - {"PRECIP_STORM",PRECIP_STORM}, - {"PRECIP_SNOW",PRECIP_SNOW}, - {"PRECIP_RAIN",PRECIP_RAIN}, - {"PRECIP_BLANK",PRECIP_BLANK}, - {"PRECIP_STORM_NORAIN",PRECIP_STORM_NORAIN}, - {"PRECIP_STORM_NOSTRIKES",PRECIP_STORM_NOSTRIKES}, - - // Shields - {"SH_NONE",SH_NONE}, - // Shield flags - {"SH_PROTECTFIRE",SH_PROTECTFIRE}, - {"SH_PROTECTWATER",SH_PROTECTWATER}, - {"SH_PROTECTELECTRIC",SH_PROTECTELECTRIC}, - {"SH_PROTECTSPIKE",SH_PROTECTSPIKE}, - // Indivisible shields - {"SH_PITY",SH_PITY}, - {"SH_WHIRLWIND",SH_WHIRLWIND}, - {"SH_ARMAGEDDON",SH_ARMAGEDDON}, - {"SH_PINK",SH_PINK}, - // normal shields that use flags - {"SH_ATTRACT",SH_ATTRACT}, - {"SH_ELEMENTAL",SH_ELEMENTAL}, - // Sonic 3 shields - {"SH_FLAMEAURA",SH_FLAMEAURA}, - {"SH_BUBBLEWRAP",SH_BUBBLEWRAP}, - {"SH_THUNDERCOIN",SH_THUNDERCOIN}, - // The force shield uses the lower 8 bits to count how many extra hits are left. - {"SH_FORCE",SH_FORCE}, - {"SH_FORCEHP",SH_FORCEHP}, // to be used as a bitmask only - // Mostly for use with Mario mode. - {"SH_FIREFLOWER",SH_FIREFLOWER}, - {"SH_STACK",SH_STACK}, - {"SH_NOSTACK",SH_NOSTACK}, - - // Carrying - {"CR_NONE",CR_NONE}, - {"CR_GENERIC",CR_GENERIC}, - {"CR_PLAYER",CR_PLAYER}, - {"CR_NIGHTSMODE",CR_NIGHTSMODE}, - {"CR_NIGHTSFALL",CR_NIGHTSFALL}, - {"CR_BRAKGOOP",CR_BRAKGOOP}, - {"CR_ZOOMTUBE",CR_ZOOMTUBE}, - {"CR_ROPEHANG",CR_ROPEHANG}, - {"CR_MACESPIN",CR_MACESPIN}, - {"CR_MINECART",CR_MINECART}, - {"CR_ROLLOUT",CR_ROLLOUT}, - {"CR_PTERABYTE",CR_PTERABYTE}, - {"CR_DUSTDEVIL",CR_DUSTDEVIL}, - - // Ring weapons (ringweapons_t) - // Useful for A_GiveWeapon - {"RW_AUTO",RW_AUTO}, - {"RW_BOUNCE",RW_BOUNCE}, - {"RW_SCATTER",RW_SCATTER}, - {"RW_GRENADE",RW_GRENADE}, - {"RW_EXPLODE",RW_EXPLODE}, - {"RW_RAIL",RW_RAIL}, - - // Character flags (skinflags_t) - {"SF_SUPER",SF_SUPER}, - {"SF_NOSUPERSPIN",SF_NOSUPERSPIN}, - {"SF_NOSPINDASHDUST",SF_NOSPINDASHDUST}, - {"SF_HIRES",SF_HIRES}, - {"SF_NOSKID",SF_NOSKID}, - {"SF_NOSPEEDADJUST",SF_NOSPEEDADJUST}, - {"SF_RUNONWATER",SF_RUNONWATER}, - {"SF_NOJUMPSPIN",SF_NOJUMPSPIN}, - {"SF_NOJUMPDAMAGE",SF_NOJUMPDAMAGE}, - {"SF_STOMPDAMAGE",SF_STOMPDAMAGE}, - {"SF_MARIODAMAGE",SF_MARIODAMAGE}, - {"SF_MACHINE",SF_MACHINE}, - {"SF_DASHMODE",SF_DASHMODE}, - {"SF_FASTEDGE",SF_FASTEDGE}, - {"SF_MULTIABILITY",SF_MULTIABILITY}, - {"SF_NONIGHTSROTATION",SF_NONIGHTSROTATION}, - {"SF_NONIGHTSSUPER",SF_NONIGHTSSUPER}, - {"SF_NOSUPERSPRITES",SF_NOSUPERSPRITES}, - {"SF_NOSUPERJUMPBOOST",SF_NOSUPERJUMPBOOST}, - {"SF_CANBUSTWALLS",SF_CANBUSTWALLS}, - - // Dashmode constants - {"DASHMODE_THRESHOLD",DASHMODE_THRESHOLD}, - {"DASHMODE_MAX",DASHMODE_MAX}, - - // Character abilities! - // Primary - {"CA_NONE",CA_NONE}, // now slot 0! - {"CA_THOK",CA_THOK}, - {"CA_FLY",CA_FLY}, - {"CA_GLIDEANDCLIMB",CA_GLIDEANDCLIMB}, - {"CA_HOMINGTHOK",CA_HOMINGTHOK}, - {"CA_DOUBLEJUMP",CA_DOUBLEJUMP}, - {"CA_FLOAT",CA_FLOAT}, - {"CA_SLOWFALL",CA_SLOWFALL}, - {"CA_SWIM",CA_SWIM}, - {"CA_TELEKINESIS",CA_TELEKINESIS}, - {"CA_FALLSWITCH",CA_FALLSWITCH}, - {"CA_JUMPBOOST",CA_JUMPBOOST}, - {"CA_AIRDRILL",CA_AIRDRILL}, - {"CA_JUMPTHOK",CA_JUMPTHOK}, - {"CA_BOUNCE",CA_BOUNCE}, - {"CA_TWINSPIN",CA_TWINSPIN}, - // Secondary - {"CA2_NONE",CA2_NONE}, // now slot 0! - {"CA2_SPINDASH",CA2_SPINDASH}, - {"CA2_GUNSLINGER",CA2_GUNSLINGER}, - {"CA2_MELEE",CA2_MELEE}, - - // Sound flags - {"SF_TOTALLYSINGLE",SF_TOTALLYSINGLE}, - {"SF_NOMULTIPLESOUND",SF_NOMULTIPLESOUND}, - {"SF_OUTSIDESOUND",SF_OUTSIDESOUND}, - {"SF_X4AWAYSOUND",SF_X4AWAYSOUND}, - {"SF_X8AWAYSOUND",SF_X8AWAYSOUND}, - {"SF_NOINTERRUPT",SF_NOINTERRUPT}, - {"SF_X2AWAYSOUND",SF_X2AWAYSOUND}, - - // Global emblem var flags - {"GE_NIGHTSPULL",GE_NIGHTSPULL}, - {"GE_NIGHTSITEM",GE_NIGHTSITEM}, - - // Map emblem var flags - {"ME_ALLEMERALDS",ME_ALLEMERALDS}, - {"ME_ULTIMATE",ME_ULTIMATE}, - {"ME_PERFECT",ME_PERFECT}, - - // p_local.h constants - {"FLOATSPEED",FLOATSPEED}, - {"MAXSTEPMOVE",MAXSTEPMOVE}, - {"USERANGE",USERANGE}, - {"MELEERANGE",MELEERANGE}, - {"MISSILERANGE",MISSILERANGE}, - {"ONFLOORZ",ONFLOORZ}, // INT32_MIN - {"ONCEILINGZ",ONCEILINGZ}, //INT32_MAX - // for P_FlashPal - {"PAL_WHITE",PAL_WHITE}, - {"PAL_MIXUP",PAL_MIXUP}, - {"PAL_RECYCLE",PAL_RECYCLE}, - {"PAL_NUKE",PAL_NUKE}, - // for P_DamageMobj - //// Damage types - {"DMG_WATER",DMG_WATER}, - {"DMG_FIRE",DMG_FIRE}, - {"DMG_ELECTRIC",DMG_ELECTRIC}, - {"DMG_SPIKE",DMG_SPIKE}, - {"DMG_NUKE",DMG_NUKE}, - //// Death types - {"DMG_INSTAKILL",DMG_INSTAKILL}, - {"DMG_DROWNED",DMG_DROWNED}, - {"DMG_SPACEDROWN",DMG_SPACEDROWN}, - {"DMG_DEATHPIT",DMG_DEATHPIT}, - {"DMG_CRUSHED",DMG_CRUSHED}, - {"DMG_SPECTATOR",DMG_SPECTATOR}, - //// Masks - {"DMG_CANHURTSELF",DMG_CANHURTSELF}, - {"DMG_DEATHMASK",DMG_DEATHMASK}, - - // Intermission types - {"int_none",int_none}, - {"int_coop",int_coop}, - {"int_match",int_match}, - {"int_teammatch",int_teammatch}, - //{"int_tag",int_tag}, - {"int_ctf",int_ctf}, - {"int_spec",int_spec}, - {"int_race",int_race}, - {"int_comp",int_comp}, - - // Jingles (jingletype_t) - {"JT_NONE",JT_NONE}, - {"JT_OTHER",JT_OTHER}, - {"JT_MASTER",JT_MASTER}, - {"JT_1UP",JT_1UP}, - {"JT_SHOES",JT_SHOES}, - {"JT_INV",JT_INV}, - {"JT_MINV",JT_MINV}, - {"JT_DROWN",JT_DROWN}, - {"JT_SUPER",JT_SUPER}, - {"JT_GOVER",JT_GOVER}, - {"JT_NIGHTSTIMEOUT",JT_NIGHTSTIMEOUT}, - {"JT_SSTIMEOUT",JT_SSTIMEOUT}, - // {"JT_LCLEAR",JT_LCLEAR}, - // {"JT_RACENT",JT_RACENT}, - // {"JT_CONTSC",JT_CONTSC}, - - // Player state (playerstate_t) - {"PST_LIVE",PST_LIVE}, // Playing or camping. - {"PST_DEAD",PST_DEAD}, // Dead on the ground, view follows killer. - {"PST_REBORN",PST_REBORN}, // Ready to restart/respawn??? - - // Player animation (panim_t) - {"PA_ETC",PA_ETC}, - {"PA_IDLE",PA_IDLE}, - {"PA_EDGE",PA_EDGE}, - {"PA_WALK",PA_WALK}, - {"PA_RUN",PA_RUN}, - {"PA_DASH",PA_DASH}, - {"PA_PAIN",PA_PAIN}, - {"PA_ROLL",PA_ROLL}, - {"PA_JUMP",PA_JUMP}, - {"PA_SPRING",PA_SPRING}, - {"PA_FALL",PA_FALL}, - {"PA_ABILITY",PA_ABILITY}, - {"PA_ABILITY2",PA_ABILITY2}, - {"PA_RIDE",PA_RIDE}, - - // Current weapon - {"WEP_AUTO",WEP_AUTO}, - {"WEP_BOUNCE",WEP_BOUNCE}, - {"WEP_SCATTER",WEP_SCATTER}, - {"WEP_GRENADE",WEP_GRENADE}, - {"WEP_EXPLODE",WEP_EXPLODE}, - {"WEP_RAIL",WEP_RAIL}, - {"NUM_WEAPONS",NUM_WEAPONS}, - - // Value for infinite lives - {"INFLIVES",INFLIVES}, - - // Got Flags, for player->gotflag! - // Used to be MF_ for some stupid reason, now they're GF_ to stop them looking like mobjflags - {"GF_REDFLAG",GF_REDFLAG}, - {"GF_BLUEFLAG",GF_BLUEFLAG}, - - // Customisable sounds for Skins, from sounds.h - {"SKSSPIN",SKSSPIN}, - {"SKSPUTPUT",SKSPUTPUT}, - {"SKSPUDPUD",SKSPUDPUD}, - {"SKSPLPAN1",SKSPLPAN1}, // Ouchies - {"SKSPLPAN2",SKSPLPAN2}, - {"SKSPLPAN3",SKSPLPAN3}, - {"SKSPLPAN4",SKSPLPAN4}, - {"SKSPLDET1",SKSPLDET1}, // Deaths - {"SKSPLDET2",SKSPLDET2}, - {"SKSPLDET3",SKSPLDET3}, - {"SKSPLDET4",SKSPLDET4}, - {"SKSPLVCT1",SKSPLVCT1}, // Victories - {"SKSPLVCT2",SKSPLVCT2}, - {"SKSPLVCT3",SKSPLVCT3}, - {"SKSPLVCT4",SKSPLVCT4}, - {"SKSTHOK",SKSTHOK}, - {"SKSSPNDSH",SKSSPNDSH}, - {"SKSZOOM",SKSZOOM}, - {"SKSSKID",SKSSKID}, - {"SKSGASP",SKSGASP}, - {"SKSJUMP",SKSJUMP}, - - // 3D Floor/Fake Floor/FOF/whatever flags - {"FF_EXISTS",FF_EXISTS}, ///< Always set, to check for validity. - {"FF_BLOCKPLAYER",FF_BLOCKPLAYER}, ///< Solid to player, but nothing else - {"FF_BLOCKOTHERS",FF_BLOCKOTHERS}, ///< Solid to everything but player - {"FF_SOLID",FF_SOLID}, ///< Clips things. - {"FF_RENDERSIDES",FF_RENDERSIDES}, ///< Renders the sides. - {"FF_RENDERPLANES",FF_RENDERPLANES}, ///< Renders the floor/ceiling. - {"FF_RENDERALL",FF_RENDERALL}, ///< Renders everything. - {"FF_SWIMMABLE",FF_SWIMMABLE}, ///< Is a water block. - {"FF_NOSHADE",FF_NOSHADE}, ///< Messes with the lighting? - {"FF_CUTSOLIDS",FF_CUTSOLIDS}, ///< Cuts out hidden solid pixels. - {"FF_CUTEXTRA",FF_CUTEXTRA}, ///< Cuts out hidden translucent pixels. - {"FF_CUTLEVEL",FF_CUTLEVEL}, ///< Cuts out all hidden pixels. - {"FF_CUTSPRITES",FF_CUTSPRITES}, ///< Final step in making 3D water. - {"FF_BOTHPLANES",FF_BOTHPLANES}, ///< Render inside and outside planes. - {"FF_EXTRA",FF_EXTRA}, ///< Gets cut by ::FF_CUTEXTRA. - {"FF_TRANSLUCENT",FF_TRANSLUCENT}, ///< See through! - {"FF_FOG",FF_FOG}, ///< Fog "brush." - {"FF_INVERTPLANES",FF_INVERTPLANES}, ///< Only render inside planes. - {"FF_ALLSIDES",FF_ALLSIDES}, ///< Render inside and outside sides. - {"FF_INVERTSIDES",FF_INVERTSIDES}, ///< Only render inside sides. - {"FF_DOUBLESHADOW",FF_DOUBLESHADOW}, ///< Make two lightlist entries to reset light? - {"FF_FLOATBOB",FF_FLOATBOB}, ///< Floats on water and bobs if you step on it. - {"FF_NORETURN",FF_NORETURN}, ///< Used with ::FF_CRUMBLE. Will not return to its original position after falling. - {"FF_CRUMBLE",FF_CRUMBLE}, ///< Falls 2 seconds after being stepped on, and randomly brings all touching crumbling 3dfloors down with it, providing their master sectors share the same tag (allows crumble platforms above or below, to also exist). - {"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. - {"FF_MARIO",FF_MARIO}, ///< Acts like a question block when hit from underneath. Goodie spawned at top is determined by master sector. - {"FF_QUICKSAND",FF_QUICKSAND}, ///< Quicksand! - {"FF_PLATFORM",FF_PLATFORM}, ///< You can jump up through this to the top. - {"FF_REVERSEPLATFORM",FF_REVERSEPLATFORM}, ///< A fall-through floor in normal gravity, a platform in reverse gravity. - {"FF_INTANGIBLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangible, but the sides are still solid. - {"FF_INTANGABLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangable, but the sides are still solid. - {"FF_RIPPLE",FF_RIPPLE}, ///< Ripple the flats - {"FF_COLORMAPONLY",FF_COLORMAPONLY}, ///< Only copy the colormap, not the lightlevel - {"FF_BOUNCY",FF_BOUNCY}, ///< Bounces players - {"FF_SPLAT",FF_SPLAT}, ///< Use splat flat renderer (treat cyan pixels as invisible) - - // FOF special flags - {"FS_PUSHABLES",FS_PUSHABLES}, - {"FS_EXECUTOR",FS_EXECUTOR}, - {"FS_ONLYBOTTOM",FS_ONLYBOTTOM}, - {"FS_BUSTMASK",FS_BUSTMASK}, - {"FS_DAMPEN",FS_DAMPEN}, - - // Bustable FOF type - {"BT_TOUCH",BT_TOUCH}, - {"BT_SPINBUST",BT_SPINBUST}, - {"BT_REGULAR",BT_REGULAR}, - {"BT_STRONG",BT_STRONG}, - - // PolyObject flags - {"POF_CLIPLINES",POF_CLIPLINES}, ///< Test against lines for collision - {"POF_CLIPPLANES",POF_CLIPPLANES}, ///< Test against tops and bottoms for collision - {"POF_SOLID",POF_SOLID}, ///< Clips things. - {"POF_TESTHEIGHT",POF_TESTHEIGHT}, ///< Test line collision with heights - {"POF_RENDERSIDES",POF_RENDERSIDES}, ///< Renders the sides. - {"POF_RENDERTOP",POF_RENDERTOP}, ///< Renders the top. - {"POF_RENDERBOTTOM",POF_RENDERBOTTOM}, ///< Renders the bottom. - {"POF_RENDERPLANES",POF_RENDERPLANES}, ///< Renders top and bottom. - {"POF_RENDERALL",POF_RENDERALL}, ///< Renders everything. - {"POF_INVERT",POF_INVERT}, ///< Inverts collision (like a cage). - {"POF_INVERTPLANES",POF_INVERTPLANES}, ///< Render inside planes. - {"POF_INVERTPLANESONLY",POF_INVERTPLANESONLY}, ///< Only render inside planes. - {"POF_PUSHABLESTOP",POF_PUSHABLESTOP}, ///< Pushables will stop movement. - {"POF_LDEXEC",POF_LDEXEC}, ///< This PO triggers a linedef executor. - {"POF_ONESIDE",POF_ONESIDE}, ///< Only use the first side of the linedef. - {"POF_NOSPECIALS",POF_NOSPECIALS}, ///< Don't apply sector specials. - {"POF_SPLAT",POF_SPLAT}, ///< Use splat flat renderer (treat cyan pixels as invisible). - -#ifdef HAVE_LUA_SEGS - // Node flags - {"NF_SUBSECTOR",NF_SUBSECTOR}, // Indicate a leaf. -#endif - - // Slope flags - {"SL_NOPHYSICS",SL_NOPHYSICS}, - {"SL_DYNAMIC",SL_DYNAMIC}, - - // Angles - {"ANG1",ANG1}, - {"ANG2",ANG2}, - {"ANG10",ANG10}, - {"ANG15",ANG15}, - {"ANG20",ANG20}, - {"ANG30",ANG30}, - {"ANG60",ANG60}, - {"ANG64h",ANG64h}, - {"ANG105",ANG105}, - {"ANG210",ANG210}, - {"ANG255",ANG255}, - {"ANG340",ANG340}, - {"ANG350",ANG350}, - {"ANGLE_11hh",ANGLE_11hh}, - {"ANGLE_22h",ANGLE_22h}, - {"ANGLE_45",ANGLE_45}, - {"ANGLE_67h",ANGLE_67h}, - {"ANGLE_90",ANGLE_90}, - {"ANGLE_112h",ANGLE_112h}, - {"ANGLE_135",ANGLE_135}, - {"ANGLE_157h",ANGLE_157h}, - {"ANGLE_180",ANGLE_180}, - {"ANGLE_202h",ANGLE_202h}, - {"ANGLE_225",ANGLE_225}, - {"ANGLE_247h",ANGLE_247h}, - {"ANGLE_270",ANGLE_270}, - {"ANGLE_292h",ANGLE_292h}, - {"ANGLE_315",ANGLE_315}, - {"ANGLE_337h",ANGLE_337h}, - {"ANGLE_MAX",ANGLE_MAX}, - - // P_Chase directions (dirtype_t) - {"DI_NODIR",DI_NODIR}, - {"DI_EAST",DI_EAST}, - {"DI_NORTHEAST",DI_NORTHEAST}, - {"DI_NORTH",DI_NORTH}, - {"DI_NORTHWEST",DI_NORTHWEST}, - {"DI_WEST",DI_WEST}, - {"DI_SOUTHWEST",DI_SOUTHWEST}, - {"DI_SOUTH",DI_SOUTH}, - {"DI_SOUTHEAST",DI_SOUTHEAST}, - {"NUMDIRS",NUMDIRS}, - - // Sprite rotation axis (rotaxis_t) - {"ROTAXIS_X",ROTAXIS_X}, - {"ROTAXIS_Y",ROTAXIS_Y}, - {"ROTAXIS_Z",ROTAXIS_Z}, - - // Buttons (ticcmd_t) - {"BT_WEAPONMASK",BT_WEAPONMASK}, //our first four bits. - {"BT_WEAPONNEXT",BT_WEAPONNEXT}, - {"BT_WEAPONPREV",BT_WEAPONPREV}, - {"BT_ATTACK",BT_ATTACK}, // shoot rings - {"BT_SPIN",BT_SPIN}, - {"BT_CAMLEFT",BT_CAMLEFT}, // turn camera left - {"BT_CAMRIGHT",BT_CAMRIGHT}, // turn camera right - {"BT_TOSSFLAG",BT_TOSSFLAG}, - {"BT_JUMP",BT_JUMP}, - {"BT_FIRENORMAL",BT_FIRENORMAL}, // Fire a normal ring no matter what - {"BT_CUSTOM1",BT_CUSTOM1}, // Lua customizable - {"BT_CUSTOM2",BT_CUSTOM2}, // Lua customizable - {"BT_CUSTOM3",BT_CUSTOM3}, // Lua customizable - - // Lua command registration flags - {"COM_ADMIN",COM_ADMIN}, - {"COM_SPLITSCREEN",COM_SPLITSCREEN}, - {"COM_LOCAL",COM_LOCAL}, - - // cvflags_t - {"CV_SAVE",CV_SAVE}, - {"CV_CALL",CV_CALL}, - {"CV_NETVAR",CV_NETVAR}, - {"CV_NOINIT",CV_NOINIT}, - {"CV_FLOAT",CV_FLOAT}, - {"CV_NOTINNET",CV_NOTINNET}, - {"CV_MODIFIED",CV_MODIFIED}, - {"CV_SHOWMODIF",CV_SHOWMODIF}, - {"CV_SHOWMODIFONETIME",CV_SHOWMODIFONETIME}, - {"CV_NOSHOWHELP",CV_NOSHOWHELP}, - {"CV_HIDEN",CV_HIDEN}, - {"CV_HIDDEN",CV_HIDEN}, - {"CV_CHEAT",CV_CHEAT}, - {"CV_NOLUA",CV_NOLUA}, - - // v_video flags - {"V_NOSCALEPATCH",V_NOSCALEPATCH}, - {"V_SMALLSCALEPATCH",V_SMALLSCALEPATCH}, - {"V_MEDSCALEPATCH",V_MEDSCALEPATCH}, - {"V_6WIDTHSPACE",V_6WIDTHSPACE}, - {"V_OLDSPACING",V_OLDSPACING}, - {"V_MONOSPACE",V_MONOSPACE}, - - {"V_MAGENTAMAP",V_MAGENTAMAP}, - {"V_YELLOWMAP",V_YELLOWMAP}, - {"V_GREENMAP",V_GREENMAP}, - {"V_BLUEMAP",V_BLUEMAP}, - {"V_REDMAP",V_REDMAP}, - {"V_GRAYMAP",V_GRAYMAP}, - {"V_ORANGEMAP",V_ORANGEMAP}, - {"V_SKYMAP",V_SKYMAP}, - {"V_PURPLEMAP",V_PURPLEMAP}, - {"V_AQUAMAP",V_AQUAMAP}, - {"V_PERIDOTMAP",V_PERIDOTMAP}, - {"V_AZUREMAP",V_AZUREMAP}, - {"V_BROWNMAP",V_BROWNMAP}, - {"V_ROSYMAP",V_ROSYMAP}, - {"V_INVERTMAP",V_INVERTMAP}, - - {"V_TRANSLUCENT",V_TRANSLUCENT}, - {"V_10TRANS",V_10TRANS}, - {"V_20TRANS",V_20TRANS}, - {"V_30TRANS",V_30TRANS}, - {"V_40TRANS",V_40TRANS}, - {"V_50TRANS",V_TRANSLUCENT}, // alias - {"V_60TRANS",V_60TRANS}, - {"V_70TRANS",V_70TRANS}, - {"V_80TRANS",V_80TRANS}, - {"V_90TRANS",V_90TRANS}, - {"V_HUDTRANSHALF",V_HUDTRANSHALF}, - {"V_HUDTRANS",V_HUDTRANS}, - {"V_HUDTRANSDOUBLE",V_HUDTRANSDOUBLE}, - {"V_AUTOFADEOUT",V_AUTOFADEOUT}, - {"V_RETURN8",V_RETURN8}, - {"V_OFFSET",V_OFFSET}, - {"V_ALLOWLOWERCASE",V_ALLOWLOWERCASE}, - {"V_FLIP",V_FLIP}, - {"V_CENTERNAMETAG",V_CENTERNAMETAG}, - {"V_SNAPTOTOP",V_SNAPTOTOP}, - {"V_SNAPTOBOTTOM",V_SNAPTOBOTTOM}, - {"V_SNAPTOLEFT",V_SNAPTOLEFT}, - {"V_SNAPTORIGHT",V_SNAPTORIGHT}, - {"V_WRAPX",V_WRAPX}, - {"V_WRAPY",V_WRAPY}, - {"V_NOSCALESTART",V_NOSCALESTART}, - {"V_PERPLAYER",V_PERPLAYER}, - - {"V_PARAMMASK",V_PARAMMASK}, - {"V_SCALEPATCHMASK",V_SCALEPATCHMASK}, - {"V_SPACINGMASK",V_SPACINGMASK}, - {"V_CHARCOLORMASK",V_CHARCOLORMASK}, - {"V_ALPHAMASK",V_ALPHAMASK}, - - {"V_CHARCOLORSHIFT",V_CHARCOLORSHIFT}, - {"V_ALPHASHIFT",V_ALPHASHIFT}, - - //Kick Reasons - {"KR_KICK",KR_KICK}, - {"KR_PINGLIMIT",KR_PINGLIMIT}, - {"KR_SYNCH",KR_SYNCH}, - {"KR_TIMEOUT",KR_TIMEOUT}, - {"KR_BAN",KR_BAN}, - {"KR_LEAVE",KR_LEAVE}, - - // translation colormaps - {"TC_DEFAULT",TC_DEFAULT}, - {"TC_BOSS",TC_BOSS}, - {"TC_METALSONIC",TC_METALSONIC}, - {"TC_ALLWHITE",TC_ALLWHITE}, - {"TC_RAINBOW",TC_RAINBOW}, - {"TC_BLINK",TC_BLINK}, - {"TC_DASHMODE",TC_DASHMODE}, - - // marathonmode flags - {"MA_INIT",MA_INIT}, - {"MA_RUNNING",MA_RUNNING}, - {"MA_NOCUTSCENES",MA_NOCUTSCENES}, - {"MA_INGAME",MA_INGAME}, - - // gamestates - {"GS_NULL",GS_NULL}, - {"GS_LEVEL",GS_LEVEL}, - {"GS_INTERMISSION",GS_INTERMISSION}, - {"GS_CONTINUING",GS_CONTINUING}, - {"GS_TITLESCREEN",GS_TITLESCREEN}, - {"GS_TIMEATTACK",GS_TIMEATTACK}, - {"GS_CREDITS",GS_CREDITS}, - {"GS_EVALUATION",GS_EVALUATION}, - {"GS_GAMEEND",GS_GAMEEND}, - {"GS_INTRO",GS_INTRO}, - {"GS_ENDING",GS_ENDING}, - {"GS_CUTSCENE",GS_CUTSCENE}, - {"GS_DEDICATEDSERVER",GS_DEDICATEDSERVER}, - {"GS_WAITINGPLAYERS",GS_WAITINGPLAYERS}, - - {NULL,0} -}; - -static mobjtype_t get_mobjtype(const char *word) -{ // Returns the value of MT_ enumerations - mobjtype_t i; - if (*word >= '0' && *word <= '9') - return atoi(word); - if (fastncmp("MT_",word,3)) - word += 3; // take off the MT_ - for (i = 0; i < NUMMOBJFREESLOTS; i++) { - if (!FREE_MOBJS[i]) - break; - if (fastcmp(word, FREE_MOBJS[i])) - return MT_FIRSTFREESLOT+i; - } - for (i = 0; i < MT_FIRSTFREESLOT; i++) - if (fastcmp(word, MOBJTYPE_LIST[i]+3)) - return i; - deh_warning("Couldn't find mobjtype named 'MT_%s'",word); - return MT_NULL; -} - -static statenum_t get_state(const char *word) -{ // Returns the value of S_ enumerations - statenum_t i; - if (*word >= '0' && *word <= '9') - return atoi(word); - if (fastncmp("S_",word,2)) - word += 2; // take off the S_ - for (i = 0; i < NUMSTATEFREESLOTS; i++) { - if (!FREE_STATES[i]) - break; - if (fastcmp(word, FREE_STATES[i])) - return S_FIRSTFREESLOT+i; - } - for (i = 0; i < S_FIRSTFREESLOT; i++) - if (fastcmp(word, STATE_LIST[i]+2)) - return i; - deh_warning("Couldn't find state named 'S_%s'",word); - return S_NULL; -} - -skincolornum_t get_skincolor(const char *word) -{ // Returns the value of SKINCOLOR_ enumerations - skincolornum_t i; - if (*word >= '0' && *word <= '9') - return atoi(word); - if (fastncmp("SKINCOLOR_",word,10)) - word += 10; // take off the SKINCOLOR_ - for (i = 0; i < NUMCOLORFREESLOTS; i++) { - if (!FREE_SKINCOLORS[i]) - break; - if (fastcmp(word, FREE_SKINCOLORS[i])) - return SKINCOLOR_FIRSTFREESLOT+i; - } - for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++) - if (fastcmp(word, COLOR_ENUMS[i])) - return i; - deh_warning("Couldn't find skincolor named 'SKINCOLOR_%s'",word); - return SKINCOLOR_GREEN; -} - -static spritenum_t get_sprite(const char *word) -{ // Returns the value of SPR_ enumerations - spritenum_t i; - if (*word >= '0' && *word <= '9') - return atoi(word); - if (fastncmp("SPR_",word,4)) - word += 4; // take off the SPR_ - for (i = 0; i < NUMSPRITES; i++) - if (!sprnames[i][4] && memcmp(word,sprnames[i],4)==0) - return i; - deh_warning("Couldn't find sprite named 'SPR_%s'",word); - return SPR_NULL; -} - -static playersprite_t get_sprite2(const char *word) -{ // Returns the value of SPR2_ enumerations - playersprite_t i; - if (*word >= '0' && *word <= '9') - return atoi(word); - if (fastncmp("SPR2_",word,5)) - word += 5; // take off the SPR2_ - for (i = 0; i < NUMPLAYERSPRITES; i++) - if (!spr2names[i][4] && memcmp(word,spr2names[i],4)==0) - return i; - deh_warning("Couldn't find sprite named 'SPR2_%s'",word); - return SPR2_STND; -} - -static sfxenum_t get_sfx(const char *word) -{ // Returns the value of SFX_ enumerations - sfxenum_t i; - if (*word >= '0' && *word <= '9') - return atoi(word); - if (fastncmp("SFX_",word,4)) - word += 4; // take off the SFX_ - else if (fastncmp("DS",word,2)) - word += 2; // take off the DS - for (i = 0; i < NUMSFX; i++) - if (S_sfx[i].name && fasticmp(word, S_sfx[i].name)) - return i; - deh_warning("Couldn't find sfx named 'SFX_%s'",word); - return sfx_None; -} - -#ifdef MUSICSLOT_COMPATIBILITY -static UINT16 get_mus(const char *word, UINT8 dehacked_mode) -{ // Returns the value of MUS_ enumerations - UINT16 i; - char lumptmp[4]; - - if (*word >= '0' && *word <= '9') - return atoi(word); - if (!word[2] && toupper(word[0]) >= 'A' && toupper(word[0]) <= 'Z') - return (UINT16)M_MapNumber(word[0], word[1]); - - if (fastncmp("MUS_",word,4)) - word += 4; // take off the MUS_ - else if (fastncmp("O_",word,2) || fastncmp("D_",word,2)) - word += 2; // take off the O_ or D_ - - strncpy(lumptmp, word, 4); - lumptmp[3] = 0; - if (fasticmp("MAP",lumptmp)) - { - word += 3; - if (toupper(word[0]) >= 'A' && toupper(word[0]) <= 'Z') - return (UINT16)M_MapNumber(word[0], word[1]); - else if ((i = atoi(word))) - return i; - - word -= 3; - if (dehacked_mode) - deh_warning("Couldn't find music named 'MUS_%s'",word); - return 0; - } - for (i = 0; compat_special_music_slots[i][0]; ++i) - if (fasticmp(word, compat_special_music_slots[i])) - return i + 1036; - if (dehacked_mode) - deh_warning("Couldn't find music named 'MUS_%s'",word); - return 0; -} -#endif - -static hudnum_t get_huditem(const char *word) -{ // Returns the value of HUD_ enumerations - hudnum_t i; - if (*word >= '0' && *word <= '9') - return atoi(word); - if (fastncmp("HUD_",word,4)) - word += 4; // take off the HUD_ - for (i = 0; i < NUMHUDITEMS; i++) - if (fastcmp(word, HUDITEMS_LIST[i])) - return i; - deh_warning("Couldn't find huditem named 'HUD_%s'",word); - return HUD_LIVES; -} - -static menutype_t get_menutype(const char *word) -{ // Returns the value of MN_ enumerations - menutype_t i; - if (*word >= '0' && *word <= '9') - return atoi(word); - if (fastncmp("MN_",word,3)) - word += 3; // take off the MN_ - for (i = 0; i < NUMMENUTYPES; i++) - if (fastcmp(word, MENUTYPES_LIST[i])) - return i; - deh_warning("Couldn't find menutype named 'MN_%s'",word); - return MN_NONE; -} - -/*static INT16 get_gametype(const char *word) -{ // Returns the value of GT_ enumerations - INT16 i; - if (*word >= '0' && *word <= '9') - return atoi(word); - if (fastncmp("GT_",word,3)) - word += 3; // take off the GT_ - for (i = 0; i < NUMGAMETYPES; i++) - if (fastcmp(word, Gametype_ConstantNames[i]+3)) - return i; - deh_warning("Couldn't find gametype named 'GT_%s'",word); - return GT_COOP; -} - -static powertype_t get_power(const char *word) -{ // Returns the value of pw_ enumerations - powertype_t i; - if (*word >= '0' && *word <= '9') - return atoi(word); - if (fastncmp("PW_",word,3)) - word += 3; // take off the pw_ - for (i = 0; i < NUMPOWERS; i++) - if (fastcmp(word, POWERS_LIST[i])) - return i; - deh_warning("Couldn't find power named 'pw_%s'",word); - return pw_invulnerability; -}*/ - -/// \todo Make ANY of this completely over-the-top math craziness obey the order of operations. -static fixed_t op_mul(fixed_t a, fixed_t b) { return a*b; } -static fixed_t op_div(fixed_t a, fixed_t b) { return a/b; } -static fixed_t op_add(fixed_t a, fixed_t b) { return a+b; } -static fixed_t op_sub(fixed_t a, fixed_t b) { return a-b; } -static fixed_t op_or(fixed_t a, fixed_t b) { return a|b; } -static fixed_t op_and(fixed_t a, fixed_t b) { return a&b; } -static fixed_t op_lshift(fixed_t a, fixed_t b) { return a<<b; } -static fixed_t op_rshift(fixed_t a, fixed_t b) { return a>>b; } - -struct { - const char c; - fixed_t (*v)(fixed_t,fixed_t); -} OPERATIONS[] = { - {'*',op_mul}, - {'/',op_div}, - {'+',op_add}, - {'-',op_sub}, - {'|',op_or}, - {'&',op_and}, - {'<',op_lshift}, - {'>',op_rshift}, - {0,NULL} -}; - -// Returns the full word, cut at the first symbol or whitespace -/*static char *read_word(const char *line) -{ - // Part 1: You got the start of the word, now find the end. - const char *p; - INT32 i; - for (p = line+1; *p; p++) { - if (*p == ' ' || *p == '\t') - break; - for (i = 0; OPERATIONS[i].c; i++) - if (*p == OPERATIONS[i].c) { - i = -1; - break; - } - if (i == -1) - break; - } - - // Part 2: Make a copy of the word and return it. - { - size_t len = (p-line); - char *word = malloc(len+1); - M_Memcpy(word,line,len); - word[len] = '\0'; - return word; - } -} - -static INT32 operation_pad(const char **word) -{ // Brings word the next operation and returns the operation number. - INT32 i; - for (; **word; (*word)++) { - if (**word == ' ' || **word == '\t') - continue; - for (i = 0; OPERATIONS[i].c; i++) - if (**word == OPERATIONS[i].c) - { - if ((**word == '<' && *(*word+1) == '<') || (**word == '>' && *(*word+1) == '>')) (*word)++; // These operations are two characters long. - else if (**word == '<' || **word == '>') continue; // ... do not accept one character long. - (*word)++; - return i; - } - deh_warning("Unknown operation '%c'",**word); - return -1; - } - return -1; -} - -static void const_warning(const char *type, const char *word) -{ - deh_warning("Couldn't find %s named '%s'",type,word); -} - -static fixed_t find_const(const char **rword) -{ // Finds the value of constants and returns it, bringing word to the next operation. - INT32 i; - fixed_t r; - char *word = read_word(*rword); - *rword += strlen(word); - if ((*word >= '0' && *word <= '9') || *word == '-') { // Parse a number - r = atoi(word); - free(word); - return r; - } - if (!*(word+1) && // Turn a single A-z symbol into numbers, like sprite frames. - ((*word >= 'A' && *word <= 'Z') || (*word >= 'a' && *word <= 'z'))) { - r = R_Char2Frame(*word); - free(word); - return r; - } - if (fastncmp("MF_", word, 3)) { - char *p = word+3; - for (i = 0; MOBJFLAG_LIST[i]; i++) - if (fastcmp(p, MOBJFLAG_LIST[i])) { - free(word); - return (1<<i); - } - - // Not found error - const_warning("mobj flag",word); - free(word); - return 0; - } - else if (fastncmp("MF2_", word, 4)) { - char *p = word+4; - for (i = 0; MOBJFLAG2_LIST[i]; i++) - if (fastcmp(p, MOBJFLAG2_LIST[i])) { - free(word); - return (1<<i); - } - - // Not found error - const_warning("mobj flag2",word); - free(word); - return 0; - } - else if (fastncmp("MFE_", word, 4)) { - char *p = word+4; - for (i = 0; MOBJEFLAG_LIST[i]; i++) - if (fastcmp(p, MOBJEFLAG_LIST[i])) { - free(word); - return (1<<i); - } - - // Not found error - const_warning("mobj eflag",word); - free(word); - return 0; - } - else if (fastncmp("PF_", word, 3)) { - char *p = word+3; - for (i = 0; PLAYERFLAG_LIST[i]; i++) - if (fastcmp(p, PLAYERFLAG_LIST[i])) { - free(word); - return (1<<i); - } - if (fastcmp(p, "FULLSTASIS")) - return PF_FULLSTASIS; - - // Not found error - const_warning("player flag",word); - free(word); - return 0; - } - else if (fastncmp("S_",word,2)) { - r = get_state(word); - free(word); - return r; - } - else if (fastncmp("SKINCOLOR_",word,10)) { - r = get_skincolor(word); - free(word); - return r; - } - else if (fastncmp("MT_",word,3)) { - r = get_mobjtype(word); - free(word); - return r; - } - else if (fastncmp("SPR_",word,4)) { - r = get_sprite(word); - free(word); - return r; - } - else if (fastncmp("SFX_",word,4) || fastncmp("DS",word,2)) { - r = get_sfx(word); - free(word); - return r; - } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastncmp("MUS_",word,4) || fastncmp("O_",word,2)) { - r = get_mus(word, true); - free(word); - return r; - } -#endif - else if (fastncmp("PW_",word,3)) { - r = get_power(word); - free(word); - return r; - } - else if (fastncmp("MN_",word,3)) { - r = get_menutype(word); - free(word); - return r; - } - else if (fastncmp("GT_",word,3)) { - r = get_gametype(word); - free(word); - return r; - } - else if (fastncmp("GTR_", word, 4)) { - char *p = word+4; - for (i = 0; GAMETYPERULE_LIST[i]; i++) - if (fastcmp(p, GAMETYPERULE_LIST[i])) { - free(word); - return (1<<i); - } - - // Not found error - const_warning("game type rule",word); - free(word); - return 0; - } - else if (fastncmp("TOL_", word, 4)) { - char *p = word+4; - for (i = 0; TYPEOFLEVEL[i].name; i++) - if (fastcmp(p, TYPEOFLEVEL[i].name)) { - free(word); - return TYPEOFLEVEL[i].flag; - } - - // Not found error - const_warning("typeoflevel",word); - free(word); - return 0; - } - else if (fastncmp("HUD_",word,4)) { - r = get_huditem(word); - free(word); - return r; - } - else if (fastncmp("GRADE_",word,6)) - { - char *p = word+6; - for (i = 0; NIGHTSGRADE_LIST[i]; i++) - if (*p == NIGHTSGRADE_LIST[i]) - { - free(word); - return i; - } - const_warning("NiGHTS grade",word); - free(word); - return 0; - } - for (i = 0; INT_CONST[i].n; i++) - if (fastcmp(word,INT_CONST[i].n)) { - free(word); - return INT_CONST[i].v; - } - - // Not found error. - const_warning("constant",word); - free(word); - return 0; -}*/ - -// Loops through every constant and operation in word and performs its calculations, returning the final value. -fixed_t get_number(const char *word) -{ - return LUA_EvalMath(word); - - /*// DESPERATELY NEEDED: Order of operations support! :x - fixed_t i = find_const(&word); - INT32 o; - while(*word) { - o = operation_pad(&word); - if (o != -1) - i = OPERATIONS[o].v(i,find_const(&word)); - else - break; - } - return i;*/ -} - -void DEH_Check(void) -{ -#if defined(_DEBUG) || defined(PARANOIA) - const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*); - const size_t dehmobjs = sizeof(MOBJTYPE_LIST)/sizeof(const char*); - const size_t dehpowers = sizeof(POWERS_LIST)/sizeof(const char*); - const size_t dehcolors = sizeof(COLOR_ENUMS)/sizeof(const char*); - - if (dehstates != S_FIRSTFREESLOT) - I_Error("You forgot to update the Dehacked states list, you dolt!\n(%d states defined, versus %s in the Dehacked list)\n", S_FIRSTFREESLOT, sizeu1(dehstates)); - - if (dehmobjs != MT_FIRSTFREESLOT) - I_Error("You forgot to update the Dehacked mobjtype list, you dolt!\n(%d mobj types defined, versus %s in the Dehacked list)\n", MT_FIRSTFREESLOT, sizeu1(dehmobjs)); - - if (dehpowers != NUMPOWERS) - I_Error("You forgot to update the Dehacked powers list, you dolt!\n(%d powers defined, versus %s in the Dehacked list)\n", NUMPOWERS, sizeu1(dehpowers)); - - if (dehcolors != SKINCOLOR_FIRSTFREESLOT) - I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", SKINCOLOR_FIRSTFREESLOT, sizeu1(dehcolors)); -#endif -} - -#include "lua_script.h" -#include "lua_libs.h" - -// freeslot takes a name (string only!) -// and allocates it to the appropriate free slot. -// Returns the slot number allocated for it or nil if failed. -// ex. freeslot("MT_MYTHING","S_MYSTATE1","S_MYSTATE2") -// TODO: Error checking! @.@; There's currently no way to know which ones failed and why! -// -static inline int lib_freeslot(lua_State *L) -{ - int n = lua_gettop(L); - int r = 0; // args returned - char *s, *type,*word; - - if (!lua_lumploading) - return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); - - while (n-- > 0) - { - s = Z_StrDup(luaL_checkstring(L,1)); - type = strtok(s, "_"); - if (type) - strupr(type); - else { - Z_Free(s); - return luaL_error(L, "Unknown enum type in '%s'\n", luaL_checkstring(L, 1)); - } - - word = strtok(NULL, "\n"); - if (word) - strupr(word); - else { - Z_Free(s); - return luaL_error(L, "Missing enum name in '%s'\n", luaL_checkstring(L, 1)); - } - if (fastcmp(type, "SFX")) { - sfxenum_t sfx; - strlwr(word); - CONS_Printf("Sound sfx_%s allocated.\n",word); - sfx = S_AddSoundFx(word, false, 0, false); - if (sfx != sfx_None) { - lua_pushinteger(L, sfx); - r++; - } else - CONS_Alert(CONS_WARNING, "Ran out of free SFX slots!\n"); - } - else if (fastcmp(type, "SPR")) - { - char wad; - spritenum_t j; - lua_getfield(L, LUA_REGISTRYINDEX, "WAD"); - wad = (char)lua_tointeger(L, -1); - lua_pop(L, 1); - for (j = SPR_FIRSTFREESLOT; j <= SPR_LASTFREESLOT; j++) - { - if (used_spr[(j-SPR_FIRSTFREESLOT)/8] & (1<<(j%8))) - { - if (!sprnames[j][4] && memcmp(sprnames[j],word,4)==0) - sprnames[j][4] = wad; - continue; // Already allocated, next. - } - // Found a free slot! - CONS_Printf("Sprite SPR_%s allocated.\n",word); - strncpy(sprnames[j],word,4); - //sprnames[j][4] = 0; - used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now. - lua_pushinteger(L, j); - r++; - break; - } - if (j > SPR_LASTFREESLOT) - CONS_Alert(CONS_WARNING, "Ran out of free sprite slots!\n"); - } - else if (fastcmp(type, "S")) - { - statenum_t i; - for (i = 0; i < NUMSTATEFREESLOTS; i++) - if (!FREE_STATES[i]) { - CONS_Printf("State S_%s allocated.\n",word); - FREE_STATES[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); - strcpy(FREE_STATES[i],word); - lua_pushinteger(L, S_FIRSTFREESLOT + i); - r++; - break; + // zero-based, but let's start at 1 + deh_warning("Menu number %d out of range (1 - %d)", i, NUMMENUTYPES-1); + ignorelines(f); + } } - if (i == NUMSTATEFREESLOTS) - CONS_Alert(CONS_WARNING, "Ran out of free State slots!\n"); - } - else if (fastcmp(type, "MT")) - { - mobjtype_t i; - for (i = 0; i < NUMMOBJFREESLOTS; i++) - if (!FREE_MOBJS[i]) { - CONS_Printf("MobjType MT_%s allocated.\n",word); - FREE_MOBJS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); - strcpy(FREE_MOBJS[i],word); - lua_pushinteger(L, MT_FIRSTFREESLOT + i); - r++; - break; + else if (fastcmp(word, "UNLOCKABLE")) + { + if (!mainfile && !gamedataadded) + { + deh_warning("You must define a custom gamedata to use \"%s\"", word); + ignorelines(f); + } + else if (i > 0 && i <= MAXUNLOCKABLES) + readunlockable(f, i - 1); + else + { + deh_warning("Unlockable number %d out of range (1 - %d)", i, MAXUNLOCKABLES); + ignorelines(f); + } } - if (i == NUMMOBJFREESLOTS) - CONS_Alert(CONS_WARNING, "Ran out of free MobjType slots!\n"); - } - else if (fastcmp(type, "SKINCOLOR")) - { - skincolornum_t i; - for (i = 0; i < NUMCOLORFREESLOTS; i++) - if (!FREE_SKINCOLORS[i]) { - CONS_Printf("Skincolor SKINCOLOR_%s allocated.\n",word); - FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); - strcpy(FREE_SKINCOLORS[i],word); - M_AddMenuColor(numskincolors++); - lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT + i); - r++; - break; + else if (fastcmp(word, "CONDITIONSET")) + { + if (!mainfile && !gamedataadded) + { + deh_warning("You must define a custom gamedata to use \"%s\"", word); + ignorelines(f); + } + else if (i > 0 && i <= MAXCONDITIONSETS) + readconditionset(f, (UINT8)i); + else + { + deh_warning("Condition set number %d out of range (1 - %d)", i, MAXCONDITIONSETS); + ignorelines(f); + } } - if (i == NUMCOLORFREESLOTS) - CONS_Alert(CONS_WARNING, "Ran out of free skincolor slots!\n"); - } - else if (fastcmp(type, "SPR2")) - { - // Search if we already have an SPR2 by that name... - playersprite_t i; - for (i = SPR2_FIRSTFREESLOT; i < free_spr2; i++) - if (memcmp(spr2names[i],word,4) == 0) - break; - // We don't, so allocate a new one. - if (i >= free_spr2) { - if (free_spr2 < NUMPLAYERSPRITES) + else if (fastcmp(word, "SRB2")) { - CONS_Printf("Sprite SPR2_%s allocated.\n",word); - strncpy(spr2names[free_spr2],word,4); - spr2defaults[free_spr2] = 0; - lua_pushinteger(L, free_spr2); - r++; - spr2names[free_spr2++][4] = 0; - } else - CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n"); - } - } - else if (fastcmp(type, "TOL")) - { - // Search if we already have a typeoflevel by that name... - int i; - for (i = 0; TYPEOFLEVEL[i].name; i++) - if (fastcmp(word, TYPEOFLEVEL[i].name)) - break; - - // We don't, so allocate a new one. - if (TYPEOFLEVEL[i].name == NULL) { - if (lastcustomtol == (UINT32)MAXTOL) // Unless you have way too many, since they're flags. - CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n"); - else { - CONS_Printf("TypeOfLevel TOL_%s allocated.\n",word); - G_AddTOL(lastcustomtol, word); - lua_pushinteger(L, lastcustomtol); - lastcustomtol <<= 1; - r++; + if (isdigit(word2[0])) + { + i = atoi(word2); + if (i != PATCHVERSION) + { + deh_warning( + "Patch is for SRB2 version %d, " + "only version %d is supported", + i, + PATCHVERSION + ); + } + } + else + { + deh_warning( + "SRB2 version definition has incorrect format, " + "use \"SRB2 %d\"", + PATCHVERSION + ); + } } - } - } - Z_Free(s); - lua_remove(L, 1); - continue; - } - return r; -} + // Clear all data in certain locations (mostly for unlocks) + // Unless you REALLY want to piss people off, + // define a custom gamedata /before/ doing this!! + // (then again, modifiedgame will prevent game data saving anyway) + else if (fastcmp(word, "CLEAR")) + { + boolean clearall = (fastcmp(word2, "ALL")); -// Wrapper for ALL A_Action functions. -// Arguments: mobj_t actor, int var1, int var2 -static int action_call(lua_State *L) -{ - //actionf_t *action = lua_touserdata(L,lua_upvalueindex(1)); - actionf_t *action = *((actionf_t **)luaL_checkudata(L, 1, META_ACTION)); - mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); - var1 = (INT32)luaL_optinteger(L, 3, 0); - var2 = (INT32)luaL_optinteger(L, 4, 0); - if (!actor) - return LUA_ErrInvalid(L, "mobj_t"); - action->acp1(actor); - return 0; -} + if (!mainfile && !gamedataadded) + { + deh_warning("You must define a custom gamedata to use \"%s\"", word); + continue; + } -// Hardcoded A_Action name to call for super() or NULL if super() would be invalid. -// Set in lua_infolib. -const char *superactions[MAXRECURSION]; -UINT8 superstack = 0; + if (clearall || fastcmp(word2, "UNLOCKABLES")) + memset(&unlockables, 0, sizeof(unlockables)); -static int lib_dummysuper(lua_State *L) -{ - return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions being called by state changes!"); // convoluted, I know. @_@;; -} + if (clearall || fastcmp(word2, "EMBLEMS")) + { + memset(&emblemlocations, 0, sizeof(emblemlocations)); + numemblems = 0; + } -static inline int lib_getenum(lua_State *L) -{ - const char *word, *p; - fixed_t i; - boolean mathlib = lua_toboolean(L, lua_upvalueindex(1)); - if (lua_type(L,2) != LUA_TSTRING) - return 0; - word = lua_tostring(L,2); - if (strlen(word) == 1) { // Assume sprite frame if length 1. - if (*word >= 'A' && *word <= '~') - { - lua_pushinteger(L, *word-'A'); - return 1; - } - if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word); - return 0; - } - else if (fastncmp("MF_", word, 3)) { - p = word+3; - for (i = 0; MOBJFLAG_LIST[i]; i++) - if (fastcmp(p, MOBJFLAG_LIST[i])) { - lua_pushinteger(L, ((lua_Integer)1<<i)); - return 1; - } - if (mathlib) return luaL_error(L, "mobjflag '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("MF2_", word, 4)) { - p = word+4; - for (i = 0; MOBJFLAG2_LIST[i]; i++) - if (fastcmp(p, MOBJFLAG2_LIST[i])) { - lua_pushinteger(L, ((lua_Integer)1<<i)); - return 1; - } - if (mathlib) return luaL_error(L, "mobjflag2 '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("MFE_", word, 4)) { - p = word+4; - for (i = 0; MOBJEFLAG_LIST[i]; i++) - if (fastcmp(p, MOBJEFLAG_LIST[i])) { - lua_pushinteger(L, ((lua_Integer)1<<i)); - return 1; - } - if (mathlib) return luaL_error(L, "mobjeflag '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("MTF_", word, 4)) { - p = word+4; - for (i = 0; i < 4; i++) - if (MAPTHINGFLAG_LIST[i] && fastcmp(p, MAPTHINGFLAG_LIST[i])) { - lua_pushinteger(L, ((lua_Integer)1<<i)); - return 1; - } - if (mathlib) return luaL_error(L, "mapthingflag '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("PF_", word, 3)) { - p = word+3; - for (i = 0; PLAYERFLAG_LIST[i]; i++) - if (fastcmp(p, PLAYERFLAG_LIST[i])) { - lua_pushinteger(L, ((lua_Integer)1<<i)); - return 1; - } - if (fastcmp(p, "FULLSTASIS")) - { - lua_pushinteger(L, (lua_Integer)PF_FULLSTASIS); - return 1; - } - else if (fastcmp(p, "USEDOWN")) // Remove case when 2.3 nears release... - { - lua_pushinteger(L, (lua_Integer)PF_SPINDOWN); - return 1; - } - if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("GT_", word, 3)) { - p = word; - for (i = 0; Gametype_ConstantNames[i]; i++) - if (fastcmp(p, Gametype_ConstantNames[i])) { - lua_pushinteger(L, i); - return 1; - } - if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("GTR_", word, 4)) { - p = word+4; - for (i = 0; GAMETYPERULE_LIST[i]; i++) - if (fastcmp(p, GAMETYPERULE_LIST[i])) { - lua_pushinteger(L, ((lua_Integer)1<<i)); - return 1; - } - if (mathlib) return luaL_error(L, "game type rule '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("TOL_", word, 4)) { - p = word+4; - for (i = 0; TYPEOFLEVEL[i].name; i++) - if (fastcmp(p, TYPEOFLEVEL[i].name)) { - lua_pushinteger(L, TYPEOFLEVEL[i].flag); - return 1; - } - if (mathlib) return luaL_error(L, "typeoflevel '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("ML_", word, 3)) { - p = word+3; - for (i = 0; i < 16; i++) - if (ML_LIST[i] && fastcmp(p, ML_LIST[i])) { - lua_pushinteger(L, ((lua_Integer)1<<i)); - return 1; - } - if (mathlib) return luaL_error(L, "linedef flag '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("S_",word,2)) { - p = word+2; - for (i = 0; i < NUMSTATEFREESLOTS; i++) { - if (!FREE_STATES[i]) - break; - if (fastcmp(p, FREE_STATES[i])) { - lua_pushinteger(L, S_FIRSTFREESLOT+i); - return 1; - } - } - for (i = 0; i < S_FIRSTFREESLOT; i++) - if (fastcmp(p, STATE_LIST[i]+2)) { - lua_pushinteger(L, i); - return 1; - } - return luaL_error(L, "state '%s' does not exist.\n", word); - } - else if (fastncmp("MT_",word,3)) { - p = word+3; - for (i = 0; i < NUMMOBJFREESLOTS; i++) { - if (!FREE_MOBJS[i]) - break; - if (fastcmp(p, FREE_MOBJS[i])) { - lua_pushinteger(L, MT_FIRSTFREESLOT+i); - return 1; - } - } - for (i = 0; i < MT_FIRSTFREESLOT; i++) - if (fastcmp(p, MOBJTYPE_LIST[i]+3)) { - lua_pushinteger(L, i); - return 1; - } - return luaL_error(L, "mobjtype '%s' does not exist.\n", word); - } - else if (fastncmp("SPR_",word,4)) { - p = word+4; - for (i = 0; i < NUMSPRITES; i++) - if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) { - lua_pushinteger(L, i); - return 1; - } - if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("SPR2_",word,5)) { - p = word+5; - for (i = 0; i < (fixed_t)free_spr2; i++) - if (!spr2names[i][4]) - { - // special 3-char cases, e.g. SPR2_RUN - // the spr2names entry will have "_" on the end, as in "RUN_" - if (spr2names[i][3] == '_' && !p[3]) { - if (fastncmp(p,spr2names[i],3)) { - lua_pushinteger(L, i); - return 1; + if (clearall || fastcmp(word2, "EXTRAEMBLEMS")) + { + memset(&extraemblems, 0, sizeof(extraemblems)); + numextraemblems = 0; } + + if (clearall || fastcmp(word2, "CONDITIONSETS")) + clear_conditionsets(); + + if (clearall || fastcmp(word2, "LEVELS")) + clear_levels(); } - else if (fastncmp(p,spr2names[i],4)) { - lua_pushinteger(L, i); - return 1; - } - } - if (mathlib) return luaL_error(L, "player sprite '%s' could not be found.\n", word); - return 0; - } - else if (!mathlib && fastncmp("sfx_",word,4)) { - p = word+4; - for (i = 0; i < NUMSFX; i++) - if (S_sfx[i].name && fastcmp(p, S_sfx[i].name)) { - lua_pushinteger(L, i); - return 1; - } - return 0; - } - else if (mathlib && fastncmp("SFX_",word,4)) { // SOCs are ALL CAPS! - p = word+4; - for (i = 0; i < NUMSFX; i++) - if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) { - lua_pushinteger(L, i); - return 1; - } - return luaL_error(L, "sfx '%s' could not be found.\n", word); - } - else if (mathlib && fastncmp("DS",word,2)) { - p = word+2; - for (i = 0; i < NUMSFX; i++) - if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) { - lua_pushinteger(L, i); - return 1; - } - if (mathlib) return luaL_error(L, "sfx '%s' could not be found.\n", word); - return 0; - } -#ifdef MUSICSLOT_COMPATIBILITY - else if (!mathlib && fastncmp("mus_",word,4)) { - p = word+4; - if ((i = get_mus(p, false)) == 0) - return 0; - lua_pushinteger(L, i); - return 1; - } - else if (mathlib && fastncmp("MUS_",word,4)) { // SOCs are ALL CAPS! - p = word+4; - if ((i = get_mus(p, false)) == 0) - return luaL_error(L, "music '%s' could not be found.\n", word); - lua_pushinteger(L, i); - return 1; - } - else if (mathlib && (fastncmp("O_",word,2) || fastncmp("D_",word,2))) { - p = word+2; - if ((i = get_mus(p, false)) == 0) - return luaL_error(L, "music '%s' could not be found.\n", word); - lua_pushinteger(L, i); - return 1; - } -#endif - else if (!mathlib && fastncmp("pw_",word,3)) { - p = word+3; - for (i = 0; i < NUMPOWERS; i++) - if (fasticmp(p, POWERS_LIST[i])) { - lua_pushinteger(L, i); - return 1; - } - return 0; - } - else if (mathlib && fastncmp("PW_",word,3)) { // SOCs are ALL CAPS! - p = word+3; - for (i = 0; i < NUMPOWERS; i++) - if (fastcmp(p, POWERS_LIST[i])) { - lua_pushinteger(L, i); - return 1; - } - return luaL_error(L, "power '%s' could not be found.\n", word); - } - else if (fastncmp("HUD_",word,4)) { - p = word+4; - for (i = 0; i < NUMHUDITEMS; i++) - if (fastcmp(p, HUDITEMS_LIST[i])) { - lua_pushinteger(L, i); - return 1; - } - if (mathlib) return luaL_error(L, "huditem '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("SKINCOLOR_",word,10)) { - p = word+10; - for (i = 0; i < NUMCOLORFREESLOTS; i++) { - if (!FREE_SKINCOLORS[i]) - break; - if (fastcmp(p, FREE_SKINCOLORS[i])) { - lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT+i); - return 1; + else + deh_warning("Unknown word: %s", word); } + else + deh_warning("missing argument for '%s'", word); } - for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++) - if (fastcmp(p, COLOR_ENUMS[i])) { - lua_pushinteger(L, i); - return 1; - } - return luaL_error(L, "skincolor '%s' could not be found.\n", word); - } - else if (fastncmp("GRADE_",word,6)) - { - p = word+6; - for (i = 0; NIGHTSGRADE_LIST[i]; i++) - if (*p == NIGHTSGRADE_LIST[i]) - { - lua_pushinteger(L, i); - return 1; - } - if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word); - return 0; - } - else if (fastncmp("MN_",word,3)) { - p = word+3; - for (i = 0; i < NUMMENUTYPES; i++) - if (fastcmp(p, MENUTYPES_LIST[i])) { - lua_pushinteger(L, i); - return 1; - } - if (mathlib) return luaL_error(L, "menutype '%s' could not be found.\n", word); - return 0; - } - else if (!mathlib && fastncmp("A_",word,2)) { - char *caps; - // Try to get a Lua action first. - /// \todo Push a closure that sets superactions[] and superstack. - lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS); - // actions are stored in all uppercase. - caps = Z_StrDup(word); - strupr(caps); - lua_getfield(L, -1, caps); - Z_Free(caps); - if (!lua_isnil(L, -1)) - return 1; // Success! :D That was easy. - // Welp, that failed. - lua_pop(L, 2); // pop nil and LREG_ACTIONS + else + deh_warning("No word in this line: %s", s); + } // end while - // Hardcoded actions as callable Lua functions! - // Retrieving them from this metatable allows them to be case-insensitive! - for (i = 0; actionpointers[i].name; i++) - if (fasticmp(word, actionpointers[i].name)) { - // We push the actionf_t* itself as userdata! - LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION); - return 1; - } - return 0; - } - else if (!mathlib && fastcmp("super",word)) + if (gamedataadded) + G_LoadGameData(); + + if (gamestate == GS_TITLESCREEN) { - if (!superstack) + if (introchanged) { - lua_pushcfunction(L, lib_dummysuper); - return 1; + menuactive = false; + I_UpdateMouseGrab(); + COM_BufAddText("playintro"); + } + else if (titlechanged) + { + menuactive = false; + I_UpdateMouseGrab(); + COM_BufAddText("exitgame"); // Command_ExitGame_f() but delayed } - for (i = 0; actionpointers[i].name; i++) - if (fasticmp(superactions[superstack-1], actionpointers[i].name)) { - LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION); - return 1; - } - return 0; } - if (fastcmp(word, "BT_USE")) // Remove case when 2.3 nears release... + dbg_line = -1; + if (deh_num_warning) { - lua_pushinteger(L, (lua_Integer)BT_SPIN); - return 1; - } - - for (i = 0; INT_CONST[i].n; i++) - if (fastcmp(word,INT_CONST[i].n)) { - lua_pushinteger(L, INT_CONST[i].v); - return 1; + CONS_Printf(M_GetText("%d warning%s in the SOC lump\n"), deh_num_warning, deh_num_warning == 1 ? "" : "s"); + if (devparm) { + I_Error("%s%s",va(M_GetText("%d warning%s in the SOC lump\n"), deh_num_warning, deh_num_warning == 1 ? "" : "s"), M_GetText("See log.txt for details.\n")); + //while (!I_GetKey()) + //I_OsPolling(); } + } - if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word); - - // DYNAMIC variables too!! - // Try not to add anything that would break netgames or timeattack replays here. - // You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime. - return LUA_PushGlobals(L, word); + deh_loaded = true; + Z_Free(s); } -int LUA_EnumLib(lua_State *L) +// read dehacked lump in a wad (there is special trick for for deh +// file that are converted to wad in w_wad.c) +void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump, boolean mainfile) { - if (lua_gettop(L) == 0) - lua_pushboolean(L, 0); - - // Set the global metatable - lua_createtable(L, 0, 1); - lua_pushvalue(L, 1); // boolean passed to LUA_EnumLib as first argument. - lua_pushcclosure(L, lib_getenum, 1); - lua_setfield(L, -2, "__index"); - lua_setmetatable(L, LUA_GLOBALSINDEX); - return 0; + MYFILE f; + f.wad = wad; + f.size = W_LumpLengthPwad(wad, lump); + f.data = Z_Malloc(f.size + 1, PU_STATIC, NULL); + W_ReadLumpPwad(wad, lump, f.data); + f.curpos = f.data; + f.data[f.size] = 0; + DEH_LoadDehackedFile(&f, mainfile); + Z_Free(f.data); } -// getActionName(action) -> return action's string name -static int lib_getActionName(lua_State *L) +void DEH_LoadDehackedLump(lumpnum_t lumpnum) { - if (lua_isuserdata(L, 1)) // arg 1 is built-in action, expect action userdata - { - actionf_t *action = *((actionf_t **)luaL_checkudata(L, 1, META_ACTION)); - const char *name = NULL; - if (!action) - return luaL_error(L, "not a valid action?"); - name = LUA_GetActionName(action); - if (!name) // that can't be right? - return luaL_error(L, "no name string could be found for this action"); - lua_pushstring(L, name); - return 1; - } - else if (lua_isfunction(L, 1)) // arg 1 is a function (either C or Lua) - { - lua_settop(L, 1); // set top of stack to 1 (removing any extra args, which there shouldn't be) - // get the name for this action, if possible. - lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS); - lua_pushnil(L); - // Lua stack at this point: - // 1 ... -2 -1 - // arg ... LREG_ACTIONS nil - while (lua_next(L, -2)) - { - // Lua stack at this point: - // 1 ... -3 -2 -1 - // arg ... LREG_ACTIONS "A_ACTION" function - if (lua_rawequal(L, -1, 1)) // is this the same as the arg? - { - // make sure the key (i.e. "A_ACTION") is a string first - // (note: we don't use lua_isstring because it also returns true for numbers) - if (lua_type(L, -2) == LUA_TSTRING) - { - lua_pushvalue(L, -2); // push "A_ACTION" string to top of stack - return 1; - } - lua_pop(L, 2); // pop the name and function - break; // probably should have succeeded but we didn't, so end the loop - } - lua_pop(L, 1); - } - lua_pop(L, 1); // pop LREG_ACTIONS - return 0; // return nothing (don't error) - } - - return luaL_typerror(L, 1, "action userdata or Lua function"); + DEH_LoadDehackedLumpPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum), false); } - - -int LUA_SOCLib(lua_State *L) +void DEH_Check(void) { - lua_register(L,"freeslot",lib_freeslot); - lua_register(L,"getActionName",lib_getActionName); +#if defined(_DEBUG) || defined(PARANOIA) + const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*); + const size_t dehmobjs = sizeof(MOBJTYPE_LIST)/sizeof(const char*); + const size_t dehpowers = sizeof(POWERS_LIST)/sizeof(const char*); + const size_t dehcolors = sizeof(COLOR_ENUMS)/sizeof(const char*); - luaL_newmetatable(L, META_ACTION); - lua_pushcfunction(L, action_call); - lua_setfield(L, -2, "__call"); - lua_pop(L, 1); + if (dehstates != S_FIRSTFREESLOT) + I_Error("You forgot to update the Dehacked states list, you dolt!\n(%d states defined, versus %s in the Dehacked list)\n", S_FIRSTFREESLOT, sizeu1(dehstates)); - return 0; -} + if (dehmobjs != MT_FIRSTFREESLOT) + I_Error("You forgot to update the Dehacked mobjtype list, you dolt!\n(%d mobj types defined, versus %s in the Dehacked list)\n", MT_FIRSTFREESLOT, sizeu1(dehmobjs)); -const char *LUA_GetActionName(void *action) -{ - actionf_t *act = (actionf_t *)action; - size_t z; - for (z = 0; actionpointers[z].name; z++) - { - if (actionpointers[z].action.acv == act->acv) - return actionpointers[z].name; - } - return NULL; -} + if (dehpowers != NUMPOWERS) + I_Error("You forgot to update the Dehacked powers list, you dolt!\n(%d powers defined, versus %s in the Dehacked list)\n", NUMPOWERS, sizeu1(dehpowers)); -void LUA_SetActionByName(void *state, const char *actiontocompare) -{ - state_t *st = (state_t *)state; - size_t z; - for (z = 0; actionpointers[z].name; z++) - { - if (fasticmp(actiontocompare, actionpointers[z].name)) - { - st->action = actionpointers[z].action; - st->action.acv = actionpointers[z].action.acv; // assign - st->action.acp1 = actionpointers[z].action.acp1; - return; - } - } + if (dehcolors != SKINCOLOR_FIRSTFREESLOT) + I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", SKINCOLOR_FIRSTFREESLOT, sizeu1(dehcolors)); +#endif } diff --git a/src/dehacked.h b/src/dehacked.h index 54225f36e8c851b67e968b3b25167ac1acf61306..d5256be23f0b05b9b51e80faf12823e3a43e0366 100644 --- a/src/dehacked.h +++ b/src/dehacked.h @@ -33,13 +33,15 @@ void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump, boolean mainfile); void DEH_Check(void); fixed_t get_number(const char *word); - -boolean LUA_SetLuaAction(void *state, const char *actiontocompare); -const char *LUA_GetActionName(void *action); -void LUA_SetActionByName(void *state, const char *actiontocompare); +FUNCPRINTF void deh_warning(const char *first, ...); +void deh_strlcpy(char *dst, const char *src, size_t size, const char *warntext); extern boolean deh_loaded; +extern boolean gamedataadded; +extern boolean titlechanged; +extern boolean introchanged; + #define MAXRECURSION 30 extern const char *superactions[MAXRECURSION]; extern UINT8 superstack; @@ -60,4 +62,5 @@ typedef struct } MYFILE; #define myfeof(a) (a->data + a->size <= a->curpos) char *myfgets(char *buf, size_t bufsize, MYFILE *f); +char *myhashfgets(char *buf, size_t bufsize, MYFILE *f); #endif diff --git a/src/doomdef.h b/src/doomdef.h index b9ee1ce5f59cb7bd3c66beab532256533550687b..d0b7ea0c2391334c703051d02e0dae693dfdfe19 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -628,9 +628,6 @@ 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 3abaf298882beec742fe5bc3fb64beb64dd3ce41..2d28b81af7f007b380e466242c2ff0e49c317f01 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -410,7 +410,7 @@ enum GameType GT_LASTFREESLOT = GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1, NUMGAMETYPES }; -// If you alter this list, update dehacked.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c +// If you alter this list, update deh_tables.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c // Gametype rules enum GameTypeRules diff --git a/src/dummy/i_video.c b/src/dummy/i_video.c index 2b0478220eac8119ec36dff4b0b8a05cf92158fc..3b0a12a328df587e1cd20d0312cf96ce6c8df847 100644 --- a/src/dummy/i_video.c +++ b/src/dummy/i_video.c @@ -3,6 +3,7 @@ #include "../i_video.h" rendermode_t rendermode = render_none; +rendermode_t chosenrendermode = render_none; boolean highcolor = false; @@ -40,8 +41,15 @@ INT32 VID_SetMode(INT32 modenum) return 0; } -void VID_CheckRenderer(void) {} -void VID_CheckGLLoaded(rendermode_t oldrender) {} +boolean VID_CheckRenderer(void) +{ + return false; +} + +void VID_CheckGLLoaded(rendermode_t oldrender) +{ + (void)oldrender; +} const char *VID_GetModeName(INT32 modenum) { diff --git a/src/f_finale.c b/src/f_finale.c index d7f81b9df0e7f3f4f31d56e12d84368a457b149b..688cd4fc7f24cf472d2e8302b0bd2f496cc9f427 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -533,78 +533,78 @@ static void F_IntroDrawScene(void) bgxoffs = 28; break; case 1: - background = W_CachePatchName("INTRO1", PU_PATCH); + background = W_CachePatchName("INTRO1", PU_PATCH_LOWPRIORITY); break; case 2: - background = W_CachePatchName("INTRO2", PU_PATCH); + background = W_CachePatchName("INTRO2", PU_PATCH_LOWPRIORITY); break; case 3: - background = W_CachePatchName("INTRO3", PU_PATCH); + background = W_CachePatchName("INTRO3", PU_PATCH_LOWPRIORITY); break; case 4: - background = W_CachePatchName("INTRO4", PU_PATCH); + background = W_CachePatchName("INTRO4", PU_PATCH_LOWPRIORITY); break; case 5: if (intro_curtime >= 5*TICRATE) - background = W_CachePatchName("RADAR", PU_PATCH); + background = W_CachePatchName("RADAR", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("DRAT", PU_PATCH); + background = W_CachePatchName("DRAT", PU_PATCH_LOWPRIORITY); break; case 6: - background = W_CachePatchName("INTRO6", PU_PATCH); + background = W_CachePatchName("INTRO6", PU_PATCH_LOWPRIORITY); cx = 180; cy = 8; break; case 7: { if (intro_curtime >= 7*TICRATE + ((TICRATE/7)*2)) - background = W_CachePatchName("SGRASS5", PU_PATCH); + background = W_CachePatchName("SGRASS5", PU_PATCH_LOWPRIORITY); else if (intro_curtime >= 7*TICRATE + (TICRATE/7)) - background = W_CachePatchName("SGRASS4", PU_PATCH); + background = W_CachePatchName("SGRASS4", PU_PATCH_LOWPRIORITY); else if (intro_curtime >= 7*TICRATE) - background = W_CachePatchName("SGRASS3", PU_PATCH); + background = W_CachePatchName("SGRASS3", PU_PATCH_LOWPRIORITY); else if (intro_curtime >= 6*TICRATE) - background = W_CachePatchName("SGRASS2", PU_PATCH); + background = W_CachePatchName("SGRASS2", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("SGRASS1", PU_PATCH); + background = W_CachePatchName("SGRASS1", PU_PATCH_LOWPRIORITY); break; } case 8: - background = W_CachePatchName("WATCHING", PU_PATCH); + background = W_CachePatchName("WATCHING", PU_PATCH_LOWPRIORITY); break; case 9: - background = W_CachePatchName("ZOOMING", PU_PATCH); + background = W_CachePatchName("ZOOMING", PU_PATCH_LOWPRIORITY); break; case 10: break; case 11: - background = W_CachePatchName("INTRO5", PU_PATCH); + background = W_CachePatchName("INTRO5", PU_PATCH_LOWPRIORITY); break; case 12: - background = W_CachePatchName("REVENGE", PU_PATCH); + background = W_CachePatchName("REVENGE", PU_PATCH_LOWPRIORITY); cx = 208; cy = 8; break; case 13: - background = W_CachePatchName("CONFRONT", PU_PATCH); + background = W_CachePatchName("CONFRONT", PU_PATCH_LOWPRIORITY); cy += 48; break; case 14: - background = W_CachePatchName("TAILSSAD", PU_PATCH); + background = W_CachePatchName("TAILSSAD", PU_PATCH_LOWPRIORITY); bgxoffs = 144; cx = 8; cy = 8; break; case 15: if (intro_curtime >= 7*TICRATE) - background = W_CachePatchName("SONICDO2", PU_PATCH); + background = W_CachePatchName("SONICDO2", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("SONICDO1", PU_PATCH); + background = W_CachePatchName("SONICDO1", PU_PATCH_LOWPRIORITY); cx = 224; cy = 8; break; case 16: - background = W_CachePatchName("INTRO7", PU_PATCH); + background = W_CachePatchName("INTRO7", PU_PATCH_LOWPRIORITY); break; default: break; @@ -635,7 +635,7 @@ static void F_IntroDrawScene(void) strncpy(stjrintro, "STJRI029", 9); S_ChangeMusicInternal("_stjr", false); - background = W_CachePatchName(stjrintro, PU_PATCH); + background = W_CachePatchName(stjrintro, PU_PATCH_LOWPRIORITY); wipestyleflags = WSF_FADEIN; F_WipeStartScreen(); F_TryColormapFade(31); @@ -646,7 +646,7 @@ static void F_IntroDrawScene(void) if (!WipeInAction) // Draw the patch if not in a wipe { - background = W_CachePatchName(stjrintro, PU_PATCH); + background = W_CachePatchName(stjrintro, PU_PATCH_LOWPRIORITY); V_DrawSmallScaledPatch(bgxoffs, 84, 0, background); } } @@ -656,27 +656,27 @@ static void F_IntroDrawScene(void) if (timetonext > 5*TICRATE && timetonext < 6*TICRATE) { if (!(finalecount & 3)) - background = W_CachePatchName("BRITEGG1", PU_PATCH); + background = W_CachePatchName("BRITEGG1", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("DARKEGG1", PU_PATCH); + background = W_CachePatchName("DARKEGG1", PU_PATCH_LOWPRIORITY); V_DrawSmallScaledPatch(0, 0, 0, background); } else if (timetonext > 3*TICRATE && timetonext < 4*TICRATE) { if (!(finalecount & 3)) - background = W_CachePatchName("BRITEGG2", PU_PATCH); + background = W_CachePatchName("BRITEGG2", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("DARKEGG2", PU_PATCH); + background = W_CachePatchName("DARKEGG2", PU_PATCH_LOWPRIORITY); V_DrawSmallScaledPatch(0, 0, 0, background); } else if (timetonext > 1*TICRATE && timetonext < 2*TICRATE) { if (!(finalecount & 3)) - background = W_CachePatchName("BRITEGG3", PU_PATCH); + background = W_CachePatchName("BRITEGG3", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("DARKEGG3", PU_PATCH); + background = W_CachePatchName("DARKEGG3", PU_PATCH_LOWPRIORITY); V_DrawSmallScaledPatch(0, 0, 0, background); } @@ -708,79 +708,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_PATCH))); + V_DrawSmallScaledPatch(skyx, 0, 0, (patch = W_CachePatchName("INTROSKY", PU_PATCH_LOWPRIORITY))); V_DrawSmallScaledPatch(skyx - 320, 0, 0, patch); W_UnlockCachedPatch(patch); - V_DrawSmallScaledPatch(grassx, 0, 0, (patch = W_CachePatchName("INTROGRS", PU_PATCH))); + V_DrawSmallScaledPatch(grassx, 0, 0, (patch = W_CachePatchName("INTROGRS", PU_PATCH_LOWPRIORITY))); V_DrawSmallScaledPatch(grassx - 320, 0, 0, patch); W_UnlockCachedPatch(patch); if (finalecount & 1) { // Sonic - V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN2", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Appendages if (finalecount & 2) { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT4", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT4", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } else { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT2", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } // Tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY2", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Knuckles - V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE2", PU_PATCH))); + V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } else { // Sonic - V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN1", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Appendages if (finalecount & 2) { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT3", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT3", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } else { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT1", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } // Tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY1", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Knuckles - V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE1", PU_PATCH))); + V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } @@ -813,8 +813,8 @@ static void F_IntroDrawScene(void) y += (30*(FRACUNIT-scale)); } - rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (worktics % 35)), PU_PATCH); - glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(worktics & 1)), PU_PATCH); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (worktics % 35)), PU_PATCH_LOWPRIORITY); + glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(worktics & 1)), PU_PATCH_LOWPRIORITY); if (worktics >= 5) trans = (worktics-5)>>1; @@ -934,7 +934,7 @@ void F_IntroDrawer(void) { if (intro_scenenum == 5 && intro_curtime == 5*TICRATE) { - patch_t *radar = W_CachePatchName("RADAR", PU_PATCH); + patch_t *radar = W_CachePatchName("RADAR", PU_PATCH_LOWPRIORITY); F_WipeStartScreen(); F_WipeColorFill(31); @@ -947,7 +947,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_PATCH); + patch_t *grass = W_CachePatchName("SGRASS2", PU_PATCH_LOWPRIORITY); F_WipeStartScreen(); F_WipeColorFill(31); @@ -960,7 +960,7 @@ void F_IntroDrawer(void) } /*else if (intro_scenenum == 11 && intro_curtime == 7*TICRATE) { - patch_t *confront = W_CachePatchName("CONFRONT", PU_PATCH); + patch_t *confront = W_CachePatchName("CONFRONT", PU_PATCH_LOWPRIORITY); F_WipeStartScreen(); F_WipeColorFill(31); @@ -973,7 +973,7 @@ void F_IntroDrawer(void) }*/ if (intro_scenenum == 15 && intro_curtime == 7*TICRATE) { - patch_t *sdo = W_CachePatchName("SONICDO2", PU_PATCH); + patch_t *sdo = W_CachePatchName("SONICDO2", PU_PATCH_LOWPRIORITY); F_WipeStartScreen(); F_WipeColorFill(31); @@ -1303,14 +1303,14 @@ void F_CreditDrawer(void) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Zig Zagz - 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)); + V_DrawScaledPatch(-16, zagpos, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); + V_DrawScaledPatch(-16, zagpos - 320, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); + V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); + V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos - 320, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); // Draw background pictures first for (i = 0; credits_pics[i].patch; i++) - V_DrawSciencePatch(credits_pics[i].x<<FRACBITS, (280<<FRACBITS) + (((i*credits_height)<<FRACBITS)/(credits_numpics)) - 4*(animtimer<<FRACBITS)/5, 0, W_CachePatchName(credits_pics[i].patch, PU_PATCH), FRACUNIT>>1); + V_DrawSciencePatch(credits_pics[i].x<<FRACBITS, (280<<FRACBITS) + (((i*credits_height)<<FRACBITS)/(credits_numpics)) - 4*(animtimer<<FRACBITS)/5, 0, W_CachePatchName(credits_pics[i].patch, PU_PATCH_LOWPRIORITY), FRACUNIT>>1); // Dim the background V_DrawFadeScreen(0xFF00, 16); @@ -1519,14 +1519,14 @@ void F_GameEvaluationDrawer(void) if (goodending) { - rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (finalecount % 35)), PU_PATCH); - glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_PATCH); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (finalecount % 35)), PU_PATCH_LOWPRIORITY); + glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_PATCH_LOWPRIORITY); x -= FRACUNIT; } else { - rockpat = W_CachePatchName("ROID0000", PU_LEVEL); - glow = W_CachePatchName(va("ENDGLOW%.1d", (finalecount & 1)), PU_PATCH); + rockpat = W_CachePatchName("ROID0000", PU_PATCH_LOWPRIORITY); + glow = W_CachePatchName(va("ENDGLOW%.1d", (finalecount & 1)), PU_PATCH_LOWPRIORITY); } if (finalecount >= 5) @@ -1558,20 +1558,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_PATCH), 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_LOWPRIORITY), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_AQUA, GTC_CACHE)); } j--; } } else { - patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_PATCH); + patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_PATCH_LOWPRIORITY); V_DrawFixedPatch(x, y, scale, 0, eggrock, colormap[0]); if (trans < 10) V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, eggrock, colormap[1]); else if (sparklloop) V_DrawFixedPatch(x, y, scale, (10-sparklloop)<<V_ALPHASHIFT, - W_CachePatchName("ENDEGRK0", PU_PATCH), colormap[1]); + W_CachePatchName("ENDEGRK0", PU_PATCH_LOWPRIORITY), colormap[1]); } } @@ -1585,7 +1585,7 @@ void F_GameEvaluationDrawer(void) eemeralds_cur += (360<<FRACBITS)/7; patchname[4] = 'A'+(char)i; - V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<<i)) ? 0 : V_80TRANS), W_CachePatchName(patchname, PU_PATCH), NULL); + V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<<i)) ? 0 : V_80TRANS), W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY), NULL); } V_DrawCreditString((BASEVIDWIDTH - V_CreditStringWidth(endingtext))<<(FRACBITS-1), (BASEVIDHEIGHT-100)<<(FRACBITS-1), 0, endingtext); @@ -1714,32 +1714,32 @@ void F_GameEvaluationTicker(void) static void F_CacheEnding(void) { - endbrdr[1] = W_CachePatchName("ENDBRDR1", PU_PATCH); + endbrdr[1] = W_CachePatchName("ENDBRDR1", PU_PATCH_LOWPRIORITY); - endegrk[0] = W_CachePatchName("ENDEGRK0", PU_PATCH); - endegrk[1] = W_CachePatchName("ENDEGRK1", PU_PATCH); + endegrk[0] = W_CachePatchName("ENDEGRK0", PU_PATCH_LOWPRIORITY); + endegrk[1] = W_CachePatchName("ENDEGRK1", PU_PATCH_LOWPRIORITY); - endglow[0] = W_CachePatchName("ENDGLOW0", PU_PATCH); - endglow[1] = W_CachePatchName("ENDGLOW1", PU_PATCH); + endglow[0] = W_CachePatchName("ENDGLOW0", PU_PATCH_LOWPRIORITY); + endglow[1] = W_CachePatchName("ENDGLOW1", PU_PATCH_LOWPRIORITY); - endbgsp[0] = W_CachePatchName("ENDBGSP0", PU_PATCH); - endbgsp[1] = W_CachePatchName("ENDBGSP1", PU_PATCH); - endbgsp[2] = W_CachePatchName("ENDBGSP2", PU_PATCH); + endbgsp[0] = W_CachePatchName("ENDBGSP0", PU_PATCH_LOWPRIORITY); + endbgsp[1] = W_CachePatchName("ENDBGSP1", PU_PATCH_LOWPRIORITY); + endbgsp[2] = W_CachePatchName("ENDBGSP2", PU_PATCH_LOWPRIORITY); - endspkl[0] = W_CachePatchName("ENDSPKL0", PU_PATCH); - endspkl[1] = W_CachePatchName("ENDSPKL1", PU_PATCH); - endspkl[2] = W_CachePatchName("ENDSPKL2", PU_PATCH); + endspkl[0] = W_CachePatchName("ENDSPKL0", PU_PATCH_LOWPRIORITY); + endspkl[1] = W_CachePatchName("ENDSPKL1", PU_PATCH_LOWPRIORITY); + endspkl[2] = W_CachePatchName("ENDSPKL2", PU_PATCH_LOWPRIORITY); - endxpld[0] = W_CachePatchName("ENDXPLD0", PU_PATCH); - endxpld[1] = W_CachePatchName("ENDXPLD1", PU_PATCH); - endxpld[2] = W_CachePatchName("ENDXPLD2", PU_PATCH); - endxpld[3] = W_CachePatchName("ENDXPLD3", PU_PATCH); + endxpld[0] = W_CachePatchName("ENDXPLD0", PU_PATCH_LOWPRIORITY); + endxpld[1] = W_CachePatchName("ENDXPLD1", PU_PATCH_LOWPRIORITY); + endxpld[2] = W_CachePatchName("ENDXPLD2", PU_PATCH_LOWPRIORITY); + endxpld[3] = W_CachePatchName("ENDXPLD3", PU_PATCH_LOWPRIORITY); - endescp[0] = W_CachePatchName("ENDESCP0", PU_PATCH); - endescp[1] = W_CachePatchName("ENDESCP1", PU_PATCH); - endescp[2] = W_CachePatchName("ENDESCP2", PU_PATCH); - endescp[3] = W_CachePatchName("ENDESCP3", PU_PATCH); - endescp[4] = W_CachePatchName("ENDESCP4", PU_PATCH); + endescp[0] = W_CachePatchName("ENDESCP0", PU_PATCH_LOWPRIORITY); + endescp[1] = W_CachePatchName("ENDESCP1", PU_PATCH_LOWPRIORITY); + endescp[2] = W_CachePatchName("ENDESCP2", PU_PATCH_LOWPRIORITY); + endescp[3] = W_CachePatchName("ENDESCP3", PU_PATCH_LOWPRIORITY); + endescp[4] = W_CachePatchName("ENDESCP4", PU_PATCH_LOWPRIORITY); // so we only need to check once if ((goodending = ALL7EMERALDS(emeralds))) @@ -1752,41 +1752,41 @@ static void F_CacheEnding(void) sprdef = &skins[skinnum].sprites[SPR2_XTRA]; // character head, skin specific sprframe = &sprdef->spriteframes[XTRA_ENDING]; - endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); + endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY); sprframe = &sprdef->spriteframes[XTRA_ENDING+1]; - endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); + endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY); sprframe = &sprdef->spriteframes[XTRA_ENDING+2]; - endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); + endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY); } 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); + endfwrk[0] = W_CachePatchName("ENDFWRK3", PU_PATCH_LOWPRIORITY); + endfwrk[1] = W_CachePatchName("ENDFWRK4", PU_PATCH_LOWPRIORITY); + endfwrk[2] = W_CachePatchName("ENDFWRK5", PU_PATCH_LOWPRIORITY); } - endbrdr[0] = W_CachePatchName("ENDBRDR2", PU_PATCH); + endbrdr[0] = W_CachePatchName("ENDBRDR2", PU_PATCH_LOWPRIORITY); } 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); + endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_PATCH_LOWPRIORITY); + endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_PATCH_LOWPRIORITY); + endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_PATCH_LOWPRIORITY); - endbrdr[0] = W_CachePatchName("ENDBRDR0", PU_LEVEL); + endbrdr[0] = W_CachePatchName("ENDBRDR0", PU_PATCH_LOWPRIORITY); } } static void F_CacheGoodEnding(void) { - endegrk[0] = W_CachePatchName("ENDEGRK2", PU_PATCH); - endegrk[1] = W_CachePatchName("ENDEGRK3", PU_PATCH); + endegrk[0] = W_CachePatchName("ENDEGRK2", PU_PATCH_LOWPRIORITY); + endegrk[1] = W_CachePatchName("ENDEGRK3", PU_PATCH_LOWPRIORITY); - endglow[0] = W_CachePatchName("ENDGLOW2", PU_PATCH); - endglow[1] = W_CachePatchName("ENDGLOW3", PU_PATCH); + endglow[0] = W_CachePatchName("ENDGLOW2", PU_PATCH_LOWPRIORITY); + endglow[1] = W_CachePatchName("ENDGLOW3", PU_PATCH_LOWPRIORITY); - endxpld[0] = W_CachePatchName("ENDEGRK4", PU_PATCH); + endxpld[0] = W_CachePatchName("ENDEGRK4", PU_PATCH_LOWPRIORITY); } void F_StartEnding(void) @@ -1843,17 +1843,10 @@ 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_PATCH); + rockpat = W_CachePatchName("ROID0000", PU_PATCH_LOWPRIORITY); else - rockpat = W_CachePatchName(va("ROID00%.2d", 34 - ((finalecount - INFLECTIONPOINT) % 35)), PU_PATCH); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - ((finalecount - INFLECTIONPOINT) % 35)), PU_PATCH_LOWPRIORITY); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); @@ -2190,7 +2183,7 @@ void F_EndingDrawer(void) eemeralds_cur[0] += (360<<FRACBITS)/7; patchname[4] = 'A'+(char)i; - V_DrawFixedPatch(x, y, FRACUNIT, 0, W_CachePatchName(patchname, PU_LEVEL), NULL); + V_DrawFixedPatch(x, y, FRACUNIT, 0, W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY), NULL); } } // if (goodending... } // (finalecount > 20) @@ -2337,14 +2330,14 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) if (!scrollxspeed && !scrollyspeed) { - V_DrawPatchFill(W_CachePatchName(patchname, PU_PATCH)); + V_DrawPatchFill(W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY)); return; } - pat = W_CachePatchName(patchname, PU_PATCH); + pat = W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY); - patwidth = SHORT(pat->width); - patheight = SHORT(pat->height); + patwidth = pat->width; + patheight = pat->height; pw = patwidth * dupz; ph = patheight * dupz; @@ -2380,7 +2373,7 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) lumpnum = W_CheckNumForName(name); \ if (lumpnum != LUMPERROR) \ { \ - arr[0] = W_CachePatchName(name, PU_LEVEL); \ + arr[0] = W_CachePatchName(name, PU_PATCH_LOWPRIORITY); \ arr[min(1, maxf-1)] = 0; \ } \ else if (strlen(name) <= 6) \ @@ -2393,7 +2386,7 @@ else if (strlen(name) <= 6) \ lumpname[8] = 0; \ lumpnum = W_CheckNumForName(lumpname); \ if (lumpnum != LUMPERROR) \ - arr[i] = W_CachePatchName(lumpname, PU_LEVEL); \ + arr[i] = W_CachePatchName(lumpname, PU_PATCH_LOWPRIORITY); \ else \ break; \ } \ @@ -2408,21 +2401,21 @@ static void F_CacheTitleScreen(void) { 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); + ttbanner = W_CachePatchName("TTBANNER", PU_PATCH_LOWPRIORITY); + ttwing = W_CachePatchName("TTWING", PU_PATCH_LOWPRIORITY); + ttsonic = W_CachePatchName("TTSONIC", PU_PATCH_LOWPRIORITY); + ttswave1 = W_CachePatchName("TTSWAVE1", PU_PATCH_LOWPRIORITY); + ttswave2 = W_CachePatchName("TTSWAVE2", PU_PATCH_LOWPRIORITY); + ttswip1 = W_CachePatchName("TTSWIP1", PU_PATCH_LOWPRIORITY); + ttsprep1 = W_CachePatchName("TTSPREP1", PU_PATCH_LOWPRIORITY); + ttsprep2 = W_CachePatchName("TTSPREP2", PU_PATCH_LOWPRIORITY); + ttspop1 = W_CachePatchName("TTSPOP1", PU_PATCH_LOWPRIORITY); + ttspop2 = W_CachePatchName("TTSPOP2", PU_PATCH_LOWPRIORITY); + ttspop3 = W_CachePatchName("TTSPOP3", PU_PATCH_LOWPRIORITY); + ttspop4 = W_CachePatchName("TTSPOP4", PU_PATCH_LOWPRIORITY); + ttspop5 = W_CachePatchName("TTSPOP5", PU_PATCH_LOWPRIORITY); + ttspop6 = W_CachePatchName("TTSPOP6", PU_PATCH_LOWPRIORITY); + ttspop7 = W_CachePatchName("TTSPOP7", PU_PATCH_LOWPRIORITY); break; // don't load alacroix gfx yet; we do that upon first draw. @@ -2542,7 +2535,7 @@ void F_StartTitleScreen(void) static void F_UnloadAlacroixGraphics(SINT8 oldttscale) { - // This all gets freed by PU_LEVEL when exiting the menus. + // This all gets freed by PU_PATCH_LOWPRIORITY when exiting the menus. // When re-visiting the menus (e.g., from exiting in-game), the gfx are force-reloaded. // So leftover addresses here should not be a problem. @@ -2648,17 +2641,12 @@ static void F_FigureActiveTtScale(void) SINT8 newttscale = max(1, min(6, vid.dupx)); SINT8 oldttscale = activettscale; - if (needpatchrecache) - ttloaded[0] = ttloaded[1] = ttloaded[2] = ttloaded[3] = ttloaded[4] = ttloaded[5] = 0; - else - { - if (newttscale == testttscale) - return; + if (newttscale == testttscale) + return; - // We have a new ttscale, so load gfx - if(oldttscale > 0) - F_UnloadAlacroixGraphics(oldttscale); - } + // We have a new ttscale, so load gfx + if(oldttscale > 0) + F_UnloadAlacroixGraphics(oldttscale); testttscale = newttscale; @@ -2692,9 +2680,6 @@ 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); @@ -3658,7 +3643,7 @@ void F_ContinueDrawer(void) V_DrawLevelTitle(x - (V_LevelNameWidth("Continue?")>>1), 16, 0, "Continue?"); // Two stars... - patch = W_CachePatchName("CONTSTAR", PU_PATCH); + patch = W_CachePatchName("CONTSTAR", PU_PATCH_LOWPRIORITY); V_DrawScaledPatch(x-32, 160, 0, patch); V_DrawScaledPatch(x+32, 160, 0, patch); @@ -3666,14 +3651,14 @@ void F_ContinueDrawer(void) if (timeleft > 9) { numbuf[7] = '1'; - V_DrawScaledPatch(x - 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH)); + V_DrawScaledPatch(x - 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH_LOWPRIORITY)); numbuf[7] = '0'; - V_DrawScaledPatch(x + 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH)); + V_DrawScaledPatch(x + 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH_LOWPRIORITY)); } else { numbuf[7] = '0'+timeleft; - V_DrawScaledPatch(x, 160, 0, W_CachePatchName(numbuf, PU_PATCH)); + V_DrawScaledPatch(x, 160, 0, W_CachePatchName(numbuf, PU_PATCH_LOWPRIORITY)); } // Draw the continue markers! Show continues. @@ -3702,7 +3687,7 @@ void F_ContinueDrawer(void) } // Spotlight - V_DrawScaledPatch(x, 140, 0, W_CachePatchName("CONTSPOT", PU_PATCH)); + V_DrawScaledPatch(x, 140, 0, W_CachePatchName("CONTSPOT", PU_PATCH_LOWPRIORITY)); // warping laser if (continuetime) @@ -3739,7 +3724,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_PATCH);\ + patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH_LOWPRIORITY);\ V_DrawFixedPatch((dx), (dy), contskins[n]->highresscale, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);\ } @@ -4004,10 +3989,10 @@ void F_CutsceneDrawer(void) { if (cutscenes[cutnum]->scene[scenenum].pichires[picnum]) V_DrawSmallScaledPatch(picxpos, picypos, 0, - W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH)); + W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY)); else V_DrawScaledPatch(picxpos,picypos, 0, - W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH)); + W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY)); } if (dofadenow && rendermode != render_none) @@ -4493,10 +4478,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_PATCH)); + W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY)); else V_DrawScaledPatch(picxpos,picypos, 0, - W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH)); + W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY)); } // Draw background @@ -4506,7 +4491,7 @@ void F_TextPromptDrawer(void) if (iconlump != LUMPERROR) { INT32 iconx, icony, scale, scaledsize; - patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_PATCH); + patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_PATCH_LOWPRIORITY); // scale and center if (patch->width > patch->height) diff --git a/src/f_wipe.c b/src/f_wipe.c index f5b9bd72230ae7f5763b7fdc97cbbca9398d0ff5..6afb8a6a7934709c90b1428fcd5f5a6f55d54c20 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -293,7 +293,7 @@ static void F_DoWipe(fademask_t *fademask) else { // pointer to transtable that this mask would use - transtbl = transtables + ((9 - *mask)<<FF_TRANSSHIFT); + transtbl = R_GetTranslucencyTable((9 - *mask) + 1); // DRAWING LOOP while (draw_linestogo--) diff --git a/src/g_demo.c b/src/g_demo.c index 0f72ad1094e443523f6be3fdb6b5fa345fa48539..9d3b8601584385d06bbd14e5ff8a2ec4ea63ca3c 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -453,8 +453,7 @@ void G_WriteGhostTic(mobj_t *ghost) WRITEUINT16(demo_p,oldghost.sprite); if (ghostext.flags & EZT_HEIGHT) { - height >>= FRACBITS; - WRITEINT16(demo_p, height); + WRITEFIXED(demo_p, height); } ghostext.flags = 0; } @@ -610,7 +609,7 @@ void G_ConsGhostTic(void) if (xziptic & EZT_SPRITE) demo_p += sizeof(UINT16); if (xziptic & EZT_HEIGHT) - demo_p += sizeof(INT16); + demo_p += (demoversion < 0x000e) ? sizeof(INT16) : sizeof(fixed_t); } if (ziptic & GZT_FOLLOW) @@ -842,7 +841,7 @@ void G_GhostTicker(void) g->mo->sprite = READUINT16(g->p); if (xziptic & EZT_HEIGHT) { - fixed_t temp = READINT16(g->p)<<FRACBITS; + fixed_t temp = (g->version < 0x000e) ? READINT16(g->p)<<FRACBITS : READFIXED(g->p); g->mo->height = FixedMul(temp, g->mo->scale); } } @@ -1106,7 +1105,7 @@ void G_ReadMetalTic(mobj_t *metal) metal->sprite = READUINT16(metal_p); if (xziptic & EZT_HEIGHT) { - fixed_t temp = READINT16(metal_p)<<FRACBITS; + fixed_t temp = (metalversion < 0x000e) ? READINT16(metal_p)<<FRACBITS : READFIXED(metal_p); metal->height = FixedMul(temp, metal->scale); } } @@ -1293,8 +1292,7 @@ void G_WriteMetalTic(mobj_t *metal) WRITEUINT16(demo_p,oldmetal.sprite); if (ghostext.flags & EZT_HEIGHT) { - height >>= FRACBITS; - WRITEINT16(demo_p, height); + WRITEFIXED(demo_p, height); } ghostext.flags = 0; } @@ -1474,8 +1472,8 @@ void G_BeginRecording(void) WRITEUINT8(demo_p,player->thrustfactor); WRITEUINT8(demo_p,player->accelstart); WRITEUINT8(demo_p,player->acceleration); - WRITEUINT8(demo_p,player->height>>FRACBITS); - WRITEUINT8(demo_p,player->spinheight>>FRACBITS); + WRITEFIXED(demo_p,player->height); + WRITEFIXED(demo_p,player->spinheight); WRITEUINT8(demo_p,player->camerascale>>FRACBITS); WRITEUINT8(demo_p,player->shieldscale>>FRACBITS); @@ -1901,8 +1899,8 @@ void G_DoPlayDemo(char *defdemoname) thrustfactor = READUINT8(demo_p); accelstart = READUINT8(demo_p); acceleration = READUINT8(demo_p); - height = (fixed_t)READUINT8(demo_p)<<FRACBITS; - spinheight = (fixed_t)READUINT8(demo_p)<<FRACBITS; + height = (demoversion < 0x000e) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); + spinheight = (demoversion < 0x000e) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); camerascale = (fixed_t)READUINT8(demo_p)<<FRACBITS; shieldscale = (fixed_t)READUINT8(demo_p)<<FRACBITS; jumpfactor = READFIXED(demo_p); @@ -2150,8 +2148,7 @@ void G_AddGhost(char *defdemoname) p++; // thrustfactor p++; // accelstart p++; // acceleration - p++; // height - p++; // spinheight + p += (ghostversion < 0x000e) ? 2 : 2 * sizeof(fixed_t); // height and spinheight p++; // camerascale p++; // shieldscale p += 4; // jumpfactor diff --git a/src/g_game.c b/src/g_game.c index 228295b629539da319ee874798a26c91fcca0aa7..283113bbeaec2a78b7756b6361d90e33764ec315 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1677,10 +1677,26 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) } } - // Note: Lat originally made the PlayerCmd hook for SRB2 Kart so credit goes to him. + // At this point, cmd doesn't contain the final angle yet, + // So we need to temporarily transform it so Lua scripters + // don't need to handle it differently than in other hooks. if (gamestate == GS_LEVEL) + { + INT16 extra = ticcmd_oldangleturn[forplayer] - player->oldrelangleturn; + INT16 origangle = cmd->angleturn; + INT16 orighookangle = (INT16)(origangle + player->angleturn + extra); + INT16 origaiming = cmd->aiming; + + cmd->angleturn = orighookangle; + LUAh_PlayerCmd(player, cmd); + extra = cmd->angleturn - orighookangle; + cmd->angleturn = origangle + extra; + *myangle += extra << 16; + *myaiming += (cmd->aiming - origaiming) << 16; + } + //Reset away view if a command is given. if (ssplayer == 1 && (cmd->forwardmove || cmd->sidemove || cmd->buttons) && displayplayer != consoleplayer) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 8c85c5112b09aa38ebd619b13c7c7b07a147e92f..b4fa7ec6c1d8be984b7f0f86234b42980c6f3b7b 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -25,6 +25,7 @@ #include "../z_zone.h" #include "../v_video.h" #include "../r_draw.h" +#include "../r_patch.h" #include "../r_picformats.h" #include "../p_setup.h" @@ -306,7 +307,7 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, // Draw each column to the block cache for (; ncols--; block += bpp, xfrac += xfracstep) { - patchcol = (const column_t *)((const UINT8 *)realpatch + LONG(realpatch->columnofs[xfrac>>FRACBITS])); + patchcol = (const column_t *)((const UINT8 *)realpatch->columns + (realpatch->columnofs[xfrac>>FRACBITS])); HWR_DrawColumnInCache(patchcol, block, mipmap, pblockheight, blockmodulo, @@ -320,7 +321,7 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 pblockheight, texture_t *texture, texpatch_t *patch, - const patch_t *realpatch) + const softwarepatch_t *realpatch) { INT32 x, x1, x2; INT32 col, ncols; @@ -391,7 +392,7 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, bpp = format2bpp(mipmap->format); if (bpp < 1 || bpp > 4) - I_Error("HWR_DrawPatchInCache: no drawer defined for this bpp (%d)\n",bpp); + I_Error("HWR_DrawTexturePatchInCache: no drawer defined for this bpp (%d)\n",bpp); // NOTE: should this actually be pblockwidth*bpp? blockmodulo = pblockwidth*bpp; @@ -446,7 +447,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) UINT8 *block; texture_t *texture; texpatch_t *patch; - patch_t *realpatch; + softwarepatch_t *realpatch; UINT8 *pdata; INT32 blockwidth, blockheight, blocksize; @@ -502,16 +503,16 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) boolean dealloc = true; size_t lumplength = W_LumpLengthPwad(patch->wad, patch->lump); pdata = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); - realpatch = (patch_t *)pdata; + realpatch = (softwarepatch_t *)pdata; #ifndef NO_PNG_LUMPS if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) - realpatch = (patch_t *)Picture_PNGConvert(pdata, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0); + realpatch = (softwarepatch_t *)Picture_PNGConvert(pdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0); else #endif #ifdef WALLFLATS if (texture->type == TEXTURETYPE_FLAT) - realpatch = (patch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_PATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); + realpatch = (softwarepatch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_DOOMPATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); else #endif { @@ -544,36 +545,20 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) // patch may be NULL if grMipmap has been initialised already and makebitmap is false void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap) { -#ifndef NO_PNG_LUMPS - // lump is a png so convert it - size_t len = W_LumpLengthPwad(grPatch->wadnum, grPatch->lumpnum); - if ((patch != NULL) && Picture_IsLumpPNG((const UINT8 *)patch, len)) - patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, NULL, NULL, NULL, NULL, len, NULL, 0); -#endif - - // don't do it twice (like a cache) if (grMipmap->width == 0) { - // save the original patch header so that the GLPatch can be casted - // into a standard patch_t struct and the existing code can get the - // orginal patch dimensions and offsets. - grPatch->width = SHORT(patch->width); - grPatch->height = SHORT(patch->height); - grPatch->leftoffset = SHORT(patch->leftoffset); - grPatch->topoffset = SHORT(patch->topoffset); - grMipmap->width = grMipmap->height = 1; - while (grMipmap->width < grPatch->width) grMipmap->width <<= 1; - while (grMipmap->height < grPatch->height) grMipmap->height <<= 1; + while (grMipmap->width < patch->width) grMipmap->width <<= 1; + while (grMipmap->height < patch->height) grMipmap->height <<= 1; // no wrap around, no chroma key grMipmap->flags = 0; + // setup the texture info grMipmap->format = patchformat; - //grPatch->max_s = grPatch->max_t = 1.0f; - grPatch->max_s = (float)grPatch->width / (float)grMipmap->width; - grPatch->max_t = (float)grPatch->height / (float)grMipmap->height; + grPatch->max_s = (float)patch->width / (float)grMipmap->width; + grPatch->max_t = (float)patch->height / (float)grMipmap->height; } Z_Free(grMipmap->data); @@ -585,7 +570,7 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm HWR_DrawPatchInCache(grMipmap, grMipmap->width, grMipmap->height, - grPatch->width, grPatch->height, + patch->width, patch->height, patch); } } @@ -598,20 +583,56 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm static size_t gl_numtextures = 0; // Texture count static GLMapTexture_t *gl_textures; // For all textures static GLMapTexture_t *gl_flats; // For all (texture) flats, as normal flats don't need to be cached +boolean gl_maptexturesloaded = false; -void HWR_InitTextureCache(void) +void HWR_FreeTextureData(patch_t *patch) { - gl_textures = NULL; - gl_flats = NULL; + GLPatch_t *grPatch; + + if (!patch || !patch->hardware) + return; + + grPatch = patch->hardware; + + if (vid.glstate == VID_GL_LIBRARY_LOADED) + HWD.pfnDeleteTexture(grPatch->mipmap); + if (grPatch->mipmap->data) + Z_Free(grPatch->mipmap->data); +} + +void HWR_FreeTexture(patch_t *patch) +{ + if (!patch) + return; + + if (patch->hardware) + { + GLPatch_t *grPatch = patch->hardware; + + HWR_FreeTextureColormaps(patch); + + if (grPatch->mipmap) + { + HWR_FreeTextureData(patch); + Z_Free(grPatch->mipmap); + } + + Z_Free(patch->hardware); + } + + patch->hardware = NULL; } -// Callback function for HWR_FreeTextureCache. -static void FreeMipmapColormap(INT32 patchnum, void *patch) +// Called by HWR_FreePatchCache. +void HWR_FreeTextureColormaps(patch_t *patch) { - GLPatch_t* const pat = patch; - (void)patchnum; //unused + GLPatch_t *pat; // The patch must be valid, obviously + if (!patch) + return; + + pat = patch->hardware; if (!pat) return; @@ -627,7 +648,7 @@ static void FreeMipmapColormap(INT32 patchnum, void *patch) if (!pat->mipmap) break; - // No colormap mipmap either. + // No colormap mipmaps either. if (!pat->mipmap->nextcolormap) break; @@ -639,34 +660,61 @@ static void FreeMipmapColormap(INT32 patchnum, void *patch) if (next->data) Z_Free(next->data); next->data = NULL; + HWD.pfnDeleteTexture(next); // Free the old colormap mipmap from memory. free(next); } } -void HWR_FreeMipmapCache(void) +static void HWR_FreePatchCache(boolean freeall) { INT32 i; - // free references to the textures - HWD.pfnClearMipMapCache(); + for (i = 0; i < numwadfiles; i++) + { + INT32 j = 0; + for (; j < wadfiles[i]->numlumps; j++) + (freeall ? HWR_FreeTexture : HWR_FreeTextureColormaps)(wadfiles[i]->patchcache[j]); + } +} - // free all hardware-converted graphics cached in the heap - // our gool is only the textures since user of the texture is the texture cache - Z_FreeTag(PU_HWRCACHE); - Z_FreeTag(PU_HWRCACHE_UNLOCKED); +// free all textures after each level +void HWR_ClearAllTextures(void) +{ + HWD.pfnClearMipMapCache(); // free references to the textures + HWR_FreePatchCache(true); +} - // Alam: free the Z_Blocks before freeing it's users - // free all patch colormaps after each level: must be done after ClearMipMapCache! - for (i = 0; i < numwadfiles; i++) - M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap); +void HWR_FreeColormapCache(void) +{ + HWR_FreePatchCache(false); +} + +void HWR_InitMapTextures(void) +{ + gl_textures = NULL; + gl_flats = NULL; + gl_maptexturesloaded = false; +} + +static void FreeMapTexture(GLMapTexture_t *tex) +{ + HWD.pfnDeleteTexture(&tex->mipmap); + if (tex->mipmap.data) + Z_Free(tex->mipmap.data); + tex->mipmap.data = NULL; } -void HWR_FreeTextureCache(void) +void HWR_FreeMapTextures(void) { - // free references to the textures - HWR_FreeMipmapCache(); + size_t i; + + for (i = 0; i < gl_numtextures; i++) + { + FreeMapTexture(&gl_textures[i]); + FreeMapTexture(&gl_flats[i]); + } // now the heap don't have any 'user' pointing to our // texturecache info, we can free it @@ -677,22 +725,22 @@ void HWR_FreeTextureCache(void) gl_textures = NULL; gl_flats = NULL; gl_numtextures = 0; + gl_maptexturesloaded = false; } -void HWR_LoadTextures(size_t pnumtextures) +void HWR_LoadMapTextures(size_t pnumtextures) { - // we must free it since numtextures changed - HWR_FreeTextureCache(); + // we must free it since numtextures may have changed + HWR_FreeMapTextures(); - // Why not Z_Malloc? gl_numtextures = pnumtextures; gl_textures = calloc(gl_numtextures, sizeof(*gl_textures)); gl_flats = calloc(gl_numtextures, sizeof(*gl_flats)); - // Doesn't tell you which it _is_, but hopefully - // should never ever happen (right?!) if ((gl_textures == NULL) || (gl_flats == NULL)) - I_Error("HWR_LoadTextures: ran out of memory for OpenGL textures. Sad!"); + I_Error("HWR_LoadMapTextures: ran out of memory for OpenGL textures"); + + gl_maptexturesloaded = true; } void HWR_SetPalette(RGBA_t *palette) @@ -730,7 +778,6 @@ GLMapTexture_t *HWR_GetTexture(INT32 tex) // If hardware does not have the texture, then call pfnSetTexture to upload it if (!grtex->mipmap.downloaded) HWD.pfnSetTexture(&grtex->mipmap); - HWR_SetCurrentTexture(&grtex->mipmap); // The system-memory data can be purged now. @@ -806,17 +853,19 @@ static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum) void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum) { GLMipmap_t *grmip; + patch_t *patch; + if (flatlumpnum == LUMPERROR) return; - grmip = HWR_GetCachedGLPatch(flatlumpnum)->mipmap; + patch = HWR_GetCachedGLPatch(flatlumpnum); + grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap; if (!grmip->downloaded && !grmip->data) HWR_CacheFlat(grmip, flatlumpnum); // If hardware does not have the texture, then call pfnSetTexture to upload it if (!grmip->downloaded) HWD.pfnSetTexture(grmip); - HWR_SetCurrentTexture(grmip); // The system-memory data can be purged now. @@ -854,7 +903,6 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) // If hardware does not have the texture, then call pfnSetTexture to upload it if (!grtex->mipmap.downloaded) HWD.pfnSetTexture(&grtex->mipmap); - HWR_SetCurrentTexture(&grtex->mipmap); // The system-memory data can be purged now. @@ -862,9 +910,9 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) } else if (levelflat->type == LEVELFLAT_PATCH) { - GLPatch_t *patch = W_CachePatchNum(levelflat->u.flat.lumpnum, PU_CACHE); - levelflat->width = (UINT16)SHORT(patch->width); - levelflat->height = (UINT16)SHORT(patch->height); + patch_t *patch = W_CachePatchNum(levelflat->u.flat.lumpnum, PU_CACHE); + levelflat->width = (UINT16)(patch->width); + levelflat->height = (UINT16)(patch->height); HWR_GetPatch(patch); } #ifndef NO_PNG_LUMPS @@ -911,89 +959,61 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) HWR_SetCurrentTexture(NULL); } -// -// HWR_LoadMappedPatch(): replace the skin color of the sprite in cache -// : load it first in doom cache if not already -// -static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch) +// --------------------+ +// HWR_LoadPatchMipmap : Generates a patch into a mipmap, usually the mipmap inside the patch itself +// --------------------+ +static void HWR_LoadPatchMipmap(patch_t *patch, GLMipmap_t *grMipmap) { - if (!grmip->downloaded && !grmip->data) - { - patch_t *patch = gpatch->rawpatch; - if (!patch) - patch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); - HWR_MakePatch(patch, gpatch, grmip, true); - - // You can't free rawpatch for some reason? - // (Obviously I can't, sprite rotation needs that...) - if (!gpatch->rawpatch) - Z_Free(patch); - } + GLPatch_t *grPatch = patch->hardware; + if (!grMipmap->downloaded && !grMipmap->data) + HWR_MakePatch(patch, grPatch, grMipmap, true); // If hardware does not have the texture, then call pfnSetTexture to upload it - if (!grmip->downloaded) - HWD.pfnSetTexture(grmip); - - HWR_SetCurrentTexture(grmip); + if (!grMipmap->downloaded) + HWD.pfnSetTexture(grMipmap); + HWR_SetCurrentTexture(grMipmap); // The system-memory data can be purged now. - Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED); + Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED); } // -----------------+ // HWR_GetPatch : Download a patch to the hardware cache and make it ready for use // -----------------+ -void HWR_GetPatch(GLPatch_t *gpatch) +void HWR_GetPatch(patch_t *patch) { - // is it in hardware cache - if (!gpatch->mipmap->downloaded && !gpatch->mipmap->data) - { - // load the software patch, PU_STATIC or the Z_Malloc for hardware patch will - // flush the software patch before the conversion! oh yeah I suffered - patch_t *ptr = gpatch->rawpatch; - if (!ptr) - ptr = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); - HWR_MakePatch(ptr, gpatch, gpatch->mipmap, true); - - // this is inefficient.. but the hardware patch in heap is purgeable so it should - // not fragment memory, and besides the REAL cache here is the hardware memory - if (!gpatch->rawpatch) - Z_Free(ptr); - } - - // If hardware does not have the texture, then call pfnSetTexture to upload it - if (!gpatch->mipmap->downloaded) - HWD.pfnSetTexture(gpatch->mipmap); - - HWR_SetCurrentTexture(gpatch->mipmap); - - // The system-memory patch data can be purged now. - Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED); + if (!patch->hardware) + Patch_CreateGL(patch); + HWR_LoadPatchMipmap(patch, ((GLPatch_t *)patch->hardware)->mipmap); } - // -------------------+ // HWR_GetMappedPatch : Same as HWR_GetPatch for sprite color // -------------------+ -void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap) +void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap) { - GLMipmap_t *grmip, *newmip; + GLPatch_t *grPatch; + GLMipmap_t *grMipmap, *newMipmap; + + if (!patch->hardware) + Patch_CreateGL(patch); + grPatch = patch->hardware; if (colormap == colormaps || colormap == NULL) { - // Load the default (green) color in doom cache (temporary?) AND hardware cache - HWR_GetPatch(gpatch); + // Load the default (green) color in hardware cache + HWR_GetPatch(patch); return; } // search for the mimmap // skip the first (no colormap translated) - for (grmip = gpatch->mipmap; grmip->nextcolormap; ) + for (grMipmap = grPatch->mipmap; grMipmap->nextcolormap; ) { - grmip = grmip->nextcolormap; - if (grmip->colormap == colormap) + grMipmap = grMipmap->nextcolormap; + if (grMipmap->colormap == colormap) { - HWR_LoadMappedPatch(grmip, gpatch); + HWR_LoadPatchMipmap(patch, grMipmap); return; } } @@ -1002,15 +1022,15 @@ void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap) //BP: WARNING: don't free it manually without clearing the cache of harware renderer // (it have a liste of mipmap) - // this malloc is cleared in HWR_FreeTextureCache + // this malloc is cleared in HWR_FreeColormapCache // (...) unfortunately z_malloc fragment alot the memory :(so malloc is better - newmip = calloc(1, sizeof (*newmip)); - if (newmip == NULL) + newMipmap = calloc(1, sizeof (*newMipmap)); + if (newMipmap == NULL) I_Error("%s: Out of memory", "HWR_GetMappedPatch"); - grmip->nextcolormap = newmip; + grMipmap->nextcolormap = newMipmap; - newmip->colormap = colormap; - HWR_LoadMappedPatch(newmip, gpatch); + newMipmap->colormap = colormap; + HWR_LoadPatchMipmap(patch, newMipmap); } void HWR_UnlockCachedPatch(GLPatch_t *gpatch) @@ -1100,79 +1120,73 @@ static void HWR_DrawPicInCache(UINT8 *block, INT32 pblockwidth, INT32 pblockheig // HWR_GetPic : Download a Doom pic (raw row encoded with no 'holes') // Returns : // -----------------+ -GLPatch_t *HWR_GetPic(lumpnum_t lumpnum) +patch_t *HWR_GetPic(lumpnum_t lumpnum) { - GLPatch_t *grpatch = HWR_GetCachedGLPatch(lumpnum); - if (!grpatch->mipmap->downloaded && !grpatch->mipmap->data) + patch_t *patch = HWR_GetCachedGLPatch(lumpnum); + GLPatch_t *grPatch = (GLPatch_t *)(patch->hardware); + + if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data) { pic_t *pic; UINT8 *block; size_t len; pic = W_CacheLumpNum(lumpnum, PU_CACHE); - grpatch->width = SHORT(pic->width); - grpatch->height = SHORT(pic->height); + patch->width = SHORT(pic->width); + patch->height = SHORT(pic->height); len = W_LumpLength(lumpnum) - sizeof (pic_t); - grpatch->leftoffset = 0; - grpatch->topoffset = 0; - - grpatch->mipmap->width = (UINT16)grpatch->width; - grpatch->mipmap->height = (UINT16)grpatch->height; + grPatch->mipmap->width = (UINT16)patch->width; + grPatch->mipmap->height = (UINT16)patch->height; if (pic->mode == PALETTE) - grpatch->mipmap->format = textureformat; // can be set by driver + grPatch->mipmap->format = textureformat; // can be set by driver else - grpatch->mipmap->format = picmode2GR[pic->mode]; + grPatch->mipmap->format = picmode2GR[pic->mode]; - Z_Free(grpatch->mipmap->data); + Z_Free(grPatch->mipmap->data); // allocate block - block = MakeBlock(grpatch->mipmap); + block = MakeBlock(grPatch->mipmap); - if (grpatch->width == SHORT(pic->width) && - grpatch->height == SHORT(pic->height) && - format2bpp(grpatch->mipmap->format) == format2bpp(picmode2GR[pic->mode])) + if (patch->width == SHORT(pic->width) && + patch->height == SHORT(pic->height) && + format2bpp(grPatch->mipmap->format) == format2bpp(picmode2GR[pic->mode])) { // no conversion needed - M_Memcpy(grpatch->mipmap->data, pic->data,len); + M_Memcpy(grPatch->mipmap->data, pic->data,len); } else HWR_DrawPicInCache(block, SHORT(pic->width), SHORT(pic->height), - SHORT(pic->width)*format2bpp(grpatch->mipmap->format), + SHORT(pic->width)*format2bpp(grPatch->mipmap->format), pic, - format2bpp(grpatch->mipmap->format)); + format2bpp(grPatch->mipmap->format)); Z_Unlock(pic); Z_ChangeTag(block, PU_HWRCACHE_UNLOCKED); - grpatch->mipmap->flags = 0; - grpatch->max_s = grpatch->max_t = 1.0f; + grPatch->mipmap->flags = 0; + grPatch->max_s = grPatch->max_t = 1.0f; } - HWD.pfnSetTexture(grpatch->mipmap); - //CONS_Debug(DBG_RENDER, "picloaded at %x as texture %d\n",grpatch->mipmap.data, grpatch->mipmap.downloaded); + HWD.pfnSetTexture(grPatch->mipmap); + //CONS_Debug(DBG_RENDER, "picloaded at %x as texture %d\n",grPatch->mipmap->data, grPatch->mipmap->downloaded); - return grpatch; + return patch; } -GLPatch_t *HWR_GetCachedGLPatchPwad(UINT16 wadnum, UINT16 lumpnum) +patch_t *HWR_GetCachedGLPatchPwad(UINT16 wadnum, UINT16 lumpnum) { - aatree_t *hwrcache = wadfiles[wadnum]->hwrcache; - GLPatch_t *grpatch; - - if (!(grpatch = M_AATreeGet(hwrcache, lumpnum))) + lumpcache_t *lumpcache = wadfiles[wadnum]->patchcache; + if (!lumpcache[lumpnum]) { - grpatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL); - grpatch->wadnum = wadnum; - grpatch->lumpnum = lumpnum; - grpatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL); - M_AATreeSet(hwrcache, lumpnum, grpatch); + void *ptr = Z_Calloc(sizeof(patch_t), PU_PATCH, &lumpcache[lumpnum]); + Patch_Create(NULL, 0, ptr); + Patch_AllocateHardwarePatch(ptr); } - - return grpatch; + return (patch_t *)(lumpcache[lumpnum]); } -GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum) +patch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum) { return HWR_GetCachedGLPatchPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum)); } @@ -1192,8 +1206,8 @@ static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 W_ReadLump(fademasklumpnum, Z_Malloc(W_LumpLength(fademasklumpnum), PU_HWRCACHE, &flat)); - stepy = ((INT32)SHORT(fmheight)<<FRACBITS)/pblockheight; - stepx = ((INT32)SHORT(fmwidth)<<FRACBITS)/pblockwidth; + stepy = ((INT32)fmheight<<FRACBITS)/pblockheight; + stepx = ((INT32)fmwidth<<FRACBITS)/pblockwidth; posy = 0; for (j = 0; j < pblockheight; j++) { @@ -1265,7 +1279,8 @@ static void HWR_CacheFadeMask(GLMipmap_t *grMipmap, lumpnum_t fademasklumpnum) void HWR_GetFadeMask(lumpnum_t fademasklumpnum) { - GLMipmap_t *grmip = HWR_GetCachedGLPatch(fademasklumpnum)->mipmap; + patch_t *patch = HWR_GetCachedGLPatch(fademasklumpnum); + GLMipmap_t *grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap; if (!grmip->downloaded && !grmip->data) HWR_CacheFadeMask(grmip, fademasklumpnum); diff --git a/src/hardware/hw_data.h b/src/hardware/hw_data.h index e5477d7292b3701a4bb8966c19715c0cd508d881..3ae4ef8bc2145430846a728523e5d85dc577dd8e 100644 --- a/src/hardware/hw_data.h +++ b/src/hardware/hw_data.h @@ -43,20 +43,19 @@ typedef enum GLTextureFormat_e // NULL if the texture is not in Doom heap cache. struct GLMipmap_s { - //for TexDownloadMipMap - GLTextureFormat_t format; - void *data; + // for TexDownloadMipMap + GLTextureFormat_t format; + void *data; - UINT32 flags; - UINT16 height; - UINT16 width; - UINT32 downloaded; // the dll driver have it in there cache ? + UINT32 flags; + UINT16 height; + UINT16 width; + UINT32 downloaded; // The GPU has this texture. struct GLMipmap_s *nextcolormap; const UINT8 *colormap; - // opengl - struct GLMipmap_s *nextmipmap; // opengl : liste of all texture in opengl driver + struct GLMipmap_s *nextmipmap; // Linked list of all textures }; typedef struct GLMipmap_s GLMipmap_t; @@ -73,23 +72,10 @@ struct GLMapTexture_s typedef struct GLMapTexture_s GLMapTexture_t; -// a cached patch as converted to hardware format, holding the original patch_t -// header so that the existing code can retrieve ->width, ->height as usual -// This is returned by W_CachePatchNum()/W_CachePatchName(), when rendermode -// is 'render_opengl'. Else it returns the normal patch_t data. - +// a cached patch as converted to hardware format struct GLPatch_s { - // the 4 first fields come right away from the original patch_t - INT16 width; - INT16 height; - INT16 leftoffset; // pixels to the left of origin - INT16 topoffset; // pixels below the origin - // float max_s,max_t; - UINT16 wadnum; // the software patch lump num for when the hardware patch - UINT16 lumpnum; // was flushed, and we need to re-create it - void *rawpatch; // :^) GLMipmap_t *mipmap; } ATTRPACK; typedef struct GLPatch_s GLPatch_t; diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 644ab0ca2c3ff31db3615f12b2fd5871ea431662..a782762a38c46dbb4161468b43b3041d215e8d2e 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -212,35 +212,32 @@ typedef struct // You pass a combination of these flags to DrawPolygon() enum EPolyFlags { - // the first 5 are mutually exclusive - - PF_Masked = 0x00000001, // Poly is alpha scaled and 0 alpha pels are discarded (holes in texture) + // Mutually exclusive blend flags + PF_Masked = 0x00000001, // Poly is alpha scaled and 0 alpha pixels are discarded (holes in texture) PF_Translucent = 0x00000002, // Poly is transparent, alpha = level of transparency - PF_Additive = 0x00000004, // Poly is added to the frame buffer - PF_Environment = 0x00000008, // Poly should be drawn environment mapped. - // Hurdler: used for text drawing - PF_Substractive = 0x00000010, // for splat - PF_NoAlphaTest = 0x00000020, // hiden param - PF_Fog = 0x00000040, // Fog blocks - PF_Blending = (PF_Environment|PF_Additive|PF_Translucent|PF_Masked|PF_Substractive|PF_Fog)&~PF_NoAlphaTest, - - // other flag bits - - PF_Occlude = 0x00000100, // Update the depth buffer - PF_NoDepthTest = 0x00000200, // Disable the depth test mode - PF_Invisible = 0x00000400, // Disable write to color buffer - PF_Decal = 0x00000800, // Enable polygon offset + PF_Environment = 0x00000004, // Poly should be drawn environment mapped. (Hurdler: used for text drawing) + PF_Additive = 0x00000008, // Additive color blending + PF_AdditiveSource = 0x00000010, // Source blending factor is additive. This is the opposite of regular additive blending. + PF_Subtractive = 0x00000020, // Subtractive color blending + PF_ReverseSubtract = 0x00000040, // Reverse subtract, used in wall splats (decals) + PF_Multiplicative = 0x00000080, // Multiplicative color blending + PF_Fog = 0x20000000, // Fog blocks + PF_NoAlphaTest = 0x40000000, // Disables alpha testing + PF_Blending = (PF_Masked|PF_Translucent|PF_Environment|PF_Additive|PF_AdditiveSource|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Fog) & ~PF_NoAlphaTest, + + // other flag bits + PF_Occlude = 0x00000100, // Updates the depth buffer + PF_NoDepthTest = 0x00000200, // Disables the depth test mode + PF_Invisible = 0x00000400, // Disables write to color buffer + PF_Decal = 0x00000800, // Enables polygon offset PF_Modulated = 0x00001000, // Modulation (multiply output with constant ARGB) // When set, pass the color constant into the FSurfaceInfo -> PolyColor - PF_NoTexture = 0x00002000, // Use the small white texture - PF_Corona = 0x00004000, // Tell the rendrer we are drawing a corona - PF_Ripple = 0x00008000, // Water shader effect - PF_RemoveYWrap = 0x00010000, // Force clamp texture on Y - PF_ForceWrapX = 0x00020000, // Force repeat texture on X - PF_ForceWrapY = 0x00040000, // Force repeat texture on Y - PF_Clip = 0x40000000, // clip to frustum and nearz plane (glide only, automatic in opengl) - PF_NoZClip = 0x20000000, // in conjonction with PF_Clip - PF_Debug = 0x80000000 // print debug message in driver :) + PF_NoTexture = 0x00002000, // Disables texturing + PF_Corona = 0x00004000, // Tells the renderer we are drawing a corona + PF_Ripple = 0x00008000, // Water effect shader + PF_RemoveYWrap = 0x00010000, // Forces clamp texture on Y + PF_ForceWrapX = 0x00020000, // Forces repeat texture on X + PF_ForceWrapY = 0x00040000 // Forces repeat texture on Y }; diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index f5a984d5d3a23ed3bd80d4d7e690bcba8d42422c..b9cb288e910b1263dfa46e48b792c811de9d9beb 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -68,10 +68,11 @@ static UINT8 softwaretranstogl_lo[11] = { 0, 12, 24, 36, 48, 60, 71, 83, 95,111 // Notes : x,y : positions relative to the original Doom resolution // : textes(console+score) + menus + status bar // -----------------+ -void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) +void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option) { FOutVector v[4]; FBITFIELD flags; + GLPatch_t *hwrPatch; // 3--2 // | /| @@ -84,6 +85,7 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) // make patch ready in hardware cache HWR_GetPatch(gpatch); + hwrPatch = ((GLPatch_t *)gpatch->hardware); switch (option & V_SCALEPATCHMASK) { @@ -103,17 +105,17 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) if (option & V_NOSCALESTART) sdupx = sdupy = 2.0f; - v[0].x = v[3].x = (x*sdupx-SHORT(gpatch->leftoffset)*pdupx)/vid.width - 1; - v[2].x = v[1].x = (x*sdupx+(SHORT(gpatch->width)-SHORT(gpatch->leftoffset))*pdupx)/vid.width - 1; - v[0].y = v[1].y = 1-(y*sdupy-SHORT(gpatch->topoffset)*pdupy)/vid.height; - v[2].y = v[3].y = 1-(y*sdupy+(SHORT(gpatch->height)-SHORT(gpatch->topoffset))*pdupy)/vid.height; + v[0].x = v[3].x = (x*sdupx-(gpatch->leftoffset)*pdupx)/vid.width - 1; + v[2].x = v[1].x = (x*sdupx+(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1; + v[0].y = v[1].y = 1-(y*sdupy-(gpatch->topoffset)*pdupy)/vid.height; + v[2].y = v[3].y = 1-(y*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; v[0].s = v[3].s = 0.0f; - v[2].s = v[1].s = gpatch->max_s; + v[2].s = v[1].s = hwrPatch->max_s; v[0].t = v[1].t = 0.0f; - v[2].t = v[3].t = gpatch->max_t; + v[2].t = v[3].t = hwrPatch->max_t; flags = PF_Translucent|PF_NoDepthTest; @@ -126,13 +128,14 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) HWD.pfnDrawPolygon(NULL, v, 4, flags); } -void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap) +void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap) { FOutVector v[4]; FBITFIELD flags; float cx = FIXED_TO_FLOAT(x); float cy = FIXED_TO_FLOAT(y); UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT); + GLPatch_t *hwrPatch; // 3--2 // | /| @@ -151,6 +154,8 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t else HWR_GetMappedPatch(gpatch, colormap); + hwrPatch = ((GLPatch_t *)gpatch->hardware); + dupx = (float)vid.dupx; dupy = (float)vid.dupy; @@ -181,13 +186,13 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t // left offset if (option & V_FLIP) - offsetx = (float)(SHORT(gpatch->width) - SHORT(gpatch->leftoffset)) * fscalew; + offsetx = (float)(gpatch->width - gpatch->leftoffset) * fscalew; else - offsetx = (float)SHORT(gpatch->leftoffset) * fscalew; + offsetx = (float)(gpatch->leftoffset) * fscalew; // top offset // TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!? - offsety = (float)SHORT(gpatch->topoffset) * fscaleh; + offsety = (float)(gpatch->topoffset) * fscaleh; if ((option & (V_NOSCALESTART|V_OFFSET)) == (V_NOSCALESTART|V_OFFSET)) // Multiply by dupx/dupy for crosshairs { @@ -277,17 +282,14 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT) // cx and cy are possibly *slightly* off from float maths // This is done before here compared to software because we directly alter cx and cy to centre - if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) + if (cx >= -0.1f && cx <= 0.1f && gpatch->width == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && gpatch->height == BASEVIDHEIGHT) { - // Need to temporarily cache the real patch to get the colour of the top left pixel - patch_t *realpatch = W_CacheSoftwarePatchNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); - const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); + const column_t *column = (const column_t *)((const UINT8 *)(gpatch->columns) + (gpatch->columnofs[0])); if (!column->topdelta) { const UINT8 *source = (const UINT8 *)(column) + 3; HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); } - Z_Free(realpatch); } // centre screen if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) @@ -317,13 +319,13 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t if (pscale != FRACUNIT || (splitscreen && option & V_PERPLAYER)) { - fwidth = (float)SHORT(gpatch->width) * fscalew * dupx; - fheight = (float)SHORT(gpatch->height) * fscaleh * dupy; + fwidth = (float)(gpatch->width) * fscalew * dupx; + fheight = (float)(gpatch->height) * fscaleh * dupy; } else { - fwidth = (float)SHORT(gpatch->width) * dupx; - fheight = (float)SHORT(gpatch->height) * dupy; + fwidth = (float)(gpatch->width) * dupx; + fheight = (float)(gpatch->height) * dupy; } // positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1 @@ -345,17 +347,17 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t if (option & V_FLIP) { - v[0].s = v[3].s = gpatch->max_s; + v[0].s = v[3].s = hwrPatch->max_s; v[2].s = v[1].s = 0.0f; } else { v[0].s = v[3].s = 0.0f; - v[2].s = v[1].s = gpatch->max_s; + v[2].s = v[1].s = hwrPatch->max_s; } v[0].t = v[1].t = 0.0f; - v[2].t = v[3].t = gpatch->max_t; + v[2].t = v[3].t = hwrPatch->max_t; flags = PF_Translucent|PF_NoDepthTest; @@ -380,13 +382,14 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t HWD.pfnDrawPolygon(NULL, v, 4, flags); } -void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) +void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) { FOutVector v[4]; FBITFIELD flags; float cx = FIXED_TO_FLOAT(x); float cy = FIXED_TO_FLOAT(y); UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT); + GLPatch_t *hwrPatch; // 3--2 // | /| @@ -399,6 +402,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal // make patch ready in hardware cache HWR_GetPatch(gpatch); + hwrPatch = ((GLPatch_t *)gpatch->hardware); dupx = (float)vid.dupx; dupy = (float)vid.dupy; @@ -423,8 +427,8 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal // fuck it, no GL support for croppedpatch v_perplayer right now. it's not like it's accessible to Lua or anything, and we only use it for menus... - cy -= (float)SHORT(gpatch->topoffset) * fscale; - cx -= (float)SHORT(gpatch->leftoffset) * fscale; + cy -= (float)(gpatch->topoffset) * fscale; + cx -= (float)(gpatch->leftoffset) * fscale; if (!(option & V_NOSCALESTART)) { @@ -436,17 +440,14 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT) // cx and cy are possibly *slightly* off from float maths // This is done before here compared to software because we directly alter cx and cy to centre - if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) + if (cx >= -0.1f && cx <= 0.1f && gpatch->width == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && gpatch->height == BASEVIDHEIGHT) { - // Need to temporarily cache the real patch to get the colour of the top left pixel - patch_t *realpatch = W_CacheSoftwarePatchNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); - const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); + const column_t *column = (const column_t *)((const UINT8 *)(gpatch->columns) + (gpatch->columnofs[0])); if (!column->topdelta) { const UINT8 *source = (const UINT8 *)(column) + 3; HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); } - Z_Free(realpatch); } // centre screen if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) @@ -469,11 +470,11 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal fwidth = w; fheight = h; - if (fwidth > SHORT(gpatch->width)) - fwidth = SHORT(gpatch->width); + if (fwidth > gpatch->width) + fwidth = gpatch->width; - if (fheight > SHORT(gpatch->height)) - fheight = SHORT(gpatch->height); + if (fheight > gpatch->height) + fheight = gpatch->height; if (pscale != FRACUNIT) { @@ -503,17 +504,17 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].s = v[3].s = ((sx )/(float)SHORT(gpatch->width) )*gpatch->max_s; - if (sx + w > SHORT(gpatch->width)) - v[2].s = v[1].s = gpatch->max_s; + v[0].s = v[3].s = ((sx)/(float)(gpatch->width))*hwrPatch->max_s; + if (sx + w > gpatch->width) + v[2].s = v[1].s = hwrPatch->max_s; else - v[2].s = v[1].s = ((sx+w)/(float)SHORT(gpatch->width) )*gpatch->max_s; + v[2].s = v[1].s = ((sx+w)/(float)(gpatch->width))*hwrPatch->max_s; - v[0].t = v[1].t = ((sy )/(float)SHORT(gpatch->height))*gpatch->max_t; - if (sy + h > SHORT(gpatch->height)) - v[2].t = v[3].t = gpatch->max_t; + v[0].t = v[1].t = ((sy)/(float)(gpatch->height))*hwrPatch->max_t; + if (sy + h > gpatch->height) + v[2].t = v[3].t = hwrPatch->max_t; else - v[2].t = v[3].t = ((sy+h)/(float)SHORT(gpatch->height))*gpatch->max_t; + v[2].t = v[3].t = ((sy+h)/(float)(gpatch->height))*hwrPatch->max_t; flags = PF_Translucent|PF_NoDepthTest; @@ -541,7 +542,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum) { FOutVector v[4]; - const GLPatch_t *patch; + const patch_t *patch; // make pic ready in hardware cache patch = HWR_GetPic(lumpnum); @@ -558,10 +559,10 @@ void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum) v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].s = v[3].s = 0; - v[2].s = v[1].s = patch->max_s; - v[0].t = v[1].t = 0; - v[2].t = v[3].t = patch->max_t; + v[0].s = v[3].s = 0; + v[2].s = v[1].s = ((GLPatch_t *)patch->hardware)->max_s; + v[0].t = v[1].t = 0; + v[2].t = v[3].t = ((GLPatch_t *)patch->hardware)->max_t; //Hurdler: Boris, the same comment as above... but maybe for pics @@ -570,7 +571,7 @@ void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum) // But then, the question is: why not 0 instead of PF_Masked ? // or maybe PF_Environment ??? (like what I said above) // BP: PF_Environment don't change anything ! and 0 is undifined - HWD.pfnDrawPolygon(NULL, v, 4, PF_Translucent | PF_NoDepthTest | PF_Clip | PF_NoZClip); + HWD.pfnDrawPolygon(NULL, v, 4, PF_Translucent | PF_NoDepthTest); } // ========================================================================== @@ -934,7 +935,7 @@ void HWR_DrawViewBorder(INT32 clearlines) INT32 top, side; INT32 baseviewwidth, baseviewheight; INT32 basewindowx, basewindowy; - GLPatch_t *patch; + patch_t *patch; // if (gl_viewwidth == vid.width) // return; diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 2661341057442fa62c590981e4b43c7333b3ed5a..5a2e0e44eaeb13ffc0465403fdd606e2f556fe2e 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -42,9 +42,11 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags); EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor); EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *TexInfo); +EXPORT void HWRAPI(DeleteTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); +EXPORT void HWRAPI(ClearCacheList) (void); //Hurdler: added for backward compatibility EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); @@ -95,9 +97,11 @@ struct hwdriver_s ClearBuffer pfnClearBuffer; SetTexture pfnSetTexture; UpdateTexture pfnUpdateTexture; + DeleteTexture pfnDeleteTexture; ReadRect pfnReadRect; GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; + ClearCacheList pfnClearCacheList; SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility DrawModel pfnDrawModel; CreateModelVBOs pfnCreateModelVBOs; diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 6ede8448bf88cc6ee2b9a7083546e2b2e059e904..87405d3d457080e1fccd86206ac2d0dfb9b97db4 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -62,19 +62,32 @@ typedef struct typedef struct gl_vissprite_s { float x1, x2; - float tz, ty; + float z1, z2; + float gz, gzt; + + float tz; float tracertz; // for MF2_LINKDRAW sprites, this contains tracer's tz for use in sorting - //lumpnum_t patchlumpnum; - GLPatch_t *gpatch; - boolean flip; - UINT8 translucency; //alpha level 0-255 - mobj_t *mobj; // NOTE: This is a precipmobj_t if precip is true !!! Watch out. + + float scale; + float shadowheight, shadowscale; + + float spritexscale, spriteyscale; + float spritexoffset, spriteyoffset; + + UINT32 renderflags; + UINT8 rotateflags; + + boolean flip, vflip; boolean precip; // Tails 08-25-2002 - boolean vflip; - //Hurdler: 25/04/2000: now support colormap in hardware mode + boolean rotated; + UINT8 translucency; //alpha level 0-255 + + //Hurdler: 25/04/2000: now support colormap in hardware mode UINT8 *colormap; INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing - float z1, z2; + + patch_t *gpatch; + mobj_t *mobj; // NOTE: This is a precipmobj_t if precip is true !!! Watch out. } gl_vissprite_t; // -------- @@ -86,25 +99,36 @@ extern size_t addsubsector; void HWR_InitPolyPool(void); void HWR_FreePolyPool(void); +void HWR_FreeExtraSubsectors(void); + // -------- // hw_cache.c // -------- -void HWR_InitTextureCache(void); -void HWR_FreeTextureCache(void); -void HWR_FreeMipmapCache(void); -void HWR_FreeExtraSubsectors(void); +void HWR_InitMapTextures(void); +void HWR_LoadMapTextures(size_t pnumtextures); +void HWR_FreeMapTextures(void); + +patch_t *HWR_GetCachedGLPatchPwad(UINT16 wad, UINT16 lump); +patch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum); + +void HWR_GetPatch(patch_t *patch); +void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap); +void HWR_GetFadeMask(lumpnum_t fademasklumpnum); +patch_t *HWR_GetPic(lumpnum_t lumpnum); +GLMapTexture_t *HWR_GetTexture(INT32 tex); void HWR_GetLevelFlat(levelflat_t *levelflat); void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum); -GLMapTexture_t *HWR_GetTexture(INT32 tex); -void HWR_GetPatch(GLPatch_t *gpatch); -void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap); + +void HWR_FreeTexture(patch_t *patch); +void HWR_FreeTextureData(patch_t *patch); +void HWR_FreeTextureColormaps(patch_t *patch); +void HWR_ClearAllTextures(void); +void HWR_FreeColormapCache(void); void HWR_UnlockCachedPatch(GLPatch_t *gpatch); -GLPatch_t *HWR_GetPic(lumpnum_t lumpnum); + void HWR_SetPalette(RGBA_t *palette); -GLPatch_t *HWR_GetCachedGLPatchPwad(UINT16 wad, UINT16 lump); -GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum); -void HWR_GetFadeMask(lumpnum_t fademasklumpnum); + // -------- // hw_draw.c diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 32c2d550d4355b02b039bb2a8ee708b9afd17c51..987d70c69e22b293bb8d07cce5ce10520b5d387e 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -35,8 +35,7 @@ #define DL_HIGH_QUALITY //#define STATICLIGHT //Hurdler: TODO! -//#define LIGHTMAPFLAGS (PF_Masked|PF_Clip|PF_NoAlphaTest) // debug see overdraw -#define LIGHTMAPFLAGS (PF_Modulated|PF_Additive|PF_Clip) +#define LIGHTMAPFLAGS (PF_Modulated|PF_AdditiveSource) #ifdef ALAM_LIGHTING static dynlights_t view_dynlights[2]; // 2 players in splitscreen mode @@ -1056,7 +1055,7 @@ void HWR_DoCoronasLighting(FOutVector *outVerts, gl_vissprite_t *spr) HWR_GetPic(coronalumpnum); /// \todo use different coronas - HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_Clip | PF_Corona | PF_NoDepthTest); + HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_AdditiveSource | PF_Corona | PF_NoDepthTest); } } #endif @@ -1144,7 +1143,7 @@ void HWR_DrawCoronas(void) light[3].y = cy+size*1.33f; light[3].s = 0.0f; light[3].t = 1.0f; - HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_Clip | PF_NoDepthTest | PF_Corona); + HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_AdditiveSource | PF_NoDepthTest | PF_Corona); } } #endif diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index d694be8237efb8b0384e673bb22e1077a45774b2..5dd2727bcc71207ad006943ab7b22e96f5606585 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -25,6 +25,7 @@ #include "../p_local.h" #include "../p_setup.h" #include "../r_local.h" +#include "../r_patch.h" #include "../r_picformats.h" #include "../r_bsp.h" #include "../d_clisrv.h" @@ -163,9 +164,11 @@ int ps_hw_numcolors = 0; int ps_hw_batchsorttime = 0; int ps_hw_batchdrawtime = 0; +boolean gl_init = false; +boolean gl_maploaded = false; +boolean gl_sessioncommandsadded = false; boolean gl_shadersavailable = true; - // ========================================================================== // Lighting // ========================================================================== @@ -693,101 +696,73 @@ static void HWR_RenderSkyPlane(extrasubsector_t *xsub, fixed_t fixedheight) v3d->z = pv->y; } - HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts, - PF_Clip|PF_Invisible|PF_NoTexture|PF_Occlude); + HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts, PF_Invisible|PF_NoTexture|PF_Occlude); } #endif //polysky #endif //doplanes -/* - wallVerts order is : - 3--2 - | /| - |/ | - 0--1 -*/ -#ifdef WALLSPLATS -static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) +FBITFIELD HWR_GetBlendModeFlag(INT32 ast) { - FOutVector wallVerts[4]; - wallsplat_t *splat; - GLPatch_t *gpatch; - fixed_t i; - // seg bbox - fixed_t segbbox[4]; - - M_ClearBox(segbbox); - M_AddToBox(segbbox, - FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv1)->x), - FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv1)->y)); - M_AddToBox(segbbox, - FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv2)->x), - FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv2)->y)); - - splat = (wallsplat_t *)gl_curline->linedef->splats; - for (; splat; splat = splat->next) - { - //BP: don't draw splat extern to this seg - // this is quick fix best is explain in logboris.txt at 12-4-2000 - 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_PATCH); - HWR_GetPatch(gpatch); - - wallVerts[0].x = wallVerts[3].x = FIXED_TO_FLOAT(splat->v1.x); - wallVerts[0].z = wallVerts[3].z = FIXED_TO_FLOAT(splat->v1.y); - wallVerts[2].x = wallVerts[1].x = FIXED_TO_FLOAT(splat->v2.x); - wallVerts[2].z = wallVerts[1].z = FIXED_TO_FLOAT(splat->v2.y); + switch (ast) + { + case AST_ADD: + return PF_Additive; + case AST_SUBTRACT: + return PF_Subtractive; + case AST_REVERSESUBTRACT: + return PF_ReverseSubtract; + case AST_MODULATE: + return PF_Multiplicative; + default: + return PF_Translucent; + } - i = splat->top; - if (splat->yoffset) - i += *splat->yoffset; + return 0; +} - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(i)+(gpatch->height>>1); - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(i)-(gpatch->height>>1); +UINT8 HWR_GetTranstableAlpha(INT32 transtablenum) +{ + transtablenum = max(min(transtablenum, tr_trans90), 0); - wallVerts[3].s = wallVerts[3].t = wallVerts[2].s = wallVerts[0].t = 0.0f; - wallVerts[1].s = wallVerts[1].t = wallVerts[2].t = wallVerts[0].s = 1.0f; + switch (transtablenum) + { + case 0 : return 0xff; + case tr_trans10 : return 0xe6; + case tr_trans20 : return 0xcc; + case tr_trans30 : return 0xb3; + case tr_trans40 : return 0x99; + case tr_trans50 : return 0x80; + case tr_trans60 : return 0x66; + case tr_trans70 : return 0x4c; + case tr_trans80 : return 0x33; + case tr_trans90 : return 0x19; + } - switch (splat->flags & SPLATDRAWMODE_MASK) - { - case SPLATDRAWMODE_OPAQUE : - pSurf.PolyColor.s.alpha = 0xff; - i = PF_Translucent; - break; - case SPLATDRAWMODE_TRANS : - pSurf.PolyColor.s.alpha = 128; - i = PF_Translucent; - break; - case SPLATDRAWMODE_SHADE : - pSurf.PolyColor.s.alpha = 0xff; - i = PF_Substractive; - break; - } + return 0xff; +} - HWD.pfnSetShader(SHADER_WALL); // wall shader - HWD.pfnDrawPolygon(&pSurf, wallVerts, 4, i|PF_Modulated|PF_Decal); +FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf) +{ + if (!transtablenum) + { + pSurf->PolyColor.s.alpha = 0xff; + return PF_Masked; } + + pSurf->PolyColor.s.alpha = HWR_GetTranstableAlpha(transtablenum); + return HWR_GetBlendModeFlag(style); } -#endif FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf) { - switch (transtablenum) + if (!transtablenum) { - case 0 : pSurf->PolyColor.s.alpha = 0x00;return PF_Masked; - case tr_trans10 : pSurf->PolyColor.s.alpha = 0xe6;return PF_Translucent; - case tr_trans20 : pSurf->PolyColor.s.alpha = 0xcc;return PF_Translucent; - case tr_trans30 : pSurf->PolyColor.s.alpha = 0xb3;return PF_Translucent; - case tr_trans40 : pSurf->PolyColor.s.alpha = 0x99;return PF_Translucent; - case tr_trans50 : pSurf->PolyColor.s.alpha = 0x80;return PF_Translucent; - case tr_trans60 : pSurf->PolyColor.s.alpha = 0x66;return PF_Translucent; - case tr_trans70 : pSurf->PolyColor.s.alpha = 0x4c;return PF_Translucent; - case tr_trans80 : pSurf->PolyColor.s.alpha = 0x33;return PF_Translucent; - case tr_trans90 : pSurf->PolyColor.s.alpha = 0x19;return PF_Translucent; + pSurf->PolyColor.s.alpha = 0x00; + return PF_Masked; } + + pSurf->PolyColor.s.alpha = HWR_GetTranstableAlpha(transtablenum); return PF_Translucent; } @@ -797,19 +772,21 @@ static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, I // Wall generation from subsector segs // ========================================================================== +/* + wallVerts order is : + 3--2 + | /| + |/ | + 0--1 +*/ + // // HWR_ProjectWall // static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap) { HWR_Lighting(pSurf, lightlevel, wallcolormap); - HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, SHADER_WALL, false); // wall shader - -#ifdef WALLSPLATS - if (gl_curline->linedef->splats && cv_splats.value) - HWR_DrawSegsSplats(pSurf); -#endif } // ========================================================================== @@ -1168,7 +1145,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom texturevpegtop += gl_sidedef->rowoffset; // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway - texturevpegtop %= SHORT(textures[gl_toptexture]->height)<<FRACBITS; + texturevpegtop %= (textures[gl_toptexture]->height)<<FRACBITS; wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gl_frontsector->ceilingheight - gl_backsector->ceilingheight) * grTex->scaleY; @@ -1234,7 +1211,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom texturevpegbottom += gl_sidedef->rowoffset; // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway - texturevpegbottom %= SHORT(textures[gl_bottomtexture]->height)<<FRACBITS; + texturevpegbottom %= (textures[gl_bottomtexture]->height)<<FRACBITS; wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gl_backsector->floorheight - gl_frontsector->floorheight) * grTex->scaleY; @@ -2863,10 +2840,10 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, if (blendmode & PF_Translucent) { Surf.PolyColor.s.alpha = (UINT8)alpha; - blendmode |= PF_Modulated|PF_Occlude|PF_Clip; + blendmode |= PF_Modulated|PF_Occlude; } else - blendmode |= PF_Masked|PF_Modulated|PF_Clip; + blendmode |= PF_Masked|PF_Modulated; HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, SHADER_FLOOR, false); // floor shader } @@ -3536,7 +3513,7 @@ static void HWR_LinkDrawHackFinish(void) { // draw sprite shape, only to z-buffer HWR_GetPatch(linkdrawlist[i].spr->gpatch); - HWR_ProcessPolygon(&surf, linkdrawlist[i].verts, 4, PF_Translucent|PF_Occlude|PF_Invisible|PF_Clip, 0, false); + HWR_ProcessPolygon(&surf, linkdrawlist[i].verts, 4, PF_Translucent|PF_Occlude|PF_Invisible, 0, false); } // reset list linkdrawcount = 0; @@ -3584,7 +3561,7 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) { - GLPatch_t *gpatch; + patch_t *gpatch; FOutVector shadowVerts[4]; FSurfaceInfo sSurf; float fscale; float fx; float fy; float offset; @@ -3610,12 +3587,12 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) if (alpha >= 255) return; alpha = 255 - alpha; - gpatch = (GLPatch_t *)W_CachePatchName("DSHADOW", PU_CACHE); - if (!(gpatch && gpatch->mipmap->format)) return; + gpatch = (patch_t *)W_CachePatchName("DSHADOW", PU_SPRITE); + if (!(gpatch && ((GLPatch_t *)gpatch->hardware)->mipmap->format)) return; HWR_GetPatch(gpatch); scalemul = FixedMul(FRACUNIT - floordiff/640, scale); - scalemul = FixedMul(scalemul, (thing->radius*2) / SHORT(gpatch->height)); + scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height); fscale = FIXED_TO_FLOAT(scalemul); fx = FIXED_TO_FLOAT(thing->x); @@ -3627,9 +3604,9 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) // 0--1 if (thing && fabsf(fscale - 1.0f) > 1.0E-36f) - offset = (SHORT(gpatch->height)/2) * fscale; + offset = ((gpatch->height)/2) * fscale; else - offset = (float)(SHORT(gpatch->height)/2); + offset = (float)((gpatch->height)/2); shadowVerts[2].x = shadowVerts[3].x = fx + offset; shadowVerts[1].x = shadowVerts[0].x = fx - offset; @@ -3659,28 +3636,29 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) } shadowVerts[0].s = shadowVerts[3].s = 0; - shadowVerts[2].s = shadowVerts[1].s = gpatch->max_s; + shadowVerts[2].s = shadowVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s; shadowVerts[3].t = shadowVerts[2].t = 0; - shadowVerts[0].t = shadowVerts[1].t = gpatch->max_t; + shadowVerts[0].t = shadowVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t; - if (thing->subsector->sector->numlights) + if (!(thing->renderflags & RF_NOCOLORMAPS)) { - light = R_GetPlaneLight(thing->subsector->sector, groundz, false); // Always use the light at the top instead of whatever I was doing before + if (thing->subsector->sector->numlights) + { + // Always use the light at the top instead of whatever I was doing before + light = R_GetPlaneLight(thing->subsector->sector, groundz, false); - if (*thing->subsector->sector->lightlist[light].extra_colormap) - colormap = *thing->subsector->sector->lightlist[light].extra_colormap; - } - else - { - if (thing->subsector->sector->extra_colormap) + if (*thing->subsector->sector->lightlist[light].extra_colormap) + colormap = *thing->subsector->sector->lightlist[light].extra_colormap; + } + else if (thing->subsector->sector->extra_colormap) colormap = thing->subsector->sector->extra_colormap; } HWR_Lighting(&sSurf, 0, colormap); sSurf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated, SHADER_SPRITE, false); // sprite shader } // This is expecting a pointer to an array containing 4 wallVerts for a sprite @@ -3700,17 +3678,17 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts // X, Y, AND Z need to be manipulated for the polys to rotate around the // origin, because of how the origin setting works I believe that should // be mobj->z or mobj->z + mobj->height - wallVerts[2].y = wallVerts[3].y = (spr->ty - basey) * gl_viewludsin + basey; + wallVerts[2].y = wallVerts[3].y = (spr->gzt - basey) * gl_viewludsin + basey; wallVerts[0].y = wallVerts[1].y = (lowy - basey) * gl_viewludsin + basey; // translate back to be around 0 before translating back - wallVerts[3].x += ((spr->ty - basey) * gl_viewludcos) * gl_viewcos; - wallVerts[2].x += ((spr->ty - basey) * gl_viewludcos) * gl_viewcos; + wallVerts[3].x += ((spr->gzt - basey) * gl_viewludcos) * gl_viewcos; + wallVerts[2].x += ((spr->gzt - basey) * gl_viewludcos) * gl_viewcos; wallVerts[0].x += ((lowy - basey) * gl_viewludcos) * gl_viewcos; wallVerts[1].x += ((lowy - basey) * gl_viewludcos) * gl_viewcos; - wallVerts[3].z += ((spr->ty - basey) * gl_viewludcos) * gl_viewsin; - wallVerts[2].z += ((spr->ty - basey) * gl_viewludcos) * gl_viewsin; + wallVerts[3].z += ((spr->gzt - basey) * gl_viewludcos) * gl_viewsin; + wallVerts[2].z += ((spr->gzt - basey) * gl_viewludcos) * gl_viewsin; wallVerts[0].z += ((lowy - basey) * gl_viewludcos) * gl_viewsin; wallVerts[1].z += ((lowy - basey) * gl_viewludcos) * gl_viewsin; @@ -3719,17 +3697,17 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts static void HWR_SplitSprite(gl_vissprite_t *spr) { - float this_scale = 1.0f; FOutVector wallVerts[4]; FOutVector baseWallVerts[4]; // This is what the verts should end up as - GLPatch_t *gpatch; + patch_t *gpatch; FSurfaceInfo Surf; - const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); - extracolormap_t *colormap; + extracolormap_t *colormap = NULL; FUINT lightlevel; + boolean lightset = true; FBITFIELD blend = 0; FBITFIELD occlusion; boolean use_linkdraw_hack = false; + boolean splat = R_ThingIsFloorSprite(spr->mobj); UINT8 alpha; INT32 i; @@ -3745,12 +3723,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) fixed_t temp; fixed_t v1x, v1y, v2x, v2y; - this_scale = FIXED_TO_FLOAT(spr->mobj->scale); - - if (hires) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale); - - gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); + gpatch = spr->gpatch; // cache the patch in the graphics card memory //12/12/99: Hurdler: same comment as above (for md2) @@ -3762,11 +3735,8 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) baseWallVerts[0].z = baseWallVerts[3].z = spr->z1; baseWallVerts[1].z = baseWallVerts[2].z = spr->z2; - baseWallVerts[2].y = baseWallVerts[3].y = spr->ty; - if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f) - baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height * this_scale; - else - baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height; + baseWallVerts[2].y = baseWallVerts[3].y = spr->gzt; + baseWallVerts[0].y = baseWallVerts[1].y = spr->gz; v1x = FLOAT_TO_FIXED(spr->x1); v1y = FLOAT_TO_FIXED(spr->z1); @@ -3775,39 +3745,42 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) if (spr->flip) { - baseWallVerts[0].s = baseWallVerts[3].s = gpatch->max_s; + baseWallVerts[0].s = baseWallVerts[3].s = ((GLPatch_t *)gpatch->hardware)->max_s; baseWallVerts[2].s = baseWallVerts[1].s = 0; } else { baseWallVerts[0].s = baseWallVerts[3].s = 0; - baseWallVerts[2].s = baseWallVerts[1].s = gpatch->max_s; + baseWallVerts[2].s = baseWallVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s; } // flip the texture coords (look familiar?) if (spr->vflip) { - baseWallVerts[3].t = baseWallVerts[2].t = gpatch->max_t; + baseWallVerts[3].t = baseWallVerts[2].t = ((GLPatch_t *)gpatch->hardware)->max_t; baseWallVerts[0].t = baseWallVerts[1].t = 0; } else { baseWallVerts[3].t = baseWallVerts[2].t = 0; - baseWallVerts[0].t = baseWallVerts[1].t = gpatch->max_t; + baseWallVerts[0].t = baseWallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t; } - // if it has a dispoffset, push it a little towards the camera - if (spr->dispoffset) { - float co = -gl_viewcos*(0.05f*spr->dispoffset); - float si = -gl_viewsin*(0.05f*spr->dispoffset); - baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si; - baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si; - baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co; - baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co; - } + if (!splat) + { + // if it has a dispoffset, push it a little towards the camera + if (spr->dispoffset) { + float co = -gl_viewcos*(0.05f*spr->dispoffset); + float si = -gl_viewsin*(0.05f*spr->dispoffset); + baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si; + baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si; + baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co; + baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co; + } - // Let dispoffset work first since this adjust each vertex - HWR_RotateSpritePolyToAim(spr, baseWallVerts, false); + // Let dispoffset work first since this adjust each vertex + HWR_RotateSpritePolyToAim(spr, baseWallVerts, false); + } realtop = top = baseWallVerts[3].y; realbot = bot = baseWallVerts[0].y; @@ -3839,10 +3812,15 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) else if (spr->mobj->flags2 & MF2_SHADOW) { Surf.PolyColor.s.alpha = 0x40; - blend = PF_Translucent; + blend = HWR_GetBlendModeFlag(spr->mobj->blendmode); } else if (spr->mobj->frame & FF_TRANSMASK) - blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + { + INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; + if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) + return; + blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf); + } else { // BP: i agree that is little better in environement but it don't @@ -3850,7 +3828,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|occlusion; + blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|occlusion; if (!occlusion) use_linkdraw_hack = true; } @@ -3858,21 +3836,28 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // Start with the lightlevel and colormap from the top of the sprite lightlevel = *list[sector->numlights - 1].lightlevel; - colormap = *list[sector->numlights - 1].extra_colormap; + if (!(spr->mobj->renderflags & RF_NOCOLORMAPS)) + colormap = *list[sector->numlights - 1].extra_colormap; + i = 0; temp = FLOAT_TO_FIXED(realtop); - if (spr->mobj->frame & FF_FULLBRIGHT) + if (R_ThingIsFullBright(spr->mobj)) lightlevel = 255; + else if (R_ThingIsFullDark(spr->mobj)) + lightlevel = 0; + else + lightset = false; for (i = 1; i < sector->numlights; i++) { fixed_t h = P_GetLightZAt(§or->lightlist[i], spr->mobj->x, spr->mobj->y); if (h <= temp) { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (!lightset) lightlevel = *list[i-1].lightlevel > 255 ? 255 : *list[i-1].lightlevel; - colormap = *list[i-1].extra_colormap; + if (!(spr->mobj->renderflags & RF_NOCOLORMAPS)) + colormap = *list[i-1].extra_colormap; break; } } @@ -3885,9 +3870,10 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES)) { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (!lightset) lightlevel = *list[i].lightlevel > 255 ? 255 : *list[i].lightlevel; - colormap = *list[i].extra_colormap; + if (!(spr->mobj->renderflags & RF_NOCOLORMAPS)) + colormap = *list[i].extra_colormap; } if (i + 1 < sector->numlights) @@ -3954,7 +3940,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -3983,7 +3969,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -3996,16 +3982,10 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // -----------------+ static void HWR_DrawSprite(gl_vissprite_t *spr) { - float this_scale = 1.0f; FOutVector wallVerts[4]; - GLPatch_t *gpatch; // sprite patch converted to hardware + patch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; - const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); - //const boolean papersprite = (spr->mobj && (spr->mobj->frame & FF_PAPERSPRITE)); - if (spr->mobj) - this_scale = FIXED_TO_FLOAT(spr->mobj->scale); - if (hires) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale); + const boolean splat = R_ThingIsFloorSprite(spr->mobj); if (!spr->mobj) return; @@ -4013,7 +3993,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) if (!spr->mobj->subsector) return; - if (spr->mobj->subsector->sector->numlights) + if (spr->mobj->subsector->sector->numlights && !splat) { HWR_SplitSprite(spr); return; @@ -4025,7 +4005,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // sure to do it the right way. So actually, we keep normal sprite // in memory and we add the md2 model if it exists for that sprite - gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); + gpatch = spr->gpatch; #ifdef ALAM_LIGHTING if (!(spr->mobj->flags2 & MF2_DEBRIS) && (spr->mobj->sprite != SPR_PLAY || @@ -4040,37 +4020,144 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // |/ | // 0--1 - // these were already scaled in HWR_ProjectSprite - wallVerts[0].x = wallVerts[3].x = spr->x1; - wallVerts[2].x = wallVerts[1].x = spr->x2; - wallVerts[2].y = wallVerts[3].y = spr->ty; - if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f) - wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height * this_scale; + if (splat) + { + F2DCoord verts[4]; + F2DCoord rotated[4]; + + angle_t angle; + float ca, sa; + float w, h; + float xscale, yscale; + float xoffset, yoffset; + float leftoffset, topoffset; + float scale = spr->scale; + float zoffset = (P_MobjFlip(spr->mobj) * 0.05f); + pslope_t *splatslope = NULL; + INT32 i; + + renderflags_t renderflags = spr->renderflags; + if (renderflags & RF_SHADOWEFFECTS) + scale *= spr->shadowscale; + + if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) + angle = spr->mobj->angle; + else + angle = viewangle; + + if (!spr->rotated) + angle += spr->mobj->rollangle; + + angle = -angle; + angle += ANGLE_90; + + topoffset = spr->spriteyoffset; + leftoffset = spr->spritexoffset; + if (spr->flip) + leftoffset = ((float)gpatch->width - leftoffset); + + xscale = spr->scale * spr->spritexscale; + yscale = spr->scale * spr->spriteyscale; + + xoffset = leftoffset * xscale; + yoffset = topoffset * yscale; + + w = (float)gpatch->width * xscale; + h = (float)gpatch->height * yscale; + + // Set positions + + // 3--2 + // | | + // 0--1 + + verts[3].x = -xoffset; + verts[3].y = yoffset; + + verts[2].x = w - xoffset; + verts[2].y = yoffset; + + verts[1].x = w - xoffset; + verts[1].y = -h + yoffset; + + verts[0].x = -xoffset; + verts[0].y = -h + yoffset; + + ca = FIXED_TO_FLOAT(FINECOSINE((-angle)>>ANGLETOFINESHIFT)); + sa = FIXED_TO_FLOAT(FINESINE((-angle)>>ANGLETOFINESHIFT)); + + // Rotate + for (i = 0; i < 4; i++) + { + rotated[i].x = (verts[i].x * ca) - (verts[i].y * sa); + rotated[i].y = (verts[i].x * sa) + (verts[i].y * ca); + } + + // Translate + for (i = 0; i < 4; i++) + { + wallVerts[i].x = rotated[i].x + FIXED_TO_FLOAT(spr->mobj->x); + wallVerts[i].z = rotated[i].y + FIXED_TO_FLOAT(spr->mobj->y); + } + + if (renderflags & (RF_SLOPESPLAT | RF_OBJECTSLOPESPLAT)) + { + pslope_t *standingslope = spr->mobj->standingslope; // The slope that the object is standing on. + + // The slope that was defined for the sprite. + if (renderflags & RF_SLOPESPLAT) + splatslope = spr->mobj->floorspriteslope; + + if (standingslope && (renderflags & RF_OBJECTSLOPESPLAT)) + splatslope = standingslope; + } + + // Set vertical position + if (splatslope) + { + for (i = 0; i < 4; i++) + { + fixed_t slopez = P_GetSlopeZAt(splatslope, FLOAT_TO_FIXED(wallVerts[i].x), FLOAT_TO_FIXED(wallVerts[i].z)); + wallVerts[i].y = FIXED_TO_FLOAT(slopez) + zoffset; + } + } + else + { + for (i = 0; i < 4; i++) + wallVerts[i].y = FIXED_TO_FLOAT(spr->mobj->z) + zoffset; + } + } else - wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height; + { + // these were already scaled in HWR_ProjectSprite + wallVerts[0].x = wallVerts[3].x = spr->x1; + wallVerts[2].x = wallVerts[1].x = spr->x2; + wallVerts[2].y = wallVerts[3].y = spr->gzt; + wallVerts[0].y = wallVerts[1].y = spr->gz; - // make a wall polygon (with 2 triangles), using the floor/ceiling heights, - // and the 2d map coords of start/end vertices - wallVerts[0].z = wallVerts[3].z = spr->z1; - wallVerts[1].z = wallVerts[2].z = spr->z2; + // make a wall polygon (with 2 triangles), using the floor/ceiling heights, + // and the 2d map coords of start/end vertices + wallVerts[0].z = wallVerts[3].z = spr->z1; + wallVerts[1].z = wallVerts[2].z = spr->z2; + } if (spr->flip) { - wallVerts[0].s = wallVerts[3].s = gpatch->max_s; + wallVerts[0].s = wallVerts[3].s = ((GLPatch_t *)gpatch->hardware)->max_s; wallVerts[2].s = wallVerts[1].s = 0; }else{ wallVerts[0].s = wallVerts[3].s = 0; - wallVerts[2].s = wallVerts[1].s = gpatch->max_s; + wallVerts[2].s = wallVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s; } // flip the texture coords (look familiar?) if (spr->vflip) { - wallVerts[3].t = wallVerts[2].t = gpatch->max_t; + wallVerts[3].t = wallVerts[2].t = ((GLPatch_t *)gpatch->hardware)->max_t; wallVerts[0].t = wallVerts[1].t = 0; }else{ wallVerts[3].t = wallVerts[2].t = 0; - wallVerts[0].t = wallVerts[1].t = gpatch->max_t; + wallVerts[0].t = wallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t; } // cache the patch in the graphics card memory @@ -4078,18 +4165,21 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) //Hurdler: 25/04/2000: now support colormap in hardware mode HWR_GetMappedPatch(gpatch, spr->colormap); - // if it has a dispoffset, push it a little towards the camera - if (spr->dispoffset) { - float co = -gl_viewcos*(0.05f*spr->dispoffset); - float si = -gl_viewsin*(0.05f*spr->dispoffset); - wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si; - wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si; - wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co; - wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; - } + if (!splat) + { + // if it has a dispoffset, push it a little towards the camera + if (spr->dispoffset) { + float co = -gl_viewcos*(0.05f*spr->dispoffset); + float si = -gl_viewsin*(0.05f*spr->dispoffset); + wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si; + wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si; + wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co; + wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; + } - // Let dispoffset work first since this adjust each vertex - HWR_RotateSpritePolyToAim(spr, wallVerts, false); + // Let dispoffset work first since this adjust each vertex + HWR_RotateSpritePolyToAim(spr, wallVerts, false); + } // This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black. // sprite lighting by modulating the RGB components @@ -4098,10 +4188,31 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // colormap test { sector_t *sector = spr->mobj->subsector->sector; - UINT8 lightlevel = 255; - extracolormap_t *colormap = sector->extra_colormap; + UINT8 lightlevel = 0; + boolean lightset = true; + extracolormap_t *colormap = NULL; + + if (R_ThingIsFullBright(spr->mobj)) + lightlevel = 255; + else if (R_ThingIsFullDark(spr->mobj)) + lightlevel = 0; + else + lightset = false; + + if (!(spr->mobj->renderflags & RF_NOCOLORMAPS)) + colormap = sector->extra_colormap; - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (splat && sector->numlights) + { + INT32 light = R_GetPlaneLight(sector, spr->mobj->z, false); + + if (!lightset) + lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel; + + if (*sector->lightlist[light].extra_colormap && !(spr->mobj->renderflags & RF_NOCOLORMAPS)) + colormap = *sector->lightlist[light].extra_colormap; + } + else if (!lightset) lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel; HWR_Lighting(&Surf, lightlevel, colormap); @@ -4128,10 +4239,15 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) else if (spr->mobj->flags2 & MF2_SHADOW) { Surf.PolyColor.s.alpha = 0x40; - blend = PF_Translucent; + blend = HWR_GetBlendModeFlag(spr->mobj->blendmode); } else if (spr->mobj->frame & FF_TRANSMASK) - blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + { + INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; + if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) + return; + blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf); + } else { // BP: i agree that is little better in environement but it don't @@ -4139,11 +4255,23 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; + blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|occlusion; + if (!occlusion) use_linkdraw_hack = true; + } + + if (spr->renderflags & RF_SHADOWEFFECTS) + { + INT32 alpha = Surf.PolyColor.s.alpha; + alpha -= ((INT32)(spr->shadowheight / 4.0f)) + 75; + if (alpha < 1) + return; + + Surf.PolyColor.s.alpha = (UINT8)(alpha); blend = PF_Translucent|occlusion; if (!occlusion) use_linkdraw_hack = true; } - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -4156,7 +4284,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) { FBITFIELD blend = 0; FOutVector wallVerts[4]; - GLPatch_t *gpatch; // sprite patch converted to hardware + patch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; if (!spr->mobj) @@ -4166,7 +4294,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) return; // cache sprite graphics - gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); + gpatch = spr->gpatch; // create the sprite billboard // @@ -4176,8 +4304,8 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) // 0--1 wallVerts[0].x = wallVerts[3].x = spr->x1; wallVerts[2].x = wallVerts[1].x = spr->x2; - wallVerts[2].y = wallVerts[3].y = spr->ty; - wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height; + wallVerts[2].y = wallVerts[3].y = spr->gzt; + wallVerts[0].y = wallVerts[1].y = spr->gz; // make a wall polygon (with 2 triangles), using the floor/ceiling heights, // and the 2d map coords of start/end vertices @@ -4188,10 +4316,10 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) HWR_RotateSpritePolyToAim(spr, wallVerts, true); wallVerts[0].s = wallVerts[3].s = 0; - wallVerts[2].s = wallVerts[1].s = gpatch->max_s; + wallVerts[2].s = wallVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s; wallVerts[3].t = wallVerts[2].t = 0; - wallVerts[0].t = wallVerts[1].t = gpatch->max_t; + wallVerts[0].t = wallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t; // cache the patch in the graphics card memory //12/12/99: Hurdler: same comment as above (for md2) @@ -4206,9 +4334,8 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) if (sector->numlights) { - INT32 light; - - light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before + // Always use the light at the top instead of whatever I was doing before + INT32 light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel; @@ -4228,13 +4355,13 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) HWR_Lighting(&Surf, lightlevel, colormap); } - if (spr->mobj->flags2 & MF2_SHADOW) + if (spr->mobj->frame & FF_TRANSMASK) { - Surf.PolyColor.s.alpha = 0x40; - blend = PF_Translucent; + INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; + if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) + return; + blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf); } - else if (spr->mobj->frame & FF_TRANSMASK) - blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); else { // BP: i agree that is little better in environement but it don't @@ -4242,10 +4369,10 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|PF_Occlude; + blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|PF_Occlude; } - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader } #endif @@ -4709,7 +4836,7 @@ static void HWR_DrawSprites(void) // (Other states probably don't matter. Here I left them same as in LinkDrawHackFinish) // Without this workaround the rest of the draw calls in this frame (including UI, screen texture) // can get drawn using an incorrect glBlendFunc, resulting in a occasional black screen. - HWD.pfnSetBlend(PF_Translucent|PF_Occlude|PF_Clip|PF_Masked); + HWD.pfnSetBlend(PF_Translucent|PF_Occlude|PF_Masked); } // -------------------------------------------------------------------------- @@ -4774,23 +4901,28 @@ static void HWR_ProjectSprite(mobj_t *thing) float tracertz = 0.0f; float x1, x2; float rightsin, rightcos; - float this_scale; + float this_scale, this_xscale, this_yscale; + float spritexscale, spriteyscale; + float shadowheight = 1.0f, shadowscale = 1.0f; float gz, gzt; spritedef_t *sprdef; spriteframe_t *sprframe; +#ifdef ROTSPRITE spriteinfo_t *sprinfo; +#endif md2_t *md2; size_t lumpoff; unsigned rot; UINT16 flip; - boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); + boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(thing)); boolean mirrored = thing->mirrored; - boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored); + boolean hflip = (!R_ThingHorizontallyFlipped(thing) != !mirrored); INT32 dispoffset; angle_t ang; INT32 heightsec, phs; - const boolean papersprite = (thing->frame & FF_PAPERSPRITE); + const boolean papersprite = R_ThingIsPaperSprite(thing); + const boolean splat = R_ThingIsFloorSprite(thing); angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle); float z1, z2; @@ -4804,9 +4936,14 @@ static void HWR_ProjectSprite(mobj_t *thing) if (!thing) return; + if (thing->spritexscale < 1 || thing->spriteyscale < 1) + return; + dispoffset = thing->info->dispoffset; this_scale = FIXED_TO_FLOAT(thing->scale); + spritexscale = FIXED_TO_FLOAT(thing->spritexscale); + spriteyscale = FIXED_TO_FLOAT(thing->spriteyscale); // transform the origin point tr_x = FIXED_TO_FLOAT(thing->x) - gl_viewx; @@ -4816,7 +4953,7 @@ static void HWR_ProjectSprite(mobj_t *thing) tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin); // thing is behind view plane? - if (tz < ZCLIP_PLANE && !papersprite) + if (tz < ZCLIP_PLANE && !(papersprite || splat)) { if (cv_glmodels.value) //Yellow: Only MD2's dont disappear { @@ -4848,12 +4985,16 @@ static void HWR_ProjectSprite(mobj_t *thing) if (thing->skin && thing->sprite == SPR_PLAY) { sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2]; +#ifdef ROTSPRITE sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2]; +#endif } else { sprdef = &sprites[thing->sprite]; - sprinfo = NULL; +#ifdef ROTSPRITE + sprinfo = &spriteinfo[thing->sprite]; +#endif } if (rot >= sprdef->numframes) @@ -4863,7 +5004,9 @@ static void HWR_ProjectSprite(mobj_t *thing) thing->sprite = states[S_UNKNOWN].sprite; thing->frame = states[S_UNKNOWN].frame; sprdef = &sprites[thing->sprite]; - sprinfo = NULL; +#ifdef ROTSPRITE + sprinfo = &spriteinfo[thing->sprite]; +#endif rot = thing->frame&FF_FRAMEMASK; thing->state->sprite = thing->sprite; thing->state->frame = thing->frame; @@ -4914,7 +5057,7 @@ static void HWR_ProjectSprite(mobj_t *thing) } if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale); + this_scale *= FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale); spr_width = spritecachedinfo[lumpoff].width; spr_height = spritecachedinfo[lumpoff].height; @@ -4922,24 +5065,42 @@ static void HWR_ProjectSprite(mobj_t *thing) spr_topoffset = spritecachedinfo[lumpoff].topoffset; #ifdef ROTSPRITE - if (thing->rollangle) + if (thing->rollangle + && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE))) { rollangle = R_GetRollAngle(thing->rollangle); - if (!(sprframe->rotsprite.cached & (1<<rot))) - R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip); - rotsprite = sprframe->rotsprite.patch[rot][rollangle]; + rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); + if (rotsprite != NULL) { - spr_width = SHORT(rotsprite->width) << FRACBITS; - spr_height = SHORT(rotsprite->height) << FRACBITS; - spr_offset = SHORT(rotsprite->leftoffset) << FRACBITS; - spr_topoffset = SHORT(rotsprite->topoffset) << FRACBITS; + spr_width = rotsprite->width << FRACBITS; + spr_height = rotsprite->height << FRACBITS; + spr_offset = rotsprite->leftoffset << FRACBITS; + spr_topoffset = rotsprite->topoffset << FRACBITS; + spr_topoffset += FEETADJUST; + // flip -> rotate, not rotate -> flip flip = 0; } } #endif + if (thing->renderflags & RF_ABSOLUTEOFFSETS) + { + spr_offset = thing->spritexoffset; + spr_topoffset = thing->spriteyoffset; + } + else + { + SINT8 flipoffset = 1; + + if ((thing->renderflags & RF_FLIPOFFSETS) && flip) + flipoffset = -1; + + spr_offset += thing->spritexoffset * flipoffset; + spr_topoffset += thing->spriteyoffset * flipoffset; + } + if (papersprite) { rightsin = FIXED_TO_FLOAT(FINESINE((mobjangle)>>ANGLETOFINESHIFT)); @@ -4953,15 +5114,36 @@ static void HWR_ProjectSprite(mobj_t *thing) flip = !flip != !hflip; + if (thing->renderflags & RF_SHADOWEFFECTS) + { + mobj_t *caster = thing->target; + + if (caster && !P_MobjWasRemoved(caster)) + { + fixed_t groundz = R_GetShadowZ(thing, NULL); + fixed_t floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + caster->z - groundz); + + shadowheight = FIXED_TO_FLOAT(floordiff); + shadowscale = FIXED_TO_FLOAT(FixedMul(FRACUNIT - floordiff/640, caster->scale)); + + if (splat) + spritexscale *= shadowscale; + spriteyscale *= shadowscale; + } + } + + this_xscale = spritexscale * this_scale; + this_yscale = spriteyscale * this_scale; + if (flip) { - x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_scale); - x2 = (FIXED_TO_FLOAT(spr_offset) * this_scale); + x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); + x2 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); } else { - x1 = (FIXED_TO_FLOAT(spr_offset) * this_scale); - x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_scale); + x1 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); + x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); } // test if too close @@ -4983,13 +5165,13 @@ static void HWR_ProjectSprite(mobj_t *thing) if (vflip) { - gz = FIXED_TO_FLOAT(thing->z+thing->height) - FIXED_TO_FLOAT(spr_topoffset) * this_scale; - gzt = gz + FIXED_TO_FLOAT(spr_height) * this_scale; + gz = FIXED_TO_FLOAT(thing->z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale); } else { - gzt = FIXED_TO_FLOAT(thing->z) + FIXED_TO_FLOAT(spr_topoffset) * this_scale; - gz = gzt - FIXED_TO_FLOAT(spr_height) * this_scale; + gzt = FIXED_TO_FLOAT(thing->z) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gz = gzt - (FIXED_TO_FLOAT(spr_height) * this_yscale); } if (thing->subsector->sector->cullheight) @@ -5046,20 +5228,39 @@ static void HWR_ProjectSprite(mobj_t *thing) vis = HWR_NewVisSprite(); vis->x1 = x1; vis->x2 = x2; + vis->z1 = z1; + vis->z2 = z2; + vis->tz = tz; // Keep tz for the simple sprite sorting that happens vis->tracertz = tracertz; + + vis->renderflags = thing->renderflags; + vis->rotateflags = sprframe->rotate; + + vis->shadowheight = shadowheight; + vis->shadowscale = shadowscale; vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST - //vis->patchlumpnum = sprframe->lumppat[rot]; + vis->flip = flip; + + vis->scale = this_scale; + vis->spritexscale = spritexscale; + vis->spriteyscale = spriteyscale; + vis->spritexoffset = FIXED_TO_FLOAT(spr_offset); + vis->spriteyoffset = FIXED_TO_FLOAT(spr_topoffset); + + vis->rotated = false; + #ifdef ROTSPRITE if (rotsprite) - vis->gpatch = (GLPatch_t *)rotsprite; + { + vis->gpatch = (patch_t *)rotsprite; + vis->rotated = true; + } else #endif - vis->gpatch = (GLPatch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE); - vis->flip = flip; + vis->gpatch = (patch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE); + vis->mobj = thing; - vis->z1 = z1; - vis->z2 = z2; //Hurdler: 25/04/2000: now support colormap in hardware mode if ((vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" @@ -5097,7 +5298,8 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->colormap = colormaps; // set top/bottom coords - vis->ty = gzt; + vis->gzt = gzt; + vis->gz = gz; //CONS_Debug(DBG_RENDER, "------------------\nH: sprite : %d\nH: frame : %x\nH: type : %d\nH: sname : %s\n\n", // thing->sprite, thing->frame, thing->type, sprnames[thing->sprite]); @@ -5190,15 +5392,15 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->z2 = z2; vis->tz = tz; vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST - //vis->patchlumpnum = sprframe->lumppat[rot]; - vis->gpatch = (GLPatch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE); + vis->gpatch = (patch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE); vis->flip = flip; vis->mobj = (mobj_t *)thing; vis->colormap = colormaps; // set top/bottom coords - vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); + vis->gzt = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); + vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height); vis->precip = true; @@ -6017,6 +6219,22 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE); } +void HWR_LoadLevel(void) +{ +#ifdef ALAM_LIGHTING + // BP: reset light between levels (we draw preview frame lights on current frame) + HWR_ResetLights(); +#endif + + HWR_CreatePlanePolygons((INT32)numnodes - 1); + + // Build the sky dome + HWR_ClearSkyDome(); + HWR_BuildSkyDome(); + + gl_maploaded = true; +} + // ========================================================================== // 3D ENGINE COMMANDS // ========================================================================== @@ -6112,13 +6330,10 @@ void HWR_AddCommands(void) void HWR_AddSessionCommands(void) { - static boolean alreadycalled = false; - if (alreadycalled) + if (gl_sessioncommandsadded) return; - CV_RegisterVar(&cv_glanisotropicmode); - - alreadycalled = true; + gl_sessioncommandsadded = true; } // -------------------------------------------------------------------------- @@ -6126,16 +6341,13 @@ void HWR_AddSessionCommands(void) // -------------------------------------------------------------------------- void HWR_Startup(void) { - static boolean startupdone = false; - - // do this once - if (!startupdone) + if (!gl_init) { CONS_Printf("HWR_Startup()...\n"); HWR_InitPolyPool(); HWR_AddSessionCommands(); - HWR_InitTextureCache(); + HWR_InitMapTextures(); HWR_InitModels(); #ifdef ALAM_LIGHTING HWR_InitLight(); @@ -6149,7 +6361,7 @@ void HWR_Startup(void) if (rendermode == render_opengl) textureformat = patchformat = GL_TEXFMT_RGBA; - startupdone = true; + gl_init = true; } // -------------------------------------------------------------------------- @@ -6157,9 +6369,24 @@ void HWR_Startup(void) // -------------------------------------------------------------------------- void HWR_Switch(void) { + // Add session commands + if (!gl_sessioncommandsadded) + HWR_AddSessionCommands(); + // Set special states from CVARs HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_glfiltermode.value); HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value); + + // Load textures + if (!gl_maptexturesloaded) + HWR_LoadMapTextures(numtextures); + + // Create plane polygons + if (!gl_maploaded && (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) + { + HWR_ClearAllTextures(); + HWR_LoadLevel(); + } } // -------------------------------------------------------------------------- @@ -6170,7 +6397,7 @@ void HWR_Shutdown(void) CONS_Printf("HWR_Shutdown()\n"); HWR_FreeExtraSubsectors(); HWR_FreePolyPool(); - HWR_FreeTextureCache(); + HWR_FreeMapTextures(); HWD.pfnFlushScreenTextures(); } @@ -6246,13 +6473,7 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, } blendmode |= PF_Modulated; // No PF_Occlude means overlapping (incorrect) transparency - HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode, shader, false); - -#ifdef WALLSPLATS - if (gl_curline->linedef->splats && cv_splats.value) - HWR_DrawSegsSplats(pSurf); -#endif } INT32 HWR_GetTextureUsed(void) @@ -6293,7 +6514,7 @@ void HWR_DoPostProcessor(player_t *player) Surf.PolyColor.s.alpha = 0xc0; // match software mode - HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Additive|PF_NoTexture|PF_NoDepthTest|PF_Clip|PF_NoZClip); + HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_AdditiveSource|PF_NoTexture|PF_NoDepthTest); } // Capture the screen for intermission and screen waving diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 3a6b1a4e99cc967515050297b86a19d2217d17cb..2ce918408b041780b3a5e0294a9ce059a5326381 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -37,13 +37,12 @@ void HWR_DrawViewBorder(INT32 clearlines); void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum); void HWR_InitTextureMapping(void); void HWR_SetViewSize(void); -void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option); -void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap); -void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); +void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option); +void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap); +void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap); void HWR_CreatePlanePolygons(INT32 bspnum); void HWR_CreateStaticLightmaps(INT32 bspnum); -void HWR_LoadTextures(size_t pnumtextures); void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color); void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength); void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32 actualcolor); // Lat: separate flags from color since color needs to be an uint to work right. @@ -55,7 +54,6 @@ boolean HWR_Screenshot(const char *pathname); void HWR_AddCommands(void); void HWR_AddSessionCommands(void); void transform(float *cx, float *cy, float *cz); -FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); INT32 HWR_GetTextureUsed(void); void HWR_DoPostProcessor(player_t *player); void HWR_StartScreenWipe(void); @@ -66,10 +64,15 @@ void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum); void HWR_MakeScreenFinalTexture(void); void HWR_DrawScreenFinalTexture(int width, int height); -// This stuff is put here so MD2's can use them +// This stuff is put here so models can use them void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap); UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work +UINT8 HWR_GetTranstableAlpha(INT32 transtablenum); +FBITFIELD HWR_GetBlendModeFlag(INT32 ast); +FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf); +FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); + boolean HWR_CompileShaders(void); void HWR_LoadAllCustomShaders(void); @@ -130,6 +133,10 @@ extern int ps_hw_numcolors; extern int ps_hw_batchsorttime; extern int ps_hw_batchdrawtime; +extern boolean gl_init; +extern boolean gl_maploaded; +extern boolean gl_maptexturesloaded; +extern boolean gl_sessioncommandsadded; extern boolean gl_shadersavailable; #endif diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 0c1b14b20879f1136a33b7ccd982c7436fbbd0bb..9c786e67ed5a40e395ceb362b28cc3a58a1254c5 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -364,48 +364,53 @@ static GLTextureFormat_t PCX_Load(const char *filename, int *w, int *h, // -----------------+ static void md2_loadTexture(md2_t *model) { - GLPatch_t *grpatch; + patch_t *patch; + GLPatch_t *grPatch = NULL; const char *filename = model->filename; if (model->grpatch) { - grpatch = model->grpatch; - Z_Free(grpatch->mipmap->data); + patch = model->grpatch; + grPatch = (GLPatch_t *)(patch->hardware); + if (grPatch) + Z_Free(grPatch->mipmap->data); } else - { - grpatch = Z_Calloc(sizeof *grpatch, PU_HWRPATCHINFO, - &(model->grpatch)); - grpatch->mipmap = Z_Calloc(sizeof (GLMipmap_t), PU_HWRPATCHINFO, NULL); - } + model->grpatch = patch = Patch_Create(NULL, 0, NULL); - if (!grpatch->mipmap->downloaded && !grpatch->mipmap->data) + if (!patch->hardware) + Patch_AllocateHardwarePatch(patch); + + if (grPatch == NULL) + grPatch = (GLPatch_t *)(patch->hardware); + + if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data) { int w = 0, h = 0; UINT32 size; RGBA_t *image; #ifdef HAVE_PNG - grpatch->mipmap->format = PNG_Load(filename, &w, &h, grpatch); - if (grpatch->mipmap->format == 0) + grPatch->mipmap->format = PNG_Load(filename, &w, &h, grPatch); + if (grPatch->mipmap->format == 0) #endif - grpatch->mipmap->format = PCX_Load(filename, &w, &h, grpatch); - if (grpatch->mipmap->format == 0) + grPatch->mipmap->format = PCX_Load(filename, &w, &h, grPatch); + if (grPatch->mipmap->format == 0) { model->notexturefile = true; // mark it so its not searched for again repeatedly return; } - grpatch->mipmap->downloaded = 0; - grpatch->mipmap->flags = 0; + grPatch->mipmap->downloaded = 0; + grPatch->mipmap->flags = 0; - grpatch->width = (INT16)w; - grpatch->height = (INT16)h; - grpatch->mipmap->width = (UINT16)w; - grpatch->mipmap->height = (UINT16)h; + patch->width = (INT16)w; + patch->height = (INT16)h; + grPatch->mipmap->width = (UINT16)w; + grPatch->mipmap->height = (UINT16)h; // Lactozilla: Apply colour cube - image = grpatch->mipmap->data; + image = grPatch->mipmap->data; size = w*h; while (size--) { @@ -413,7 +418,7 @@ static void md2_loadTexture(md2_t *model) image++; } } - HWD.pfnSetTexture(grpatch->mipmap); + HWD.pfnSetTexture(grPatch->mipmap); } // -----------------+ @@ -421,48 +426,53 @@ static void md2_loadTexture(md2_t *model) // -----------------+ static void md2_loadBlendTexture(md2_t *model) { - GLPatch_t *grpatch; + patch_t *patch; + GLPatch_t *grPatch = NULL; char *filename = Z_Malloc(strlen(model->filename)+7, PU_STATIC, NULL); - strcpy(filename, model->filename); + strcpy(filename, model->filename); FIL_ForceExtension(filename, "_blend.png"); if (model->blendgrpatch) { - grpatch = model->blendgrpatch; - Z_Free(grpatch->mipmap->data); + patch = model->blendgrpatch; + grPatch = (GLPatch_t *)(patch->hardware); + if (grPatch) + Z_Free(grPatch->mipmap->data); } else - { - grpatch = Z_Calloc(sizeof *grpatch, PU_HWRPATCHINFO, - &(model->blendgrpatch)); - grpatch->mipmap = Z_Calloc(sizeof (GLMipmap_t), PU_HWRPATCHINFO, NULL); - } + model->blendgrpatch = patch = Patch_Create(NULL, 0, NULL); + + if (!patch->hardware) + Patch_AllocateHardwarePatch(patch); - if (!grpatch->mipmap->downloaded && !grpatch->mipmap->data) + if (grPatch == NULL) + grPatch = (GLPatch_t *)(patch->hardware); + + if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data) { int w = 0, h = 0; #ifdef HAVE_PNG - grpatch->mipmap->format = PNG_Load(filename, &w, &h, grpatch); - if (grpatch->mipmap->format == 0) + grPatch->mipmap->format = PNG_Load(filename, &w, &h, grPatch); + if (grPatch->mipmap->format == 0) #endif - grpatch->mipmap->format = PCX_Load(filename, &w, &h, grpatch); - if (grpatch->mipmap->format == 0) + grPatch->mipmap->format = PCX_Load(filename, &w, &h, grPatch); + if (grPatch->mipmap->format == 0) { model->noblendfile = true; // mark it so its not searched for again repeatedly Z_Free(filename); return; } - grpatch->mipmap->downloaded = 0; - grpatch->mipmap->flags = 0; + grPatch->mipmap->downloaded = 0; + grPatch->mipmap->flags = 0; - grpatch->width = (INT16)w; - grpatch->height = (INT16)h; - grpatch->mipmap->width = (UINT16)w; - grpatch->mipmap->height = (UINT16)h; + patch->width = (INT16)w; + patch->height = (INT16)h; + grPatch->mipmap->width = (UINT16)w; + grPatch->mipmap->height = (UINT16)h; } - HWD.pfnSetTexture(grpatch->mipmap); // We do need to do this so that it can be cleared and knows to recreate it when necessary + HWD.pfnSetTexture(grPatch->mipmap); // We do need to do this so that it can be cleared and knows to recreate it when necessary Z_Free(filename); } @@ -517,7 +527,7 @@ void HWR_InitModels(void) return; } } - + // length of the player model prefix prefixlen = strlen(PLAYERMODELPREFIX); @@ -692,8 +702,10 @@ spritemodelfound: #define SETBRIGHTNESS(brightness,r,g,b) \ brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000)) -static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolornum_t color) +static void HWR_CreateBlendedTexture(patch_t *gpatch, patch_t *blendgpatch, GLMipmap_t *grMipmap, INT32 skinnum, skincolornum_t color) { + GLPatch_t *hwrPatch = gpatch->hardware; + GLPatch_t *hwrBlendPatch = blendgpatch->hardware; UINT16 w = gpatch->width, h = gpatch->height; UINT32 size = w*h; RGBA_t *image, *blendimage, *cur, blendcolor; @@ -706,28 +718,29 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, memset(translation, 0, sizeof(translation)); memset(cutoff, 0, sizeof(cutoff)); - if (grmip->width == 0) + if (grMipmap->width == 0) { - grmip->width = gpatch->width; - grmip->height = gpatch->height; + grMipmap->width = gpatch->width; + grMipmap->height = gpatch->height; // no wrap around, no chroma key - grmip->flags = 0; + grMipmap->flags = 0; + // setup the texture info - grmip->format = GL_TEXFMT_RGBA; + grMipmap->format = GL_TEXFMT_RGBA; } - if (grmip->data) + if (grMipmap->data) { - Z_Free(grmip->data); - grmip->data = NULL; + Z_Free(grMipmap->data); + grMipmap->data = NULL; } - cur = Z_Malloc(size*4, PU_HWRMODELTEXTURE, &grmip->data); + cur = Z_Malloc(size*4, PU_HWRMODELTEXTURE, &grMipmap->data); memset(cur, 0x00, size*4); - image = gpatch->mipmap->data; - blendimage = blendgpatch->mipmap->data; + image = hwrPatch->mipmap->data; + blendimage = hwrBlendPatch->mipmap->data; // TC_METALSONIC includes an actual skincolor translation, on top of its flashing. if (skinnum == TC_METALSONIC) @@ -1066,37 +1079,39 @@ skippixel: #undef SETBRIGHTNESS -static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT32 skinnum, const UINT8 *colormap, skincolornum_t color) +static void HWR_GetBlendedTexture(patch_t *patch, patch_t *blendpatch, INT32 skinnum, const UINT8 *colormap, skincolornum_t color) { // mostly copied from HWR_GetMappedPatch, hence the similarities and comment - GLMipmap_t *grmip, *newmip; + GLPatch_t *grPatch = patch->hardware; + GLPatch_t *grBlendPatch = NULL; + GLMipmap_t *grMipmap, *newMipmap; - if (colormap == colormaps || colormap == NULL) + if (blendpatch == NULL || colormap == colormaps || colormap == NULL) { // Don't do any blending - HWD.pfnSetTexture(gpatch->mipmap); + HWD.pfnSetTexture(grPatch->mipmap); return; } - if ((blendgpatch && blendgpatch->mipmap->format) - && (gpatch->width != blendgpatch->width || gpatch->height != blendgpatch->height)) + if ((blendpatch && (grBlendPatch = blendpatch->hardware) && grBlendPatch->mipmap->format) + && (patch->width != blendpatch->width || patch->height != blendpatch->height)) { // Blend image exists, but it's bad. - HWD.pfnSetTexture(gpatch->mipmap); + HWD.pfnSetTexture(grPatch->mipmap); return; } // search for the mipmap // skip the first (no colormap translated) - for (grmip = gpatch->mipmap; grmip->nextcolormap; ) + for (grMipmap = grPatch->mipmap; grMipmap->nextcolormap; ) { - grmip = grmip->nextcolormap; - if (grmip->colormap == colormap) + grMipmap = grMipmap->nextcolormap; + if (grMipmap->colormap == colormap) { - if (grmip->downloaded && grmip->data) + if (grMipmap->downloaded && grMipmap->data) { - HWD.pfnSetTexture(grmip); // found the colormap, set it to the correct texture - Z_ChangeTag(grmip->data, PU_HWRMODELTEXTURE_UNLOCKED); + HWD.pfnSetTexture(grMipmap); // found the colormap, set it to the correct texture + Z_ChangeTag(grMipmap->data, PU_HWRMODELTEXTURE_UNLOCKED); return; } } @@ -1107,18 +1122,18 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT //BP: WARNING: don't free it manually without clearing the cache of harware renderer // (it have a liste of mipmap) - // this malloc is cleared in HWR_FreeTextureCache + // this malloc is cleared in HWR_FreeColormapCache // (...) unfortunately z_malloc fragment alot the memory :(so malloc is better - newmip = calloc(1, sizeof (*newmip)); - if (newmip == NULL) + newMipmap = calloc(1, sizeof (*newMipmap)); + if (newMipmap == NULL) I_Error("%s: Out of memory", "HWR_GetBlendedTexture"); - grmip->nextcolormap = newmip; - newmip->colormap = colormap; + grMipmap->nextcolormap = newMipmap; + newMipmap->colormap = colormap; - HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, skinnum, color); + HWR_CreateBlendedTexture(patch, blendpatch, newMipmap, skinnum, color); - HWD.pfnSetTexture(newmip); - Z_ChangeTag(newmip->data, PU_HWRMODELTEXTURE_UNLOCKED); + HWD.pfnSetTexture(newMipmap); + Z_ChangeTag(newMipmap->data, PU_HWRMODELTEXTURE_UNLOCKED); } #define NORMALFOG 0x00000000 @@ -1206,9 +1221,11 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t } // Adjust texture coords of model to fit into a patch's max_s and max_t -static void adjustTextureCoords(model_t *model, GLPatch_t *gpatch) +static void adjustTextureCoords(model_t *model, patch_t *patch) { int i; + GLPatch_t *gpatch = ((GLPatch_t *)patch->hardware); + for (i = 0; i < model->numMeshes; i++) { int j; @@ -1308,7 +1325,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // Look at HWR_ProjectSprite for more { - GLPatch_t *gpatch; + patch_t *gpatch, *blendgpatch; + GLPatch_t *hwrPatch = NULL, *hwrBlendPatch = NULL; INT32 durs = spr->mobj->state->tics; INT32 tics = spr->mobj->tics; //mdlframe_t *next = NULL; @@ -1326,15 +1344,16 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) //if (tics > durs) //durs = tics; - if (spr->mobj->flags2 & MF2_SHADOW) - Surf.PolyColor.s.alpha = 0x40; - else if (spr->mobj->frame & FF_TRANSMASK) - HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + if (spr->mobj->frame & FF_TRANSMASK) + Surf.PolyFlags = HWR_SurfaceBlend(spr->mobj->blendmode, (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); else - Surf.PolyColor.s.alpha = 0xFF; + { + Surf.PolyColor.s.alpha = (spr->mobj->flags2 & MF2_SHADOW) ? 0x40 : 0xff; + Surf.PolyFlags = HWR_GetBlendModeFlag(spr->mobj->blendmode); + } - // dont forget to enabled the depth test because we can't do this like - // before: polygons models are not sorted + // don't forget to enable the depth test because we can't do this + // like before: model polygons are not sorted // 1. load model+texture if not already loaded // 2. draw model with correct position, rotation,... @@ -1353,14 +1372,26 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // texture loading before model init, so it knows if sprite graphics are used, which // means that texture coordinates have to be adjusted gpatch = md2->grpatch; - if (!gpatch || ((!gpatch->mipmap->format || !gpatch->mipmap->downloaded) && !md2->notexturefile)) + if (gpatch) + hwrPatch = ((GLPatch_t *)gpatch->hardware); + + if (!gpatch || !hwrPatch + || ((!hwrPatch->mipmap->format || !hwrPatch->mipmap->downloaded) && !md2->notexturefile)) md2_loadTexture(md2); - gpatch = md2->grpatch; // Load it again, because it isn't being loaded into gpatch after md2_loadtexture... - if ((gpatch && gpatch->mipmap->format) // don't load the blend texture if the base texture isn't available - && (!md2->blendgrpatch - || ((!((GLPatch_t *)md2->blendgrpatch)->mipmap->format || !((GLPatch_t *)md2->blendgrpatch)->mipmap->downloaded) - && !md2->noblendfile))) + // Load it again, because it isn't being loaded into gpatch after md2_loadtexture... + gpatch = md2->grpatch; + if (gpatch) + hwrPatch = ((GLPatch_t *)gpatch->hardware); + + // Load blend texture + blendgpatch = md2->blendgrpatch; + if (blendgpatch) + hwrBlendPatch = ((GLPatch_t *)blendgpatch->hardware); + + if ((gpatch && hwrPatch && hwrPatch->mipmap->format) // don't load the blend texture if the base texture isn't available + && (!blendgpatch || !hwrBlendPatch + || ((!hwrBlendPatch->mipmap->format || !hwrBlendPatch->mipmap->downloaded) && !md2->noblendfile))) md2_loadBlendTexture(md2); if (md2->error) @@ -1376,7 +1407,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) md2_printModelInfo(md2->model); // If model uses sprite patch as texture, then // adjust texture coordinates to take power of two textures into account - if (!gpatch || !gpatch->mipmap->format) + if (!gpatch || !hwrPatch->mipmap->format) adjustTextureCoords(md2->model, spr->gpatch); // note down the max_s and max_t that end up in the VBO md2->model->vbo_max_s = md2->model->max_s; @@ -1395,7 +1426,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) finalscale = md2->scale; //Hurdler: arf, I don't like that implementation at all... too much crappy - if (gpatch && gpatch->mipmap->format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture + if (gpatch && hwrPatch && hwrPatch->mipmap->format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture { INT32 skinnum = TC_DEFAULT; @@ -1428,21 +1459,19 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) } // Translation or skin number found - HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolornum_t)spr->mobj->color); + HWR_GetBlendedTexture(gpatch, blendgpatch, skinnum, spr->colormap, (skincolornum_t)spr->mobj->color); } - else + else // Sprite { - // Sprite - gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); // Check if sprite dimensions are different from previously used sprite. // If so, uvs need to be readjusted. // Comparing floats with the != operator here should be okay because they // are just copies of glpatches' max_s and max_t values. // Instead of the != operator, memcmp is used to avoid a compiler warning. - if (memcmp(&(gpatch->max_s), &(md2->model->max_s), sizeof(md2->model->max_s)) != 0 || - memcmp(&(gpatch->max_t), &(md2->model->max_t), sizeof(md2->model->max_t)) != 0) - adjustTextureCoords(md2->model, gpatch); - HWR_GetMappedPatch(gpatch, spr->colormap); + if (memcmp(&(hwrPatch->max_s), &(md2->model->max_s), sizeof(md2->model->max_s)) != 0 || + memcmp(&(hwrPatch->max_t), &(md2->model->max_t), sizeof(md2->model->max_t)) != 0) + adjustTextureCoords(md2->model, spr->gpatch); + HWR_GetMappedPatch(spr->gpatch, spr->colormap); } if (spr->mobj->frame & FF_ANIMATE) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 1d2852d91888a39832968efe89d302b371ca3c80..8cd948eeadf57a34fa1290479b2f84d26210ba28 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -419,6 +419,10 @@ static PFNglBufferData pglBufferData; typedef void (APIENTRY * PFNglDeleteBuffers) (GLsizei n, const GLuint *buffers); static PFNglDeleteBuffers pglDeleteBuffers; +/* 2.0 functions */ +typedef void (APIENTRY * PFNglBlendEquation) (GLenum mode); +static PFNglBlendEquation pglBlendEquation; + /* 1.2 Parms */ /* GL_CLAMP_TO_EDGE_EXT */ @@ -874,6 +878,9 @@ void SetupGLFunc4(void) pglBufferData = GetGLFunc("glBufferData"); pglDeleteBuffers = GetGLFunc("glDeleteBuffers"); + /* 2.0 funcs */ + pglBlendEquation = GetGLFunc("glBlendEquation"); + #ifdef GL_SHADERS pglCreateShader = GetGLFunc("glCreateShader"); pglShaderSource = GetGLFunc("glShaderSource"); @@ -1234,6 +1241,7 @@ void SetStates(void) pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + pglEnable(GL_ALPHA_TEST); pglAlphaFunc(GL_NOTEQUAL, 0.0f); //pglBlendFunc(GL_ONE, GL_ZERO); // copy pixel to frame buffer (opaque) @@ -1276,6 +1284,17 @@ void SetStates(void) } +// -----------------+ +// DeleteTexture : Deletes a texture from the GPU and frees its data +// -----------------+ +EXPORT void HWRAPI(DeleteTexture) (FTextureInfo *pTexInfo) +{ + if (pTexInfo->downloaded) + pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded); + pTexInfo->downloaded = 0; +} + + // -----------------+ // Flush : flush OpenGL textures // : Clear list of downloaded mipmaps @@ -1286,17 +1305,24 @@ void Flush(void) while (gl_cachehead) { - if (gl_cachehead->downloaded) - pglDeleteTextures(1, (GLuint *)&gl_cachehead->downloaded); - gl_cachehead->downloaded = 0; + DeleteTexture(gl_cachehead); gl_cachehead = gl_cachehead->nextmipmap; } - gl_cachetail = gl_cachehead = NULL; //Hurdler: well, gl_cachehead is already NULL + ClearCacheList(); //Hurdler: well, gl_cachehead is already NULL tex_downloaded = 0; } +// -----------------+ +// ClearCacheList : Clears the texture cache tail and head +// -----------------+ +EXPORT void HWRAPI(ClearCacheList) (void) +{ + gl_cachetail = gl_cachehead = NULL; +} + + // -----------------+ // isExtAvailable : Look if an OpenGL extension is available // Returns : true if extension available @@ -1493,64 +1519,110 @@ EXPORT void HWRAPI(Draw2DLine) (F2DCoord * v1, pglEnable(GL_TEXTURE_2D); } + +// -----------------+ +// SetBlend : Set render mode +// -----------------+ +// PF_Masked - we could use an ALPHA_TEST of GL_EQUAL, and alpha ref of 0, +// is it faster when pixels are discarded ? + static void Clamp2D(GLenum pname) { pglTexParameteri(GL_TEXTURE_2D, pname, GL_CLAMP); // fallback clamp pglTexParameteri(GL_TEXTURE_2D, pname, GL_CLAMP_TO_EDGE); } +static void SetBlendEquation(GLenum mode) +{ + if (pglBlendEquation) + pglBlendEquation(mode); +} + +static void SetBlendMode(FBITFIELD flags) +{ + // Set blending function + switch (flags) + { + case PF_Translucent & PF_Blending: + pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency + break; + case PF_Masked & PF_Blending: + // Hurdler: does that mean lighting is only made by alpha src? + // it sounds ok, but not for polygonsmooth + pglBlendFunc(GL_SRC_ALPHA, GL_ZERO); // 0 alpha = holes in texture + break; + case PF_Additive & PF_Blending: + case PF_Subtractive & PF_Blending: + case PF_ReverseSubtract & PF_Blending: + case PF_Environment & PF_Blending: + pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + break; + case PF_AdditiveSource & PF_Blending: + pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest + break; + case PF_Multiplicative & PF_Blending: + pglBlendFunc(GL_DST_COLOR, GL_ZERO); + break; + case PF_Fog & PF_Fog: + // Sryder: Fog + // multiplies input colour by input alpha, and destination colour by input colour, then adds them + pglBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR); + break; + default: // must be 0, otherwise it's an error + // No blending + pglBlendFunc(GL_ONE, GL_ZERO); // the same as no blending + break; + } + + // Set blending equation + switch (flags) + { + case PF_Subtractive & PF_Blending: + SetBlendEquation(GL_FUNC_SUBTRACT); + break; + case PF_ReverseSubtract & PF_Blending: + // good for shadow + // not really but what else ? + SetBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + break; + default: + SetBlendEquation(GL_FUNC_ADD); + break; + } + + // Alpha test + switch (flags) + { + case PF_Masked & PF_Blending: + pglAlphaFunc(GL_GREATER, 0.5f); + break; + case PF_Translucent & PF_Blending: + case PF_Additive & PF_Blending: + case PF_AdditiveSource & PF_Blending: + case PF_Subtractive & PF_Blending: + case PF_ReverseSubtract & PF_Blending: + case PF_Environment & PF_Blending: + case PF_Multiplicative & PF_Blending: + pglAlphaFunc(GL_NOTEQUAL, 0.0f); + break; + case PF_Fog & PF_Fog: + pglAlphaFunc(GL_ALWAYS, 0.0f); // Don't discard zero alpha fragments + break; + default: + pglAlphaFunc(GL_GREATER, 0.5f); + break; + } +} -// -----------------+ -// SetBlend : Set render mode -// -----------------+ -// PF_Masked - we could use an ALPHA_TEST of GL_EQUAL, and alpha ref of 0, -// is it faster when pixels are discarded ? EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) { FBITFIELD Xor; Xor = CurrentPolyFlags^PolyFlags; - if (Xor & (PF_Blending|PF_RemoveYWrap|PF_ForceWrapX|PF_ForceWrapY|PF_Occlude|PF_NoTexture|PF_Modulated|PF_NoDepthTest|PF_Decal|PF_Invisible|PF_NoAlphaTest)) + if (Xor & (PF_Blending|PF_RemoveYWrap|PF_ForceWrapX|PF_ForceWrapY|PF_Occlude|PF_NoTexture|PF_Modulated|PF_NoDepthTest|PF_Decal|PF_Invisible)) { - if (Xor&(PF_Blending)) // if blending mode must be changed - { - switch (PolyFlags & PF_Blending) { - case PF_Translucent & PF_Blending: - pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Masked & PF_Blending: - // Hurdler: does that mean lighting is only made by alpha src? - // it sounds ok, but not for polygonsmooth - pglBlendFunc(GL_SRC_ALPHA, GL_ZERO); // 0 alpha = holes in texture - pglAlphaFunc(GL_GREATER, 0.5f); - break; - case PF_Additive & PF_Blending: - pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Environment & PF_Blending: - pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Substractive & PF_Blending: - // good for shadow - // not really but what else ? - pglBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Fog & PF_Fog: - // Sryder: Fog - // multiplies input colour by input alpha, and destination colour by input colour, then adds them - pglBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR); - pglAlphaFunc(GL_ALWAYS, 0.0f); // Don't discard zero alpha fragments - break; - default : // must be 0, otherwise it's an error - // No blending - pglBlendFunc(GL_ONE, GL_ZERO); // the same as no blending - pglAlphaFunc(GL_GREATER, 0.5f); - break; - } - } + if (Xor & PF_Blending) // if blending mode must be changed + SetBlendMode(PolyFlags & PF_Blending); + if (Xor & PF_NoAlphaTest) { if (PolyFlags & PF_NoAlphaTest) @@ -1567,7 +1639,7 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) pglDisable(GL_POLYGON_OFFSET_FILL); } - if (Xor&PF_NoDepthTest) + if (Xor & PF_NoDepthTest) { if (PolyFlags & PF_NoDepthTest) pglDepthFunc(GL_ALWAYS); //pglDisable(GL_DEPTH_TEST); @@ -1575,25 +1647,25 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) pglDepthFunc(GL_LEQUAL); //pglEnable(GL_DEPTH_TEST); } - if (Xor&PF_RemoveYWrap) + if (Xor & PF_RemoveYWrap) { if (PolyFlags & PF_RemoveYWrap) Clamp2D(GL_TEXTURE_WRAP_T); } - if (Xor&PF_ForceWrapX) + if (Xor & PF_ForceWrapX) { if (PolyFlags & PF_ForceWrapX) pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); } - if (Xor&PF_ForceWrapY) + if (Xor & PF_ForceWrapY) { if (PolyFlags & PF_ForceWrapY) pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } - if (Xor&PF_Modulated) + if (Xor & PF_Modulated) { #if defined (__unix__) || defined (UNIXCOMMON) if (oglflags & GLF_NOTEXENV) @@ -1867,13 +1939,15 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) { UpdateTexture(pTexInfo); pTexInfo->nextmipmap = NULL; + + // insertion at the tail if (gl_cachetail) - { // insertion at the tail + { gl_cachetail->nextmipmap = pTexInfo; gl_cachetail = pTexInfo; } else // initialization of the linked list - gl_cachetail = gl_cachehead = pTexInfo; + gl_cachetail = gl_cachehead = pTexInfo; } } @@ -2569,6 +2643,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 boolean useVBO = true; + FBITFIELD flags; int i; // Because otherwise, scaling the screen negatively vertically breaks the lighting @@ -2636,8 +2711,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 else pglColor4ubv((GLubyte*)&Surface->PolyColor.s); - SetBlend((poly.alpha < 1 ? PF_Translucent : (PF_Masked|PF_Occlude))|PF_Modulated); - tint.red = byte2float[Surface->TintColor.s.red]; tint.green = byte2float[Surface->TintColor.s.green]; tint.blue = byte2float[Surface->TintColor.s.blue]; @@ -2648,6 +2721,13 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 fade.blue = byte2float[Surface->FadeColor.s.blue]; fade.alpha = byte2float[Surface->FadeColor.s.alpha]; + flags = (Surface->PolyFlags | PF_Modulated); + if (Surface->PolyFlags & (PF_Additive|PF_AdditiveSource|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative)) + flags |= PF_Occlude; + else if (Surface->PolyColor.s.alpha == 0xFF) + flags |= (PF_Occlude | PF_Masked); + + SetBlend(flags); Shader_SetUniforms(Surface, &poly, &tint, &fade); pglEnable(GL_CULL_FACE); @@ -3217,7 +3297,7 @@ EXPORT void HWRAPI(DoScreenWipe)(void) pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - SetBlend(PF_Modulated|PF_NoDepthTest|PF_Clip|PF_NoZClip); + SetBlend(PF_Modulated|PF_NoDepthTest); pglEnable(GL_TEXTURE_2D); // Draw the original screen @@ -3227,7 +3307,7 @@ EXPORT void HWRAPI(DoScreenWipe)(void) pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest|PF_Clip|PF_NoZClip); + SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest); // Draw the end screen that fades in pglActiveTexture(GL_TEXTURE0); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 604a509e0d447420ed835e4d22e2def744af78de..7e9144f98fd995ae3b2218f76472f3a92792db56 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1794,8 +1794,8 @@ static void HU_DrawChat_Old(void) size_t i = 0; const char *ntalk = "Say: ", *ttalk = "Say-Team: "; const char *talk = ntalk; - INT32 charwidth = 8 * con_scalefactor; //SHORT(hu_font['A'-HU_FONTSTART]->width) * con_scalefactor; - INT32 charheight = 8 * con_scalefactor; //SHORT(hu_font['A'-HU_FONTSTART]->height) * con_scalefactor; + INT32 charwidth = 8 * con_scalefactor; //(hu_font['A'-HU_FONTSTART]->width) * con_scalefactor; + INT32 charheight = 8 * con_scalefactor; //(hu_font['A'-HU_FONTSTART]->height) * con_scalefactor; if (teamtalk) { talk = ttalk; @@ -1816,7 +1816,7 @@ static void HU_DrawChat_Old(void) } else { - //charwidth = SHORT(hu_font[talk[i]-HU_FONTSTART]->width) * con_scalefactor; + //charwidth = (hu_font[talk[i]-HU_FONTSTART]->width) * con_scalefactor; V_DrawCharacter(HU_INPUTX + c, y, talk[i++] | cv_constextsize.value | V_NOSCALESTART, true); } c += charwidth; @@ -1844,7 +1844,7 @@ static void HU_DrawChat_Old(void) } else { - //charwidth = SHORT(hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor; + //charwidth = (hu_font[w_chat[i]-HU_FONTSTART]->width) * con_scalefactor; V_DrawCharacter(HU_INPUTX + c, y, w_chat[i++] | cv_constextsize.value | V_NOSCALESTART | t, true); } @@ -2364,7 +2364,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I } if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED)) - V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon); + V_DrawSmallScaledPatch(x - exiticon->width/2 - 1, y-3, 0, exiticon); if (gametyperankings[gametype] == GT_RACE) { @@ -2668,7 +2668,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline V_DrawSmallScaledPatch(x-28, y-4, 0, tagico); if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED)) - V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon); + V_DrawSmallScaledPatch(x - exiticon->width/2 - 1, y-3, 0, exiticon); // Draw emeralds if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1)) @@ -3094,7 +3094,7 @@ static void HU_DrawCoopOverlay(void) if (LUA_HudEnabled(hud_tabemblems) && (!modifiedgame || savemoddata)) { V_DrawString(160, 144, 0, va("- %d/%d", M_CountEmblems(), numemblems+numextraemblems)); - V_DrawScaledPatch(128, 144 - SHORT(emblemicon->height)/4, 0, emblemicon); + V_DrawScaledPatch(128, 144 - emblemicon->height/4, 0, emblemicon); } if (!LUA_HudEnabled(hud_coopemeralds)) diff --git a/src/i_sound.h b/src/i_sound.h index a2249a10273fa48c95650a75fa692b84d4de37d8..d45c0b323ef4ca34ea936e49b8e598471eb9d290 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -21,15 +21,12 @@ // copied from SDL mixer, plus GME typedef enum { MU_NONE, - MU_CMD, MU_WAV, MU_MOD, MU_MID, MU_OGG, MU_MP3, - MU_MP3_MAD_UNUSED, // use MU_MP3 instead MU_FLAC, - MU_MODPLUG_UNUSED, // use MU_MOD instead MU_GME, MU_MOD_EX, // libopenmpt MU_MID_EX // Non-native MIDI diff --git a/src/i_video.h b/src/i_video.h index 98ed7f38a18822d8038ec0973ef3c680572c2d89..ab48881d4405036b515ff65988a81bab89e7236a 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -36,10 +36,9 @@ typedef enum */ extern rendermode_t rendermode; -/** \brief OpenGL state - 0 = never loaded, 1 = loaded successfully, -1 = failed loading +/** \brief render mode set by command line arguments */ -extern INT32 vid_opengl_state; +extern rendermode_t chosenrendermode; /** \brief use highcolor modes if true */ @@ -90,8 +89,9 @@ INT32 VID_GetModeForSize(INT32 w, INT32 h); INT32 VID_SetMode(INT32 modenum); /** \brief Checks the render state + \return true if the renderer changed */ -void VID_CheckRenderer(void); +boolean VID_CheckRenderer(void); /** \brief Load OpenGL mode */ diff --git a/src/info.h b/src/info.h index d84461617c41ec2cc93a774da39e1dc8c09cc376..604922bebff2190e3c09296c5fff11772ba3b3e7 100644 --- a/src/info.h +++ b/src/info.h @@ -19,11 +19,279 @@ #include "sounds.h" #include "m_fixed.h" -// dehacked.c now has lists for the more named enums! PLEASE keep them up to date! +// deh_tables.c now has lists for the more named enums! PLEASE keep them up to date! // For great modding!! +// IMPORTANT! +// DO NOT FORGET TO SYNC THIS LIST WITH THE ACTIONPOINTERS ARRAY IN DEH_TABLES.C +enum actionnum +{ + A_EXPLODE = 0, + A_PAIN, + A_FALL, + A_MONITORPOP, + A_GOLDMONITORPOP, + A_GOLDMONITORRESTORE, + A_GOLDMONITORSPARKLE, + A_LOOK, + A_CHASE, + A_FACESTABCHASE, + A_FACESTABREV, + A_FACESTABHURL, + A_FACESTABMISS, + A_STATUEBURST, + A_FACETARGET, + A_FACETRACER, + A_SCREAM, + A_BOSSDEATH, + A_CUSTOMPOWER, + A_GIVEWEAPON, + A_RINGBOX, + A_INVINCIBILITY, + A_SUPERSNEAKERS, + A_BUNNYHOP, + A_BUBBLESPAWN, + A_FANBUBBLESPAWN, + A_BUBBLERISE, + A_BUBBLECHECK, + A_AWARDSCORE, + A_EXTRALIFE, + A_GIVESHIELD, + A_GRAVITYBOX, + A_SCORERISE, + A_ATTRACTCHASE, + A_DROPMINE, + A_FISHJUMP, + A_THROWNRING, + A_SETSOLIDSTEAM, + A_UNSETSOLIDSTEAM, + A_SIGNSPIN, + A_SIGNPLAYER, + A_OVERLAYTHINK, + A_JETCHASE, + A_JETBTHINK, + A_JETGTHINK, + A_JETGSHOOT, + A_SHOOTBULLET, + A_MINUSDIGGING, + A_MINUSPOPUP, + A_MINUSCHECK, + A_CHICKENCHECK, + A_MOUSETHINK, + A_DETONCHASE, + A_CAPECHASE, + A_ROTATESPIKEBALL, + A_SLINGAPPEAR, + A_UNIDUSBALL, + A_ROCKSPAWN, + A_SETFUSE, + A_CRAWLACOMMANDERTHINK, + A_SMOKETRAILER, + A_RINGEXPLODE, + A_OLDRINGEXPLODE, + A_MIXUP, + A_RECYCLEPOWERS, + A_BOSS1CHASE, + A_FOCUSTARGET, + A_BOSS2CHASE, + A_BOSS2POGO, + A_BOSSZOOM, + A_BOSSSCREAM, + A_BOSS2TAKEDAMAGE, + A_BOSS7CHASE, + A_GOOPSPLAT, + A_BOSS2POGOSFX, + A_BOSS2POGOTARGET, + A_BOSSJETFUME, + A_EGGMANBOX, + A_TURRETFIRE, + A_SUPERTURRETFIRE, + A_TURRETSTOP, + A_JETJAWROAM, + A_JETJAWCHOMP, + A_POINTYTHINK, + A_CHECKBUDDY, + A_HOODFIRE, + A_HOODTHINK, + A_HOODFALL, + A_ARROWBONKS, + A_SNAILERTHINK, + A_SHARPCHASE, + A_SHARPSPIN, + A_SHARPDECEL, + A_CRUSHSTACEANWALK, + A_CRUSHSTACEANPUNCH, + A_CRUSHCLAWAIM, + A_CRUSHCLAWLAUNCH, + A_VULTUREVTOL, + A_VULTURECHECK, + A_VULTUREHOVER, + A_VULTUREBLAST, + A_VULTUREFLY, + A_SKIMCHASE, + A_1UPTHINKER, + A_SKULLATTACK, + A_LOBSHOT, + A_FIRESHOT, + A_SUPERFIRESHOT, + A_BOSSFIRESHOT, + A_BOSS7FIREMISSILES, + A_BOSS1LASER, + A_BOSS4REVERSE, + A_BOSS4SPEEDUP, + A_BOSS4RAISE, + A_SPARKFOLLOW, + A_BUZZFLY, + A_GUARDCHASE, + A_EGGSHIELD, + A_SETREACTIONTIME, + A_BOSS1SPIKEBALLS, + A_BOSS3TAKEDAMAGE, + A_BOSS3PATH, + A_BOSS3SHOCKTHINK, + A_LINEDEFEXECUTE, + A_PLAYSEESOUND, + A_PLAYATTACKSOUND, + A_PLAYACTIVESOUND, + A_SPAWNOBJECTABSOLUTE, + A_SPAWNOBJECTRELATIVE, + A_CHANGEANGLERELATIVE, + A_CHANGEANGLEABSOLUTE, + A_ROLLANGLE, + A_CHANGEROLLANGLERELATIVE, + A_CHANGEROLLANGLEABSOLUTE, + A_PLAYSOUND, + A_FINDTARGET, + A_FINDTRACER, + A_SETTICS, + A_SETRANDOMTICS, + A_CHANGECOLORRELATIVE, + A_CHANGECOLORABSOLUTE, + A_DYE, + A_MOVERELATIVE, + A_MOVEABSOLUTE, + A_THRUST, + A_ZTHRUST, + A_SETTARGETSTARGET, + A_SETOBJECTFLAGS, + A_SETOBJECTFLAGS2, + A_RANDOMSTATE, + A_RANDOMSTATERANGE, + A_DUALACTION, + A_REMOTEACTION, + A_TOGGLEFLAMEJET, + A_ORBITNIGHTS, + A_GHOSTME, + A_SETOBJECTSTATE, + A_SETOBJECTTYPESTATE, + A_KNOCKBACK, + A_PUSHAWAY, + A_RINGDRAIN, + A_SPLITSHOT, + A_MISSILESPLIT, + A_MULTISHOT, + A_INSTALOOP, + A_CUSTOM3DROTATE, + A_SEARCHFORPLAYERS, + A_CHECKRANDOM, + A_CHECKTARGETRINGS, + A_CHECKRINGS, + A_CHECKTOTALRINGS, + A_CHECKHEALTH, + A_CHECKRANGE, + A_CHECKHEIGHT, + A_CHECKTRUERANGE, + A_CHECKTHINGCOUNT, + A_CHECKAMBUSH, + A_CHECKCUSTOMVALUE, + A_CHECKCUSVALMEMO, + A_SETCUSTOMVALUE, + A_USECUSVALMEMO, + A_RELAYCUSTOMVALUE, + A_CUSVALACTION, + A_FORCESTOP, + A_FORCEWIN, + A_SPIKERETRACT, + A_INFOSTATE, + A_REPEAT, + A_SETSCALE, + A_REMOTEDAMAGE, + A_HOMINGCHASE, + A_TRAPSHOT, + A_VILETARGET, + A_VILEATTACK, + A_VILEFIRE, + A_BRAKCHASE, + A_BRAKFIRESHOT, + A_BRAKLOBSHOT, + A_NAPALMSCATTER, + A_SPAWNFRESHCOPY, + A_FLICKYSPAWN, + A_FLICKYCENTER, + A_FLICKYAIM, + A_FLICKYFLY, + A_FLICKYSOAR, + A_FLICKYCOAST, + A_FLICKYHOP, + A_FLICKYFLOUNDER, + A_FLICKYCHECK, + A_FLICKYHEIGHTCHECK, + A_FLICKYFLUTTER, + A_FLAMEPARTICLE, + A_FADEOVERLAY, + A_BOSS5JUMP, + A_LIGHTBEAMRESET, + A_MINEEXPLODE, + A_MINERANGE, + A_CONNECTTOGROUND, + A_SPAWNPARTICLERELATIVE, + A_MULTISHOTDIST, + A_WHOCARESIFYOURSONISABEE, + A_PARENTTRIESTOSLEEP, + A_CRYINGTOMOMMA, + A_CHECKFLAGS2, + A_BOSS5FINDWAYPOINT, + A_DONPCSKID, + A_DONPCPAIN, + A_PREPAREREPEAT, + A_BOSS5EXTRAREPEAT, + A_BOSS5CALM, + A_BOSS5CHECKONGROUND, + A_BOSS5CHECKFALLING, + A_BOSS5PINCHSHOT, + A_BOSS5MAKEITRAIN, + A_BOSS5MAKEJUNK, + A_LOOKFORBETTER, + A_BOSS5BOMBEXPLODE, + A_DUSTDEVILTHINK, + A_TNTEXPLODE, + A_DEBRISRANDOM, + A_TRAINCAMEO, + A_TRAINCAMEO2, + A_CANARIVOREGAS, + A_KILLSEGMENTS, + A_SNAPPERSPAWN, + A_SNAPPERTHINKER, + A_SALOONDOORSPAWN, + A_MINECARTSPARKTHINK, + A_MODULOTOSTATE, + A_LAVAFALLROCKS, + A_LAVAFALLLAVA, + A_FALLINGLAVACHECK, + A_FIRESHRINK, + A_SPAWNPTERABYTES, + A_PTERABYTEHOVER, + A_ROLLOUTSPAWN, + A_ROLLOUTROCK, + A_DRAGONBOMBERSPAWN, + A_DRAGONWING, + A_DRAGONSEGMENT, + A_CHANGEHEIGHT, + NUMACTIONS +}; + // IMPORTANT NOTE: If you add/remove from this list of action -// functions, don't forget to update them in dehacked.c! +// functions, don't forget to update them in deh_tables.c! void A_Explode(); void A_Pain(); void A_Fall(); @@ -286,6 +554,8 @@ void A_DragonWing(); void A_DragonSegment(); void A_ChangeHeight(); +extern boolean actionsoverridden[NUMACTIONS]; + // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 512 #define NUMSPRITEFREESLOTS NUMMOBJFREESLOTS diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 1295cbf4ed004225923e0a5c3e8abc5db4ecbe82..4667fdbf4a7549ae226075ff8d5f09feeb9cc05f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -966,6 +966,28 @@ static int lib_pMaceRotate(lua_State *L) return 0; } +static int lib_pCreateFloorSpriteSlope(lua_State *L) +{ + mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + NOHUD + INLEVEL + if (!mobj) + return LUA_ErrInvalid(L, "mobj_t"); + LUA_PushUserdata(L, (pslope_t *)P_CreateFloorSpriteSlope(mobj), META_SLOPE); + return 1; +} + +static int lib_pRemoveFloorSpriteSlope(lua_State *L) +{ + mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + NOHUD + INLEVEL + if (!mobj) + return LUA_ErrInvalid(L, "mobj_t"); + P_RemoveFloorSpriteSlope(mobj); + return 1; +} + static int lib_pRailThinker(lua_State *L) { mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -3057,6 +3079,185 @@ static int lib_sStartMusicCaption(lua_State *L) return 0; } +static int lib_sMusicType(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushinteger(L, S_MusicType()); + else + lua_pushnil(L); + return 1; +} + +static int lib_sMusicPlaying(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushboolean(L, S_MusicPlaying()); + else + lua_pushnil(L); + return 1; +} + +static int lib_sMusicPaused(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushboolean(L, S_MusicPaused()); + else + lua_pushnil(L); + return 1; +} + +static int lib_sMusicName(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushstring(L, S_MusicName()); + else + lua_pushnil(L); + return 1; +} + +static int lib_sMusicExists(lua_State *L) +{ + boolean checkMIDI = lua_opttrueboolean(L, 2); + boolean checkDigi = lua_opttrueboolean(L, 3); +#ifdef MUSICSLOT_COMPATIBILITY + const char *music_name; + UINT32 music_num; + char music_compat_name[7]; + UINT16 music_flags = 0; + NOHUD + if (lua_isnumber(L, 1)) + { + music_num = (UINT32)luaL_checkinteger(L, 1); + music_flags = (UINT16)(music_num & 0x0000FFFF); + if (music_flags && music_flags <= 1035) + snprintf(music_compat_name, 7, "%sM", G_BuildMapName((INT32)music_flags)); + else if (music_flags && music_flags <= 1050) + strncpy(music_compat_name, compat_special_music_slots[music_flags - 1036], 7); + else + music_compat_name[0] = 0; // becomes empty string + music_compat_name[6] = 0; + music_name = (const char *)&music_compat_name; + } + else + { + music_num = 0; + music_name = luaL_checkstring(L, 1); + } +#else + const char *music_name = luaL_checkstring(L, 1); +#endif + NOHUD + lua_pushboolean(L, S_MusicExists(music_name, checkMIDI, checkDigi)); + return 1; +} + +static int lib_sSetMusicLoopPoint(lua_State *L) +{ + UINT32 looppoint = (UINT32)luaL_checkinteger(L, 1); + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + { + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushboolean(L, S_SetMusicLoopPoint(looppoint)); + else + lua_pushnil(L); + return 1; +} + +static int lib_sGetMusicLoopPoint(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushinteger(L, (int)S_GetMusicLoopPoint()); + else + lua_pushnil(L); + return 1; +} + +static int lib_sPauseMusic(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + { + S_PauseAudio(); + lua_pushboolean(L, true); + } + else + lua_pushnil(L); + return 1; +} + +static int lib_sResumeMusic(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + { + S_ResumeAudio(); + lua_pushboolean(L, true); + } + else + lua_pushnil(L); + return 1; +} + // G_GAME //////////// @@ -3606,6 +3807,8 @@ static luaL_Reg lib[] = { {"P_CheckSolidLava",lib_pCheckSolidLava}, {"P_CanRunOnWater",lib_pCanRunOnWater}, {"P_MaceRotate",lib_pMaceRotate}, + {"P_CreateFloorSpriteSlope",lib_pCreateFloorSpriteSlope}, + {"P_RemoveFloorSpriteSlope",lib_pRemoveFloorSpriteSlope}, {"P_RailThinker",lib_pRailThinker}, {"P_XYMovement",lib_pXYMovement}, {"P_RingXYMovement",lib_pRingXYMovement}, @@ -3765,6 +3968,15 @@ static luaL_Reg lib[] = { {"S_IdPlaying",lib_sIdPlaying}, {"S_SoundPlaying",lib_sSoundPlaying}, {"S_StartMusicCaption", lib_sStartMusicCaption}, + {"S_MusicType",lib_sMusicType}, + {"S_MusicPlaying",lib_sMusicPlaying}, + {"S_MusicPaused",lib_sMusicPaused}, + {"S_MusicName",lib_sMusicName}, + {"S_MusicExists",lib_sMusicExists}, + {"S_SetMusicLoopPoint",lib_sSetMusicLoopPoint}, + {"S_GetMusicLoopPoint",lib_sGetMusicLoopPoint}, + {"S_PauseMusic",lib_sPauseMusic}, + {"S_ResumeMusic", lib_sResumeMusic}, // g_game {"G_AddGametype", lib_gAddGametype}, diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index c6b082930385d3edd4762d846532028be1c9ade1..84bfeaee2c07dbbae2257b083635eb9bb39e94fb 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -40,6 +40,10 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum) // like sending random junk lua commands to crash the server if (!gL) goto deny; + + lua_settop(gL, 0); // Just in case... + lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command if (!lua_istable(gL, -1)) goto deny; @@ -76,7 +80,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum) READSTRINGN(*cp, buf, 255); lua_pushstring(gL, buf); } - LUA_Call(gL, (int)argc); // argc is 1-based, so this will cover the player we passed too. + LUA_Call(gL, (int)argc, 0, 1); // argc is 1-based, so this will cover the player we passed too. return; deny: @@ -98,6 +102,10 @@ void COM_Lua_f(void) INT32 playernum = consoleplayer; I_Assert(gL != NULL); + + lua_settop(gL, 0); // Just in case... + lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command I_Assert(lua_istable(gL, -1)); @@ -167,7 +175,7 @@ void COM_Lua_f(void) LUA_PushUserdata(gL, &players[playernum], META_PLAYER); for (i = 1; i < COM_Argc(); i++) lua_pushstring(gL, COM_Argv(i)); - LUA_Call(gL, (int)COM_Argc()); // COM_Argc is 1-based, so this will cover the player we passed too. + LUA_Call(gL, (int)COM_Argc(), 0, 1); // COM_Argc is 1-based, so this will cover the player we passed too. } // Wrapper for COM_AddCommand @@ -277,6 +285,9 @@ static void Lua_OnChange(void) /// \todo Network this! XD_LUAVAR + lua_settop(gL, 0); // Just in case... + lua_pushcfunction(gL, LUA_GetErrorMessage); + // From CV_OnChange registry field, get the function for this cvar by name. lua_getfield(gL, LUA_REGISTRYINDEX, "CV_OnChange"); I_Assert(lua_istable(gL, -1)); @@ -288,7 +299,7 @@ static void Lua_OnChange(void) lua_getfield(gL, -1, cvname); // get consvar_t* userdata. lua_remove(gL, -2); // pop the CV_Vars table. - LUA_Call(gL, 1); // call function(cvar) + LUA_Call(gL, 1, 0, 1); // call function(cvar) lua_pop(gL, 1); // pop CV_OnChange table } @@ -440,6 +451,9 @@ static int CVarSetFunction ){ consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); + if (cvar->flags & CV_NOLUA) + return luaL_error(L, "Variable %s cannot be set from Lua.", cvar->name); + switch (lua_type(L, 2)) { case LUA_TSTRING: @@ -468,7 +482,12 @@ static int lib_cvStealthSet(lua_State *L) static int lib_cvAddValue(lua_State *L) { consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); + + if (cvar->flags & CV_NOLUA) + return luaL_error(L, "Variable %s cannot be set from Lua.", cvar->name); + CV_AddValue(cvar, (INT32)luaL_checknumber(L, 2)); + return 0; } diff --git a/src/lua_hook.h b/src/lua_hook.h index 47850812f059c5825e3f53428c4bbecda4e7a5ef..796f3a9d287dcf0e3997d6963949b33111dceb0d 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -60,6 +60,7 @@ enum hook { hook_ShouldJingleContinue, hook_GameQuit, hook_PlayerCmd, + hook_MusicChange, hook_MAX // last hook }; @@ -118,3 +119,4 @@ boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend); // Hook for MT_ boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname); // Hook for whether a jingle of the given music should continue playing void LUAh_GameQuit(void); // Hook for game quitting boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Hook for building player's ticcmd struct (Ported from SRB2Kart) +boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boolean *looping, UINT32 *position, UINT32 *prefadems, UINT32 *fadeinms); // Hook for music changes \ No newline at end of file diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 65d483dc1a9f1518fab22a70adde2bc78aa20ad3..117aa48a303e7ba7945f2b970cb20d0292cced2a 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -76,6 +76,7 @@ const char *const hookNames[hook_MAX+1] = { "ShouldJingleContinue", "GameQuit", "PlayerCmd", + "MusicChange", NULL }; @@ -1912,3 +1913,62 @@ boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd) hook_cmd_running = false; return hooked; } + +// Hook for music changes +boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boolean *looping, + UINT32 *position, UINT32 *prefadems, UINT32 *fadeinms) +{ + hook_p hookp; + boolean hooked = false; + + if (!gL || !(hooksAvailable[hook_MusicChange/8] & (1<<(hook_MusicChange%8)))) + return false; + + lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_MusicChange) + { + PushHook(gL, hookp); + lua_pushstring(gL, oldname); + lua_pushstring(gL, newname); + lua_pushinteger(gL, *mflags); + lua_pushboolean(gL, *looping); + lua_pushinteger(gL, *position); + lua_pushinteger(gL, *prefadems); + lua_pushinteger(gL, *fadeinms); + if (lua_pcall(gL, 7, 6, 1)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + lua_pop(gL, 1); + continue; + } + + // output 1: true, false, or string musicname override + if (lua_isboolean(gL, -6) && lua_toboolean(gL, -6)) + hooked = true; + else if (lua_isstring(gL, -6)) + strncpy(newname, lua_tostring(gL, -6), 7); + // output 2: mflags override + if (lua_isnumber(gL, -5)) + *mflags = lua_tonumber(gL, -5); + // output 3: looping override + if (lua_isboolean(gL, -4)) + *looping = lua_toboolean(gL, -4); + // output 4: position override + if (lua_isboolean(gL, -3)) + *position = lua_tonumber(gL, -3); + // output 5: prefadems override + if (lua_isboolean(gL, -2)) + *prefadems = lua_tonumber(gL, -2); + // output 6: fadeinms override + if (lua_isboolean(gL, -1)) + *fadeinms = lua_tonumber(gL, -1); + + lua_pop(gL, 7); // Pop returned values and error handler + } + + lua_settop(gL, 0); + newname[6] = 0; + return hooked; +} \ No newline at end of file diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 6b87dc93034060d5af15ff1d7a5687cb3fcb8b12..684e47c381d63dbcd7dee7c376f82ba0777a33a3 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -35,11 +35,6 @@ 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", @@ -292,11 +287,7 @@ 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 invalidated when switching renderers @@ -314,16 +305,16 @@ static int patch_get(lua_State *L) lua_pushboolean(L, patch != NULL); break; case patch_width: - lua_pushinteger(L, SHORT(patch->width)); + lua_pushinteger(L, patch->width); break; case patch_height: - lua_pushinteger(L, SHORT(patch->height)); + lua_pushinteger(L, patch->height); break; case patch_leftoffset: - lua_pushinteger(L, SHORT(patch->leftoffset)); + lua_pushinteger(L, patch->leftoffset); break; case patch_topoffset: - lua_pushinteger(L, SHORT(patch->topoffset)); + lua_pushinteger(L, patch->topoffset); break; } return 1; @@ -403,59 +394,8 @@ 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 - - luapat = patchinfohead; - lumpnum = W_CheckNumForLongName(luaL_checkstring(L, 1)); - if (lumpnum == LUMPERROR) - lumpnum = W_GetNumForLongName("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_CachePatchLongName(luaL_checkstring(L, 1), PU_PATCH), META_PATCH); -#endif return 1; } @@ -518,9 +458,8 @@ static int libd_getSpritePatch(lua_State *L) INT32 rot = R_GetRollAngle(rollangle); if (rot) { - if (!(sprframe->rotsprite.cached & (1<<angle))) - R_CacheRotSprite(i, frame, NULL, sprframe, angle, sprframe->flip & (1<<angle)); - LUA_PushUserdata(L, sprframe->rotsprite.patch[angle][rot], META_PATCH); + patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), true, &spriteinfo[i], rot); + LUA_PushUserdata(L, rotsprite, META_PATCH); lua_pushboolean(L, false); lua_pushboolean(L, true); return 3; @@ -529,7 +468,7 @@ static int libd_getSpritePatch(lua_State *L) #endif // push both the patch and it's "flip" value - LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_PATCH), META_PATCH); + LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_SPRITE), META_PATCH); lua_pushboolean(L, (sprframe->flip & (1<<angle)) != 0); return 2; } @@ -631,9 +570,8 @@ static int libd_getSprite2Patch(lua_State *L) INT32 rot = R_GetRollAngle(rollangle); if (rot) { - if (!(sprframe->rotsprite.cached & (1<<angle))) - R_CacheRotSprite(SPR_PLAY, frame, &skins[i].sprinfo[j], sprframe, angle, sprframe->flip & (1<<angle)); - LUA_PushUserdata(L, sprframe->rotsprite.patch[angle][rot], META_PATCH); + patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), true, &skins[i].sprinfo[j], rot); + LUA_PushUserdata(L, rotsprite, META_PATCH); lua_pushboolean(L, false); lua_pushboolean(L, true); return 3; @@ -642,7 +580,7 @@ static int libd_getSprite2Patch(lua_State *L) #endif // push both the patch and it's "flip" value - LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_PATCH), META_PATCH); + LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_SPRITE), META_PATCH); lua_pushboolean(L, (sprframe->flip & (1<<angle)) != 0); return 2; } @@ -651,22 +589,14 @@ static int libd_draw(lua_State *L) { INT32 x, y, flags; patch_t *patch; -#ifdef LUA_PATCH_SAFETY - patchinfo_t *luapat; -#endif const UINT8 *colormap = NULL; HUDONLY x = luaL_checkinteger(L, 1); y = luaL_checkinteger(L, 2); -#ifdef LUA_PATCH_SAFETY - luapat = *((patchinfo_t **)luaL_checkudata(L, 3, META_PATCH)); - patch = W_CachePatchNum((luapat->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)); @@ -682,9 +612,6 @@ 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 @@ -693,14 +620,9 @@ 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)); @@ -1261,10 +1183,6 @@ 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); @@ -1343,7 +1261,9 @@ void LUAh_GameHUD(player_t *stplayr) return; hud_running = true; - lua_pop(gL, -1); + lua_settop(gL, 0); + + lua_pushcfunction(gL, LUA_GetErrorMessage); lua_getfield(gL, LUA_REGISTRYINDEX, "HUD"); I_Assert(lua_istable(gL, -1)); @@ -1365,9 +1285,9 @@ void LUAh_GameHUD(player_t *stplayr) lua_pushvalue(gL, -5); // graphics library (HUD[1]) lua_pushvalue(gL, -5); // stplayr lua_pushvalue(gL, -5); // camera - LUA_Call(gL, 3); + LUA_Call(gL, 3, 0, 1); } - lua_pop(gL, -1); + lua_settop(gL, 0); hud_running = false; } @@ -1377,7 +1297,9 @@ void LUAh_ScoresHUD(void) return; hud_running = true; - lua_pop(gL, -1); + lua_settop(gL, 0); + + lua_pushcfunction(gL, LUA_GetErrorMessage); lua_getfield(gL, LUA_REGISTRYINDEX, "HUD"); I_Assert(lua_istable(gL, -1)); @@ -1390,9 +1312,9 @@ void LUAh_ScoresHUD(void) lua_pushnil(gL); while (lua_next(gL, -3) != 0) { lua_pushvalue(gL, -3); // graphics library (HUD[1]) - LUA_Call(gL, 1); + LUA_Call(gL, 1, 0, 1); } - lua_pop(gL, -1); + lua_settop(gL, 0); hud_running = false; } @@ -1402,7 +1324,9 @@ void LUAh_TitleHUD(void) return; hud_running = true; - lua_pop(gL, -1); + lua_settop(gL, 0); + + lua_pushcfunction(gL, LUA_GetErrorMessage); lua_getfield(gL, LUA_REGISTRYINDEX, "HUD"); I_Assert(lua_istable(gL, -1)); @@ -1415,9 +1339,9 @@ void LUAh_TitleHUD(void) lua_pushnil(gL); while (lua_next(gL, -3) != 0) { lua_pushvalue(gL, -3); // graphics library (HUD[1]) - LUA_Call(gL, 1); + LUA_Call(gL, 1, 0, 1); } - lua_pop(gL, -1); + lua_settop(gL, 0); hud_running = false; } @@ -1427,7 +1351,9 @@ void LUAh_TitleCardHUD(player_t *stplayr) return; hud_running = true; - lua_pop(gL, -1); + lua_settop(gL, 0); + + lua_pushcfunction(gL, LUA_GetErrorMessage); lua_getfield(gL, LUA_REGISTRYINDEX, "HUD"); I_Assert(lua_istable(gL, -1)); @@ -1448,10 +1374,10 @@ void LUAh_TitleCardHUD(player_t *stplayr) lua_pushvalue(gL, -6); // stplayr lua_pushvalue(gL, -6); // lt_ticker lua_pushvalue(gL, -6); // lt_endtime - LUA_Call(gL, 4); + LUA_Call(gL, 4, 0, 1); } - lua_pop(gL, -1); + lua_settop(gL, 0); hud_running = false; } @@ -1461,7 +1387,9 @@ void LUAh_IntermissionHUD(void) return; hud_running = true; - lua_pop(gL, -1); + lua_settop(gL, 0); + + lua_pushcfunction(gL, LUA_GetErrorMessage); lua_getfield(gL, LUA_REGISTRYINDEX, "HUD"); I_Assert(lua_istable(gL, -1)); @@ -1474,8 +1402,8 @@ void LUAh_IntermissionHUD(void) lua_pushnil(gL); while (lua_next(gL, -3) != 0) { lua_pushvalue(gL, -3); // graphics library (HUD[1]) - LUA_Call(gL, 1); + LUA_Call(gL, 1, 0, 1); } - lua_pop(gL, -1); + lua_settop(gL, 0); hud_running = false; } diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 5e5a1dbc4029ba27f338c525340570e2b9141c7a..4c6ef35287500d973d85af6d76412a0f4bc12202 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -14,9 +14,12 @@ #include "fastcmp.h" #include "info.h" #include "dehacked.h" +#include "deh_tables.h" +#include "deh_lua.h" #include "p_mobj.h" #include "p_local.h" #include "z_zone.h" +#include "r_patch.h" #include "r_picformats.h" #include "r_things.h" #include "r_draw.h" // R_GetColorByName @@ -30,7 +33,7 @@ extern CV_PossibleValue_t Color_cons_t[]; extern UINT8 skincolor_modified[]; -boolean LUA_CallAction(const char *action, mobj_t *actor); +boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor); state_t *astate; enum sfxinfo_read { @@ -63,6 +66,8 @@ const char *const sfxinfo_wopt[] = { "caption", NULL}; +boolean actionsoverridden[NUMACTIONS] = {false}; + // // Sprite Names // @@ -375,17 +380,13 @@ static int lib_setSpriteInfo(lua_State *L) if (hud_running) return luaL_error(L, "Do not alter spriteinfo_t in HUD rendering code!"); if (hook_cmd_running) - return luaL_error(L, "Do not alter spriteinfo_t in CMD building code!"); + return luaL_error(L, "Do not alter spriteinfo_t in CMD building code!"); lua_remove(L, 1); { UINT32 i = luaL_checkinteger(L, 1); if (i == 0 || i >= NUMSPRITES) return luaL_error(L, "spriteinfo[] index %d out of range (1 - %d)", i, NUMSPRITES-1); -#ifdef ROTSPRITE - if (sprites != NULL) - R_FreeSingleRotSprite(&sprites[i]); -#endif info = &spriteinfo[i]; // get the spriteinfo to assign to. } luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table. @@ -469,11 +470,6 @@ static int spriteinfo_set(lua_State *L) lua_remove(L, 1); // remove field lua_settop(L, 1); // leave only one value -#ifdef ROTSPRITE - if (sprites != NULL) - R_FreeSingleRotSprite(&sprites[sprinfo-spriteinfo]); -#endif - if (fastcmp(field, "pivot")) { // pivot[] is a table @@ -630,6 +626,9 @@ static void A_Lua(mobj_t *actor) boolean found = false; I_Assert(actor != NULL); + lua_settop(gL, 0); // Just in case... + lua_pushcfunction(gL, LUA_GetErrorMessage); + // get the action for this state lua_getfield(gL, LUA_REGISTRYINDEX, LREG_STATEACTION); I_Assert(lua_istable(gL, -1)); @@ -658,7 +657,7 @@ static void A_Lua(mobj_t *actor) LUA_PushUserdata(gL, actor, META_MOBJ); lua_pushinteger(gL, var1); lua_pushinteger(gL, var2); - LUA_Call(gL, 3); + LUA_Call(gL, 3, 0, 1); if (found) { @@ -813,36 +812,33 @@ boolean LUA_SetLuaAction(void *stv, const char *action) return true; // action successfully set. } -boolean LUA_CallAction(const char *csaction, mobj_t *actor) +boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor) { - I_Assert(csaction != NULL); I_Assert(actor != NULL); - if (!gL) // Lua isn't loaded, + if (!actionsoverridden[actionnum]) // The action is not overriden, return false; // action not called. - if (superstack && fasticmp(csaction, superactions[superstack-1])) // the action is calling itself, + if (superstack && fasticmp(actionpointers[actionnum].name, superactions[superstack-1])) // the action is calling itself, return false; // let it call the hardcoded function instead. + lua_pushcfunction(gL, LUA_GetErrorMessage); + // grab function by uppercase name. lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); - { - char *action = Z_StrDup(csaction); - strupr(action); - lua_getfield(gL, -1, action); - Z_Free(action); - } + lua_getfield(gL, -1, actionpointers[actionnum].name); lua_remove(gL, -2); // pop LREG_ACTIONS if (lua_isnil(gL, -1)) // no match { - lua_pop(gL, 1); // pop nil + lua_pop(gL, 2); // pop nil and error handler return false; // action not called. } if (superstack == MAXRECURSION) { CONS_Alert(CONS_WARNING, "Max Lua Action recursion reached! Cool it on the calling A_Action functions from inside A_Action functions!\n"); + lua_pop(gL, 2); // pop function and error handler return true; } @@ -853,10 +849,11 @@ boolean LUA_CallAction(const char *csaction, mobj_t *actor) lua_pushinteger(gL, var1); lua_pushinteger(gL, var2); - superactions[superstack] = csaction; + superactions[superstack] = actionpointers[actionnum].name; ++superstack; - LUA_Call(gL, 3); + LUA_Call(gL, 3, 0, -(2 + 3)); + lua_pop(gL, -1); // Error handler --superstack; superactions[superstack] = NULL; diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 824e9df6ba938b3a0dbe769eb040f172f15c59a0..7aae18c90a31f43dd43fefc6e33c6085003d20af 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -39,6 +39,11 @@ enum mobj_e { mobj_frame, mobj_sprite2, mobj_anim_duration, + mobj_spritexscale, + mobj_spriteyscale, + mobj_spritexoffset, + mobj_spriteyoffset, + mobj_floorspriteslope, mobj_touching_sectorlist, mobj_subsector, mobj_floorz, @@ -56,8 +61,10 @@ enum mobj_e { mobj_flags, mobj_flags2, mobj_eflags, + mobj_renderflags, mobj_skin, mobj_color, + mobj_blendmode, mobj_bnext, mobj_bprev, mobj_hnext, @@ -108,6 +115,11 @@ static const char *const mobj_opt[] = { "frame", "sprite2", "anim_duration", + "spritexscale", + "spriteyscale", + "spritexoffset", + "spriteyoffset", + "floorspriteslope", "touching_sectorlist", "subsector", "floorz", @@ -125,8 +137,10 @@ static const char *const mobj_opt[] = { "flags", "flags2", "eflags", + "renderflags", "skin", "color", + "blendmode", "bnext", "bprev", "hnext", @@ -227,6 +241,21 @@ static int mobj_get(lua_State *L) case mobj_anim_duration: lua_pushinteger(L, mo->anim_duration); break; + case mobj_spritexscale: + lua_pushfixed(L, mo->spritexscale); + break; + case mobj_spriteyscale: + lua_pushfixed(L, mo->spriteyscale); + break; + case mobj_spritexoffset: + lua_pushfixed(L, mo->spritexoffset); + break; + case mobj_spriteyoffset: + lua_pushfixed(L, mo->spriteyoffset); + break; + case mobj_floorspriteslope: + LUA_PushUserdata(L, mo->floorspriteslope, META_SLOPE); + break; case mobj_touching_sectorlist: return UNIMPLEMENTED; case mobj_subsector: @@ -277,6 +306,9 @@ static int mobj_get(lua_State *L) case mobj_eflags: lua_pushinteger(L, mo->eflags); break; + case mobj_renderflags: + lua_pushinteger(L, mo->renderflags); + break; case mobj_skin: // skin name or nil, not struct if (!mo->skin) return 0; @@ -285,6 +317,9 @@ static int mobj_get(lua_State *L) case mobj_color: lua_pushinteger(L, mo->color); break; + case mobj_blendmode: + lua_pushinteger(L, mo->blendmode); + break; case mobj_bnext: LUA_PushUserdata(L, mo->bnext, META_MOBJ); break; @@ -492,6 +527,20 @@ static int mobj_set(lua_State *L) case mobj_anim_duration: mo->anim_duration = (UINT16)luaL_checkinteger(L, 3); break; + case mobj_spritexscale: + mo->spritexscale = luaL_checkfixed(L, 3); + break; + case mobj_spriteyscale: + mo->spriteyscale = luaL_checkfixed(L, 3); + break; + case mobj_spritexoffset: + mo->spritexoffset = luaL_checkfixed(L, 3); + break; + case mobj_spriteyoffset: + mo->spriteyoffset = luaL_checkfixed(L, 3); + break; + case mobj_floorspriteslope: + return NOSET; case mobj_touching_sectorlist: return UNIMPLEMENTED; case mobj_subsector: @@ -580,6 +629,9 @@ static int mobj_set(lua_State *L) case mobj_eflags: mo->eflags = (UINT32)luaL_checkinteger(L, 3); break; + case mobj_renderflags: + mo->renderflags = (UINT32)luaL_checkinteger(L, 3); + break; case mobj_skin: // set skin by name { INT32 i; @@ -603,6 +655,9 @@ static int mobj_set(lua_State *L) mo->color = newcolor; break; } + case mobj_blendmode: + mo->blendmode = (INT32)luaL_checkinteger(L, 3); + break; case mobj_bnext: return NOSETPOS; case mobj_bprev: diff --git a/src/lua_script.c b/src/lua_script.c index bb022f9ce1b4d52c92b0ebbb11dbf5469ce0ce53..eb4737f7655d018ced5cec7bd83625768b9b8caf 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -13,6 +13,7 @@ #include "doomdef.h" #include "fastcmp.h" #include "dehacked.h" +#include "deh_lua.h" #include "z_zone.h" #include "w_wad.h" #include "p_setup.h" @@ -133,6 +134,19 @@ int LUA_GetErrorMessage(lua_State *L) return 1; } +int LUA_Call(lua_State *L, int nargs, int nresults, int errorhandlerindex) +{ + int err = lua_pcall(L, nargs, nresults, errorhandlerindex); + + if (err) + { + CONS_Alert(CONS_WARNING, "%s\n", lua_tostring(L, -1)); + lua_pop(L, 1); + } + + return err; +} + // Moved here from lib_getenum. int LUA_PushGlobals(lua_State *L, const char *word) { @@ -376,6 +390,44 @@ int LUA_CheckGlobals(lua_State *L, const char *word) redscore = (UINT32)luaL_checkinteger(L, 2); else if (fastcmp(word, "bluescore")) bluescore = (UINT32)luaL_checkinteger(L, 2); + else if (fastcmp(word, "skincolor_redteam")) + skincolor_redteam = (UINT16)luaL_checkinteger(L, 2); + else if (fastcmp(word, "skincolor_blueteam")) + skincolor_blueteam = (UINT16)luaL_checkinteger(L, 2); + else if (fastcmp(word, "skincolor_redring")) + skincolor_redring = (UINT16)luaL_checkinteger(L, 2); + else if (fastcmp(word, "skincolor_bluering")) + skincolor_bluering = (UINT16)luaL_checkinteger(L, 2); + else if (fastcmp(word, "emeralds")) + emeralds = (UINT16)luaL_checkinteger(L, 2); + else if (fastcmp(word, "token")) + token = (UINT32)luaL_checkinteger(L, 2); + else if (fastcmp(word, "gravity")) + gravity = (fixed_t)luaL_checkinteger(L, 2); + else if (fastcmp(word, "stoppedclock")) + stoppedclock = luaL_checkboolean(L, 2); + else if (fastcmp(word, "displayplayer")) + { + player_t *player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + + if (player) + displayplayer = player - players; + } + else if (fastcmp(word, "mapmusname")) + { + size_t strlength; + const char *str = luaL_checklstring(L, 2, &strlength); + + if (strlength > 6) + return luaL_error(L, "string length out of range (maximum 6 characters)"); + + if (strlen(str) < strlength) + return luaL_error(L, "string must not contain embedded zeros!"); + + strncpy(mapmusname, str, strlength); + } + else if (fastcmp(word, "mapmusflags")) + mapmusflags = (UINT16)luaL_checkinteger(L, 2); else return 0; @@ -388,6 +440,7 @@ static int setglobals(lua_State *L) { const char *csname; char *name; + enum actionnum actionnum; lua_remove(L, 1); // we're not gonna be using _G csname = lua_tostring(L, 1); @@ -406,6 +459,10 @@ static int setglobals(lua_State *L) lua_rawset(L, -3); // rawset doesn't trigger this metatable again. // otherwise we would've used setfield, obviously. + actionnum = LUA_GetActionNumByName(name); + if (actionnum < NUMACTIONS) + actionsoverridden[actionnum] = true; + Z_Free(name); return 0; } @@ -437,7 +494,7 @@ static void LUA_ClearState(void) // open base libraries luaL_openlibs(L); - lua_pop(L, -1); + lua_settop(L, 0); // make LREG_VALID table for all pushed userdata cache. lua_newtable(L); @@ -640,7 +697,7 @@ fixed_t LUA_EvalMath(const char *word) *b = '\0'; // eval string. - lua_pop(L, -1); + lua_settop(L, 0); if (luaL_dostring(L, buf)) { p = lua_tostring(L, -1); diff --git a/src/lua_script.h b/src/lua_script.h index 5a3520d11996db85806704f6e88be1d9f8a16f6c..79ba0bb38a5e1aeb6af476fb4c5b01b39aeb63f2 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -40,6 +40,7 @@ void LUA_ClearExtVars(void); extern INT32 lua_lumploading; // is LUA_LoadLump being called? int LUA_GetErrorMessage(lua_State *L); +int LUA_Call(lua_State *L, int nargs, int nresults, int errorhandlerindex); void LUA_LoadLump(UINT16 wad, UINT16 lump, boolean noresults); #ifdef LUA_ALLOW_BYTECODE void LUA_DumpFile(const char *filename); @@ -65,14 +66,6 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc); // Console wrapper void COM_Lua_f(void); -#define LUA_Call(L,a)\ -{\ - if (lua_pcall(L, a, 0, 0)) {\ - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(L,-1));\ - lua_pop(L, 1);\ - }\ -} - #define LUA_ErrInvalid(L, type) luaL_error(L, "accessed " type " doesn't exist anymore, please check 'valid' before using " type "."); // Deprecation warnings diff --git a/src/m_menu.c b/src/m_menu.c index 5860f00ca1a1f4dc5399982f06ccebc21c3d469b..77648f877c7adc9ff2b3b5c4fc9f0be7eb532a05 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -425,7 +425,7 @@ static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}}; consvar_t cv_chooseskin = CVAR_INIT ("chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_cons_t, Nextmap_OnChange); // This gametype list is integral for many different reasons. -// When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h! +// When you add gametypes here, don't forget to update them in deh_tables.c and doomstat.h! CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1]; consvar_t cv_newgametype = CVAR_INIT ("newgametype", "Co-op", CV_HIDEN|CV_CALL, gametype_cons_t, Newgametype_OnChange); @@ -1483,7 +1483,7 @@ static menuitem_t OP_SoundOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "MIDI Music", &cv_gamemidimusic, 36}, {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "MIDI Music Volume", &cv_midimusicvolume, 41}, - + {IT_STRING | IT_CVAR, NULL, "Music Preference", &cv_musicpref, 51}, {IT_HEADER, NULL, "Miscellaneous", NULL, 61}, @@ -2145,15 +2145,20 @@ menu_t OP_PlaystyleDef = { static void M_VideoOptions(INT32 choice) { (void)choice; + + OP_VideoOptionsMenu[op_video_renderer].status = (IT_TRANSTEXT | IT_PAIR); + OP_VideoOptionsMenu[op_video_renderer].patch = "Renderer"; + OP_VideoOptionsMenu[op_video_renderer].text = "Software"; + #ifdef HWRENDER - if (vid_opengl_state == -1) + if (vid.glstate != VID_GL_LIBRARY_ERROR) { - OP_VideoOptionsMenu[op_video_renderer].status = (IT_TRANSTEXT | IT_PAIR); - OP_VideoOptionsMenu[op_video_renderer].patch = "Renderer"; - OP_VideoOptionsMenu[op_video_renderer].text = "Software"; + OP_VideoOptionsMenu[op_video_renderer].status = (IT_STRING | IT_CVAR); + OP_VideoOptionsMenu[op_video_renderer].patch = NULL; + OP_VideoOptionsMenu[op_video_renderer].text = "Renderer"; } - #endif + M_SetupNextMenu(&OP_VideoOptionsDef); } @@ -4026,7 +4031,7 @@ static void M_DrawThermo(INT32 x, INT32 y, consvar_t *cv) cursorlump = W_GetNumForName("M_THERMO"); V_DrawScaledPatch(xx, y, 0, p = W_CachePatchNum(leftlump,PU_PATCH)); - xx += SHORT(p->width) - SHORT(p->leftoffset); + xx += p->width - p->leftoffset; for (i = 0; i < 16; i++) { V_DrawScaledPatch(xx, y, V_WRAPX, W_CachePatchNum(centerlump[i & 1], PU_PATCH)); @@ -4165,7 +4170,7 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_ fixed_t sw, pw; patch = W_CachePatchName("LSSTATIC", PU_PATCH); - pw = SHORT(patch->width) - (sw = w*2); //FixedDiv(w, scale); -- for scale FRACUNIT/2 + pw = patch->width - (sw = w*2); //FixedDiv(w, scale); -- for scale FRACUNIT/2 /*if (pw > 0) -- model code for modders providing weird LSSTATIC { @@ -4262,8 +4267,8 @@ static void M_DrawMenuTitle(void) if (p->height > 24) // title is larger than normal { - INT32 xtitle = (BASEVIDWIDTH - (SHORT(p->width)/2))/2; - INT32 ytitle = (30 - (SHORT(p->height)/2))/2; + INT32 xtitle = (BASEVIDWIDTH - (p->width/2))/2; + INT32 ytitle = (30 - (p->height/2))/2; if (xtitle < 0) xtitle = 0; @@ -4274,8 +4279,8 @@ static void M_DrawMenuTitle(void) } else { - INT32 xtitle = (BASEVIDWIDTH - SHORT(p->width))/2; - INT32 ytitle = (30 - SHORT(p->height))/2; + INT32 xtitle = (BASEVIDWIDTH - p->width)/2; + INT32 ytitle = (30 - p->height)/2; if (xtitle < 0) xtitle = 0; @@ -4311,7 +4316,7 @@ static void M_DrawGenericMenu(void) { patch_t *p; p = W_CachePatchName(currentMenu->menuitems[i].patch, PU_PATCH); - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, y, 0, p); + V_DrawScaledPatch((BASEVIDWIDTH - p->width)/2, y, 0, p); } else { @@ -4842,7 +4847,7 @@ static void M_DrawCenteredMenu(void) { patch_t *p; p = W_CachePatchName(currentMenu->menuitems[i].patch, PU_PATCH); - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, y, 0, p); + V_DrawScaledPatch((BASEVIDWIDTH - p->width)/2, y, 0, p); } else { @@ -5585,9 +5590,6 @@ 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])) { @@ -5619,9 +5621,6 @@ 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])) { @@ -5696,7 +5695,7 @@ static void M_DrawRecordAttackForeground(void) angle_t fa; INT32 i; - INT32 height = (SHORT(fg->height)/2); + INT32 height = (fg->height / 2); INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); for (i = -12; i < (BASEVIDHEIGHT/height) + 12; i++) @@ -5731,9 +5730,9 @@ 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_PATCH); - INT16 w = SHORT(background->width); + INT16 w = background->width; INT32 x = FixedInt(-bgscrollx) % w; - INT32 y = BASEVIDHEIGHT - SHORT(background->height)*2; + INT32 y = BASEVIDHEIGHT - (background->height * 2); if (vid.height != BASEVIDHEIGHT * dupz) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 158); @@ -5758,18 +5757,18 @@ static void M_DrawNightsAttackBackground(void) // top 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); + INT32 backtopwidth = backtopfg->width; + //INT32 backtopheight = backtopfg->height; + INT32 fronttopwidth = fronttopfg->width; + //INT32 fronttopheight = fronttopfg->height; // bottom 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); - INT32 frontbottomheight = SHORT(frontbottomfg->height); + INT32 backbottomwidth = backbottomfg->width; + INT32 backbottomheight = backbottomfg->height; + INT32 frontbottomwidth = frontbottomfg->width; + INT32 frontbottomheight = frontbottomfg->height; // background M_DrawNightsAttackMountains(); @@ -5831,8 +5830,6 @@ static void M_DrawNightsAttackSuperSonic(void) const UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_YELLOW, GTC_CACHE); INT32 timer = (ntsatkdrawtimer/4) % 2; angle_t fa = (FixedAngle(((ntsatkdrawtimer * 4) % 360)<<FRACBITS)>>ANGLETOFINESHIFT) & FINEMASK; - ntssupersonic[0] = W_CachePatchName("NTSSONC1", PU_PATCH); - ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_PATCH); V_DrawFixedPatch(235<<FRACBITS, (120<<FRACBITS) - (8*FINESINE(fa)), FRACUNIT, 0, ntssupersonic[timer], colormap); } @@ -6154,7 +6151,7 @@ static void M_DrawMessageMenu(void) } V_DrawString((BASEVIDWIDTH - V_StringWidth(string, 0))/2,y,V_ALLOWLOWERCASE,string); - y += 8; //SHORT(hu_font[0]->height); + y += 8; //hu_font[0]->height; } } @@ -6176,7 +6173,7 @@ static void M_StopMessage(INT32 choice) static void M_DrawImageDef(void) { // Grr. Need to autodetect for pic_ts. - pic_t *pictest = (pic_t *)W_CachePatchName(currentMenu->menuitems[itemOn].text,PU_CACHE); + pic_t *pictest = (pic_t *)W_CacheLumpName(currentMenu->menuitems[itemOn].text,PU_CACHE); if (!pictest->zero) V_DrawScaledPic(0,0,0,W_GetNumForName(currentMenu->menuitems[itemOn].text)); else @@ -6444,10 +6441,6 @@ 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 @@ -7602,9 +7595,6 @@ 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) { @@ -8252,9 +8242,6 @@ 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; prev_i; i = -(i + ((UINT32)i >> 31))) // draws from outwards in; 2, -2, 1, -1, 0 { prev_i = i; @@ -8958,6 +8945,7 @@ void M_ForceSaveSlotSelected(INT32 sslot) // ================ // CHARACTER SELECT // ================ + static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum) { if (!(description[i].picname[0])) @@ -8978,22 +8966,6 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum) description[i].namepic = W_CachePatchName(description[i].nametag, PU_PATCH); } -static void M_CacheCharacterSelect(void) -{ - INT32 i, skinnum; - - for (i = 0; i < MAXSKINS; 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 UINT8 M_SetupChoosePlayerDirect(INT32 choice) { INT32 skinnum; @@ -9193,16 +9165,13 @@ static void M_DrawSetupChoosePlayerMenu(void) 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); - INT16 fgwidth = SHORT(charfg->width); + INT16 bgheight = charbg->height; + INT16 fgheight = charfg->height; + INT16 bgwidth = charbg->width; + INT16 fgwidth = charfg->width; INT32 x, y; INT32 w = (vid.width/vid.dupx); - if (needpatchrecache) - M_CacheCharacterSelect(); - if (abs(char_scroll) > FRACUNIT) char_scroll -= (char_scroll>>2); else // close enough. @@ -9291,14 +9260,14 @@ static void M_DrawSetupChoosePlayerMenu(void) curoutlinecolor = col = skincolors[charskin->prefcolor].invcolor; txsh = oxsh; - ox = 8 + SHORT((description[char_on].charpic)->width)/2; + ox = 8 + ((description[char_on].charpic)->width)/2; y = my + 144; // cur { x = ox - txsh; if (curpatch) - x -= (SHORT(curpatch->width)/2); + x -= curpatch->width / 2; if (curtext[0] != '\0') { @@ -9331,7 +9300,7 @@ static void M_DrawSetupChoosePlayerMenu(void) x = (ox - txsh) - w; if (prevpatch) - x -= (SHORT(prevpatch->width)/2); + x -= prevpatch->width / 2; if (prevtext[0] != '\0') { @@ -9361,7 +9330,7 @@ static void M_DrawSetupChoosePlayerMenu(void) x = (ox - txsh) + w; if (nextpatch) - x -= (SHORT(nextpatch->width)/2); + x -= nextpatch->width / 2; if (nexttext[0] != '\0') { @@ -9383,7 +9352,7 @@ static void M_DrawSetupChoosePlayerMenu(void) { patch_t *header = W_CachePatchName("M_PICKP", PU_PATCH); INT32 xtitle = 146; - INT32 ytitle = (35 - SHORT(header->height))/2; + INT32 ytitle = (35 - header->height) / 2; V_DrawFixedPatch(xtitle<<FRACBITS, ytitle<<FRACBITS, FRACUNIT/2, 0, header, NULL); } #endif // CHOOSEPLAYER_DRAWHEADER @@ -9849,8 +9818,8 @@ void M_DrawTimeAttackMenu(void) empatch = W_CachePatchName(M_GetEmblemPatch(em, true), PU_PATCH); - empatx = SHORT(empatch->leftoffset)/2; - empaty = SHORT(empatch->topoffset)/2; + empatx = empatch->leftoffset / 2; + empaty = empatch->topoffset / 2; if (em->collected) V_DrawSmallMappedPatch(104+76+empatx, yHeight+lsheadingheight/2+empaty, 0, empatch, @@ -10086,7 +10055,7 @@ void M_DrawNightsAttackMenu(void) // Super Sonic M_DrawNightsAttackSuperSonic(); //if (P_HasGrades(cv_nextmap.value, 0)) - // V_DrawScaledPatch(235 - (SHORT((ngradeletters[bestoverall])->width)*3)/2, 135, 0, ngradeletters[bestoverall]); + // V_DrawScaledPatch(235 - (((ngradeletters[bestoverall])->width)*3)/2, 135, 0, ngradeletters[bestoverall]); if (P_HasGrades(cv_nextmap.value, cv_dummymares.value)) {//make bigger again @@ -10173,6 +10142,9 @@ 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_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 M_SetupNextMenu(&SP_NightsAttackDef); @@ -10574,10 +10546,6 @@ void M_DrawMarathon(void) angle_t fa; INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy), xspan = (vid.width/dupz), yspan = (vid.height/dupz), diffx = (xspan - BASEVIDWIDTH)/2, diffy = (yspan - BASEVIDHEIGHT)/2, maxy = BASEVIDHEIGHT + diffy; - // lactozilla: the renderer changed so recache patches - if (needpatchrecache) - M_CacheCharacterSelect(); - curbgxspeed = 0; curbgyspeed = 18; @@ -10644,7 +10612,7 @@ void M_DrawMarathon(void) { patch_t *fg = W_CachePatchName("RECATKFG", PU_PATCH); INT32 trans = V_60TRANS+((cnt&~3)<<(V_ALPHASHIFT-2)); - INT32 height = (SHORT(fg->height)/2); + INT32 height = fg->height / 2; char patchname[7] = "CEMGx0"; dupz = (w*7)/6; //(w*42*120)/(360*6); -- I don't know why this works but I'm not going to complain. @@ -11414,7 +11382,7 @@ static void M_DrawServerMenu(void) else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_PATCH); - V_DrawSmallScaledPatch(319 - (currentMenu->x + (SHORT(PictureOfLevel->width)/2)), currentMenu->y + imgheight, 0, PictureOfLevel); + V_DrawSmallScaledPatch(319 - (currentMenu->x + (PictureOfLevel->width / 2)), currentMenu->y + imgheight, 0, PictureOfLevel); } } diff --git a/src/p_enemy.c b/src/p_enemy.c index f9baf1813c7d7d894f2707d14f6f19a75682c6f7..22de9bc67325b1b2b85d076808d24345d04c27de 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -30,7 +30,7 @@ #include "hardware/hw3sound.h" #endif -boolean LUA_CallAction(const char *action, mobj_t *actor); +boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor); player_t *stplyr; INT32 var1; @@ -981,7 +981,7 @@ void A_Look(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Look", actor)) + if (LUA_CallAction(A_LOOK, actor)) return; if (!P_LookForPlayers(actor, locvar1 & 65535, false , FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale))) @@ -1014,7 +1014,7 @@ void A_Chase(mobj_t *actor) INT32 delta; INT32 locvar1 = var1; - if (LUA_CallAction("A_Chase", actor)) + if (LUA_CallAction(A_CHASE, actor)) return; I_Assert(actor != NULL); @@ -1105,7 +1105,7 @@ void A_FaceStabChase(mobj_t *actor) { INT32 delta; - if (LUA_CallAction("A_FaceStabChase", actor)) + if (LUA_CallAction(A_FACESTABCHASE, actor)) return; if (actor->reactiontime) @@ -1227,7 +1227,7 @@ void A_FaceStabRev(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FaceStabRev", actor)) + if (LUA_CallAction(A_FACESTABREV, actor)) return; if (!actor->target) @@ -1270,7 +1270,7 @@ void A_FaceStabHurl(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FaceStabHurl", actor)) + if (LUA_CallAction(A_FACESTABHURL, actor)) return; if (actor->target) @@ -1360,7 +1360,7 @@ void A_FaceStabMiss(mobj_t *actor) { INT32 locvar2 = var2; - if (LUA_CallAction("A_FaceStabMiss", actor)) + if (LUA_CallAction(A_FACESTABMISS, actor)) return; if (++actor->extravalue1 >= 3) @@ -1395,7 +1395,7 @@ void A_StatueBurst(mobj_t *actor) mobjtype_t chunktype = (mobjtype_t)actor->info->raisestate; mobj_t *new; - if (LUA_CallAction("A_StatueBurst", actor)) + if (LUA_CallAction(A_STATUEBURST, actor)) return; if (!locvar1 || !(new = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1))) @@ -1445,7 +1445,7 @@ void A_StatueBurst(mobj_t *actor) // void A_JetJawRoam(mobj_t *actor) { - if (LUA_CallAction("A_JetJawRoam", actor)) + if (LUA_CallAction(A_JETJAWROAM, actor)) return; if (actor->reactiontime) @@ -1474,7 +1474,7 @@ void A_JetJawChomp(mobj_t *actor) { INT32 delta; - if (LUA_CallAction("A_JetJawChomp", actor)) + if (LUA_CallAction(A_JETJAWCHOMP, actor)) return; // turn towards movement direction if not there yet @@ -1521,7 +1521,7 @@ void A_PointyThink(mobj_t *actor) boolean firsttime = true; INT32 sign; - if (LUA_CallAction("A_PointyThink", actor)) + if (LUA_CallAction(A_POINTYTHINK, actor)) return; actor->momx = actor->momy = actor->momz = 0; @@ -1619,7 +1619,7 @@ void A_CheckBuddy(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_CheckBuddy", actor)) + if (LUA_CallAction(A_CHECKBUDDY, actor)) return; if (locvar1 && (!actor->tracer || actor->tracer->health <= 0)) @@ -1662,7 +1662,7 @@ void A_HoodFire(mobj_t *actor) mobj_t *arrow; INT32 locvar1 = var1; - if (LUA_CallAction("A_HoodFire", actor)) + if (LUA_CallAction(A_HOODFIRE, actor)) return; // Check target first. @@ -1694,7 +1694,7 @@ void A_HoodThink(mobj_t *actor) fixed_t dx, dy, dz, dm; boolean checksight; - if (LUA_CallAction("A_HoodThink", actor)) + if (LUA_CallAction(A_HOODTHINK, actor)) return; // Check target first. @@ -1761,7 +1761,7 @@ void A_HoodThink(mobj_t *actor) // void A_HoodFall(mobj_t *actor) { - if (LUA_CallAction("A_HoodFall", actor)) + if (LUA_CallAction(A_HOODFALL, actor)) return; if (!P_IsObjectOnGround(actor)) @@ -1781,7 +1781,7 @@ void A_HoodFall(mobj_t *actor) // void A_ArrowBonks(mobj_t *actor) { - if (LUA_CallAction("A_ArrowBonks", actor)) + if (LUA_CallAction(A_ARROWBONKS, actor)) return; if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) @@ -1804,7 +1804,7 @@ void A_ArrowBonks(mobj_t *actor) // void A_SnailerThink(mobj_t *actor) { - if (LUA_CallAction("A_SnailerThink", actor)) + if (LUA_CallAction(A_SNAILERTHINK, actor)) return; if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) @@ -1877,7 +1877,7 @@ void A_SnailerThink(mobj_t *actor) // void A_SharpChase(mobj_t *actor) { - if (LUA_CallAction("A_SharpChase", actor)) + if (LUA_CallAction(A_SHARPCHASE, actor)) return; if (actor->reactiontime) @@ -1933,7 +1933,7 @@ void A_SharpSpin(mobj_t *actor) INT32 locvar2 = var2; angle_t oldang = actor->angle; - if (LUA_CallAction("A_SharpSpin", actor)) + if (LUA_CallAction(A_SHARPSPIN, actor)) return; if (actor->threshold && actor->target) @@ -1966,7 +1966,7 @@ void A_SharpSpin(mobj_t *actor) // void A_SharpDecel(mobj_t *actor) { - if (LUA_CallAction("A_SharpDecel", actor)) + if (LUA_CallAction(A_SHARPDECEL, actor)) return; if (actor->momx > 2 || actor->momy > 2) @@ -1991,7 +1991,7 @@ void A_CrushstaceanWalk(mobj_t *actor) INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate); angle_t ang = actor->angle + ((actor->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270); - if (LUA_CallAction("A_CrushstaceanWalk", actor)) + if (LUA_CallAction(A_CRUSHSTACEANWALK, actor)) return; actor->reactiontime--; @@ -2020,7 +2020,7 @@ void A_CrushstaceanPunch(mobj_t *actor) { INT32 locvar2 = (var2 ? var2 : (INT32)actor->info->spawnstate); - if (LUA_CallAction("A_CrushstaceanPunch", actor)) + if (LUA_CallAction(A_CRUSHSTACEANPUNCH, actor)) return; if (!actor->tracer) @@ -2052,7 +2052,7 @@ void A_CrushclawAim(mobj_t *actor) mobj_t *crab = actor->tracer; angle_t ang; - if (LUA_CallAction("A_CrushclawAim", actor)) + if (LUA_CallAction(A_CRUSHCLAWAIM, actor)) return; if (!crab) @@ -2113,7 +2113,7 @@ void A_CrushclawLaunch(mobj_t *actor) INT32 locvar2 = var2; mobj_t *crab = actor->tracer; - if (LUA_CallAction("A_CrushclawLaunch", actor)) + if (LUA_CallAction(A_CRUSHCLAWLAUNCH, actor)) return; if (!crab) @@ -2244,7 +2244,7 @@ void A_CrushclawLaunch(mobj_t *actor) // void A_VultureVtol(mobj_t *actor) { - if (LUA_CallAction("A_VultureVtol", actor)) + if (LUA_CallAction(A_VULTUREVTOL, actor)) return; if (!actor->target) @@ -2279,7 +2279,7 @@ void A_VultureVtol(mobj_t *actor) // void A_VultureCheck(mobj_t *actor) { - if (LUA_CallAction("A_VultureCheck", actor)) + if (LUA_CallAction(A_VULTURECHECK, actor)) return; if (actor->momx || actor->momy) @@ -2335,7 +2335,7 @@ void A_VultureHover(mobj_t *actor) fixed_t memz = actor->z; SINT8 i; - if (LUA_CallAction("A_VultureHover", actor)) + if (LUA_CallAction(A_VULTUREHOVER, actor)) return; if (!actor->target || P_MobjWasRemoved(actor->target)) @@ -2397,7 +2397,7 @@ void A_VultureBlast(mobj_t *actor) angle_t faa; fixed_t faacos, faasin; - if (LUA_CallAction("A_VultureBlast", actor)) + if (LUA_CallAction(A_VULTUREBLAST, actor)) return; S_StartSound(actor, actor->info->attacksound); @@ -2436,7 +2436,7 @@ void A_VultureFly(mobj_t *actor) mobj_t *dust; fixed_t momm; - if (LUA_CallAction("A_VultureFly", actor)) + if (LUA_CallAction(A_VULTUREFLY, actor)) return; if (!actor->target || P_MobjWasRemoved(actor->target)) @@ -2528,7 +2528,7 @@ void A_SkimChase(mobj_t *actor) { INT32 delta; - if (LUA_CallAction("A_SkimChase", actor)) + if (LUA_CallAction(A_SKIMCHASE, actor)) return; if (actor->reactiontime) @@ -2614,7 +2614,7 @@ nomissile: // void A_FaceTarget(mobj_t *actor) { - if (LUA_CallAction("A_FaceTarget", actor)) + if (LUA_CallAction(A_FACETARGET, actor)) return; if (!actor->target) @@ -2632,7 +2632,7 @@ void A_FaceTarget(mobj_t *actor) // void A_FaceTracer(mobj_t *actor) { - if (LUA_CallAction("A_FaceTracer", actor)) + if (LUA_CallAction(A_FACETRACER, actor)) return; if (!actor->tracer) @@ -2661,7 +2661,7 @@ void A_LobShot(mobj_t *actor) fixed_t vertical, horizontal; fixed_t airtime = var2 & 65535; - if (LUA_CallAction("A_LobShot", actor)) + if (LUA_CallAction(A_LOBSHOT, actor)) return; if (!actor->target) @@ -2761,7 +2761,7 @@ void A_FireShot(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FireShot", actor)) + if (LUA_CallAction(A_FIRESHOT, actor)) return; if (!actor->target) @@ -2799,7 +2799,7 @@ void A_SuperFireShot(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SuperFireShot", actor)) + if (LUA_CallAction(A_SUPERFIRESHOT, actor)) return; if (!actor->target) @@ -2846,7 +2846,7 @@ void A_BossFireShot(mobj_t *actor) INT32 locvar2 = var2; mobj_t *missile; - if (LUA_CallAction("A_BossFireShot", actor)) + if (LUA_CallAction(A_BOSSFIRESHOT, actor)) return; if (!actor->target) @@ -2930,7 +2930,7 @@ void A_Boss7FireMissiles(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Boss7FireMissiles", actor)) + if (LUA_CallAction(A_BOSS7FIREMISSILES, actor)) return; if (!actor->target) @@ -3005,7 +3005,7 @@ void A_Boss1Laser(mobj_t *actor) SKINCOLOR_SUPERRED3, }; - if (LUA_CallAction("A_Boss1Laser", actor)) + if (LUA_CallAction(A_BOSS1LASER, actor)) return; if (!actor->target) @@ -3176,7 +3176,7 @@ void A_FocusTarget(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FocusTarget", actor)) + if (LUA_CallAction(A_FOCUSTARGET, actor)) return; if (actor->target) @@ -3227,7 +3227,7 @@ void A_Boss4Reverse(mobj_t *actor) sfxenum_t locvar1 = (sfxenum_t)var1; sfxenum_t locvar2 = (sfxenum_t)var2; - if (LUA_CallAction("A_Boss4Reverse", actor)) + if (LUA_CallAction(A_BOSS4REVERSE, actor)) return; actor->reactiontime = 0; @@ -3262,7 +3262,7 @@ void A_Boss4SpeedUp(mobj_t *actor) { sfxenum_t locvar1 = (sfxenum_t)var1; - if (LUA_CallAction("A_Boss4SpeedUp", actor)) + if (LUA_CallAction(A_BOSS4SPEEDUP, actor)) return; S_StartSound(NULL, locvar1); @@ -3280,7 +3280,7 @@ void A_Boss4Raise(mobj_t *actor) { sfxenum_t locvar1 = (sfxenum_t)var1; - if (LUA_CallAction("A_Boss4Raise", actor)) + if (LUA_CallAction(A_BOSS4RAISE, actor)) return; S_StartSound(NULL, locvar1); @@ -3311,7 +3311,7 @@ void A_SkullAttack(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SkullAttack", actor)) + if (LUA_CallAction(A_SKULLATTACK, actor)) return; if (!actor->target) @@ -3429,7 +3429,7 @@ void A_BossZoom(mobj_t *actor) angle_t an; INT32 dist; - if (LUA_CallAction("A_BossZoom", actor)) + if (LUA_CallAction(A_BOSSZOOM, actor)) return; if (!actor->target) @@ -3469,7 +3469,7 @@ void A_BossScream(mobj_t *actor) INT32 locvar2 = var2; mobjtype_t explodetype; - if (LUA_CallAction("A_BossScream", actor)) + if (LUA_CallAction(A_BOSSSCREAM, actor)) return; if (locvar1 & 1) @@ -3514,7 +3514,7 @@ void A_BossScream(mobj_t *actor) // void A_Scream(mobj_t *actor) { - if (LUA_CallAction("A_Scream", actor)) + if (LUA_CallAction(A_SCREAM, actor)) return; if (actor->tracer && (actor->tracer->type == MT_SHELL || actor->tracer->type == MT_FIREBALL)) @@ -3532,7 +3532,7 @@ void A_Scream(mobj_t *actor) // void A_Pain(mobj_t *actor) { - if (LUA_CallAction("A_Pain", actor)) + if (LUA_CallAction(A_PAIN, actor)) return; if (actor->info->painsound) @@ -3553,7 +3553,7 @@ void A_Fall(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_Fall", actor)) + if (LUA_CallAction(A_FALL, actor)) return; // actor is on ground, it can be walked over @@ -3585,7 +3585,7 @@ void A_1upThinker(mobj_t *actor) fixed_t temp; INT32 closestplayer = -1; - if (LUA_CallAction("A_1upThinker", actor)) + if (LUA_CallAction(A_1UPTHINKER, actor)) return; for (i = 0; i < MAXPLAYERS; i++) @@ -3651,7 +3651,7 @@ void A_MonitorPop(mobj_t *actor) mobjtype_t item = 0; mobj_t *newmobj; - if (LUA_CallAction("A_MonitorPop", actor)) + if (LUA_CallAction(A_MONITORPOP, actor)) return; // Spawn the "pop" explosion. @@ -3732,7 +3732,7 @@ void A_GoldMonitorPop(mobj_t *actor) mobjtype_t item = 0; mobj_t *newmobj; - if (LUA_CallAction("A_GoldMonitorPop", actor)) + if (LUA_CallAction(A_GOLDMONITORPOP, actor)) return; // Don't spawn the "pop" explosion, because the monitor isn't broken. @@ -3815,7 +3815,7 @@ void A_GoldMonitorPop(mobj_t *actor) // void A_GoldMonitorRestore(mobj_t *actor) { - if (LUA_CallAction("A_GoldMonitorRestore", actor)) + if (LUA_CallAction(A_GOLDMONITORRESTORE, actor)) return; actor->flags |= MF_MONITOR|MF_SHOOTABLE; @@ -3833,7 +3833,7 @@ void A_GoldMonitorSparkle(mobj_t *actor) { fixed_t i, ngangle, xofs, yofs; - if (LUA_CallAction("A_GoldMonitorSparkle", actor)) + if (LUA_CallAction(A_GOLDMONITORSPARKLE, actor)) return; ngangle = FixedAngle(((leveltime * 21) % 360) << FRACBITS); @@ -3855,7 +3855,7 @@ void A_Explode(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_Explode", actor)) + if (LUA_CallAction(A_EXPLODE, actor)) return; P_RadiusAttack(actor, actor->target, actor->info->damage, locvar1, true); @@ -3875,7 +3875,7 @@ void A_BossDeath(mobj_t *mo) line_t junk; INT32 i; - if (LUA_CallAction("A_BossDeath", mo)) + if (LUA_CallAction(A_BOSSDEATH, mo)) return; if (mo->spawnpoint && mo->spawnpoint->extrainfo) @@ -4184,7 +4184,7 @@ void A_CustomPower(mobj_t *actor) INT32 locvar2 = var2; boolean spawnshield = false; - if (LUA_CallAction("A_CustomPower", actor)) + if (LUA_CallAction(A_CUSTOMPOWER, actor)) return; if (!actor->target || !actor->target->player) @@ -4224,7 +4224,7 @@ void A_GiveWeapon(mobj_t *actor) player_t *player; INT32 locvar1 = var1; - if (LUA_CallAction("A_GiveWeapon", actor)) + if (LUA_CallAction(A_GIVEWEAPON, actor)) return; if (!actor->target || !actor->target->player) @@ -4257,7 +4257,7 @@ void A_RingBox(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_RingBox", actor)) + if (LUA_CallAction(A_RINGBOX, actor)) return; if (!actor->target || !actor->target->player) @@ -4284,7 +4284,7 @@ void A_Invincibility(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_Invincibility", actor)) + if (LUA_CallAction(A_INVINCIBILITY, actor)) return; if (!actor->target || !actor->target->player) @@ -4317,7 +4317,7 @@ void A_SuperSneakers(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_SuperSneakers", actor)) + if (LUA_CallAction(A_SUPERSNEAKERS, actor)) return; if (!actor->target || !actor->target->player) @@ -4352,7 +4352,7 @@ void A_AwardScore(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_AwardScore", actor)) + if (LUA_CallAction(A_AWARDSCORE, actor)) return; if (!actor->target || !actor->target->player) @@ -4379,7 +4379,7 @@ void A_ExtraLife(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_ExtraLife", actor)) + if (LUA_CallAction(A_EXTRALIFE, actor)) return; if (!actor->target || !actor->target->player) @@ -4417,7 +4417,7 @@ void A_GiveShield(mobj_t *actor) player_t *player; UINT16 locvar1 = var1; - if (LUA_CallAction("A_GiveShield", actor)) + if (LUA_CallAction(A_GIVESHIELD, actor)) return; if (!actor->target || !actor->target->player) @@ -4443,7 +4443,7 @@ void A_GravityBox(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_GravityBox", actor)) + if (LUA_CallAction(A_GRAVITYBOX, actor)) return; if (!actor->target || !actor->target->player) @@ -4468,7 +4468,7 @@ void A_GravityBox(mobj_t *actor) // void A_ScoreRise(mobj_t *actor) { - if (LUA_CallAction("A_ScoreRise", actor)) + if (LUA_CallAction(A_SCORERISE, actor)) return; // make logo rise! @@ -4487,7 +4487,7 @@ void A_BunnyHop(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_BunnyHop", actor)) + if (LUA_CallAction(A_BUNNYHOP, actor)) return; if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) @@ -4511,7 +4511,7 @@ void A_BubbleSpawn(mobj_t *actor) UINT8 prandom; mobj_t *bubble = NULL; - if (LUA_CallAction("A_BubbleSpawn", actor)) + if (LUA_CallAction(A_BUBBLESPAWN, actor)) return; if (!(actor->eflags & MFE_UNDERWATER)) @@ -4564,7 +4564,7 @@ void A_FanBubbleSpawn(mobj_t *actor) mobj_t *bubble = NULL; fixed_t hz = actor->z + (4*actor->height)/5; - if (LUA_CallAction("A_FanBubbleSpawn", actor)) + if (LUA_CallAction(A_FANBUBBLESPAWN, actor)) return; if (!(actor->eflags & MFE_UNDERWATER)) @@ -4610,7 +4610,7 @@ void A_BubbleRise(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_BubbleRise", actor)) + if (LUA_CallAction(A_BUBBLERISE, actor)) return; if (actor->type == MT_EXTRALARGEBUBBLE) @@ -4646,7 +4646,7 @@ void A_BubbleRise(mobj_t *actor) // void A_BubbleCheck(mobj_t *actor) { - if (LUA_CallAction("A_BubbleCheck", actor)) + if (LUA_CallAction(A_BUBBLECHECK, actor)) return; if (actor->eflags & MFE_UNDERWATER) @@ -4664,7 +4664,7 @@ void A_BubbleCheck(mobj_t *actor) // void A_AttractChase(mobj_t *actor) { - if (LUA_CallAction("A_AttractChase", actor)) + if (LUA_CallAction(A_ATTRACTCHASE, actor)) return; if (actor->flags2 & MF2_NIGHTSPULL || !actor->health) @@ -4735,7 +4735,7 @@ void A_DropMine(mobj_t *actor) fixed_t z; mobj_t *mine; - if (LUA_CallAction("A_DropMine", actor)) + if (LUA_CallAction(A_DROPMINE, actor)) return; if (locvar2 & 65535) @@ -4783,7 +4783,7 @@ void A_FishJump(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FishJump", actor)) + if (LUA_CallAction(A_FISHJUMP, actor)) return; if (locvar2) @@ -4834,7 +4834,7 @@ void A_ThrownRing(mobj_t *actor) player_t *player; fixed_t dist; - if (LUA_CallAction("A_ThrownRing", actor)) + if (LUA_CallAction(A_THROWNRING, actor)) return; if (leveltime % (TICRATE/7) == 0) @@ -4990,7 +4990,7 @@ void A_ThrownRing(mobj_t *actor) // void A_SetSolidSteam(mobj_t *actor) { - if (LUA_CallAction("A_SetSolidSteam", actor)) + if (LUA_CallAction(A_SETSOLIDSTEAM, actor)) return; actor->flags &= ~MF_NOCLIP; @@ -5021,7 +5021,7 @@ void A_SetSolidSteam(mobj_t *actor) // void A_UnsetSolidSteam(mobj_t *actor) { - if (LUA_CallAction("A_UnsetSolidSteam", actor)) + if (LUA_CallAction(A_UNSETSOLIDSTEAM, actor)) return; actor->flags &= ~MF_SOLID; @@ -5041,7 +5041,7 @@ void A_SignSpin(mobj_t *actor) INT16 i; angle_t rotateangle = FixedAngle(locvar1 << FRACBITS); - if (LUA_CallAction("A_SignSpin", actor)) + if (LUA_CallAction(A_SIGNSPIN, actor)) return; if (P_IsObjectOnGround(actor) && P_MobjFlip(actor) * actor->momz <= 0) @@ -5112,7 +5112,7 @@ void A_SignPlayer(mobj_t *actor) facecolor = signcolor = (UINT16)locvar2; - if (LUA_CallAction("A_SignPlayer", actor)) + if (LUA_CallAction(A_SIGNPLAYER, actor)) return; if (actor->tracer == NULL || locvar1 < -3 || locvar1 >= numskins || signcolor >= numskincolors) @@ -5230,7 +5230,7 @@ void A_OverlayThink(mobj_t *actor) { fixed_t destx, desty; - if (LUA_CallAction("A_OverlayThink", actor)) + if (LUA_CallAction(A_OVERLAYTHINK, actor)) return; if (!actor->target) @@ -5282,7 +5282,7 @@ void A_JetChase(mobj_t *actor) { fixed_t thefloor; - if (LUA_CallAction("A_JetChase", actor)) + if (LUA_CallAction(A_JETCHASE, actor)) return; if (actor->flags2 & MF2_AMBUSH) @@ -5378,7 +5378,7 @@ void A_JetbThink(mobj_t *actor) sector_t *nextsector; fixed_t thefloor; - if (LUA_CallAction("A_JetbThink", actor)) + if (LUA_CallAction(A_JETBTHINK, actor)) return; if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz @@ -5443,7 +5443,7 @@ void A_JetgShoot(mobj_t *actor) { fixed_t dist; - if (LUA_CallAction("A_JetgShoot", actor)) + if (LUA_CallAction(A_JETGSHOOT, actor)) return; if (!actor->target) @@ -5483,7 +5483,7 @@ void A_ShootBullet(mobj_t *actor) { fixed_t dist; - if (LUA_CallAction("A_ShootBullet", actor)) + if (LUA_CallAction(A_SHOOTBULLET, actor)) return; if (!actor->target) @@ -5543,7 +5543,7 @@ void A_MinusDigging(mobj_t *actor) fixed_t mz = (actor->eflags & MFE_VERTICALFLIP) ? actor->ceilingz : actor->floorz; mobj_t *par; - if (LUA_CallAction("A_MinusDigging", actor)) + if (LUA_CallAction(A_MINUSDIGGING, actor)) return; if (!actor->target) @@ -5624,7 +5624,7 @@ void A_MinusPopup(mobj_t *actor) angle_t ani = FixedAngle(FRACUNIT*360/num); INT32 i; - if (LUA_CallAction("A_MinusPopup", actor)) + if (LUA_CallAction(A_MINUSPOPUP, actor)) return; if (actor->eflags & MFE_VERTICALFLIP) @@ -5659,7 +5659,7 @@ void A_MinusCheck(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_MinusCheck", actor)) + if (LUA_CallAction(A_MINUSCHECK, actor)) return; if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) || (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)) @@ -5690,7 +5690,7 @@ void A_MinusCheck(mobj_t *actor) // void A_ChickenCheck(mobj_t *actor) { - if (LUA_CallAction("A_ChickenCheck", actor)) + if (LUA_CallAction(A_CHICKENCHECK, actor)) return; if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) @@ -5721,7 +5721,7 @@ void A_JetgThink(mobj_t *actor) fixed_t thefloor; - if (LUA_CallAction("A_JetgThink", actor)) + if (LUA_CallAction(A_JETGTHINK, actor)) return; if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz @@ -5771,7 +5771,7 @@ void A_JetgThink(mobj_t *actor) // void A_MouseThink(mobj_t *actor) { - if (LUA_CallAction("A_MouseThink", actor)) + if (LUA_CallAction(A_MOUSETHINK, actor)) return; if (actor->reactiontime) @@ -5808,7 +5808,7 @@ void A_DetonChase(mobj_t *actor) angle_t exact; fixed_t xydist, dist; - if (LUA_CallAction("A_DetonChase", actor)) + if (LUA_CallAction(A_DETONCHASE, actor)) return; // modify tracer threshold @@ -5955,7 +5955,7 @@ void A_CapeChase(mobj_t *actor) INT32 locvar2 = var2; angle_t angle; - if (LUA_CallAction("A_CapeChase", actor)) + if (LUA_CallAction(A_CAPECHASE, actor)) return; CONS_Debug(DBG_GAMELOGIC, "A_CapeChase called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -6015,7 +6015,7 @@ void A_RotateSpikeBall(mobj_t *actor) INT32 locvar1 = var1; const fixed_t radius = FixedMul(12*actor->info->speed, actor->scale); - if (LUA_CallAction("A_RotateSpikeBall", actor)) + if (LUA_CallAction(A_ROTATESPIKEBALL, actor)) return; if (!((!locvar1 && (actor->target)) || (locvar1 && (actor->tracer))))// This should NEVER happen. @@ -6066,7 +6066,7 @@ void A_UnidusBall(mobj_t *actor) INT32 locvar1 = var1; boolean canthrow = false; - if (LUA_CallAction("A_UnidusBall", actor)) + if (LUA_CallAction(A_UNIDUSBALL, actor)) return; actor->angle += ANGLE_11hh; @@ -6163,7 +6163,7 @@ void A_RockSpawn(mobj_t *actor) fixed_t dist; fixed_t randomoomph; - if (LUA_CallAction("A_RockSpawn", actor)) + if (LUA_CallAction(A_ROCKSPAWN, actor)) return; if (i == -1) @@ -6216,7 +6216,7 @@ void A_SlingAppear(mobj_t *actor) UINT8 mlength = 4; mobj_t *spawnee, *hprev; - if (LUA_CallAction("A_SlingAppear", actor)) + if (LUA_CallAction(A_SLINGAPPEAR, actor)) return; P_UnsetThingPosition(actor); @@ -6266,7 +6266,7 @@ void A_SetFuse(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SetFuse", actor)) + if (LUA_CallAction(A_SETFUSE, actor)) return; if ((!actor->fuse || (locvar2 >> 16)) && (locvar2 >> 16) != 2) // set the actor's fuse value @@ -6295,7 +6295,7 @@ void A_CrawlaCommanderThink(mobj_t *actor) INT32 locvar2 = var2; boolean hovermode = (actor->health > 1 || actor->fuse); - if (LUA_CallAction("A_CrawlaCommanderThink", actor)) + if (LUA_CallAction(A_CRAWLACOMMANDERTHINK, actor)) return; if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz @@ -6453,7 +6453,7 @@ void A_RingExplode(mobj_t *actor) thinker_t *th; angle_t d; - if (LUA_CallAction("A_RingExplode", actor)) + if (LUA_CallAction(A_RINGEXPLODE, actor)) return; for (d = 0; d < 16; d++) @@ -6498,7 +6498,7 @@ void A_OldRingExplode(mobj_t *actor) { INT32 locvar1 = var1; boolean changecolor = (actor->target && actor->target->player); - if (LUA_CallAction("A_OldRingExplode", actor)) + if (LUA_CallAction(A_OLDRINGEXPLODE, actor)) return; for (i = 0; i < 32; i++) @@ -6574,7 +6574,7 @@ void A_MixUp(mobj_t *actor) boolean teleported[MAXPLAYERS]; INT32 i, numplayers = 0, prandom = 0; - if (LUA_CallAction("A_MixUp", actor)) + if (LUA_CallAction(A_MIXUP, actor)) return; if (!multiplayer) @@ -6849,7 +6849,7 @@ void A_RecyclePowers(mobj_t *actor) INT32 weapons[MAXPLAYERS]; INT32 weaponheld[MAXPLAYERS]; - if (LUA_CallAction("A_RecyclePowers", actor)) + if (LUA_CallAction(A_RECYCLEPOWERS, actor)) return; if (!multiplayer) @@ -6980,7 +6980,7 @@ void A_Boss1Chase(mobj_t *actor) { INT32 delta; - if (LUA_CallAction("A_Boss1Chase", actor)) + if (LUA_CallAction(A_BOSS1CHASE, actor)) return; if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) @@ -7103,7 +7103,7 @@ void A_Boss2Chase(mobj_t *actor) boolean reverse = false; INT32 speedvar; - if (LUA_CallAction("A_Boss2Chase", actor)) + if (LUA_CallAction(A_BOSS2CHASE, actor)) return; if (actor->health <= 0) @@ -7229,7 +7229,7 @@ void A_Boss2Chase(mobj_t *actor) // void A_Boss2Pogo(mobj_t *actor) { - if (LUA_CallAction("A_Boss2Pogo", actor)) + if (LUA_CallAction(A_BOSS2POGO, actor)) return; if (actor->z <= actor->floorz + FixedMul(8*FRACUNIT, actor->scale) && actor->momz <= 0) @@ -7277,7 +7277,7 @@ void A_Boss2TakeDamage(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_Boss2TakeDamage", actor)) + if (LUA_CallAction(A_BOSS2TAKEDAMAGE, actor)) return; A_Pain(actor); @@ -7300,7 +7300,7 @@ void A_Boss7Chase(mobj_t *actor) INT32 delta; INT32 i; - if (LUA_CallAction("A_Boss7Chase", actor)) + if (LUA_CallAction(A_BOSS7CHASE, actor)) return; if (actor->z != actor->floorz) @@ -7430,7 +7430,7 @@ void A_Boss7Chase(mobj_t *actor) // void A_GoopSplat(mobj_t *actor) { - if (LUA_CallAction("A_GoopSplat", actor)) + if (LUA_CallAction(A_GOOPSPLAT, actor)) return; P_UnsetThingPosition(actor); @@ -7455,7 +7455,7 @@ void A_Boss2PogoSFX(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Boss2PogoSFX", actor)) + if (LUA_CallAction(A_BOSS2POGOSFX, actor)) return; if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) @@ -7497,7 +7497,7 @@ void A_Boss2PogoTarget(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Boss2PogoTarget", actor)) + if (LUA_CallAction(A_BOSS2POGOTARGET, actor)) return; if (!actor->target || !(actor->target->flags & MF_SHOOTABLE) || (actor->target->player && actor->target->player->powers[pw_flashing]) @@ -7582,7 +7582,7 @@ void A_Boss2PogoTarget(mobj_t *actor) // void A_EggmanBox(mobj_t *actor) { - if (LUA_CallAction("A_EggmanBox", actor)) + if (LUA_CallAction(A_EGGMANBOX, actor)) return; if (!actor->target || !actor->target->player) @@ -7608,7 +7608,7 @@ void A_TurretFire(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_TurretFire", actor)) + if (LUA_CallAction(A_TURRETFIRE, actor)) return; if (locvar2) @@ -7646,7 +7646,7 @@ void A_SuperTurretFire(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SuperTurretFire", actor)) + if (LUA_CallAction(A_SUPERTURRETFIRE, actor)) return; if (locvar2) @@ -7682,7 +7682,7 @@ void A_TurretStop(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_TurretStop", actor)) + if (LUA_CallAction(A_TURRETSTOP, actor)) return; actor->flags2 &= ~MF2_FIRING; @@ -7701,7 +7701,7 @@ void A_TurretStop(mobj_t *actor) // void A_SparkFollow(mobj_t *actor) { - if (LUA_CallAction("A_SparkFollow", actor)) + if (LUA_CallAction(A_SPARKFOLLOW, actor)) return; if ((!actor->target || (actor->target->health <= 0)) @@ -7737,7 +7737,7 @@ void A_BuzzFly(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_BuzzFly", actor)) + if (LUA_CallAction(A_BUZZFLY, actor)) return; if (actor->flags2 & MF2_AMBUSH) @@ -7836,7 +7836,7 @@ void A_GuardChase(mobj_t *actor) { INT32 delta; - if (LUA_CallAction("A_GuardChase", actor)) + if (LUA_CallAction(A_GUARDCHASE, actor)) return; if (actor->reactiontime) @@ -7941,7 +7941,7 @@ void A_EggShield(mobj_t *actor) fixed_t movex, movey; angle_t angle; - if (LUA_CallAction("A_EggShield", actor)) + if (LUA_CallAction(A_EGGSHIELD, actor)) return; if (!actor->target || !actor->target->health) @@ -8023,7 +8023,7 @@ void A_EggShield(mobj_t *actor) // void A_SetReactionTime(mobj_t *actor) { - if (LUA_CallAction("A_SetReactionTime", actor)) + if (LUA_CallAction(A_SETREACTIONTIME, actor)) return; if (var1) @@ -8045,7 +8045,7 @@ void A_Boss1Spikeballs(mobj_t *actor) INT32 locvar2 = var2; mobj_t *ball; - if (LUA_CallAction("A_Boss1Spikeballs", actor)) + if (LUA_CallAction(A_BOSS1SPIKEBALLS, actor)) return; ball = P_SpawnMobj(actor->x, actor->y, actor->z, MT_EGGMOBILE_BALL); @@ -8067,7 +8067,7 @@ void A_Boss1Spikeballs(mobj_t *actor) // void A_Boss3TakeDamage(mobj_t *actor) { - if (LUA_CallAction("A_Boss3TakeDamage", actor)) + if (LUA_CallAction(A_BOSS3TAKEDAMAGE, actor)) return; actor->movecount = var1; @@ -8087,7 +8087,7 @@ void A_Boss3TakeDamage(mobj_t *actor) // void A_Boss3Path(mobj_t *actor) { - if (LUA_CallAction("A_Boss3Path", actor)) + if (LUA_CallAction(A_BOSS3PATH, actor)) return; if (actor->tracer && actor->tracer->health && actor->tracer->movecount) @@ -8214,7 +8214,7 @@ void A_Boss3Path(mobj_t *actor) // void A_Boss3ShockThink(mobj_t *actor) { - if (LUA_CallAction("A_Boss3ShockThink", actor)) + if (LUA_CallAction(A_BOSS3SHOCKTHINK, actor)) return; if (actor->momx || actor->momy) @@ -8267,7 +8267,7 @@ void A_LinedefExecute(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_LinedefExecute", actor)) + if (LUA_CallAction(A_LINEDEFEXECUTE, actor)) return; tagnum = locvar1; @@ -8293,7 +8293,7 @@ void A_LinedefExecute(mobj_t *actor) // void A_PlaySeeSound(mobj_t *actor) { - if (LUA_CallAction("A_PlaySeeSound", actor)) + if (LUA_CallAction(A_PLAYSEESOUND, actor)) return; if (actor->info->seesound) @@ -8309,7 +8309,7 @@ void A_PlaySeeSound(mobj_t *actor) // void A_PlayAttackSound(mobj_t *actor) { - if (LUA_CallAction("A_PlayAttackSound", actor)) + if (LUA_CallAction(A_PLAYATTACKSOUND, actor)) return; if (actor->info->attacksound) @@ -8325,7 +8325,7 @@ void A_PlayAttackSound(mobj_t *actor) // void A_PlayActiveSound(mobj_t *actor) { - if (LUA_CallAction("A_PlayActiveSound", actor)) + if (LUA_CallAction(A_PLAYACTIVESOUND, actor)) return; if (actor->info->activesound) @@ -8344,7 +8344,7 @@ void A_SmokeTrailer(mobj_t *actor) mobj_t *th; INT32 locvar1 = var1; - if (LUA_CallAction("A_SmokeTrailer", actor)) + if (LUA_CallAction(A_SMOKETRAILER, actor)) return; if (leveltime % 4) @@ -8385,7 +8385,7 @@ void A_SpawnObjectAbsolute(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SpawnObjectAbsolute", actor)) + if (LUA_CallAction(A_SPAWNOBJECTABSOLUTE, actor)) return; x = (INT16)(locvar1>>16); @@ -8421,7 +8421,7 @@ void A_SpawnObjectRelative(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SpawnObjectRelative", actor)) + if (LUA_CallAction(A_SPAWNOBJECTRELATIVE, actor)) return; CONS_Debug(DBG_GAMELOGIC, "A_SpawnObjectRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -8465,7 +8465,7 @@ void A_ChangeAngleRelative(mobj_t *actor) //const angle_t amin = FixedAngle(locvar1*FRACUNIT); //const angle_t amax = FixedAngle(locvar2*FRACUNIT); - if (LUA_CallAction("A_ChangeAngleRelative", actor)) + if (LUA_CallAction(A_CHANGEANGLERELATIVE, actor)) return; #ifdef PARANOIA @@ -8498,7 +8498,7 @@ void A_ChangeAngleAbsolute(mobj_t *actor) //const angle_t amin = FixedAngle(locvar1*FRACUNIT); //const angle_t amax = FixedAngle(locvar2*FRACUNIT); - if (LUA_CallAction("A_ChangeAngleAbsolute", actor)) + if (LUA_CallAction(A_CHANGEANGLEABSOLUTE, actor)) return; #ifdef PARANOIA @@ -8527,7 +8527,7 @@ void A_RollAngle(mobj_t *actor) INT32 locvar2 = var2; const angle_t angle = FixedAngle(locvar1*FRACUNIT); - if (LUA_CallAction("A_RollAngle", actor)) + if (LUA_CallAction(A_ROLLANGLE, actor)) return; // relative (default) @@ -8552,7 +8552,7 @@ void A_ChangeRollAngleRelative(mobj_t *actor) const fixed_t amin = locvar1*FRACUNIT; const fixed_t amax = locvar2*FRACUNIT; - if (LUA_CallAction("A_ChangeRollAngleRelative", actor)) + if (LUA_CallAction(A_CHANGEROLLANGLERELATIVE, actor)) return; #ifdef PARANOIA @@ -8577,7 +8577,7 @@ void A_ChangeRollAngleAbsolute(mobj_t *actor) const fixed_t amin = locvar1*FRACUNIT; const fixed_t amax = locvar2*FRACUNIT; - if (LUA_CallAction("A_ChangeRollAngleAbsolute", actor)) + if (LUA_CallAction(A_CHANGEROLLANGLEABSOLUTE, actor)) return; #ifdef PARANOIA @@ -8602,7 +8602,7 @@ void A_PlaySound(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_PlaySound", actor)) + if (LUA_CallAction(A_PLAYSOUND, actor)) return; if (leveltime < 2 && (locvar2 >> 16)) @@ -8627,7 +8627,7 @@ void A_FindTarget(mobj_t *actor) mobj_t *mo2; fixed_t dist1 = 0, dist2 = 0; - if (LUA_CallAction("A_FindTarget", actor)) + if (LUA_CallAction(A_FINDTARGET, actor)) return; CONS_Debug(DBG_GAMELOGIC, "A_FindTarget called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -8691,7 +8691,7 @@ void A_FindTracer(mobj_t *actor) mobj_t *mo2; fixed_t dist1 = 0, dist2 = 0; - if (LUA_CallAction("A_FindTracer", actor)) + if (LUA_CallAction(A_FINDTRACER, actor)) return; CONS_Debug(DBG_GAMELOGIC, "A_FindTracer called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -8751,7 +8751,7 @@ void A_SetTics(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SetTics", actor)) + if (LUA_CallAction(A_SETTICS, actor)) return; if (locvar1) @@ -8772,7 +8772,7 @@ void A_SetRandomTics(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SetRandomTics", actor)) + if (LUA_CallAction(A_SETRANDOMTICS, actor)) return; actor->tics = P_RandomRange(locvar1, locvar2); @@ -8790,7 +8790,7 @@ void A_ChangeColorRelative(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_ChangeColorRelative", actor)) + if (LUA_CallAction(A_CHANGECOLORRELATIVE, actor)) return; if (locvar1) @@ -8815,7 +8815,7 @@ void A_ChangeColorAbsolute(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_ChangeColorAbsolute", actor)) + if (LUA_CallAction(A_CHANGECOLORABSOLUTE, actor)) return; if (locvar1) @@ -8841,7 +8841,7 @@ void A_Dye(mobj_t *actor) mobj_t *target = ((locvar1 && actor->target) ? actor->target : actor); UINT16 color = (UINT16)locvar2; - if (LUA_CallAction("A_Dye", actor)) + if (LUA_CallAction(A_DYE, actor)) return; if (color >= numskincolors) return; @@ -8874,7 +8874,7 @@ void A_MoveRelative(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_MoveRelative", actor)) + if (LUA_CallAction(A_MOVERELATIVE, actor)) return; P_Thrust(actor, actor->angle+FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale)); @@ -8892,7 +8892,7 @@ void A_MoveAbsolute(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_MoveAbsolute", actor)) + if (LUA_CallAction(A_MOVEABSOLUTE, actor)) return; P_InstaThrust(actor, FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale)); @@ -8910,7 +8910,7 @@ void A_Thrust(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Thrust", actor)) + if (LUA_CallAction(A_THRUST, actor)) return; if (!locvar1) @@ -8936,7 +8936,7 @@ void A_ZThrust(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_ZThrust", actor)) + if (LUA_CallAction(A_ZTHRUST, actor)) return; if (!locvar1) @@ -8970,7 +8970,7 @@ void A_SetTargetsTarget(mobj_t *actor) INT32 locvar2 = var2; mobj_t *oldtarg = NULL, *newtarg = NULL; - if (LUA_CallAction("A_SetTargetsTarget", actor)) + if (LUA_CallAction(A_SETTARGETSTARGET, actor)) return; // actor's target @@ -9014,7 +9014,7 @@ void A_SetObjectFlags(mobj_t *actor) INT32 locvar2 = var2; boolean unlinkthings = false; - if (LUA_CallAction("A_SetObjectFlags", actor)) + if (LUA_CallAction(A_SETOBJECTFLAGS, actor)) return; if (locvar2 == 2) @@ -9055,7 +9055,7 @@ void A_SetObjectFlags2(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SetObjectFlags2", actor)) + if (LUA_CallAction(A_SETOBJECTFLAGS2, actor)) return; if (locvar2 == 2) @@ -9082,7 +9082,7 @@ void A_BossJetFume(mobj_t *actor) mobj_t *filler; INT32 locvar1 = var1; - if (LUA_CallAction("A_BossJetFume", actor)) + if (LUA_CallAction(A_BOSSJETFUME, actor)) return; if (locvar1 == 0) // Boss1 jet fumes @@ -9217,7 +9217,7 @@ void A_RandomState(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_RandomState", actor)) + if (LUA_CallAction(A_RANDOMSTATE, actor)) return; P_SetMobjState(actor, P_RandomChance(FRACUNIT/2) ? locvar1 : locvar2); @@ -9235,7 +9235,7 @@ void A_RandomStateRange(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_RandomStateRange", actor)) + if (LUA_CallAction(A_RANDOMSTATERANGE, actor)) return; P_SetMobjState(actor, P_RandomRange(locvar1, locvar2)); @@ -9253,7 +9253,7 @@ void A_DualAction(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_DualAction", actor)) + if (LUA_CallAction(A_DUALACTION, actor)) return; CONS_Debug(DBG_GAMELOGIC, "A_DualAction called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -9286,7 +9286,7 @@ void A_RemoteAction(mobj_t *actor) INT32 locvar2 = var2; mobj_t *originaltarget = actor->target; // Hold on to the target for later. - if (LUA_CallAction("A_RemoteAction", actor)) + if (LUA_CallAction(A_REMOTEACTION, actor)) return; // If >=0, find the closest target. @@ -9368,7 +9368,7 @@ void A_RemoteAction(mobj_t *actor) // void A_ToggleFlameJet(mobj_t* actor) { - if (LUA_CallAction("A_ToggleFlameJet", actor)) + if (LUA_CallAction(A_TOGGLEFLAMEJET, actor)) return; // threshold - off delay @@ -9415,7 +9415,7 @@ void A_OrbitNights(mobj_t* actor) boolean donotrescale = (var2 & 0x40000); INT32 xfactor = 32, yfactor = 32, zfactor = 20; - if (LUA_CallAction("A_OrbitNights", actor)) + if (LUA_CallAction(A_ORBITNIGHTS, actor)) return; if (actor->flags & MF_GRENADEBOUNCE) @@ -9488,7 +9488,7 @@ void A_GhostMe(mobj_t *actor) INT32 locvar1 = var1; mobj_t *ghost; - if (LUA_CallAction("A_GhostMe", actor)) + if (LUA_CallAction(A_GHOSTME, actor)) return; ghost = P_SpawnGhostMobj(actor); @@ -9511,7 +9511,7 @@ void A_SetObjectState(mobj_t *actor) INT32 locvar2 = var2; mobj_t *target; - if (LUA_CallAction("A_SetObjectState", actor)) + if (LUA_CallAction(A_SETOBJECTSTATE, actor)) return; if ((!locvar2 && !actor->target) || (locvar2 && !actor->tracer)) @@ -9555,7 +9555,7 @@ void A_SetObjectTypeState(mobj_t *actor) mobj_t *mo2; fixed_t dist = 0; - if (LUA_CallAction("A_SetObjectTypeState", actor)) + if (LUA_CallAction(A_SETOBJECTTYPESTATE, actor)) return; for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -9597,7 +9597,7 @@ void A_KnockBack(mobj_t *actor) INT32 locvar1 = var1; mobj_t *target; - if (LUA_CallAction("A_KnockBack", actor)) + if (LUA_CallAction(A_KNOCKBACK, actor)) return; if (!locvar1) @@ -9632,7 +9632,7 @@ void A_PushAway(mobj_t *actor) mobj_t *target; // target angle_t an; // actor to target angle - if (LUA_CallAction("A_PushAway", actor)) + if (LUA_CallAction(A_PUSHAWAY, actor)) return; if ((!(locvar2 >> 16) && !actor->target) || ((locvar2 >> 16) && !actor->tracer)) @@ -9666,7 +9666,7 @@ void A_RingDrain(mobj_t *actor) INT32 locvar1 = var1; player_t *player; - if (LUA_CallAction("A_RingDrain", actor)) + if (LUA_CallAction(A_RINGDRAIN, actor)) return; if (!actor->target || !actor->target->player) @@ -9698,7 +9698,7 @@ void A_SplitShot(mobj_t *actor) const fixed_t offs = (fixed_t)(locvar1*FRACUNIT); const fixed_t hoffs = (fixed_t)(loc2up*FRACUNIT); - if (LUA_CallAction("A_SplitShot", actor)) + if (LUA_CallAction(A_SPLITSHOT, actor)) return; if (!actor->target) @@ -9735,7 +9735,7 @@ void A_MissileSplit(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_MissileSplit", actor)) + if (LUA_CallAction(A_MISSILESPLIT, actor)) return; if (actor->eflags & MFE_VERTICALFLIP) @@ -9763,7 +9763,7 @@ void A_MultiShot(mobj_t *actor) INT32 count = 0; fixed_t ad; - if (LUA_CallAction("A_MultiShot", actor)) + if (LUA_CallAction(A_MULTISHOT, actor)) return; if (actor->target) @@ -9824,7 +9824,7 @@ void A_InstaLoop(mobj_t *actor) const fixed_t ac = FINECOSINE(fa); const fixed_t as = FINESINE(fa); - if (LUA_CallAction("A_InstaLoop", actor)) + if (LUA_CallAction(A_INSTALOOP, actor)) return; P_InstaThrust(actor, actor->angle, FixedMul(ac, FixedMul(force, actor->scale))); @@ -9857,7 +9857,7 @@ void A_Custom3DRotate(mobj_t *actor) const fixed_t hspeed = FixedMul(loc2up*FRACUNIT/10, actor->scale); const fixed_t vspeed = FixedMul(loc2lw*FRACUNIT/10, actor->scale); - if (LUA_CallAction("A_Custom3DRotate", actor)) + if (LUA_CallAction(A_CUSTOM3DROTATE, actor)) return; if (actor->target->health == 0) @@ -9916,7 +9916,7 @@ void A_SearchForPlayers(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SearchForPlayers", actor)) + if (LUA_CallAction(A_SEARCHFORPLAYERS, actor)) return; if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) @@ -9948,7 +9948,7 @@ void A_CheckRandom(mobj_t *actor) INT32 locvar2 = var2; fixed_t chance = FRACUNIT; - if (LUA_CallAction("A_CheckRandom", actor)) + if (LUA_CallAction(A_CHECKRANDOM, actor)) return; if ((locvar1 & 0xFFFF) == 0) @@ -9975,7 +9975,7 @@ void A_CheckTargetRings(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CheckTargetRings", actor)) + if (LUA_CallAction(A_CHECKTARGETRINGS, actor)) return; if (!(actor->target) || !(actor->target->player)) @@ -9998,7 +9998,7 @@ void A_CheckRings(mobj_t *actor) INT32 locvar2 = var2; INT32 i, cntr = 0; - if (LUA_CallAction("A_CheckRings", actor)) + if (LUA_CallAction(A_CHECKRINGS, actor)) return; for (i = 0; i < MAXPLAYERS; i++) @@ -10022,7 +10022,7 @@ void A_CheckTotalRings(mobj_t *actor) INT32 i, cntr = 0; - if (LUA_CallAction("A_CheckTotalRings", actor)) + if (LUA_CallAction(A_CHECKTOTALRINGS, actor)) return; for (i = 0; i < MAXPLAYERS; i++) @@ -10044,7 +10044,7 @@ void A_CheckHealth(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CheckHealth", actor)) + if (LUA_CallAction(A_CHECKHEALTH, actor)) return; if (actor->health <= locvar1) @@ -10066,7 +10066,7 @@ void A_CheckRange(mobj_t *actor) INT32 locvar2 = var2; fixed_t dist; - if (LUA_CallAction("A_CheckRange", actor)) + if (LUA_CallAction(A_CHECKRANGE, actor)) return; if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) @@ -10096,7 +10096,7 @@ void A_CheckHeight(mobj_t *actor) INT32 locvar2 = var2; fixed_t height; - if (LUA_CallAction("A_CheckHeight", actor)) + if (LUA_CallAction(A_CHECKHEIGHT, actor)) return; if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) @@ -10128,7 +10128,7 @@ void A_CheckTrueRange(mobj_t *actor) fixed_t dist; // horizontal range fixed_t l; // true range - if (LUA_CallAction("A_CheckTrueRange", actor)) + if (LUA_CallAction(A_CHECKTRUERANGE, actor)) return; if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) @@ -10179,7 +10179,7 @@ void A_CheckThingCount(mobj_t *actor) mobj_t *mo2; fixed_t dist = 0; - if (LUA_CallAction("A_CheckThingCount", actor)) + if (LUA_CallAction(A_CHECKTHINGCOUNT, actor)) return; for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -10224,7 +10224,7 @@ void A_CheckAmbush(mobj_t *actor) angle_t atp; // actor to target angle angle_t an; // angle between at and atp - if (LUA_CallAction("A_CheckAmbush", actor)) + if (LUA_CallAction(A_CHECKAMBUSH, actor)) return; if ((!locvar1 && !actor->target) || (locvar1 && !actor->tracer)) @@ -10262,7 +10262,7 @@ void A_CheckCustomValue(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CheckCustomValue", actor)) + if (LUA_CallAction(A_CHECKCUSTOMVALUE, actor)) return; if (actor->cusval >= locvar1) @@ -10281,7 +10281,7 @@ void A_CheckCusValMemo(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CheckCusValMemo", actor)) + if (LUA_CallAction(A_CHECKCUSVALMEMO, actor)) return; if (actor->cvmem >= locvar1) @@ -10306,7 +10306,7 @@ void A_SetCustomValue(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SetCustomValue", actor)) + if (LUA_CallAction(A_SETCUSTOMVALUE, actor)) return; if (cv_debug) @@ -10356,7 +10356,7 @@ void A_UseCusValMemo(mobj_t *actor) INT32 temp = actor->cusval; // value being manipulated INT32 tempM = actor->cvmem; // value used to manipulate temp with - if (LUA_CallAction("A_UseCusValMemo", actor)) + if (LUA_CallAction(A_USECUSVALMEMO, actor)) return; if (locvar1 == 1) // cvmem being changed using cusval @@ -10419,7 +10419,7 @@ void A_RelayCustomValue(mobj_t *actor) INT32 temp; // reference value - var1 lower 16 bits changes this INT32 tempT; // target's value - changed to tracer if var1 upper 16 bits set, then modified to become final value - if (LUA_CallAction("A_RelayCustomValue", actor)) + if (LUA_CallAction(A_RELAYCUSTOMVALUE, actor)) return; if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) @@ -10478,7 +10478,7 @@ void A_CusValAction(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CusValAction", actor)) + if (LUA_CallAction(A_CUSVALACTION, actor)) return; if (locvar2 == 5) @@ -10529,7 +10529,7 @@ void A_ForceStop(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_ForceStop", actor)) + if (LUA_CallAction(A_FORCESTOP, actor)) return; actor->momx = actor->momy = 0; @@ -10548,7 +10548,7 @@ void A_ForceWin(mobj_t *actor) { INT32 i; - if (LUA_CallAction("A_ForceWin", actor)) + if (LUA_CallAction(A_FORCEWIN, actor)) return; for (i = 0; i < MAXPLAYERS; i++) @@ -10582,7 +10582,7 @@ void A_SpikeRetract(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_SpikeRetract", actor)) + if (LUA_CallAction(A_SPIKERETRACT, actor)) return; if (actor->flags & MF_NOBLOCKMAP) @@ -10666,7 +10666,7 @@ void A_Repeat(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Repeat", actor)) + if (LUA_CallAction(A_REPEAT, actor)) return; if (locvar1 && (!actor->extravalue2 || actor->extravalue2 > locvar1)) @@ -10691,7 +10691,7 @@ void A_SetScale(mobj_t *actor) INT32 locvar2 = var2; mobj_t *target; - if (LUA_CallAction("A_SetScale", actor)) + if (LUA_CallAction(A_SETSCALE, actor)) return; if (locvar1 <= 0) @@ -10734,7 +10734,7 @@ void A_RemoteDamage(mobj_t *actor) mobj_t *target; // we MUST have a target mobj_t *source = NULL; // on the other hand we don't necessarily need a source - if (LUA_CallAction("A_RemoteDamage", actor)) + if (LUA_CallAction(A_REMOTEDAMAGE, actor)) return; if (locvar1 == 1) @@ -10787,7 +10787,7 @@ void A_HomingChase(mobj_t *actor) fixed_t dist; fixed_t speedmul; - if (LUA_CallAction("A_HomingChase", actor)) + if (LUA_CallAction(A_HOMINGCHASE, actor)) return; if (locvar2 == 1) @@ -10840,7 +10840,7 @@ void A_TrapShot(mobj_t *actor) fixed_t x, y, z; fixed_t speed; - if (LUA_CallAction("A_TrapShot", actor)) + if (LUA_CallAction(A_TRAPSHOT, actor)) return; x = actor->x + P_ReturnThrustX(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale)); @@ -10905,7 +10905,7 @@ void A_VileTarget(mobj_t *actor) mobjtype_t fogtype; INT32 i; - if (LUA_CallAction("A_VileTarget", actor)) + if (LUA_CallAction(A_VILETARGET, actor)) return; if (!actor->target) @@ -10992,7 +10992,7 @@ void A_VileAttack(mobj_t *actor) mobj_t *fire; INT32 i; - if (LUA_CallAction("A_VileAttack", actor)) + if (LUA_CallAction(A_VILEATTACK, actor)) return; if (!actor->target) @@ -11104,7 +11104,7 @@ void A_VileFire(mobj_t *actor) INT32 locvar2 = var2; mobj_t *dest; - if (LUA_CallAction("A_VileFire", actor)) + if (LUA_CallAction(A_VILEFIRE, actor)) return; dest = actor->tracer; @@ -11190,7 +11190,7 @@ void A_BrakChase(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_BrakChase", actor)) + if (LUA_CallAction(A_BRAKCHASE, actor)) return; // Set new tics NOW, in case the state changes while we're doing this and we try applying this to the painstate or something silly @@ -11310,7 +11310,7 @@ void A_BrakFireShot(mobj_t *actor) fixed_t x, y, z; INT32 locvar1 = var1; - if (LUA_CallAction("A_BrakFireShot", actor)) + if (LUA_CallAction(A_BRAKFIRESHOT, actor)) return; if (!actor->target) @@ -11373,7 +11373,7 @@ void A_BrakLobShot(mobj_t *actor) INT32 locvar2 = var2 & 0x0000FFFF; INT32 aimDirect = var2 & 0xFFFF0000; - if (LUA_CallAction("A_BrakLobShot", actor)) + if (LUA_CallAction(A_BRAKLOBSHOT, actor)) return; if (!actor->target) @@ -11479,7 +11479,7 @@ void A_NapalmScatter(mobj_t *actor) INT32 i; // for-loop cursor mobj_t *mo; // each and every spawned napalm burst - if (LUA_CallAction("A_NapalmScatter", actor)) + if (LUA_CallAction(A_NAPALMSCATTER, actor)) return; // Some quick sanity-checking @@ -11531,7 +11531,7 @@ void A_SpawnFreshCopy(mobj_t *actor) { mobj_t *newObject; - if (LUA_CallAction("A_SpawnFreshCopy", actor)) + if (LUA_CallAction(A_SPAWNFRESHCOPY, actor)) return; newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type); @@ -11607,7 +11607,7 @@ void A_FlickySpawn(mobj_t *actor) INT32 test = (var1 >> 16); SINT8 moveforward = 0; - if (LUA_CallAction("A_FlickySpawn", actor)) + if (LUA_CallAction(A_FLICKYSPAWN, actor)) return; if (test & 1) @@ -11675,7 +11675,7 @@ void A_FlickyCenter(mobj_t *actor) UINT8 flickycolor = ((locvar1 >> 16) & 0xFF); UINT8 flickyflags = ((locvar1 >> 20) & 0xF); - if (LUA_CallAction("A_FlickyCenter", actor)) + if (LUA_CallAction(A_FLICKYCENTER, actor)) return; if (!actor->tracer) @@ -11795,7 +11795,7 @@ void A_FlickyAim(mobj_t *actor) INT32 locvar2 = var2; boolean flickyhitwall = false; - if (LUA_CallAction("A_FlickyAim", actor)) + if (LUA_CallAction(A_FLICKYAIM, actor)) return; if ((actor->momx == actor->momy && actor->momy == 0) @@ -11895,7 +11895,7 @@ void A_FlickyFly(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FlickyFly", actor)) + if (LUA_CallAction(A_FLICKYFLY, actor)) return; P_InternalFlickyFly(actor, locvar1, locvar2, @@ -11915,7 +11915,7 @@ void A_FlickySoar(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FlickySoar", actor)) + if (LUA_CallAction(A_FLICKYSOAR, actor)) return; P_InternalFlickyFly(actor, locvar1, locvar2, @@ -11939,7 +11939,7 @@ void A_FlickyCoast(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FlickyCoast", actor)) + if (LUA_CallAction(A_FLICKYCOAST, actor)) return; if (actor->eflags & MFE_UNDERWATER) @@ -11986,7 +11986,7 @@ void A_FlickyHop(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FlickyHop", actor)) + if (LUA_CallAction(A_FLICKYHOP, actor)) return; P_InternalFlickyHop(actor, locvar1, locvar2, actor->angle); @@ -12005,7 +12005,7 @@ void A_FlickyFlounder(mobj_t *actor) INT32 locvar2 = var2; angle_t hopangle; - if (LUA_CallAction("A_FlickyFlounder", actor)) + if (LUA_CallAction(A_FLICKYFLOUNDER, actor)) return; locvar1 *= (P_RandomKey(2) + 1); @@ -12027,7 +12027,7 @@ void A_FlickyCheck(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FlickyCheck", actor)) + if (LUA_CallAction(A_FLICKYCHECK, actor)) return; if (actor->target @@ -12064,7 +12064,7 @@ void A_FlickyHeightCheck(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FlickyHeightCheck", actor)) + if (LUA_CallAction(A_FLICKYHEIGHTCHECK, actor)) return; if (actor->target @@ -12099,7 +12099,7 @@ void A_FlickyFlutter(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FlickyFlutter", actor)) + if (LUA_CallAction(A_FLICKYFLUTTER, actor)) return; var1 = locvar1; @@ -12130,7 +12130,7 @@ void A_FlameParticle(mobj_t *actor) fixed_t rad, hei; mobj_t *particle; - if (LUA_CallAction("A_FlameParticle", actor)) + if (LUA_CallAction(A_FLAMEPARTICLE, actor)) return; if (!type) @@ -12158,7 +12158,7 @@ void A_FadeOverlay(mobj_t *actor) mobj_t *fade; INT32 locvar1 = var1; - if (LUA_CallAction("A_FadeOverlay", actor)) + if (LUA_CallAction(A_FADEOVERLAY, actor)) return; fade = P_SpawnGhostMobj(actor); @@ -12199,7 +12199,7 @@ void A_Boss5Jump(mobj_t *actor) // INT32 locvar1 = var1; // INT32 locvar2 = var2; - if (LUA_CallAction("A_Boss5Jump", actor)) + if (LUA_CallAction(A_BOSS5JUMP, actor)) return; if (!actor->tracer) @@ -12276,7 +12276,7 @@ void A_LightBeamReset(mobj_t *actor) // INT32 locvar1 = var1; // INT32 locvar2 = var2; - if (LUA_CallAction("A_LightBeamReset", actor)) + if (LUA_CallAction(A_LIGHTBEAMRESET, actor)) return; actor->destscale = FRACUNIT + P_SignedRandom()*FRACUNIT/256; @@ -12306,7 +12306,7 @@ void A_MineExplode(mobj_t *actor) // INT32 locvar1 = var1; // INT32 locvar2 = var2; - if (LUA_CallAction("A_MineExplode", actor)) + if (LUA_CallAction(A_MINEEXPLODE, actor)) return; A_Scream(actor); @@ -12359,7 +12359,7 @@ void A_MineRange(mobj_t *actor) INT32 locvar1 = var1; // INT32 locvar2 = var2; - if (LUA_CallAction("A_MineRange", actor)) + if (LUA_CallAction(A_MINERANGE, actor)) return; if (!actor->target) @@ -12385,7 +12385,7 @@ void A_ConnectToGround(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_ConnectToGround", actor)) + if (LUA_CallAction(A_CONNECTTOGROUND, actor)) return; if (actor->subsector->sector->ffloors) @@ -12444,7 +12444,7 @@ void A_SpawnParticleRelative(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SpawnParticleRelative", actor)) + if (LUA_CallAction(A_SPAWNPARTICLERELATIVE, actor)) return; @@ -12482,7 +12482,7 @@ void A_MultiShotDist(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_MultiShotDist", actor)) + if (LUA_CallAction(A_MULTISHOTDIST, actor)) return; { @@ -12521,7 +12521,7 @@ void A_WhoCaresIfYourSonIsABee(mobj_t *actor) fixed_t foffsety; mobj_t *son; - if (LUA_CallAction("A_WhoCaresIfYourSonIsABee", actor)) + if (LUA_CallAction(A_WHOCARESIFYOURSONISABEE, actor)) return; A_FaceTarget(actor); @@ -12555,7 +12555,7 @@ void A_ParentTriesToSleep(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_ParentTriesToSleep", actor)) + if (LUA_CallAction(A_PARENTTRIESTOSLEEP, actor)) return; if (actor->extravalue1) @@ -12583,7 +12583,7 @@ void A_ParentTriesToSleep(mobj_t *actor) // void A_CryingToMomma(mobj_t *actor) { - if (LUA_CallAction("A_CryingToMomma", actor)) + if (LUA_CallAction(A_CRYINGTOMOMMA, actor)) return; if (actor->tracer) @@ -12613,7 +12613,7 @@ void A_CheckFlags2(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CheckFlags2", actor)) + if (LUA_CallAction(A_CHECKFLAGS2, actor)) return; if (actor->flags2 & locvar1) @@ -12634,7 +12634,7 @@ void A_Boss5FindWaypoint(mobj_t *actor) UINT32 i; UINT8 extrainfo = (actor->spawnpoint ? actor->spawnpoint->extrainfo : 0); - if (LUA_CallAction("A_Boss5FindWaypoint", actor)) + if (LUA_CallAction(A_BOSS5FINDWAYPOINT, actor)) return; avoidcenter = !actor->tracer || (actor->health == actor->info->damage+1); @@ -12851,7 +12851,7 @@ void A_DoNPCSkid(mobj_t *actor) INT32 locvar2 = var2; fixed_t x, y, z; - if (LUA_CallAction("A_DoNPCSkid", actor)) + if (LUA_CallAction(A_DONPCSKID, actor)) return; x = actor->x; @@ -12907,7 +12907,7 @@ void A_DoNPCPain(mobj_t *actor) fixed_t vspeed = 0; fixed_t hspeed = FixedMul(4*FRACUNIT, actor->scale); - if (LUA_CallAction("A_DoNPCPain", actor)) + if (LUA_CallAction(A_DONPCPAIN, actor)) return; actor->flags &= ~(MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT); @@ -12955,7 +12955,7 @@ void A_PrepareRepeat(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_PrepareRepeat", actor)) + if (LUA_CallAction(A_PREPAREREPEAT, actor)) return; actor->extravalue2 = locvar1; @@ -12976,7 +12976,7 @@ void A_Boss5ExtraRepeat(mobj_t *actor) INT32 locspawn; INT32 lochealth; - if (LUA_CallAction("A_Boss5ExtraRepeat", actor)) + if (LUA_CallAction(A_BOSS5EXTRAREPEAT, actor)) return; if (actor->extravalue2 > 0 && !(actor->flags2 & MF2_FRET)) @@ -13008,7 +13008,7 @@ void A_Boss5ExtraRepeat(mobj_t *actor) // void A_Boss5Calm(mobj_t *actor) { - if (LUA_CallAction("A_Boss5Calm", actor)) + if (LUA_CallAction(A_BOSS5CALM, actor)) return; actor->flags |= MF_SHOOTABLE; @@ -13027,7 +13027,7 @@ void A_Boss5CheckOnGround(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Boss5CheckOnGround", actor)) + if (LUA_CallAction(A_BOSS5CHECKONGROUND, actor)) return; if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) @@ -13058,7 +13058,7 @@ void A_Boss5CheckFalling(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Boss5CheckFalling", actor)) + if (LUA_CallAction(A_BOSS5CHECKFALLING, actor)) return; if (actor->health && actor->extravalue2 > 1) @@ -13087,7 +13087,7 @@ void A_Boss5PinchShot(mobj_t *actor) fixed_t zoffset; mobj_t *missile; - if (LUA_CallAction("A_Boss5PinchShot", actor)) + if (LUA_CallAction(A_BOSS5PINCHSHOT, actor)) return; if (actor->health > actor->info->damage) @@ -13122,7 +13122,7 @@ void A_Boss5MakeItRain(mobj_t *actor) INT32 offset = (48 + locvar2)<<16; // upper 16 bits, not fixed_t! INT32 i; - if (LUA_CallAction("A_Boss5MakeItRain", actor)) + if (LUA_CallAction(A_BOSS5MAKEITRAIN, actor)) return; actor->flags2 |= MF2_STRONGBOX; @@ -13158,7 +13158,7 @@ void A_Boss5MakeJunk(mobj_t *actor) angle_t ang; INT32 i = ((locvar2 & 1) ? 8 : 1); - if (LUA_CallAction("A_Boss5MakeJunk", actor)) + if (LUA_CallAction(A_BOSS5MAKEJUNK, actor)) return; if (locvar1 < 0 && (actor->flags2 & MF2_SLIDEPUSH)) // this entire action is a hack, don't judge me @@ -13248,7 +13248,7 @@ void A_LookForBetter(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_LookForBetter", actor)) + if (LUA_CallAction(A_LOOKFORBETTER, actor)) return; P_LookForPlayers(actor, (locvar1 & 65535), false, FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale)); @@ -13308,7 +13308,7 @@ void A_Boss5BombExplode(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_Boss5BombExplode", actor)) + if (LUA_CallAction(A_BOSS5BOMBEXPLODE, actor)) return; // The original Lua script did not use |= to add flags but just set these flags exactly apparently? @@ -13418,7 +13418,7 @@ void A_DustDevilThink(mobj_t *actor) INT32 bx, by, xl, xh, yl, yh; fixed_t radius = actor->radius; - if (LUA_CallAction("A_DustDevilThink", actor)) + if (LUA_CallAction(A_DUSTDEVILTHINK, actor)) return; //Chained thinker for the spiralling dust column. @@ -13560,7 +13560,7 @@ void A_TNTExplode(mobj_t *actor) INT32 xl, xh, yl, yh; static mappoint_t epicenter = {0,0,0}; - if (LUA_CallAction("A_TNTExplode", actor)) + if (LUA_CallAction(A_TNTEXPLODE, actor)) return; if (actor->tracer) @@ -13626,7 +13626,7 @@ void A_DebrisRandom(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_DebrisRandom", actor)) + if (LUA_CallAction(A_DEBRISRANDOM, actor)) return; actor->frame |= P_RandomRange(0, locvar1); @@ -13667,7 +13667,7 @@ void A_TrainCameo(mobj_t *actor) fixed_t span = locvar1*FRACUNIT; fixed_t len = locvar2*FRACUNIT; - if (LUA_CallAction("A_TrainCameo", actor)) + if (LUA_CallAction(A_TRAINCAMEO, actor)) return; //Spawn sides. @@ -13705,7 +13705,7 @@ void A_TrainCameo2(mobj_t *actor) fixed_t span = locvar1*FRACUNIT; fixed_t len = locvar2*FRACUNIT; - if (LUA_CallAction("A_TrainCameo2", actor)) + if (LUA_CallAction(A_TRAINCAMEO2, actor)) return; //Spawn sides. @@ -13731,7 +13731,7 @@ void A_CanarivoreGas(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_CanarivoreGas", actor)) + if (LUA_CallAction(A_CANARIVOREGAS, actor)) return; P_DustRing(locvar1, 4, actor->x, actor->y, actor->z + actor->height / 5, 18, 0, FRACUNIT/10, actor->scale); @@ -13752,7 +13752,7 @@ void A_KillSegments(mobj_t *actor) mobj_t *seg = actor->tracer; INT32 fuse = locvar1 ? locvar1 : TICRATE/2; - if (LUA_CallAction("A_KillSegments", actor)) + if (LUA_CallAction(A_KILLSEGMENTS, actor)) return; while (seg) @@ -13835,7 +13835,7 @@ void A_SnapperSpawn(mobj_t *actor) INT32 i; mobj_t *seg; - if (LUA_CallAction("A_SnapperSpawn", actor)) + if (LUA_CallAction(A_SNAPPERSPAWN, actor)) return; // It spawns 1 head. @@ -13885,7 +13885,7 @@ void A_SnapperThinker(mobj_t *actor) fixed_t dist; boolean chasing; - if (LUA_CallAction("A_SnapperThinker", actor)) + if (LUA_CallAction(A_SNAPPERTHINKER, actor)) return; // We make a check just in case there's no spawnpoint. @@ -14006,7 +14006,7 @@ void A_SaloonDoorSpawn(mobj_t *actor) mobj_t *door; mobjflag2_t ambush = (actor->flags2 & MF2_AMBUSH); - if (LUA_CallAction("A_SaloonDoorSpawn", actor)) + if (LUA_CallAction(A_SALOONDOORSPAWN, actor)) return; if (!locvar1) @@ -14043,7 +14043,7 @@ void A_MinecartSparkThink(mobj_t *actor) fixed_t dz, dm; UINT8 i; - if (LUA_CallAction("A_MinecartSparkThink", actor)) + if (LUA_CallAction(A_MINECARTSPARKTHINK, actor)) return; if (actor->momz == 0 && P_IsObjectOnGround(actor)) @@ -14077,7 +14077,7 @@ void A_ModuloToState(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_ModuloToState", actor)) + if (LUA_CallAction(A_MODULOTOSTATE, actor)) return; if ((modulothing % locvar1 == 0)) @@ -14096,7 +14096,7 @@ void A_LavafallRocks(mobj_t *actor) { UINT8 i; - if (LUA_CallAction("A_LavafallRocks", actor)) + if (LUA_CallAction(A_LAVAFALLROCKS, actor)) return; // Don't spawn rocks unless a player is relatively close by. @@ -14127,7 +14127,7 @@ void A_LavafallLava(mobj_t *actor) mobj_t *lavafall; UINT8 i; - if (LUA_CallAction("A_LavafallLava", actor)) + if (LUA_CallAction(A_LAVAFALLLAVA, actor)) return; if ((40 - actor->fuse) % (2*(actor->scale >> FRACBITS))) @@ -14155,7 +14155,7 @@ void A_LavafallLava(mobj_t *actor) // void A_FallingLavaCheck(mobj_t *actor) { - if (LUA_CallAction("A_FallingLavaCheck", actor)) + if (LUA_CallAction(A_FALLINGLAVACHECK, actor)) return; if (actor->eflags & MFE_TOUCHWATER || P_IsObjectOnGround(actor)) @@ -14180,7 +14180,7 @@ void A_FireShrink(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FireShrink", actor)) + if (LUA_CallAction(A_FIRESHRINK, actor)) return; actor->destscale = locvar1; @@ -14204,7 +14204,7 @@ void A_SpawnPterabytes(mobj_t *actor) UINT8 amount = 1; UINT8 i; - if (LUA_CallAction("A_SpawnPterabytes", actor)) + if (LUA_CallAction(A_SPAWNPTERABYTES, actor)) return; if (actor->spawnpoint) @@ -14239,7 +14239,7 @@ void A_PterabyteHover(mobj_t *actor) { angle_t ang, fa; - if (LUA_CallAction("A_PterabyteHover", actor)) + if (LUA_CallAction(A_PTERABYTEHOVER, actor)) return; P_InstaThrust(actor, actor->angle, actor->info->speed); @@ -14261,7 +14261,7 @@ void A_RolloutSpawn(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_RolloutSpawn", actor)) + if (LUA_CallAction(A_ROLLOUTSPAWN, actor)) return; if (!(actor->target) @@ -14297,7 +14297,7 @@ void A_RolloutRock(mobj_t *actor) fixed_t speed = P_AproxDistance(actor->momx, actor->momy), topspeed = FixedMul(actor->info->speed, actor->scale); boolean inwater = actor->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER); - if (LUA_CallAction("A_RolloutRock", actor)) + if (LUA_CallAction(A_ROLLOUTROCK, actor)) return; actor->friction = FRACUNIT; // turns out riding on solids sucks, so let's just make it easier on ourselves @@ -14380,7 +14380,7 @@ void A_DragonbomberSpawn(mobj_t *actor) UINT8 i; mobj_t *mo = actor; - if (LUA_CallAction("A_DragonbomberSpawn", actor)) + if (LUA_CallAction(A_DRAGONBOMBERSPAWN, actor)) return; for (i = 0; i < var1; i++) // spawn tail segments @@ -14416,7 +14416,7 @@ void A_DragonWing(mobj_t *actor) mobj_t *target = actor->target; fixed_t x, y; - if (LUA_CallAction("A_DragonWing", actor)) + if (LUA_CallAction(A_DRAGONWING, actor)) return; if (target == NULL || !target->health) @@ -14449,7 +14449,7 @@ void A_DragonSegment(mobj_t *actor) fixed_t ydist; fixed_t zdist; - if (LUA_CallAction("A_DragonSegment", actor)) + if (LUA_CallAction(A_DRAGONSEGMENT, actor)) return; if (target == NULL || !target->health) @@ -14487,7 +14487,7 @@ void A_ChangeHeight(mobj_t *actor) fixed_t height = locvar1; boolean reverse; - if (LUA_CallAction("A_ChangeHeight", actor)) + if (LUA_CallAction(A_CHANGEHEIGHT, actor)) return; reverse = (actor->eflags & MFE_VERTICALFLIP) || (actor->flags2 & MF2_OBJECTFLIP); diff --git a/src/p_mobj.c b/src/p_mobj.c index a53599c8db694413f35a7f9f3a8439133c8a8fba..fecfaef7218933a75e8639451e375843a1fc6083 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -38,10 +38,6 @@ static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL); -#ifdef WALLSPLATS -consvar_t cv_splats = CVAR_INIT ("splats", "On", CV_SAVE, CV_OnOff, NULL); -#endif - actioncache_t actioncachehead; static mobj_t *overlaycap = NULL; @@ -1966,29 +1962,6 @@ void P_XYMovement(mobj_t *mo) return; } - // draw damage on wall - //SPLAT TEST ---------------------------------------------------------- -#ifdef WALLSPLATS - if (blockingline && mo->type != MT_REDRING && mo->type != MT_FIREBALL - && !(mo->flags2 & (MF2_AUTOMATIC|MF2_RAILRING|MF2_BOUNCERING|MF2_EXPLOSION|MF2_SCATTER))) - // set by last P_TryMove() that failed - { - divline_t divl; - divline_t misl; - fixed_t frac; - - P_MakeDivline(blockingline, &divl); - misl.x = mo->x; - misl.y = mo->y; - misl.dx = mo->momx; - misl.dy = mo->momy; - frac = P_InterceptVector(&divl, &misl); - R_AddWallSplat(blockingline, P_PointOnLineSide(mo->x,mo->y,blockingline), - "A_DMG3", mo->z, frac, SPLATDRAWMODE_SHADE); - } -#endif - // --------------------------------------------------------- SPLAT TEST - P_ExplodeMissile(mo); return; } @@ -9615,12 +9588,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->fuse = 1; // Return to base. break; } - case MT_CANNONBALL: -#ifdef FLOORSPLATS - R_AddFloorSplat(mobj->tracer->subsector, mobj->tracer, "TARGET", mobj->tracer->x, - mobj->tracer->y, mobj->tracer->floorz, SPLATDRAWMODE_SHADE); -#endif - break; case MT_SPINDUST: // Spindash dust mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000 mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same @@ -10509,6 +10476,12 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) if ((maptol & TOL_ERZ3) && !(mobj->type == MT_BLACKEGGMAN)) mobj->destscale = FRACUNIT/2; + // Sprite rendering + mobj->blendmode = AST_TRANSLUCENT; + mobj->spritexscale = mobj->spriteyscale = mobj->scale; + mobj->spritexoffset = mobj->spriteyoffset = 0; + mobj->floorspriteslope = NULL; + // set subsector and/or block links P_SetThingPosition(mobj); I_Assert(mobj->subsector != NULL); @@ -10909,6 +10882,22 @@ static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mob return mo; } +void *P_CreateFloorSpriteSlope(mobj_t *mobj) +{ + if (mobj->floorspriteslope) + Z_Free(mobj->floorspriteslope); + mobj->floorspriteslope = Z_Calloc(sizeof(pslope_t), PU_LEVEL, NULL); + mobj->floorspriteslope->normal.z = FRACUNIT; + return (void *)mobj->floorspriteslope; +} + +void P_RemoveFloorSpriteSlope(mobj_t *mobj) +{ + if (mobj->floorspriteslope) + Z_Free(mobj->floorspriteslope); + mobj->floorspriteslope = NULL; +} + // // P_RemoveMobj // @@ -10965,11 +10954,14 @@ void P_RemoveMobj(mobj_t *mobj) P_DelSeclist(sector_list); sector_list = NULL; } + mobj->flags |= MF_NOSECTOR|MF_NOBLOCKMAP; mobj->subsector = NULL; mobj->state = NULL; mobj->player = NULL; + P_RemoveFloorSpriteSlope(mobj); + // stop any playing sound S_StopSound(mobj); @@ -13086,8 +13078,8 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, mobj = P_SpawnMobj(x, y, z, i); mobj->spawnpoint = mthing; - P_SetScale(mobj, mthing->scale); - mobj->destscale = mthing->scale; + P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale)); + mobj->destscale = FixedMul(mobj->destscale, mthing->scale); if (!P_SetupSpawnedMapThing(mthing, mobj, &doangle)) return mobj; diff --git a/src/p_mobj.h b/src/p_mobj.h index 27a6ef4f05d3a2f8a5a9cf57b8fe495fe4325ff0..5bb7c908e85463020507f1e02dbb7059d904ddf6 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -194,6 +194,7 @@ typedef enum MF2_AMBUSH = 1<<27, // Alternate behaviour typically set by MTF_AMBUSH MF2_LINKDRAW = 1<<28, // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) MF2_SHIELD = 1<<29, // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use) + MF2_SPLAT = 1<<30, // Renders as a splat // free: to and including 1<<31 } mobjflag2_t; @@ -264,6 +265,7 @@ typedef enum { // Ran the thinker this tic. PCF_THUNK = 32, } precipflag_t; + // Map Object definition. typedef struct mobj_s { @@ -285,6 +287,12 @@ typedef struct mobj_s UINT8 sprite2; // player sprites UINT16 anim_duration; // for FF_ANIMATE states + UINT32 renderflags; // render flags + INT32 blendmode; // blend mode + fixed_t spritexscale, spriteyscale; + fixed_t spritexoffset, spriteyoffset; + struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by + struct msecnode_s *touching_sectorlist; // a linked list of sectors where this object appears struct subsector_s *subsector; // Subsector the mobj resides in. @@ -399,13 +407,19 @@ typedef struct precipmobj_s struct precipmobj_s **sprev; // killough 8/11/98: change to ptr-to-ptr // More drawing info: to determine current sprite. - angle_t angle, pitch, roll; // orientation + angle_t angle, pitch, roll; // orientation angle_t rollangle; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h UINT8 sprite2; // player sprites UINT16 anim_duration; // for FF_ANIMATE states + UINT32 renderflags; // render flags + INT32 blendmode; // blend mode + fixed_t spritexscale, spriteyscale; + fixed_t spritexoffset, spriteyoffset; + struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by + struct mprecipsecnode_s *touching_sectorlist; // a linked list of sectors where this object appears struct subsector_s *subsector; // Subsector the mobj resides in. @@ -462,6 +476,8 @@ void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime); void P_SpawnHoopOfSomething(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle); void P_SpawnPrecipitation(void); void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, statenum_t nstate, angle_t rotangle, boolean spawncenter); +void *P_CreateFloorSpriteSlope(mobj_t *mobj); +void P_RemoveFloorSpriteSlope(mobj_t *mobj); boolean P_BossTargetPlayer(mobj_t *actor, boolean closest); boolean P_SupermanLook4Players(mobj_t *actor); void P_DestroyRobots(void); diff --git a/src/p_saveg.c b/src/p_saveg.c index 2abd65a9598cafe6e224d6f2d319e86aeb0cab5c..adedea049108ecbd1d44b8931bb0854365128005 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1417,6 +1417,13 @@ typedef enum MD2_MIRRORED = 1<<13, MD2_ROLLANGLE = 1<<14, MD2_SHADOWSCALE = 1<<15, + MD2_RENDERFLAGS = 1<<16, + MD2_BLENDMODE = 1<<17, + MD2_SPRITEXSCALE = 1<<18, + MD2_SPRITEYSCALE = 1<<19, + MD2_SPRITEXOFFSET = 1<<20, + MD2_SPRITEYOFFSET = 1<<21, + MD2_FLOORSPRITESLOPE = 1<<22, } mobj_diff2_t; typedef enum @@ -1629,6 +1636,27 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_ROLLANGLE; if (mobj->shadowscale) diff2 |= MD2_SHADOWSCALE; + if (mobj->renderflags) + diff2 |= MD2_RENDERFLAGS; + if (mobj->renderflags) + diff2 |= MD2_BLENDMODE; + if (mobj->spritexscale != FRACUNIT) + diff2 |= MD2_SPRITEXSCALE; + if (mobj->spriteyscale != FRACUNIT) + diff2 |= MD2_SPRITEYSCALE; + if (mobj->spritexoffset) + diff2 |= MD2_SPRITEXOFFSET; + if (mobj->floorspriteslope) + { + pslope_t *slope = mobj->floorspriteslope; + if (slope->zangle || slope->zdelta || slope->xydirection + || slope->o.x || slope->o.y || slope->o.z + || slope->d.x || slope->d.y + || slope->normal.x || slope->normal.y + || (slope->normal.z != FRACUNIT)) + diff2 |= MD2_FLOORSPRITESLOPE; + } + if (diff2 != 0) diff |= MD_MORE; @@ -1771,6 +1799,37 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEANGLE(save_p, mobj->rollangle); if (diff2 & MD2_SHADOWSCALE) WRITEFIXED(save_p, mobj->shadowscale); + if (diff2 & MD2_RENDERFLAGS) + WRITEUINT32(save_p, mobj->renderflags); + if (diff2 & MD2_BLENDMODE) + WRITEINT32(save_p, mobj->blendmode); + if (diff2 & MD2_SPRITEXSCALE) + WRITEFIXED(save_p, mobj->spritexscale); + if (diff2 & MD2_SPRITEYSCALE) + WRITEFIXED(save_p, mobj->spriteyscale); + if (diff2 & MD2_SPRITEXOFFSET) + WRITEFIXED(save_p, mobj->spritexoffset); + if (diff2 & MD2_SPRITEYOFFSET) + WRITEFIXED(save_p, mobj->spriteyoffset); + if (diff2 & MD2_FLOORSPRITESLOPE) + { + pslope_t *slope = mobj->floorspriteslope; + + WRITEFIXED(save_p, slope->zdelta); + WRITEANGLE(save_p, slope->zangle); + WRITEANGLE(save_p, slope->xydirection); + + WRITEFIXED(save_p, slope->o.x); + WRITEFIXED(save_p, slope->o.y); + WRITEFIXED(save_p, slope->o.z); + + WRITEFIXED(save_p, slope->d.x); + WRITEFIXED(save_p, slope->d.y); + + WRITEFIXED(save_p, slope->normal.x); + WRITEFIXED(save_p, slope->normal.y); + WRITEFIXED(save_p, slope->normal.z); + } WRITEUINT32(save_p, mobj->mobjnum); } @@ -2780,6 +2839,37 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->rollangle = READANGLE(save_p); if (diff2 & MD2_SHADOWSCALE) mobj->shadowscale = READFIXED(save_p); + if (diff2 & MD2_RENDERFLAGS) + mobj->renderflags = READUINT32(save_p); + if (diff2 & MD2_BLENDMODE) + mobj->blendmode = READINT32(save_p); + if (diff2 & MD2_SPRITEXSCALE) + mobj->spritexscale = READFIXED(save_p); + if (diff2 & MD2_SPRITEYSCALE) + mobj->spriteyscale = READFIXED(save_p); + if (diff2 & MD2_SPRITEXOFFSET) + mobj->spritexoffset = READFIXED(save_p); + if (diff2 & MD2_SPRITEYOFFSET) + mobj->spriteyoffset = READFIXED(save_p); + if (diff2 & MD2_FLOORSPRITESLOPE) + { + pslope_t *slope = (pslope_t *)P_CreateFloorSpriteSlope(mobj); + + slope->zdelta = READFIXED(save_p); + slope->zangle = READANGLE(save_p); + slope->xydirection = READANGLE(save_p); + + slope->o.x = READFIXED(save_p); + slope->o.y = READFIXED(save_p); + slope->o.z = READFIXED(save_p); + + slope->d.x = READFIXED(save_p); + slope->d.y = READFIXED(save_p); + + slope->normal.x = READFIXED(save_p); + slope->normal.y = READFIXED(save_p); + slope->normal.z = READFIXED(save_p); + } if (diff & MD_REDFLAG) { @@ -4016,6 +4106,12 @@ static void P_NetArchiveMisc(boolean resending) WRITEINT32(save_p, sstimer); WRITEUINT32(save_p, bluescore); WRITEUINT32(save_p, redscore); + + WRITEUINT16(save_p, skincolor_redteam); + WRITEUINT16(save_p, skincolor_blueteam); + WRITEUINT16(save_p, skincolor_redring); + WRITEUINT16(save_p, skincolor_bluering); + WRITEINT32(save_p, modulothing); WRITEINT16(save_p, autobalance); @@ -4105,6 +4201,12 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) sstimer = READINT32(save_p); bluescore = READUINT32(save_p); redscore = READUINT32(save_p); + + skincolor_redteam = READUINT16(save_p); + skincolor_blueteam = READUINT16(save_p); + skincolor_redring = READUINT16(save_p); + skincolor_bluering = READUINT16(save_p); + modulothing = READINT32(save_p); autobalance = READINT16(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index fb631fd12c85f1d9521b7e79ee1fa29b9167a9fc..9db53b0ee09afbd601c61b179680e58116c147ec 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -29,6 +29,7 @@ #include "r_data.h" #include "r_things.h" // for R_AddSpriteDefs #include "r_textures.h" +#include "r_patch.h" #include "r_picformats.h" #include "r_sky.h" #include "r_draw.h" @@ -550,7 +551,7 @@ Ploadflat (levelflat_t *levelflat, const char *flatname, boolean resize) lumpnum_t flatnum; int texturenum; - patch_t *flatpatch; + UINT8 *flatpatch; size_t lumplength; size_t i; @@ -610,7 +611,7 @@ flatfound: /* This could be a flat, patch, or PNG. */ flatpatch = W_CacheLumpNum(flatnum, PU_CACHE); lumplength = W_LumpLength(flatnum); - if (Picture_CheckIfPatch(flatpatch, lumplength)) + if (Picture_CheckIfDoomPatch((softwarepatch_t *)flatpatch, lumplength)) levelflat->type = LEVELFLAT_PATCH; else { @@ -1074,9 +1075,6 @@ static void P_InitializeLinedef(line_t *ld) ld->frontsector = ld->backsector = NULL; ld->validcount = 0; -#ifdef WALLSPLATS - ld->splats = NULL; -#endif ld->polyobj = NULL; ld->text = NULL; @@ -1341,7 +1339,7 @@ static void P_LoadSidedefs(UINT8 *data) || (msd->toptexture[0] >= 'A' && msd->toptexture[0] <= 'F')) sd->toptexture = axtoi(msd->toptexture); else - I_Error("Custom FOF (line id %d) needs a value in the linedef's back side upper texture field.", sd->line - lines); + I_Error("Custom FOF (line id %s) needs a value in the linedef's back side upper texture field.", sizeu1(sd->line - lines)); sd->midtexture = R_TextureNumForName(msd->midtexture); sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); @@ -2106,9 +2104,6 @@ static boolean P_LoadMapData(const virtres_t *virt) static void P_InitializeSubsector(subsector_t *ss) { ss->sector = NULL; -#ifdef FLOORSPLATS - ss->splats = NULL; -#endif ss->validcount = 0; } @@ -2153,7 +2148,7 @@ static void P_LoadNodes(UINT8 *data) * \param seg Seg to compute length for. * \return Length in fracunits. */ -fixed_t P_SegLength(seg_t *seg) +static fixed_t P_SegLength(seg_t *seg) { INT64 dx = (seg->v2->x - seg->v1->x)>>1; INT64 dy = (seg->v2->y - seg->v1->y)>>1; @@ -4537,13 +4532,16 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // Clear pointers that would be left dangling by the purge R_FlushTranslationColormapCache(); - Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1); - -#if defined (WALLSPLATS) || defined (FLOORSPLATS) - // clear the splats from previous level - R_ClearLevelSplats(); +#ifdef HWRENDER + // Free GPU textures before freeing patches. + if (vid.glstate == VID_GL_LIBRARY_LOADED) + HWR_ClearAllTextures(); #endif + Patch_FreeTag(PU_PATCH_LOWPRIORITY); + Patch_FreeTag(PU_PATCH_ROTATED); + Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1); + P_InitThinkers(); P_InitCachedActions(); @@ -4600,14 +4598,14 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_SpawnPrecipitation(); #ifdef HWRENDER // not win32 only 19990829 by Kin + gl_maploaded = false; + // 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 + HWR_FreeExtraSubsectors(); + + // Create plane polygons. if (rendermode == render_opengl) - HWR_SetupLevel(); + HWR_LoadLevel(); #endif // oh god I hope this helps @@ -4694,33 +4692,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) 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. - - // Sal: Unfortunately, NOT freeing them causes the dreaded Color Bug. - HWR_FreeMipmapCache(); - -#ifdef ALAM_LIGHTING - // BP: reset light between levels (we draw preview frame lights on current frame) - HWR_ResetLights(); -#endif - - HWR_CreatePlanePolygons((INT32)numnodes - 1); - - // Build the sky dome - HWR_ClearSkyDome(); - HWR_BuildSkyDome(); -} -#endif - // // P_RunSOC // @@ -4926,10 +4897,17 @@ boolean P_AddWadFile(const char *wadfilename) if (!devparm && digmreplaces) CONS_Printf(M_GetText("%s digital musics replaced\n"), sizeu1(digmreplaces)); +#ifdef HWRENDER + // Free GPU textures before freeing patches. + if (vid.glstate == VID_GL_LIBRARY_LOADED) + HWR_ClearAllTextures(); +#endif // // search for sprite replacements // + Patch_FreeTag(PU_SPRITE); + Patch_FreeTag(PU_PATCH_ROTATED); R_AddSpriteDefs(wadnum); // Reload it all anyway, just in case they diff --git a/src/p_setup.h b/src/p_setup.h index c82f93351e48a2a66bae43dfa1781d5a45265b32..34de9c93da1c4a91f7c46cc25af8107136df530e 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -99,7 +99,7 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); void P_RespawnThings(void); boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); #ifdef HWRENDER -void HWR_SetupLevel(void); +void HWR_LoadLevel(void); #endif boolean P_AddWadFile(const char *wadfilename); boolean P_RunSOC(const char *socfilename); diff --git a/src/p_tick.c b/src/p_tick.c index 451e5e6266d9084586e21f0211e9a4ff3b15210d..da2a980c480a54f22d2dc2c3ef2904e96c07a1e8 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -643,7 +643,15 @@ void P_Ticker(boolean run) if (demorecording) G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); if (demoplayback) - G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0); + { + player_t* p = &players[consoleplayer]; + G_ReadDemoTiccmd(&p->cmd, 0); + if (!cv_freedemocamera.value) + { + P_ForceLocalAngle(p, p->cmd.angleturn << 16); + localaiming = p->aiming; + } + } ps_lua_mobjhooks = 0; ps_checkposition_calls = 0; diff --git a/src/p_user.c b/src/p_user.c index d066dbba3e09135acf3372b80da39785d73d48d8..e94666b9bf8ffcc3e1cb8ff7c6ffce3f211476c6 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4839,6 +4839,8 @@ void P_DoJumpShield(player_t *player) } #undef limitangle #undef numangles + player->pflags &= ~PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); S_StartSound(player->mo, sfx_s3k45); } else @@ -5111,6 +5113,8 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock player->pflags |= PF_THOKKED|PF_SHIELDABILITY; P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); player->drawangle = player->mo->angle; + player->pflags &= ~PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); S_StartSound(player->mo, sfx_s3k43); default: break; @@ -8695,12 +8699,6 @@ void P_MovePlayer(player_t *player) player->fovadd = 0; #endif -#ifdef FLOORSPLATS - if (cv_shadow.value && rendermode == render_soft) - R_AddFloorSplat(player->mo->subsector, player->mo, "SHADOW", player->mo->x, - player->mo->y, player->mo->floorz, SPLATDRAWMODE_OPAQUE); -#endif - // Look for blocks to bust up // Because of BT_TOUCH, we should look for blocks constantly, // not just when spinning or playing as Knuckles diff --git a/src/r_bsp.c b/src/r_bsp.c index 2a3c662aa3f6e1db8bc6aeab332d488b9cfb93db..6f2a90d2d5e6c8642b4dc0eded0d47afb189012b 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -1053,11 +1053,6 @@ static void R_Subsector(size_t num) } } -#ifdef FLOORSPLATS - if (sub->splats) - R_AddVisibleFloorSplats(sub); -#endif - // killough 9/18/98: Fix underwater slowdown, by passing real sector // instead of fake one. Improve sprite lighting by basing sprite // lightlevels on floor & ceiling lightlevels in the surrounding area. diff --git a/src/r_data.c b/src/r_data.c index dd36c2ee28623ce1ce16aa49709196009702e08b..af672f6dc024ee2c6840818982d586b17ceacb07 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -20,6 +20,7 @@ #include "m_misc.h" #include "r_data.h" #include "r_textures.h" +#include "r_patch.h" #include "r_picformats.h" #include "w_wad.h" #include "z_zone.h" @@ -174,13 +175,15 @@ UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT if (alpha <= ASTTextureBlendingThreshold[1]) { UINT8 *mytransmap; + INT32 trans; // Is the patch way too translucent? Don't blend then. if (alpha < ASTTextureBlendingThreshold[0]) return background; // The equation's not exact but it works as intended. I'll call it a day for now. - mytransmap = transtables + ((8*(alpha) + 255/8)/(255 - 255/11) << FF_TRANSSHIFT); + trans = (8*(alpha) + 255/8)/(255 - 255/11); + mytransmap = R_GetTranslucencyTable(trans + 1); if (background != 0xFF) return *(mytransmap + (background<<8) + foreground); } @@ -1307,7 +1310,7 @@ void R_PrecacheLevel(void) lump = sf->lumppat[a];\ if (devparm)\ spritememory += W_LumpLength(lump);\ - W_CachePatchNum(lump, PU_PATCH);\ + W_CachePatchNum(lump, PU_SPRITE);\ } // see R_InitSprites for more about lumppat,lumpid switch (sf->rotate) diff --git a/src/r_defs.h b/src/r_defs.h index 0fe39dd7b6c32229f8f8e3b79ea61581fa300d87..b7cd2cb5fadb5d3aa3fc7a0db0b95fd3ff547edb 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -439,9 +439,6 @@ typedef struct line_s sector_t *backsector; size_t validcount; // if == validcount, already checked -#if 1//#ifdef WALLSPLATS - void *splats; // wallsplat_t list -#endif polyobj_t *polyobj; // Belongs to a polyobject? char *text; // a concatenation of all front and back texture names, for linedef specials that require a string. @@ -486,9 +483,6 @@ typedef struct subsector_s INT16 numlines; UINT16 firstline; struct polyobj_s *polyList; // haleyjd 02/19/06: list of polyobjects -#if 1//#ifdef FLOORSPLATS - void *splats; // floorsplat_t list -#endif size_t validcount; } subsector_t; @@ -681,8 +675,12 @@ typedef enum RGBA32 = 4, // 32 bit rgba } pic_mode_t; -#if defined(_MSC_VER) -#pragma pack(1) +#ifdef ROTSPRITE +typedef struct +{ + INT32 angles; + void **patches; +} rotsprite_t; #endif // Patches. @@ -690,7 +688,26 @@ typedef enum // Patches are used for sprites and all masked pictures, and we compose // textures from the TEXTURES list of patches. // -// WARNING: this structure is cloned in GLPatch_t +typedef struct +{ + INT16 width, height; + INT16 leftoffset, topoffset; + + INT32 *columnofs; // Column offsets. This is relative to patch->columns + UINT8 *columns; // Software column data + + void *hardware; // OpenGL patch, allocated whenever necessary + void *flats[4]; // The patch as flats + +#ifdef ROTSPRITE + rotsprite_t *rotated; // Rotated patches +#endif +} patch_t; + +#if defined(_MSC_VER) +#pragma pack(1) +#endif + typedef struct { INT16 width; // bounding box size @@ -699,7 +716,7 @@ typedef struct INT16 topoffset; // pixels below the origin INT32 columnofs[8]; // only [width] used // the [0] is &columnofs[width] -} ATTRPACK patch_t; +} ATTRPACK softwarepatch_t; #ifdef _MSC_VER #pragma warning(disable : 4200) @@ -725,14 +742,32 @@ typedef struct #pragma pack() #endif -// rotsprite -#ifdef ROTSPRITE -typedef struct +typedef enum { - patch_t *patch[16][ROTANGLES]; - UINT16 cached; -} rotsprite_t; -#endif/*ROTSPRITE*/ + RF_HORIZONTALFLIP = 0x0001, // Flip sprite horizontally + RF_VERTICALFLIP = 0x0002, // Flip sprite vertically + RF_ABSOLUTEOFFSETS = 0x0004, // Sprite uses the object's offsets absolutely, instead of relatively + RF_FLIPOFFSETS = 0x0008, // Relative object offsets are flipped with the sprite + + RF_SPLATMASK = 0x00F0, // --Floor sprite flags + RF_SLOPESPLAT = 0x0010, // Rotate floor sprites by a slope + RF_OBJECTSLOPESPLAT = 0x0020, // Rotate floor sprites by the object's standing slope + RF_NOSPLATBILLBOARD = 0x0040, // Don't billboard floor sprites (faces forward from the view angle) + RF_NOSPLATROLLANGLE = 0x0080, // Don't rotate floor sprites by the object's rollangle (uses rotated patches instead) + + RF_BLENDMASK = 0x0F00, // --Blending modes + RF_FULLBRIGHT = 0x0100, // Sprite is drawn at full brightness + RF_FULLDARK = 0x0200, // Sprite is drawn completely dark + RF_NOCOLORMAPS = 0x0400, // Sprite is not drawn with colormaps + + RF_SPRITETYPEMASK = 0x7000, // ---Different sprite types + RF_PAPERSPRITE = 0x1000, // Paper sprite + RF_FLOORSPRITE = 0x2000, // Floor sprite + + RF_SHADOWDRAW = 0x10000, // Stretches and skews the sprite like a shadow. + RF_SHADOWEFFECTS = 0x20000, // Scales and becomes transparent like a shadow. + RF_DROPSHADOW = (RF_SHADOWDRAW | RF_SHADOWEFFECTS | RF_FULLDARK), +} renderflags_t; typedef enum { @@ -746,24 +781,6 @@ 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. @@ -793,7 +810,7 @@ typedef struct UINT16 flip; #ifdef ROTSPRITE - rotsprite_t rotsprite; + rotsprite_t *rotated[2][16]; // Rotated patches #endif } spriteframe_t; diff --git a/src/r_draw.c b/src/r_draw.c index 2b798c3bf383c42d22e99674e1ceb4521a85c352..d9ea942a2f22b301bdbd1762e0635f31ba085d6e 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -75,6 +75,7 @@ UINT8 *dc_source; #define NUMTRANSTABLES 9 // how many translucency tables are used UINT8 *transtables; // translucency tables +UINT8 *blendtables[NUMBLENDMAPS]; /** \brief R_DrawTransColumn uses this */ @@ -98,15 +99,19 @@ INT32 dc_numlights = 0, dc_maxlights, dc_texheight; INT32 ds_y, ds_x1, ds_x2; lighttable_t *ds_colormap; +lighttable_t *ds_translation; // Lactozilla: Sprite splat drawer + fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep; +INT32 ds_waterofs, ds_bgofs; + UINT16 ds_flatwidth, ds_flatheight; boolean ds_powersoftwo; -UINT8 *ds_source; // start of a 64*64 tile image +UINT8 *ds_source; // points to the start of a flat UINT8 *ds_transmap; // one of the translucency tables -pslope_t *ds_slope; // Current slope being used -floatv3_t ds_su[MAXVIDHEIGHT], ds_sv[MAXVIDHEIGHT], ds_sz[MAXVIDHEIGHT]; // Vectors for... stuff? +// Vectors for Software's tilted slope drawers +floatv3_t *ds_su, *ds_sv, *ds_sz; floatv3_t *ds_sup, *ds_svp, *ds_szp; float focallengthf, zeroheight; @@ -115,10 +120,6 @@ float focallengthf, zeroheight; UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; -// ========================================================================== -// OLD DOOM FUZZY EFFECT -// ========================================================================== - // ========================================================================= // TRANSLATION COLORMAP CODE // ========================================================================= @@ -138,11 +139,11 @@ UINT8 skincolor_modified[MAXSKINCOLORS]; CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; -/** \brief The R_InitTranslationTables +#define TRANSTAB_AMTMUL10 (256.0f / 10.0f) - load in color translation tables +/** \brief Initializes the translucency tables used by the Software renderer. */ -void R_InitTranslationTables(void) +void R_InitTranslucencyTables(void) { // Load here the transparency lookup tables 'TINTTAB' // NOTE: the TINTTAB resource MUST BE aligned on 64k for the asm @@ -159,17 +160,94 @@ void R_InitTranslationTables(void) W_ReadLump(W_GetNumForName("TRANS70"), transtables+0x60000); W_ReadLump(W_GetNumForName("TRANS80"), transtables+0x70000); W_ReadLump(W_GetNumForName("TRANS90"), transtables+0x80000); + + R_GenerateBlendTables(); } +void R_GenerateBlendTables(void) +{ + INT32 i; -/** \brief Generates a translation colormap. + for (i = 0; i < NUMBLENDMAPS; i++) + { + if (i == blendtab_modulate) + continue; + blendtables[i] = Z_MallocAlign((NUMTRANSTABLES + 1) * 0x10000, PU_STATIC, NULL, 16); + } - \param dest_colormap colormap to populate - \param skinnum number of skin, TC_DEFAULT or TC_BOSS - \param color translation color + for (i = 0; i <= 9; i++) + { + const size_t offs = (0x10000 * i); + const UINT8 alpha = TRANSTAB_AMTMUL10 * i; - \return void -*/ + R_GenerateTranslucencyTable(blendtables[blendtab_add] + offs, AST_ADD, alpha); + R_GenerateTranslucencyTable(blendtables[blendtab_subtract] + offs, AST_SUBTRACT, alpha); + R_GenerateTranslucencyTable(blendtables[blendtab_reversesubtract] + offs, AST_REVERSESUBTRACT, alpha); + } + + // Modulation blending only requires a single table + blendtables[blendtab_modulate] = Z_MallocAlign(0x10000, PU_STATIC, NULL, 16); + R_GenerateTranslucencyTable(blendtables[blendtab_modulate], AST_MODULATE, 0); +} + +static colorlookup_t transtab_lut; + +void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt) +{ + INT16 bg, fg; + + if (table == NULL) + I_Error("R_GenerateTranslucencyTable: input table was NULL!"); + + InitColorLUT(&transtab_lut, pMasterPalette, false); + + for (bg = 0; bg < 0xFF; bg++) + { + for (fg = 0; fg < 0xFF; fg++) + { + RGBA_t backrgba = V_GetMasterColor(bg); + RGBA_t frontrgba = V_GetMasterColor(fg); + RGBA_t result; + + result.rgba = ASTBlendPixel(backrgba, frontrgba, style, blendamt); + table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue); + } + } +} + +#define ClipTransLevel(trans) max(min((trans), NUMTRANSMAPS-2), 0) + +UINT8 *R_GetTranslucencyTable(INT32 alphalevel) +{ + return transtables + (ClipTransLevel(alphalevel-1) << FF_TRANSSHIFT); +} + +UINT8 *R_GetBlendTable(int style, INT32 alphalevel) +{ + size_t offs = (ClipTransLevel(alphalevel) << FF_TRANSSHIFT); + + // Lactozilla: Returns the equivalent to AST_TRANSLUCENT + // if no alpha style matches any of the blend tables. + switch (style) + { + case AST_ADD: + return blendtables[blendtab_add] + offs; + case AST_SUBTRACT: + return blendtables[blendtab_subtract] + offs; + case AST_REVERSESUBTRACT: + return blendtables[blendtab_reversesubtract] + offs; + case AST_MODULATE: + return blendtables[blendtab_modulate]; + default: + break; + } + + // Return a normal translucency table + if (--alphalevel >= 0) + return transtables + (ClipTransLevel(alphalevel) << FF_TRANSSHIFT); + else + return NULL; +} // Define for getting accurate color brightness readings according to how the human eye sees them. // https://en.wikipedia.org/wiki/Relative_luminance @@ -227,6 +305,14 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor) #undef SETBRIGHTNESS +/** \brief Generates a translation colormap. + + \param dest_colormap colormap to populate + \param skinnum number of skin, TC_DEFAULT or TC_BOSS + \param color translation color + + \return void +*/ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT16 color) { INT32 i, starttranscolor, skinramplength; diff --git a/src/r_draw.h b/src/r_draw.h index 1ca22f18aa7f80840c9c367dcb2c0199bb62a5c0..9957541ca33bcfd84c37b03f4375184a722da459 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -37,7 +37,6 @@ extern UINT8 dc_hires; extern UINT8 *dc_source; // first pixel in a column // translucency stuff here -extern UINT8 *transtables; // translucency tables, should be (*transtables)[5][256][256] extern UINT8 *dc_transmap; // translation stuff here @@ -56,9 +55,14 @@ extern INT32 dc_texheight; extern INT32 ds_y, ds_x1, ds_x2; extern lighttable_t *ds_colormap; +extern lighttable_t *ds_translation; + extern fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep; +extern INT32 ds_waterofs, ds_bgofs; + extern UINT16 ds_flatwidth, ds_flatheight; extern boolean ds_powersoftwo; + extern UINT8 *ds_source; extern UINT8 *ds_transmap; @@ -66,8 +70,8 @@ typedef struct { float x, y, z; } floatv3_t; -extern pslope_t *ds_slope; // Current slope being used -extern floatv3_t ds_su[MAXVIDHEIGHT], ds_sv[MAXVIDHEIGHT], ds_sz[MAXVIDHEIGHT]; // Vectors for... stuff? +// Vectors for Software's tilted slope drawers +extern floatv3_t *ds_su, *ds_sv, *ds_sz; extern floatv3_t *ds_sup, *ds_svp, *ds_szp; extern float focallengthf, zeroheight; @@ -110,17 +114,36 @@ extern lumpnum_t viewborderlump[8]; #define TC_BLINK -6 // For item blinking, according to kart #define TC_DASHMODE -7 // For Metal Sonic's dashmode +// Custom player skin translation // Initialize color translation tables, for player rendering etc. -void R_InitTranslationTables(void); UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags); void R_FlushTranslationColormapCache(void); UINT16 R_GetColorByName(const char *name); UINT16 R_GetSuperColorByName(const char *name); +extern UINT8 *transtables; // translucency tables, should be (*transtables)[5][256][256] + +enum +{ + blendtab_add, + blendtab_subtract, + blendtab_reversesubtract, + blendtab_modulate, + NUMBLENDMAPS +}; + +extern UINT8 *blendtables[NUMBLENDMAPS]; + +void R_InitTranslucencyTables(void); +void R_GenerateBlendTables(void); +void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt); + +UINT8 *R_GetTranslucencyTable(INT32 alphalevel); +UINT8 *R_GetBlendTable(int style, INT32 alphalevel); + // Color ramp modification should force a recache extern UINT8 skincolor_modified[]; -// Custom player skin translation void R_InitViewBuffer(INT32 width, INT32 height); void R_InitViewBorder(void); void R_VideoErase(size_t ofs, INT32 count); @@ -149,39 +172,47 @@ void R_Draw2sMultiPatchTranslucentColumn_8(void); void R_DrawFogColumn_8(void); void R_DrawColumnShadowed_8(void); +#define PLANELIGHTFLOAT (BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) + void R_DrawSpan_8(void); -void R_DrawSplat_8(void); void R_DrawTranslucentSpan_8(void); -void R_DrawTranslucentSplat_8(void); void R_DrawTiltedSpan_8(void); void R_DrawTiltedTranslucentSpan_8(void); -#ifndef NOWATER -void R_DrawTiltedTranslucentWaterSpan_8(void); -#endif + +void R_DrawSplat_8(void); +void R_DrawTranslucentSplat_8(void); void R_DrawTiltedSplat_8(void); + +void R_DrawFloorSprite_8(void); +void R_DrawTranslucentFloorSprite_8(void); +void R_DrawTiltedFloorSprite_8(void); +void R_DrawTiltedTranslucentFloorSprite_8(void); + void R_CalcTiltedLighting(fixed_t start, fixed_t end); extern INT32 tiltlighting[MAXVIDWIDTH]; -#ifndef NOWATER + void R_DrawTranslucentWaterSpan_8(void); -extern INT32 ds_bgofs; -extern INT32 ds_waterofs; -#endif +void R_DrawTiltedTranslucentWaterSpan_8(void); + void R_DrawFogSpan_8(void); // Lactozilla: Non-powers-of-two void R_DrawSpan_NPO2_8(void); void R_DrawTranslucentSpan_NPO2_8(void); -void R_DrawSplat_NPO2_8(void); -void R_DrawTranslucentSplat_NPO2_8(void); void R_DrawTiltedSpan_NPO2_8(void); void R_DrawTiltedTranslucentSpan_NPO2_8(void); -#ifndef NOWATER -void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void); -#endif + +void R_DrawSplat_NPO2_8(void); +void R_DrawTranslucentSplat_NPO2_8(void); void R_DrawTiltedSplat_NPO2_8(void); -#ifndef NOWATER + +void R_DrawFloorSprite_NPO2_8(void); +void R_DrawTranslucentFloorSprite_NPO2_8(void); +void R_DrawTiltedFloorSprite_NPO2_8(void); +void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void); + void R_DrawTranslucentWaterSpan_NPO2_8(void); -#endif +void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void); #ifdef USEASM void ASMCALL R_DrawColumn_8_ASM(void); diff --git a/src/r_draw8.c b/src/r_draw8.c index 940ea724b31ef2411514799d4a9f7df7e284c907..e78ba8a6c49b8f39a9c54fe0af814340c9462641 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -536,6 +536,9 @@ void R_DrawTranslatedColumn_8(void) // SPANS // ========================================================================== +#define SPANSIZE 16 +#define INVSPAN 0.0625f + /** \brief The R_DrawSpan_8 function Draws the actual span. */ @@ -643,8 +646,6 @@ void R_CalcTiltedLighting(fixed_t start, fixed_t end) } } -#define PLANELIGHTFLOAT (BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) - /** \brief The R_DrawTiltedSpan_8 function Draw slopes! Holy sheit! */ @@ -704,9 +705,6 @@ void R_DrawTiltedSpan_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -839,9 +837,6 @@ void R_DrawTiltedTranslucentSpan_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -916,7 +911,6 @@ void R_DrawTiltedTranslucentSpan_8(void) #endif } -#ifndef NOWATER /** \brief The R_DrawTiltedTranslucentWaterSpan_8 function Like DrawTiltedTranslucentSpan, but for water */ @@ -977,9 +971,6 @@ void R_DrawTiltedTranslucentWaterSpan_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -1053,7 +1044,6 @@ void R_DrawTiltedTranslucentWaterSpan_8(void) } #endif } -#endif // NOWATER void R_DrawTiltedSplat_8(void) { @@ -1116,9 +1106,6 @@ void R_DrawTiltedSplat_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -1419,6 +1406,448 @@ void R_DrawTranslucentSplat_8 (void) } } +/** \brief The R_DrawFloorSprite_8 function + Just like R_DrawSplat_8, but for floor sprites. +*/ +void R_DrawFloorSprite_8 (void) +{ + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; + + size_t count = (ds_x2 - ds_x1 + 1); + UINT32 val; + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; + + // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest + // can be used for the fraction part. This allows calculation of the memory address in the + // texture with two shifts, an OR and one AND. (see below) + // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one + // bit per power of two (obviously) + // Ok, because I was able to eliminate the variable spot below, this function is now FASTER + // than the original span renderer. Whodathunkit? + xposition <<= nflatshiftup; yposition <<= nflatshiftup; + xstep <<= nflatshiftup; ystep <<= nflatshiftup; + + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + dest = ylookup[ds_y] + columnofs[ds_x1]; + + while (count >= 8) + { + // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't + // have the uber complicated math to calculate it now, so that was a memory write we didn't + // need! + // + // <Callum> 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size) + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[0] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[1] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[2] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[3] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[4] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[5] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[6] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[7] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + dest += 8; + count -= 8; + } + while (count-- && dest <= deststop) + { + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + xposition += xstep; + yposition += ystep; + } +} + +/** \brief The R_DrawTranslucentFloorSplat_8 function + Just like R_DrawFloorSprite_8, but is translucent! +*/ +void R_DrawTranslucentFloorSprite_8 (void) +{ + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; + + size_t count = (ds_x2 - ds_x1 + 1); + UINT32 val; + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; + + // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest + // can be used for the fraction part. This allows calculation of the memory address in the + // texture with two shifts, an OR and one AND. (see below) + // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one + // bit per power of two (obviously) + // Ok, because I was able to eliminate the variable spot below, this function is now FASTER + // than the original span renderer. Whodathunkit? + xposition <<= nflatshiftup; yposition <<= nflatshiftup; + xstep <<= nflatshiftup; ystep <<= nflatshiftup; + + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + dest = ylookup[ds_y] + columnofs[ds_x1]; + + while (count >= 8) + { + // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't + // have the uber complicated math to calculate it now, so that was a memory write we didn't + // need! + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[0] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[0]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[1] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[1]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[2] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[2]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[3] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[3]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[4] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[4]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[5] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[5]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[6] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[6]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[7] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[7]); + xposition += xstep; + yposition += ystep; + + dest += 8; + count -= 8; + } + while (count-- && dest <= deststop) + { + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + xposition += xstep; + yposition += ystep; + } +} + +/** \brief The R_DrawTiltedFloorSprite_8 function + Draws a tilted floor sprite. +*/ +void R_DrawTiltedFloorSprite_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + UINT16 val; + + double startz, startu, startv; + double izstep, uzstep, vzstep; + double endz, endu, endv; + UINT32 stepu, stepv; + + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); + uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); + vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + + startz = 1.f/iz; + startu = uz*startz; + startv = vz*startz; + + izstep = ds_szp->x * SPANSIZE; + uzstep = ds_sup->x * SPANSIZE; + vzstep = ds_svp->x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + stepu = (INT64)((endu - startu) * INVSPAN); + stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + } + else + { + double left = width; + iz += ds_szp->x * left; + uz += ds_sup->x * left; + vz += ds_svp->x * left; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + left = 1.f/left; + stepu = (INT64)((endu - startu) * left); + stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + + u += stepu; + v += stepv; + } + } + } +} + +/** \brief The R_DrawTiltedTranslucentFloorSprite_8 function + Draws a tilted, translucent, floor sprite. +*/ +void R_DrawTiltedTranslucentFloorSprite_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + UINT16 val; + + double startz, startu, startv; + double izstep, uzstep, vzstep; + double endz, endu, endv; + UINT32 stepu, stepv; + + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); + uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); + vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + + startz = 1.f/iz; + startu = uz*startz; + startv = vz*startz; + + izstep = ds_szp->x * SPANSIZE; + uzstep = ds_sup->x * SPANSIZE; + vzstep = ds_svp->x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + stepu = (INT64)((endu - startu) * INVSPAN); + stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + } + else + { + double left = width; + iz += ds_szp->x * left; + uz += ds_sup->x * left; + vz += ds_svp->x * left; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + left = 1.f/left; + stepu = (INT64)((endu - startu) * left); + stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + + u += stepu; + v += stepv; + } + } + } +} + /** \brief The R_DrawTranslucentSpan_8 function Draws the actual span with translucency. */ @@ -1503,7 +1932,6 @@ void R_DrawTranslucentSpan_8 (void) } } -#ifndef NOWATER void R_DrawTranslucentWaterSpan_8(void) { UINT32 xposition; @@ -1580,7 +2008,6 @@ void R_DrawTranslucentWaterSpan_8(void) yposition += ystep; } } -#endif /** \brief The R_DrawFogSpan_8 function Draws the actual span with fogging. diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c index 630b36e6f7cd9afce187ac5e29738b94c7f63708..a34a20e9a9737241bbc183d71f8bae01a982cb7a 100644 --- a/src/r_draw8_npo2.c +++ b/src/r_draw8_npo2.c @@ -15,6 +15,9 @@ // SPANS // ========================================================================== +#define SPANSIZE 16 +#define INVSPAN 0.0625f + /** \brief The R_DrawSpan_NPO2_8 function Draws the actual span. */ @@ -83,8 +86,6 @@ void R_DrawSpan_NPO2_8 (void) } } -#define PLANELIGHTFLOAT (BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) - /** \brief The R_DrawTiltedSpan_NPO2_8 function Draw slopes! Holy sheit! */ @@ -159,9 +160,6 @@ void R_DrawTiltedSpan_NPO2_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -354,9 +352,6 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -553,9 +548,6 @@ void R_DrawTiltedSplat_NPO2_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -818,6 +810,446 @@ void R_DrawTranslucentSplat_NPO2_8 (void) } } +/** \brief The R_DrawFloorSprite_NPO2_8 function + Just like R_DrawSplat_NPO2_8, but for floor sprites. +*/ +void R_DrawFloorSprite_NPO2_8 (void) +{ + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; + fixed_t x, y; + fixed_t fixedwidth, fixedheight; + + UINT16 *source; + UINT8 *translation; + UINT8 *colormap; + UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; + + size_t count = (ds_x2 - ds_x1 + 1); + UINT32 val; + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; + + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + dest = ylookup[ds_y] + columnofs[ds_x1]; + + fixedwidth = ds_flatwidth << FRACBITS; + fixedheight = ds_flatheight << FRACBITS; + + // Fix xposition and yposition if they are out of bounds. + if (xposition < 0) + xposition = fixedwidth - ((UINT32)(fixedwidth - xposition) % fixedwidth); + else if (xposition >= fixedwidth) + xposition %= fixedwidth; + if (yposition < 0) + yposition = fixedheight - ((UINT32)(fixedheight - yposition) % fixedheight); + else if (yposition >= fixedheight) + yposition %= fixedheight; + + while (count-- && dest <= deststop) + { + // The loops here keep the texture coordinates within the texture. + // They will rarely iterate multiple times, and are cheaper than a modulo operation, + // even if using libdivide. + if (xstep < 0) // These if statements are hopefully hoisted by the compiler to above this loop + while (xposition < 0) + xposition += fixedwidth; + else + while (xposition >= fixedwidth) + xposition -= fixedwidth; + if (ystep < 0) + while (yposition < 0) + yposition += fixedheight; + else + while (yposition >= fixedheight) + yposition -= fixedheight; + + x = (xposition >> FRACBITS); + y = (yposition >> FRACBITS); + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + xposition += xstep; + yposition += ystep; + } +} + +/** \brief The R_DrawTranslucentFloorSprite_NPO2_8 function + Just like R_DrawFloorSprite_NPO2_8, but is translucent! +*/ +void R_DrawTranslucentFloorSprite_NPO2_8 (void) +{ + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; + fixed_t x, y; + fixed_t fixedwidth, fixedheight; + + UINT16 *source; + UINT8 *translation; + UINT8 *colormap; + UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; + + size_t count = (ds_x2 - ds_x1 + 1); + UINT32 val; + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; + + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + dest = ylookup[ds_y] + columnofs[ds_x1]; + + fixedwidth = ds_flatwidth << FRACBITS; + fixedheight = ds_flatheight << FRACBITS; + + // Fix xposition and yposition if they are out of bounds. + if (xposition < 0) + xposition = fixedwidth - ((UINT32)(fixedwidth - xposition) % fixedwidth); + else if (xposition >= fixedwidth) + xposition %= fixedwidth; + if (yposition < 0) + yposition = fixedheight - ((UINT32)(fixedheight - yposition) % fixedheight); + else if (yposition >= fixedheight) + yposition %= fixedheight; + + while (count-- && dest <= deststop) + { + // The loops here keep the texture coordinates within the texture. + // They will rarely iterate multiple times, and are cheaper than a modulo operation, + // even if using libdivide. + if (xstep < 0) // These if statements are hopefully hoisted by the compiler to above this loop + while (xposition < 0) + xposition += fixedwidth; + else + while (xposition >= fixedwidth) + xposition -= fixedwidth; + if (ystep < 0) + while (yposition < 0) + yposition += fixedheight; + else + while (yposition >= fixedheight) + yposition -= fixedheight; + + x = (xposition >> FRACBITS); + y = (yposition >> FRACBITS); + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + xposition += xstep; + yposition += ystep; + } +} + +/** \brief The R_DrawTiltedFloorSprite_NPO2_8 function + Draws a tilted floor sprite. +*/ +void R_DrawTiltedFloorSprite_NPO2_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + UINT16 val; + + double startz, startu, startv; + double izstep, uzstep, vzstep; + double endz, endu, endv; + UINT32 stepu, stepv; + + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); + uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); + vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + + startz = 1.f/iz; + startu = uz*startz; + startv = vz*startz; + + izstep = ds_szp->x * SPANSIZE; + uzstep = ds_sup->x * SPANSIZE; + vzstep = ds_svp->x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + stepu = (INT64)((endu - startu) * INVSPAN); + stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + // Lactozilla: Non-powers-of-two + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + // Lactozilla: Non-powers-of-two + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + } + } + else + { + double left = width; + iz += ds_szp->x * left; + uz += ds_sup->x * left; + vz += ds_svp->x * left; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + left = 1.f/left; + stepu = (INT64)((endu - startu) * left); + stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + // Lactozilla: Non-powers-of-two + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + + u += stepu; + v += stepv; + } + } + } +} + +/** \brief The R_DrawTiltedTranslucentFloorSprite_NPO2_8 function + Draws a tilted, translucent, floor sprite. +*/ +void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + UINT16 val; + + double startz, startu, startv; + double izstep, uzstep, vzstep; + double endz, endu, endv; + UINT32 stepu, stepv; + + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); + uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); + vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + + startz = 1.f/iz; + startu = uz*startz; + startv = vz*startz; + + izstep = ds_szp->x * SPANSIZE; + uzstep = ds_sup->x * SPANSIZE; + vzstep = ds_svp->x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + stepu = (INT64)((endu - startu) * INVSPAN); + stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + // Lactozilla: Non-powers-of-two + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + // Lactozilla: Non-powers-of-two + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + } + } + else + { + double left = width; + iz += ds_szp->x * left; + uz += ds_sup->x * left; + vz += ds_svp->x * left; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + left = 1.f/left; + stepu = (INT64)((endu - startu) * left); + stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + // Lactozilla: Non-powers-of-two + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + + u += stepu; + v += stepv; + } + } + } +} + /** \brief The R_DrawTranslucentSpan_NPO2_8 function Draws the actual span with translucency. */ @@ -885,7 +1317,6 @@ void R_DrawTranslucentSpan_NPO2_8 (void) } } -#ifndef NOWATER void R_DrawTranslucentWaterSpan_NPO2_8(void) { fixed_t xposition; @@ -1024,9 +1455,6 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -1145,4 +1573,3 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) } #endif } -#endif // NOWATER diff --git a/src/r_main.c b/src/r_main.c index 5165b3c87b3fa51a1505fb9033715c2f713d6a46..165f74a7975515011d81b4ad8a0d2346b0ad4600 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -959,6 +959,16 @@ void R_ExecuteSetViewSize(void) dy = FixedMul(abs(dy), fovtan); yslopetab[i] = FixedDiv(centerx*FRACUNIT, dy); } + + if (ds_su) + Z_Free(ds_su); + if (ds_sv) + Z_Free(ds_sv); + if (ds_sz) + Z_Free(ds_sz); + + ds_su = ds_sv = ds_sz = NULL; + ds_sup = ds_svp = ds_szp = NULL; } memset(scalelight, 0xFF, sizeof(scalelight)); @@ -1011,8 +1021,8 @@ void R_Init(void) //I_OutputMsg("\nR_InitLightTables"); R_InitLightTables(); - //I_OutputMsg("\nR_InitTranslationTables\n"); - R_InitTranslationTables(); + //I_OutputMsg("\nR_InitTranslucencyTables\n"); + R_InitTranslucencyTables(); R_InitDrawNodes(); @@ -1473,9 +1483,6 @@ void R_RenderPlayerView(player_t *player) } R_ClearDrawSegs(); R_ClearSprites(); -#ifdef FLOORSPLATS - R_ClearVisibleFloorSplats(); -#endif Portal_InitList(); // check for new console commands. @@ -1558,9 +1565,6 @@ void R_RenderPlayerView(player_t *player) ps_sw_planetime = I_GetTimeMicros(); R_DrawPlanes(); -#ifdef FLOORSPLATS - R_DrawVisibleFloorSplats(); -#endif ps_sw_planetime = I_GetTimeMicros() - ps_sw_planetime; // draw mid texture and sprite @@ -1572,24 +1576,6 @@ void R_RenderPlayerView(player_t *player) free(masks); } -#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) -{ - ST_LoadGraphics(); - HU_LoadGraphics(); - ST_ReloadSkinFaceGraphics(); -} - // ========================================================================= // ENGINE COMMANDS & VARS // ========================================================================= diff --git a/src/r_main.h b/src/r_main.h index 379b5b8df1f5d306e50b2eed802c058749cb3928..f1cc9621f00f320ffdbb363b08b783af89fda75b 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -114,10 +114,6 @@ extern consvar_t cv_tailspickup; // Called by startup code. void R_Init(void); -#ifdef HWRENDER -void R_InitHardwareMode(void); -#endif -void R_ReloadHUDGraphics(void); void R_CheckViewMorph(void); void R_ApplyViewMorph(void); diff --git a/src/r_patch.c b/src/r_patch.c new file mode 100644 index 0000000000000000000000000000000000000000..1a08d1892d5e13d6b36ebfe59945bce9a58b75f6 --- /dev/null +++ b/src/r_patch.c @@ -0,0 +1,160 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by Jaime "Lactozilla" Passos. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_patch.c +/// \brief Patch generation. + +#include "doomdef.h" +#include "r_patch.h" +#include "r_picformats.h" +#include "r_defs.h" +#include "z_zone.h" + +#ifdef HWRENDER +#include "hardware/hw_glob.h" +#endif + +// +// Creates a patch. +// Assumes a PU_PATCH zone memory tag and no user, but can always be set later +// + +patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest) +{ + patch_t *patch = (dest == NULL) ? Z_Calloc(sizeof(patch_t), PU_PATCH, NULL) : (patch_t *)(dest); + + if (source) + { + INT32 col, colsize; + size_t size = sizeof(INT32) * SHORT(source->width); + size_t offs = (sizeof(INT16) * 4) + size; + + patch->width = SHORT(source->width); + patch->height = SHORT(source->height); + patch->leftoffset = SHORT(source->leftoffset); + patch->topoffset = SHORT(source->topoffset); + patch->columnofs = Z_Calloc(size, PU_PATCH_DATA, NULL); + + for (col = 0; col < source->width; col++) + { + // This makes the column offsets relative to the column data itself, + // instead of the entire patch data + patch->columnofs[col] = LONG(source->columnofs[col]) - offs; + } + + if (!srcsize) + I_Error("Patch_Create: no source size!"); + + colsize = (INT32)(srcsize) - (INT32)offs; + if (colsize <= 0) + I_Error("Patch_Create: no column data!"); + + patch->columns = Z_Calloc(colsize, PU_PATCH_DATA, NULL); + M_Memcpy(patch->columns, ((UINT8 *)source + LONG(source->columnofs[0])), colsize); + } + + return patch; +} + +// +// Frees a patch from memory. +// + +static void Patch_FreeData(patch_t *patch) +{ + INT32 i; + +#ifdef HWRENDER + if (patch->hardware) + HWR_FreeTexture(patch); +#endif + + for (i = 0; i < 4; i++) + { + if (patch->flats[i]) + Z_Free(patch->flats[i]); + } + +#ifdef ROTSPRITE + if (patch->rotated) + { + rotsprite_t *rotsprite = patch->rotated; + + for (i = 0; i < rotsprite->angles; i++) + { + if (rotsprite->patches[i]) + Patch_Free(rotsprite->patches[i]); + } + + Z_Free(rotsprite->patches); + Z_Free(rotsprite); + } +#endif + + if (patch->columnofs) + Z_Free(patch->columnofs); + if (patch->columns) + Z_Free(patch->columns); +} + +void Patch_Free(patch_t *patch) +{ + Patch_FreeData(patch); + Z_Free(patch); +} + +// +// Frees patches with a tag range. +// + +static boolean Patch_FreeTagsCallback(void *mem) +{ + patch_t *patch = (patch_t *)mem; + Patch_FreeData(patch); + return true; +} + +void Patch_FreeTags(INT32 lowtag, INT32 hightag) +{ + Z_IterateTags(lowtag, hightag, Patch_FreeTagsCallback); +} + +void Patch_GenerateFlat(patch_t *patch, pictureflags_t flags) +{ + UINT8 flip = (flags & (PICFLAGS_XFLIP | PICFLAGS_YFLIP)); + if (patch->flats[flip] == NULL) + patch->flats[flip] = Picture_Convert(PICFMT_PATCH, patch, PICFMT_FLAT16, 0, NULL, 0, 0, 0, 0, flags); +} + +#ifdef HWRENDER +// +// Allocates a hardware patch. +// + +void *Patch_AllocateHardwarePatch(patch_t *patch) +{ + if (!patch->hardware) + { + GLPatch_t *grPatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, &patch->hardware); + grPatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, &grPatch->mipmap); + } + return (void *)(patch->hardware); +} + +// +// Creates a hardware patch. +// + +void *Patch_CreateGL(patch_t *patch) +{ + GLPatch_t *grPatch = (GLPatch_t *)Patch_AllocateHardwarePatch(patch); + if (!grPatch->mipmap->data) // Run HWR_MakePatch in all cases, to recalculate some things + HWR_MakePatch(patch, grPatch, grPatch->mipmap, false); + return grPatch; +} +#endif // HWRENDER diff --git a/src/r_patch.h b/src/r_patch.h new file mode 100644 index 0000000000000000000000000000000000000000..32bcb3909efe057af98d54cd151f56414c71deb1 --- /dev/null +++ b/src/r_patch.h @@ -0,0 +1,44 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by Jaime "Lactozilla" Passos. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_patch.h +/// \brief Patch generation. + +#ifndef __R_PATCH__ +#define __R_PATCH__ + +#include "r_defs.h" +#include "r_picformats.h" +#include "doomdef.h" + +// Patch functions +patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest); +void Patch_Free(patch_t *patch); + +#define Patch_FreeTag(tagnum) Patch_FreeTags(tagnum, tagnum) +void Patch_FreeTags(INT32 lowtag, INT32 hightag); + +void Patch_GenerateFlat(patch_t *patch, pictureflags_t flags); + +#ifdef HWRENDER +void *Patch_AllocateHardwarePatch(patch_t *patch); +void *Patch_CreateGL(patch_t *patch); +#endif + +#ifdef ROTSPRITE +void Patch_Rotate(patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip); +patch_t *Patch_GetRotated(patch_t *patch, INT32 angle, boolean flip); +patch_t *Patch_GetRotatedSprite( + spriteframe_t *sprite, + size_t frame, size_t spriteangle, + boolean flip, boolean adjustfeet, + void *info, INT32 rotationangle); +INT32 R_GetRollAngle(angle_t rollangle); +#endif + +#endif // __R_PATCH__ diff --git a/src/r_patchrotation.c b/src/r_patchrotation.c new file mode 100644 index 0000000000000000000000000000000000000000..123c4eef229a20fa554094bf44a2cc3853e72dc8 --- /dev/null +++ b/src/r_patchrotation.c @@ -0,0 +1,273 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by Jaime "Lactozilla" Passos. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_patchrotation.c +/// \brief Patch rotation. + +#include "r_patchrotation.h" +#include "r_things.h" // FEETADJUST +#include "z_zone.h" +#include "w_wad.h" + +#ifdef ROTSPRITE +fixed_t rollcosang[ROTANGLES]; +fixed_t rollsinang[ROTANGLES]; + +INT32 R_GetRollAngle(angle_t rollangle) +{ + INT32 ra = AngleFixed(rollangle)>>FRACBITS; +#if (ROTANGDIFF > 1) + ra += (ROTANGDIFF/2); +#endif + ra /= ROTANGDIFF; + ra %= ROTANGLES; + return ra; +} + +patch_t *Patch_GetRotated(patch_t *patch, INT32 angle, boolean flip) +{ + rotsprite_t *rotsprite = patch->rotated; + if (rotsprite == NULL || angle < 1 || angle >= ROTANGLES) + return NULL; + + if (flip) + angle += rotsprite->angles; + + return rotsprite->patches[angle]; +} + +patch_t *Patch_GetRotatedSprite( + spriteframe_t *sprite, + size_t frame, size_t spriteangle, + boolean flip, boolean adjustfeet, + void *info, INT32 rotationangle) +{ + rotsprite_t *rotsprite; + spriteinfo_t *sprinfo = (spriteinfo_t *)info; + INT32 idx = rotationangle; + UINT8 type = (adjustfeet ? 1 : 0); + + if (rotationangle < 1 || rotationangle >= ROTANGLES) + return NULL; + + rotsprite = sprite->rotated[type][spriteangle]; + + if (rotsprite == NULL) + { + rotsprite = RotatedPatch_Create(ROTANGLES); + sprite->rotated[type][spriteangle] = rotsprite; + } + + if (flip) + idx += rotsprite->angles; + + if (rotsprite->patches[idx] == NULL) + { + patch_t *patch; + INT32 xpivot = 0, ypivot = 0; + lumpnum_t lump = sprite->lumppat[spriteangle]; + + if (lump == LUMPERROR) + return NULL; + + patch = W_CachePatchNum(lump, PU_SPRITE); + + if (sprinfo->available) + { + xpivot = sprinfo->pivot[frame].x; + ypivot = sprinfo->pivot[frame].y; + } + else + { + xpivot = patch->leftoffset; + ypivot = patch->height / 2; + } + + RotatedPatch_DoRotation(rotsprite, patch, rotationangle, xpivot, ypivot, flip); + + //BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer + if (adjustfeet) + ((patch_t *)rotsprite->patches[idx])->topoffset += FEETADJUST>>FRACBITS; + } + + return rotsprite->patches[idx]; +} + +void Patch_Rotate(patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip) +{ + if (patch->rotated == NULL) + patch->rotated = RotatedPatch_Create(ROTANGLES); + RotatedPatch_DoRotation(patch->rotated, patch, angle, xpivot, ypivot, flip); +} + +rotsprite_t *RotatedPatch_Create(INT32 numangles) +{ + rotsprite_t *rotsprite = Z_Calloc(sizeof(rotsprite_t), PU_STATIC, NULL); + rotsprite->angles = numangles; + rotsprite->patches = Z_Calloc(rotsprite->angles * 2 * sizeof(void *), PU_STATIC, NULL); + return rotsprite; +} + +static void RotatedPatch_CalculateDimensions( + INT32 width, INT32 height, + fixed_t ca, fixed_t sa, + INT32 *newwidth, INT32 *newheight) +{ + fixed_t fixedwidth = (width * FRACUNIT); + fixed_t fixedheight = (height * FRACUNIT); + + fixed_t w1 = abs(FixedMul(fixedwidth, ca) - FixedMul(fixedheight, sa)); + fixed_t w2 = abs(FixedMul(-fixedwidth, ca) - FixedMul(fixedheight, sa)); + fixed_t h1 = abs(FixedMul(fixedwidth, sa) + FixedMul(fixedheight, ca)); + fixed_t h2 = abs(FixedMul(-fixedwidth, sa) + FixedMul(fixedheight, ca)); + + w1 = FixedInt(FixedCeil(w1 + (FRACUNIT/2))); + w2 = FixedInt(FixedCeil(w2 + (FRACUNIT/2))); + h1 = FixedInt(FixedCeil(h1 + (FRACUNIT/2))); + h2 = FixedInt(FixedCeil(h2 + (FRACUNIT/2))); + + *newwidth = max(width, max(w1, w2)); + *newheight = max(height, max(h1, h2)); +} + +void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip) +{ + patch_t *rotated; + UINT16 *rawdst, *rawconv; + size_t size; + pictureflags_t bflip = (flip) ? PICFLAGS_XFLIP : 0; + + INT32 width = patch->width; + INT32 height = patch->height; + INT32 leftoffset = patch->leftoffset; + INT32 newwidth, newheight; + + fixed_t ca = rollcosang[angle]; + fixed_t sa = rollsinang[angle]; + fixed_t xcenter, ycenter; + INT32 idx = angle; + INT32 x, y; + INT32 sx, sy; + INT32 dx, dy; + INT32 ox, oy; + INT32 minx, miny, maxx, maxy; + + // Don't cache angle = 0 + if (angle < 1 || angle >= ROTANGLES) + return; + + if (flip) + { + idx += rotsprite->angles; + xpivot = width - xpivot; + leftoffset = width - leftoffset; + } + + if (rotsprite->patches[idx]) + return; + + // Find the dimensions of the rotated patch. + RotatedPatch_CalculateDimensions(width, height, ca, sa, &newwidth, &newheight); + + xcenter = (xpivot * FRACUNIT); + ycenter = (ypivot * FRACUNIT); + + if (xpivot != width / 2 || ypivot != height / 2) + { + newwidth *= 2; + newheight *= 2; + } + + minx = newwidth; + miny = newheight; + maxx = 0; + maxy = 0; + + // Draw the rotated sprite to a temporary buffer. + size = (newwidth * newheight); + if (!size) + size = (width * height); + rawdst = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL); + + for (dy = 0; dy < newheight; dy++) + { + for (dx = 0; dx < newwidth; dx++) + { + x = (dx - (newwidth / 2)) * FRACUNIT; + y = (dy - (newheight / 2)) * FRACUNIT; + sx = FixedMul(x, ca) + FixedMul(y, sa) + xcenter; + sy = -FixedMul(x, sa) + FixedMul(y, ca) + ycenter; + + sx >>= FRACBITS; + sy >>= FRACBITS; + + if (sx >= 0 && sy >= 0 && sx < width && sy < height) + { + void *input = Picture_GetPatchPixel(patch, PICFMT_PATCH, sx, sy, bflip); + if (input != NULL) + { + rawdst[(dy * newwidth) + dx] = (0xFF00 | (*(UINT8 *)input)); + if (dx < minx) + minx = dx; + if (dy < miny) + miny = dy; + if (dx > maxx) + maxx = dx; + if (dy > maxy) + maxy = dy; + } + } + } + } + + ox = (newwidth / 2) + (leftoffset - xpivot); + oy = (newheight / 2) + (patch->topoffset - ypivot); + width = (maxx - minx); + height = (maxy - miny); + + if ((unsigned)(width * height) != size) + { + UINT16 *src, *dest; + + size = (width * height); + rawconv = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL); + + src = &rawdst[(miny * newwidth) + minx]; + dest = rawconv; + dy = height; + + while (dy--) + { + M_Memcpy(dest, src, width * sizeof(UINT16)); + dest += width; + src += newwidth; + } + + ox -= minx; + oy -= miny; + + Z_Free(rawdst); + } + else + { + rawconv = rawdst; + width = newwidth; + height = newheight; + } + + // make patch + rotated = (patch_t *)Picture_Convert(PICFMT_FLAT16, rawconv, PICFMT_PATCH, 0, NULL, width, height, 0, 0, 0); + + Z_ChangeTag(rotated, PU_PATCH_ROTATED); + Z_SetUser(rotated, (void **)(&rotsprite->patches[idx])); + Z_Free(rawconv); + + rotated->leftoffset = ox; + rotated->topoffset = oy; +} +#endif diff --git a/src/r_patchrotation.h b/src/r_patchrotation.h new file mode 100644 index 0000000000000000000000000000000000000000..2744f71d25380469b30b1fdcf8b5112578a2abd8 --- /dev/null +++ b/src/r_patchrotation.h @@ -0,0 +1,21 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by Jaime "Lactozilla" Passos. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_patchrotation.h +/// \brief Patch rotation. + +#include "r_patch.h" +#include "r_picformats.h" + +#ifdef ROTSPRITE +rotsprite_t *RotatedPatch_Create(INT32 numangles); +void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip); + +extern fixed_t rollcosang[ROTANGLES]; +extern fixed_t rollsinang[ROTANGLES]; +#endif diff --git a/src/r_picformats.c b/src/r_picformats.c index 8d7cf37f209c123dd08b710ed153ce2a3aa25e21..02f1de4ab20d1f0edaeb8753459eacc8c452de23 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -16,10 +16,11 @@ #include "dehacked.h" #include "i_video.h" #include "r_data.h" -#include "r_textures.h" -#include "r_draw.h" +#include "r_patch.h" #include "r_picformats.h" +#include "r_textures.h" #include "r_things.h" +#include "r_draw.h" #include "v_video.h" #include "z_zone.h" #include "w_wad.h" @@ -142,10 +143,21 @@ void *Picture_PatchConvert( if (Picture_IsPatchFormat(informat)) { inpatch = (patch_t *)picture; - inwidth = SHORT(inpatch->width); - inheight = SHORT(inpatch->height); - inleftoffset = SHORT(inpatch->leftoffset); - intopoffset = SHORT(inpatch->topoffset); + if (Picture_IsDoomPatchFormat(informat)) + { + softwarepatch_t *doompatch = (softwarepatch_t *)picture; + inwidth = SHORT(doompatch->width); + inheight = SHORT(doompatch->height); + inleftoffset = SHORT(doompatch->leftoffset); + intopoffset = SHORT(doompatch->topoffset); + } + else + { + inwidth = inpatch->width; + inheight = inpatch->height; + inleftoffset = inpatch->leftoffset; + intopoffset = inpatch->topoffset; + } } // Write image size and offset @@ -275,6 +287,7 @@ void *Picture_PatchConvert( switch (outformat) { case PICFMT_PATCH32: + case PICFMT_DOOMPATCH32: { if (inbpp == PICDEPTH_32BPP) { @@ -294,6 +307,7 @@ void *Picture_PatchConvert( break; } case PICFMT_PATCH16: + case PICFMT_DOOMPATCH16: if (inbpp == PICDEPTH_32BPP) { RGBA_t in = *(RGBA_t *)input; @@ -338,9 +352,26 @@ void *Picture_PatchConvert( img = Z_Malloc(size, PU_STATIC, NULL); memcpy(img, imgbuf, size); - if (outsize != NULL) - *outsize = size; - return img; + if (Picture_IsInternalPatchFormat(outformat)) + { + patch_t *converted = Patch_Create((softwarepatch_t *)img, size, NULL); + +#ifdef HWRENDER + Patch_CreateGL(converted); +#endif + + Z_Free(img); + + if (outsize != NULL) + *outsize = sizeof(patch_t); + return converted; + } + else + { + if (outsize != NULL) + *outsize = size; + return img; + } } /** Converts a picture to a flat. @@ -391,8 +422,17 @@ void *Picture_FlatConvert( if (Picture_IsPatchFormat(informat)) { inpatch = (patch_t *)picture; - inwidth = SHORT(inpatch->width); - inheight = SHORT(inpatch->height); + if (Picture_IsDoomPatchFormat(informat)) + { + softwarepatch_t *doompatch = ((softwarepatch_t *)picture); + inwidth = SHORT(doompatch->width); + inheight = SHORT(doompatch->height); + } + else + { + inwidth = inpatch->width; + inheight = inpatch->height; + } } size = (inwidth * inheight) * (outbpp / 8); @@ -503,22 +543,25 @@ void *Picture_GetPatchPixel( UINT8 *s8 = NULL; UINT16 *s16 = NULL; UINT32 *s32 = NULL; + softwarepatch_t *doompatch = (softwarepatch_t *)patch; + INT16 width; if (patch == NULL) I_Error("Picture_GetPatchPixel: patch == NULL"); - if (x >= 0 && x < SHORT(patch->width)) + width = (Picture_IsDoomPatchFormat(informat) ? patch->width : SHORT(patch->width)); + + if (x >= 0 && x < width) { + INT32 colx = (flags & PICFLAGS_XFLIP) ? (width-1)-x : x; INT32 topdelta, prevdelta = -1; - INT32 colofs = 0; - - if (flags & PICFLAGS_XFLIP) - colofs = LONG(patch->columnofs[(SHORT(patch->width)-1)-x]); - else - colofs = LONG(patch->columnofs[x]); + INT32 colofs = (Picture_IsDoomPatchFormat(informat) ? LONG(patch->columnofs[colx]) : patch->columnofs[colx]); // Column offsets are pointers so no casting required - column = (column_t *)((UINT8 *)patch + colofs); + if (Picture_IsDoomPatchFormat(informat)) + column = (column_t *)((UINT8 *)doompatch + colofs); + else + column = (column_t *)((UINT8 *)patch->columns + colofs); while (column->topdelta != 0xff) { @@ -527,25 +570,25 @@ void *Picture_GetPatchPixel( topdelta += prevdelta; prevdelta = topdelta; s8 = (UINT8 *)(column) + 3; - if (informat == PICFMT_PATCH32) + if (Picture_FormatBPP(informat) == PICDEPTH_32BPP) s32 = (UINT32 *)s8; - else if (informat == PICFMT_PATCH16) + else if (Picture_FormatBPP(informat) == PICDEPTH_16BPP) s16 = (UINT16 *)s8; for (ofs = 0; ofs < column->length; ofs++) { if ((topdelta + ofs) == y) { - if (informat == PICFMT_PATCH32) + if (Picture_FormatBPP(informat) == PICDEPTH_32BPP) return &s32[ofs]; - else if (informat == PICFMT_PATCH16) + else if (Picture_FormatBPP(informat) == PICDEPTH_16BPP) return &s16[ofs]; - else // PICFMT_PATCH + else // PICDEPTH_8BPP return &s8[ofs]; } } - if (informat == PICFMT_PATCH32) + if (Picture_FormatBPP(informat) == PICDEPTH_32BPP) column = (column_t *)((UINT32 *)column + column->length); - else if (informat == PICFMT_PATCH16) + else if (Picture_FormatBPP(informat) == PICDEPTH_16BPP) column = (column_t *)((UINT16 *)column + column->length); else column = (column_t *)((UINT8 *)column + column->length); @@ -568,15 +611,18 @@ INT32 Picture_FormatBPP(pictureformat_t format) { case PICFMT_PATCH32: case PICFMT_FLAT32: + case PICFMT_DOOMPATCH32: case PICFMT_PNG: bpp = PICDEPTH_32BPP; break; case PICFMT_PATCH16: case PICFMT_FLAT16: + case PICFMT_DOOMPATCH16: bpp = PICDEPTH_16BPP; break; case PICFMT_PATCH: case PICFMT_FLAT: + case PICFMT_DOOMPATCH: bpp = PICDEPTH_8BPP; break; default: @@ -592,7 +638,43 @@ INT32 Picture_FormatBPP(pictureformat_t format) */ boolean Picture_IsPatchFormat(pictureformat_t format) { - return (format == PICFMT_PATCH || format == PICFMT_PATCH16 || format == PICFMT_PATCH32); + return (Picture_IsInternalPatchFormat(format) || Picture_IsDoomPatchFormat(format)); +} + +/** Checks if the specified picture format is an internal patch. + * + * \param format Input picture format. + * \return True if the picture format is an internal patch, false if not. + */ +boolean Picture_IsInternalPatchFormat(pictureformat_t format) +{ + switch (format) + { + case PICFMT_PATCH: + case PICFMT_PATCH16: + case PICFMT_PATCH32: + return true; + default: + return false; + } +} + +/** Checks if the specified picture format is a Doom patch. + * + * \param format Input picture format. + * \return True if the picture format is a Doom patch, false if not. + */ +boolean Picture_IsDoomPatchFormat(pictureformat_t format) +{ + switch (format) + { + case PICFMT_DOOMPATCH: + case PICFMT_DOOMPATCH16: + case PICFMT_DOOMPATCH32: + return true; + default: + return false; + } } /** Checks if the specified picture format is a flat. @@ -605,14 +687,14 @@ boolean Picture_IsFlatFormat(pictureformat_t format) return (format == PICFMT_FLAT || format == PICFMT_FLAT16 || format == PICFMT_FLAT32); } -/** Returns true if the lump is a valid patch. - * PICFMT_PATCH only, I think?? +/** Returns true if the lump is a valid Doom patch. + * PICFMT_DOOMPATCH only. * * \param patch Input patch. * \param picture Input patch size. * \return True if the input patch is valid. */ -boolean Picture_CheckIfPatch(patch_t *patch, size_t size) +boolean Picture_CheckIfDoomPatch(softwarepatch_t *patch, size_t size) { INT16 width, height; boolean result; @@ -1465,11 +1547,6 @@ static void R_ParseSpriteInfo(boolean spr2) info = Z_Calloc(sizeof(spriteinfo_t), PU_STATIC, NULL); info->available = true; -#ifdef ROTSPRITE - if ((sprites != NULL) && (!spr2)) - R_FreeSingleRotSprite(&sprites[sprnum]); -#endif - // Left Curly Brace sprinfoToken = M_GetToken(NULL); if (sprinfoToken == NULL) @@ -1530,9 +1607,6 @@ static void R_ParseSpriteInfo(boolean spr2) size_t skinnum = skinnumbers[i]; skin_t *skin = &skins[skinnum]; spriteinfo_t *sprinfo = skin->sprinfo; -#ifdef ROTSPRITE - R_FreeSkinRotSprite(skinnum); -#endif M_Memcpy(&sprinfo[spr2num], info, sizeof(spriteinfo_t)); } } @@ -1622,316 +1696,3 @@ void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps) R_ParseSPRTINFOLump(wadnum, i); } } - -#ifdef ROTSPRITE -// -// R_GetRollAngle -// -// Angles precalculated in R_InitSprites. -// -fixed_t rollcosang[ROTANGLES]; -fixed_t rollsinang[ROTANGLES]; -INT32 R_GetRollAngle(angle_t rollangle) -{ - INT32 ra = AngleFixed(rollangle)>>FRACBITS; -#if (ROTANGDIFF > 1) - ra += (ROTANGDIFF/2); -#endif - ra /= ROTANGDIFF; - ra %= ROTANGLES; - return ra; -} - -// -// R_CacheRotSprite -// -// Create a rotated sprite. -// -void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, spriteframe_t *sprframe, INT32 rot, UINT8 flip) -{ - INT32 angle; - patch_t *patch; - patch_t *newpatch; - UINT16 *rawdst; - size_t size; - pictureflags_t bflip = (flip) ? PICFLAGS_XFLIP : 0; - -#define SPRITE_XCENTER (leftoffset) -#define SPRITE_YCENTER (height / 2) -#define ROTSPRITE_XCENTER (newwidth / 2) -#define ROTSPRITE_YCENTER (newheight / 2) - - if (!(sprframe->rotsprite.cached & (1<<rot))) - { - INT32 dx, dy; - INT32 px, py; - INT32 width, height, leftoffset; - fixed_t ca, sa; - lumpnum_t lump = sprframe->lumppat[rot]; -#ifndef NO_PNG_LUMPS - size_t lumplength; -#endif - - if (lump == LUMPERROR) - return; - - patch = (patch_t *)W_CacheLumpNum(lump, PU_STATIC); -#ifndef NO_PNG_LUMPS - lumplength = W_LumpLength(lump); - - if (Picture_IsLumpPNG((const UINT8 *)patch, lumplength)) - patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0); - else -#endif - // Because there's something wrong with SPR_DFLM, I guess - if (!Picture_CheckIfPatch(patch, lumplength)) - return; - - width = SHORT(patch->width); - height = SHORT(patch->height); - leftoffset = SHORT(patch->leftoffset); - - // rotation pivot - px = SPRITE_XCENTER; - py = SPRITE_YCENTER; - - // get correct sprite info for sprite - if (sprinfo == NULL) - sprinfo = &spriteinfo[sprnum]; - if (sprinfo->available) - { - px = sprinfo->pivot[frame].x; - py = sprinfo->pivot[frame].y; - } - if (bflip) - { - px = width - px; - leftoffset = width - leftoffset; - } - - // Don't cache angle = 0 - for (angle = 1; angle < ROTANGLES; angle++) - { - INT32 newwidth, newheight; - - ca = rollcosang[angle]; - sa = rollsinang[angle]; - - // Find the dimensions of the rotated patch. - { - INT32 w1 = abs(FixedMul(width << FRACBITS, ca) - FixedMul(height << FRACBITS, sa)); - INT32 w2 = abs(FixedMul(-(width << FRACBITS), ca) - FixedMul(height << FRACBITS, sa)); - INT32 h1 = abs(FixedMul(width << FRACBITS, sa) + FixedMul(height << FRACBITS, ca)); - INT32 h2 = abs(FixedMul(-(width << FRACBITS), sa) + FixedMul(height << FRACBITS, ca)); - w1 = FixedInt(FixedCeil(w1 + (FRACUNIT/2))); - w2 = FixedInt(FixedCeil(w2 + (FRACUNIT/2))); - h1 = FixedInt(FixedCeil(h1 + (FRACUNIT/2))); - h2 = FixedInt(FixedCeil(h2 + (FRACUNIT/2))); - newwidth = max(width, max(w1, w2)); - newheight = max(height, max(h1, h2)); - } - - // check boundaries - { - fixed_t top[2][2]; - fixed_t bottom[2][2]; - - top[0][0] = FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, sa) + (px << FRACBITS); - top[0][1] = FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, ca) + (py << FRACBITS); - top[1][0] = FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, sa) + (px << FRACBITS); - top[1][1] = FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, ca) + (py << FRACBITS); - - bottom[0][0] = FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, sa) + (px << FRACBITS); - bottom[0][1] = -FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, ca) + (py << FRACBITS); - bottom[1][0] = FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, sa) + (px << FRACBITS); - bottom[1][1] = -FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, ca) + (py << FRACBITS); - - top[0][0] >>= FRACBITS; - top[0][1] >>= FRACBITS; - top[1][0] >>= FRACBITS; - top[1][1] >>= FRACBITS; - - bottom[0][0] >>= FRACBITS; - bottom[0][1] >>= FRACBITS; - bottom[1][0] >>= FRACBITS; - bottom[1][1] >>= FRACBITS; - -#define BOUNDARYWCHECK(b) (b[0] < 0 || b[0] >= width) -#define BOUNDARYHCHECK(b) (b[1] < 0 || b[1] >= height) -#define BOUNDARYADJUST(x) x *= 2 - // top left/right - if (BOUNDARYWCHECK(top[0]) || BOUNDARYWCHECK(top[1])) - BOUNDARYADJUST(newwidth); - // bottom left/right - else if (BOUNDARYWCHECK(bottom[0]) || BOUNDARYWCHECK(bottom[1])) - BOUNDARYADJUST(newwidth); - // top left/right - if (BOUNDARYHCHECK(top[0]) || BOUNDARYHCHECK(top[1])) - BOUNDARYADJUST(newheight); - // bottom left/right - else if (BOUNDARYHCHECK(bottom[0]) || BOUNDARYHCHECK(bottom[1])) - BOUNDARYADJUST(newheight); -#undef BOUNDARYWCHECK -#undef BOUNDARYHCHECK -#undef BOUNDARYADJUST - } - - // Draw the rotated sprite to a temporary buffer. - size = (newwidth * newheight); - if (!size) - size = (width * height); - rawdst = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL); - - for (dy = 0; dy < newheight; dy++) - { - for (dx = 0; dx < newwidth; dx++) - { - INT32 x = (dx-ROTSPRITE_XCENTER) << FRACBITS; - INT32 y = (dy-ROTSPRITE_YCENTER) << FRACBITS; - INT32 sx = FixedMul(x, ca) + FixedMul(y, sa) + (px << FRACBITS); - INT32 sy = -FixedMul(x, sa) + FixedMul(y, ca) + (py << FRACBITS); - sx >>= FRACBITS; - sy >>= FRACBITS; - if (sx >= 0 && sy >= 0 && sx < width && sy < height) - { - void *input = Picture_GetPatchPixel(patch, PICFMT_PATCH, sx, sy, bflip); - if (input != NULL) - rawdst[(dy*newwidth)+dx] = (0xFF00 | (*(UINT8 *)input)); - } - } - } - - // make patch - newpatch = (patch_t *)Picture_Convert(PICFMT_FLAT16, rawdst, PICFMT_PATCH, 0, &size, newwidth, newheight, 0, 0, 0); - { - newpatch->leftoffset = (newpatch->width / 2) + (leftoffset - px); - newpatch->topoffset = (newpatch->height / 2) + (SHORT(patch->topoffset) - py); - } - - //BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer - if (rendermode != render_none) // not for psprite - newpatch->topoffset += FEETADJUST>>FRACBITS; - - // P_PrecacheLevel - if (devparm) spritememory += size; - - // convert everything to little-endian, for big-endian support - newpatch->width = SHORT(newpatch->width); - newpatch->height = SHORT(newpatch->height); - newpatch->leftoffset = SHORT(newpatch->leftoffset); - newpatch->topoffset = SHORT(newpatch->topoffset); - -#ifdef HWRENDER - if (rendermode == render_opengl) - { - GLPatch_t *grPatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL); - grPatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL); - grPatch->rawpatch = newpatch; - sprframe->rotsprite.patch[rot][angle] = (patch_t *)grPatch; - HWR_MakePatch(newpatch, grPatch, grPatch->mipmap, false); - } - else -#endif // HWRENDER - sprframe->rotsprite.patch[rot][angle] = newpatch; - - // free rotated image data - Z_Free(rawdst); - } - - // This rotation is cached now - sprframe->rotsprite.cached |= (1<<rot); - - // free image data - Z_Free(patch); - } -#undef SPRITE_XCENTER -#undef SPRITE_YCENTER -#undef ROTSPRITE_XCENTER -#undef ROTSPRITE_YCENTER -} - -// -// R_FreeSingleRotSprite -// -// Free sprite rotation data from memory, for a single spritedef. -// -void R_FreeSingleRotSprite(spritedef_t *spritedef) -{ - UINT8 frame; - INT32 rot, ang; - - for (frame = 0; frame < spritedef->numframes; frame++) - { - spriteframe_t *sprframe = &spritedef->spriteframes[frame]; - for (rot = 0; rot < 16; rot++) - { - if (sprframe->rotsprite.cached & (1<<rot)) - { - for (ang = 0; ang < ROTANGLES; ang++) - { - patch_t *rotsprite = sprframe->rotsprite.patch[rot][ang]; - if (rotsprite) - { -#ifdef HWRENDER - if (rendermode == render_opengl) - { - GLPatch_t *grPatch = (GLPatch_t *)rotsprite; - if (grPatch->rawpatch) - { - Z_Free(grPatch->rawpatch); - grPatch->rawpatch = NULL; - } - if (grPatch->mipmap) - { - if (grPatch->mipmap->data) - { - Z_Free(grPatch->mipmap->data); - grPatch->mipmap->data = NULL; - } - Z_Free(grPatch->mipmap); - grPatch->mipmap = NULL; - } - } -#endif - Z_Free(rotsprite); - } - } - sprframe->rotsprite.cached &= ~(1<<rot); - } - } - } -} - -// -// R_FreeSkinRotSprite -// -// Free sprite rotation data from memory, for a skin. -// Calls R_FreeSingleRotSprite. -// -void R_FreeSkinRotSprite(size_t skinnum) -{ - size_t i; - skin_t *skin = &skins[skinnum]; - spritedef_t *skinsprites = skin->sprites; - for (i = 0; i < NUMPLAYERSPRITES*2; i++) - { - R_FreeSingleRotSprite(skinsprites); - 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_picformats.h b/src/r_picformats.h index 3ee76a92f1bf2c521ef92372429543e7de10cba8..8d3999013475f23b9428e0e252148d91c88c8ea2 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -24,6 +24,7 @@ typedef enum // Doom formats PICFMT_PATCH, PICFMT_FLAT, + PICFMT_DOOMPATCH, // PNG PICFMT_PNG, @@ -31,10 +32,12 @@ typedef enum // 16bpp PICFMT_PATCH16, PICFMT_FLAT16, + PICFMT_DOOMPATCH16, // 32bpp PICFMT_PATCH32, - PICFMT_FLAT32 + PICFMT_FLAT32, + PICFMT_DOOMPATCH32 } pictureformat_t; typedef enum @@ -76,8 +79,10 @@ void *Picture_TextureToFlat(size_t trickytex); INT32 Picture_FormatBPP(pictureformat_t format); boolean Picture_IsPatchFormat(pictureformat_t format); +boolean Picture_IsInternalPatchFormat(pictureformat_t format); +boolean Picture_IsDoomPatchFormat(pictureformat_t format); boolean Picture_IsFlatFormat(pictureformat_t format); -boolean Picture_CheckIfPatch(patch_t *patch, size_t size); +boolean Picture_CheckIfDoomPatch(softwarepatch_t *patch, size_t size); // Structs typedef enum @@ -120,15 +125,4 @@ extern spriteinfo_t spriteinfo[NUMSPRITES]; void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps); void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum); -// Sprite rotation -#ifdef ROTSPRITE -INT32 R_GetRollAngle(angle_t rollangle); -void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, spriteframe_t *sprframe, INT32 rot, UINT8 flip); -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__ +#endif // __R_PICFORMATS__ diff --git a/src/r_plane.c b/src/r_plane.c index 97692a4c6736fbcece5546d94ec667582bd9f3f2..2eec74c7a1e68d37a0cd55b34c626ecdbe6f0b37 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -115,33 +115,40 @@ void R_InitPlanes(void) } // -// Water ripple effect!! +// Water ripple effect // Needs the height of the plane, and the vertical position of the span. -// Sets ripple_xfrac and ripple_yfrac, added to ds_xfrac and ds_yfrac, if the span is not tilted. +// Sets planeripple.xfrac and planeripple.yfrac, added to ds_xfrac and ds_yfrac, if the span is not tilted. // -#ifndef NOWATER -INT32 ds_bgofs; -INT32 ds_waterofs; - -static INT32 wtofs=0; -static boolean itswater; -static fixed_t ripple_xfrac; -static fixed_t ripple_yfrac; +struct +{ + INT32 offset; + fixed_t xfrac, yfrac; + boolean active; +} planeripple; -static void R_PlaneRipple(visplane_t *plane, INT32 y, fixed_t plheight) +static void R_CalculatePlaneRipple(visplane_t *plane, INT32 y, fixed_t plheight, boolean calcfrac) { fixed_t distance = FixedMul(plheight, yslope[y]); - const INT32 yay = (wtofs + (distance>>9) ) & 8191; + const INT32 yay = (planeripple.offset + (distance>>9)) & 8191; + // ripples da water texture - angle_t angle = (plane->viewangle + plane->plangle)>>ANGLETOFINESHIFT; ds_bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS; - angle = (angle + 2048) & 8191; // 90 degrees - ripple_xfrac = FixedMul(FINECOSINE(angle), (ds_bgofs<<FRACBITS)); - ripple_yfrac = FixedMul(FINESINE(angle), (ds_bgofs<<FRACBITS)); + if (calcfrac) + { + angle_t angle = (plane->viewangle + plane->plangle)>>ANGLETOFINESHIFT; + angle = (angle + 2048) & 8191; // 90 degrees + planeripple.xfrac = FixedMul(FINECOSINE(angle), (ds_bgofs<<FRACBITS)); + planeripple.yfrac = FixedMul(FINESINE(angle), (ds_bgofs<<FRACBITS)); + } +} + +static void R_UpdatePlaneRipple(void) +{ + ds_waterofs = (leveltime & 1)*16384; + planeripple.offset = (leveltime * 140); } -#endif // // R_MapPlane @@ -159,7 +166,7 @@ static void R_PlaneRipple(visplane_t *plane, INT32 y, fixed_t plheight) void R_MapPlane(INT32 y, INT32 x1, INT32 x2) { angle_t angle, planecos, planesin; - fixed_t distance, span; + fixed_t distance = 0, span; size_t pindex; #ifdef RANGECHECK @@ -167,41 +174,51 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) I_Error("R_MapPlane: %d, %d at %d", x1, x2, y); #endif - // from r_splats's R_RenderFloorSplat - if (x1 >= vid.width) x1 = vid.width - 1; + if (x1 >= vid.width) + x1 = vid.width - 1; - angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; - planecos = FINECOSINE(angle); - planesin = FINESINE(angle); - - if (planeheight != cachedheight[y]) + if (!currentplane->slope) { - cachedheight[y] = planeheight; - distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); - ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale); - ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale); + angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; + planecos = FINECOSINE(angle); + planesin = FINESINE(angle); - if ((span = abs(centery-y))) + if (planeheight != cachedheight[y]) { - ds_xstep = cachedxstep[y] = FixedMul(planesin, planeheight) / span; - ds_ystep = cachedystep[y] = FixedMul(planecos, planeheight) / span; + cachedheight[y] = planeheight; + cacheddistance[y] = distance = FixedMul(planeheight, yslope[y]); + span = abs(centery - y); + + if (span) // don't divide by zero + { + ds_xstep = FixedMul(planesin, planeheight) / span; + ds_ystep = FixedMul(planecos, planeheight) / span; + } + else + { + ds_xstep = FixedMul(distance, basexscale); + ds_ystep = FixedMul(distance, baseyscale); + } + + cachedxstep[y] = ds_xstep; + cachedystep[y] = ds_ystep; + } + else + { + distance = cacheddistance[y]; + ds_xstep = cachedxstep[y]; + ds_ystep = cachedystep[y]; } - } - else - { - distance = cacheddistance[y]; - ds_xstep = cachedxstep[y]; - ds_ystep = cachedystep[y]; - } - ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; - ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; + ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; + ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; + } -#ifndef NOWATER - if (itswater) + // Water ripple effect + if (planeripple.active) { // Needed for ds_bgofs - R_PlaneRipple(currentplane, y, planeheight); + R_CalculatePlaneRipple(currentplane, y, planeheight, (!currentplane->slope)); if (currentplane->slope) { @@ -211,25 +228,25 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) } else { - ds_xfrac += ripple_xfrac; - ds_yfrac += ripple_yfrac; + ds_xfrac += planeripple.xfrac; + ds_yfrac += planeripple.yfrac; } - if (y+ds_bgofs>=viewheight) + if ((y + ds_bgofs) >= viewheight) ds_bgofs = viewheight-y-1; - if (y+ds_bgofs<0) + if ((y + ds_bgofs) < 0) ds_bgofs = -y; } -#endif - - pindex = distance >> LIGHTZSHIFT; - if (pindex >= MAXLIGHTZ) - pindex = MAXLIGHTZ - 1; if (currentplane->slope) ds_colormap = colormaps; else + { + pindex = distance >> LIGHTZSHIFT; + if (pindex >= MAXLIGHTZ) + pindex = MAXLIGHTZ - 1; ds_colormap = planezlight[pindex]; + } if (currentplane->extra_colormap) ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps); @@ -592,9 +609,7 @@ void R_DrawPlanes(void) visplane_t *pl; INT32 i; - // Note: are these two lines really needed? - // R_DrawSinglePlane and R_DrawSkyPlane do span/column drawer resets themselves anyway - spanfunc = spanfuncs[BASEDRAWFUNC]; + R_UpdatePlaneRipple(); for (i = 0; i < MAXVISPLANES; i++, pl++) { @@ -606,10 +621,6 @@ void R_DrawPlanes(void) R_DrawSinglePlane(pl); } } -#ifndef NOWATER - ds_waterofs = (leveltime & 1)*16384; - wtofs = leveltime * 140; -#endif } // R_DrawSkyPlane @@ -655,46 +666,48 @@ static void R_DrawSkyPlane(visplane_t *pl) } } -static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge) +// Potentially override other stuff for now cus we're mean. :< But draw a slope plane! +// I copied ZDoom's code and adapted it to SRB2... -Red +void R_CalculateSlopeVectors(pslope_t *slope, fixed_t planeviewx, fixed_t planeviewy, fixed_t planeviewz, fixed_t planexscale, fixed_t planeyscale, fixed_t planexoffset, fixed_t planeyoffset, angle_t planeviewangle, angle_t planeangle, float fudge) { - // Potentially override other stuff for now cus we're mean. :< But draw a slope plane! - // I copied ZDoom's code and adapted it to SRB2... -Red floatv3_t p, m, n; float ang; float vx, vy, vz; + float xscale = FIXED_TO_FLOAT(planexscale); + float yscale = FIXED_TO_FLOAT(planeyscale); // compiler complains when P_GetSlopeZAt is used in FLOAT_TO_FIXED directly // use this as a temp var to store P_GetSlopeZAt's return value each time fixed_t temp; - vx = FIXED_TO_FLOAT(pl->viewx+xoffs); - vy = FIXED_TO_FLOAT(pl->viewy-yoffs); - vz = FIXED_TO_FLOAT(pl->viewz); + vx = FIXED_TO_FLOAT(planeviewx+planexoffset); + vy = FIXED_TO_FLOAT(planeviewy-planeyoffset); + vz = FIXED_TO_FLOAT(planeviewz); - temp = P_GetSlopeZAt(pl->slope, pl->viewx, pl->viewy); + temp = P_GetSlopeZAt(slope, planeviewx, planeviewy); zeroheight = FIXED_TO_FLOAT(temp); // p is the texture origin in view space // Don't add in the offsets at this stage, because doing so can result in // errors if the flat is rotated. - ang = ANG2RAD(ANGLE_270 - pl->viewangle); + ang = ANG2RAD(ANGLE_270 - planeviewangle); p.x = vx * cos(ang) - vy * sin(ang); p.z = vx * sin(ang) + vy * cos(ang); - temp = P_GetSlopeZAt(pl->slope, -xoffs, yoffs); + temp = P_GetSlopeZAt(slope, -planexoffset, planeyoffset); p.y = FIXED_TO_FLOAT(temp) - vz; // m is the v direction vector in view space - ang = ANG2RAD(ANGLE_180 - (pl->viewangle + pl->plangle)); - m.x = cos(ang); - m.z = sin(ang); + ang = ANG2RAD(ANGLE_180 - (planeviewangle + planeangle)); + m.x = yscale * cos(ang); + m.z = yscale * sin(ang); // n is the u direction vector in view space - n.x = sin(ang); - n.z = -cos(ang); + n.x = xscale * sin(ang); + n.z = -xscale * cos(ang); - ang = ANG2RAD(pl->plangle); - temp = P_GetSlopeZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(sin(ang)), pl->viewy + FLOAT_TO_FIXED(cos(ang))); + ang = ANG2RAD(planeangle); + temp = P_GetSlopeZAt(slope, planeviewx + yscale * FLOAT_TO_FIXED(sin(ang)), planeviewy + yscale * FLOAT_TO_FIXED(cos(ang))); m.y = FIXED_TO_FLOAT(temp) - zeroheight; - temp = P_GetSlopeZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(cos(ang)), pl->viewy - FLOAT_TO_FIXED(sin(ang))); + temp = P_GetSlopeZAt(slope, planeviewx + xscale * FLOAT_TO_FIXED(cos(ang)), planeviewy - xscale * FLOAT_TO_FIXED(sin(ang))); n.y = FIXED_TO_FLOAT(temp) - zeroheight; if (ds_powersoftwo) @@ -710,42 +723,62 @@ static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge) // Eh. I tried making this stuff fixed-point and it exploded on me. Here's a macro for the only floating-point vector function I recall using. #define CROSS(d, v1, v2) \ -d.x = (v1.y * v2.z) - (v1.z * v2.y);\ -d.y = (v1.z * v2.x) - (v1.x * v2.z);\ -d.z = (v1.x * v2.y) - (v1.y * v2.x) - CROSS(ds_su[i], p, m); - CROSS(ds_sv[i], p, n); - CROSS(ds_sz[i], m, n); +d->x = (v1.y * v2.z) - (v1.z * v2.y);\ +d->y = (v1.z * v2.x) - (v1.x * v2.z);\ +d->z = (v1.x * v2.y) - (v1.y * v2.x) + CROSS(ds_sup, p, m); + CROSS(ds_svp, p, n); + CROSS(ds_szp, m, n); #undef CROSS - ds_su[i].z *= focallengthf; - ds_sv[i].z *= focallengthf; - ds_sz[i].z *= focallengthf; + ds_sup->z *= focallengthf; + ds_svp->z *= focallengthf; + ds_szp->z *= focallengthf; // Premultiply the texture vectors with the scale factors #define SFMULT 65536.f if (ds_powersoftwo) { - ds_su[i].x *= (SFMULT * (1<<nflatshiftup)); - ds_su[i].y *= (SFMULT * (1<<nflatshiftup)); - ds_su[i].z *= (SFMULT * (1<<nflatshiftup)); - ds_sv[i].x *= (SFMULT * (1<<nflatshiftup)); - ds_sv[i].y *= (SFMULT * (1<<nflatshiftup)); - ds_sv[i].z *= (SFMULT * (1<<nflatshiftup)); + ds_sup->x *= (SFMULT * (1<<nflatshiftup)); + ds_sup->y *= (SFMULT * (1<<nflatshiftup)); + ds_sup->z *= (SFMULT * (1<<nflatshiftup)); + ds_svp->x *= (SFMULT * (1<<nflatshiftup)); + ds_svp->y *= (SFMULT * (1<<nflatshiftup)); + ds_svp->z *= (SFMULT * (1<<nflatshiftup)); } else { // Lactozilla: I'm essentially multiplying the vectors by FRACUNIT... - ds_su[i].x *= SFMULT; - ds_su[i].y *= SFMULT; - ds_su[i].z *= SFMULT; - ds_sv[i].x *= SFMULT; - ds_sv[i].y *= SFMULT; - ds_sv[i].z *= SFMULT; + ds_sup->x *= SFMULT; + ds_sup->y *= SFMULT; + ds_sup->z *= SFMULT; + ds_svp->x *= SFMULT; + ds_svp->y *= SFMULT; + ds_svp->z *= SFMULT; } #undef SFMULT } +void R_SetTiltedSpan(INT32 span) +{ + if (ds_su == NULL) + ds_su = Z_Malloc(sizeof(*ds_su) * vid.height, PU_STATIC, NULL); + if (ds_sv == NULL) + ds_sv = Z_Malloc(sizeof(*ds_sv) * vid.height, PU_STATIC, NULL); + if (ds_sz == NULL) + ds_sz = Z_Malloc(sizeof(*ds_sz) * vid.height, PU_STATIC, NULL); + + ds_sup = &ds_su[span]; + ds_svp = &ds_sv[span]; + ds_szp = &ds_sz[span]; +} + +static void R_SetSlopePlaneVectors(visplane_t *pl, INT32 y, fixed_t xoff, fixed_t yoff, float fudge) +{ + R_SetTiltedSpan(y); + R_CalculateSlopeVectors(pl->slope, pl->viewx, pl->viewy, pl->viewz, FRACUNIT, FRACUNIT, xoff, yoff, pl->viewangle, pl->plangle, fudge); +} + void R_DrawSinglePlane(visplane_t *pl) { levelflat_t *levelflat; @@ -755,6 +788,7 @@ void R_DrawSinglePlane(visplane_t *pl) ffloor_t *rover; int type; int spanfunctype = BASEDRAWFUNC; + angle_t viewang = viewangle; if (!(pl->minx <= pl->maxx)) return; @@ -766,9 +800,7 @@ void R_DrawSinglePlane(visplane_t *pl) return; } -#ifndef NOWATER - itswater = false; -#endif + planeripple.active = false; spanfunc = spanfuncs[BASEDRAWFUNC]; if (pl->polyobj) @@ -779,7 +811,7 @@ void R_DrawSinglePlane(visplane_t *pl) else if (pl->polyobj->translucency > 0) { spanfunctype = (pl->polyobj->flags & POF_SPLAT) ? SPANDRAWFUNC_TRANSSPLAT : SPANDRAWFUNC_TRANS; - ds_transmap = transtables + ((pl->polyobj->translucency-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(pl->polyobj->translucency); } else if (pl->polyobj->flags & POF_SPLAT) // Opaque, but allow transparent flat pixels spanfunctype = SPANDRAWFUNC_SPLAT; @@ -818,23 +850,23 @@ void R_DrawSinglePlane(visplane_t *pl) if (pl->ffloor->alpha < 12) return; // Don't even draw it else if (pl->ffloor->alpha < 38) - ds_transmap = transtables + ((tr_trans90-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans90); else if (pl->ffloor->alpha < 64) - ds_transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans80); else if (pl->ffloor->alpha < 89) - ds_transmap = transtables + ((tr_trans70-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans70); else if (pl->ffloor->alpha < 115) - ds_transmap = transtables + ((tr_trans60-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans60); else if (pl->ffloor->alpha < 140) - ds_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans50); else if (pl->ffloor->alpha < 166) - ds_transmap = transtables + ((tr_trans40-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans40); else if (pl->ffloor->alpha < 192) - ds_transmap = transtables + ((tr_trans30-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans30); else if (pl->ffloor->alpha < 217) - ds_transmap = transtables + ((tr_trans20-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans20); else if (pl->ffloor->alpha < 243) - ds_transmap = transtables + ((tr_trans10-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans10); else // Opaque, but allow transparent flat pixels spanfunctype = SPANDRAWFUNC_SPLAT; @@ -850,12 +882,12 @@ void R_DrawSinglePlane(visplane_t *pl) } else light = (pl->lightlevel >> LIGHTSEGSHIFT); - #ifndef NOWATER if (pl->ffloor->flags & FF_RIPPLE) { INT32 top, bottom; - itswater = true; + planeripple.active = true; + if (spanfunctype == SPANDRAWFUNC_TRANS) { spanfunctype = SPANDRAWFUNC_WATER; @@ -875,26 +907,11 @@ void R_DrawSinglePlane(visplane_t *pl) vid.width, vid.width); } } - #endif } else light = (pl->lightlevel >> LIGHTSEGSHIFT); } - if (!pl->slope // Don't mess with angle on slopes! We'll handle this ourselves later - && viewangle != pl->viewangle+pl->plangle) - { - memset(cachedheight, 0, sizeof (cachedheight)); - angle = (pl->viewangle+pl->plangle-ANGLE_90)>>ANGLETOFINESHIFT; - basexscale = FixedDiv(FINECOSINE(angle),centerxfrac); - baseyscale = -FixedDiv(FINESINE(angle),centerxfrac); - viewangle = pl->viewangle+pl->plangle; - } - - xoffs = pl->xoffs; - yoffs = pl->yoffs; - planeheight = abs(pl->height - pl->viewz); - currentplane = pl; levelflat = &levelflats[pl->picnum]; @@ -919,6 +936,20 @@ void R_DrawSinglePlane(visplane_t *pl) R_CheckFlatLength(ds_flatwidth * ds_flatheight); } + if (!pl->slope // Don't mess with angle on slopes! We'll handle this ourselves later + && viewangle != pl->viewangle+pl->plangle) + { + memset(cachedheight, 0, sizeof (cachedheight)); + angle = (pl->viewangle+pl->plangle-ANGLE_90)>>ANGLETOFINESHIFT; + basexscale = FixedDiv(FINECOSINE(angle),centerxfrac); + baseyscale = -FixedDiv(FINESINE(angle),centerxfrac); + viewangle = pl->viewangle+pl->plangle; + } + + xoffs = pl->xoffs; + yoffs = pl->yoffs; + planeheight = abs(pl->height - pl->viewz); + if (light >= LIGHTLEVELS) light = LIGHTLEVELS-1; @@ -978,50 +1009,41 @@ void R_DrawSinglePlane(visplane_t *pl) xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); } + xoffs = (fixed_t)(xoffs*fudgecanyon); yoffs = (fixed_t)(yoffs/fudgecanyon); } - ds_sup = &ds_su[0]; - ds_svp = &ds_sv[0]; - ds_szp = &ds_sz[0]; - -#ifndef NOWATER - if (itswater) + if (planeripple.active) { - INT32 i; fixed_t plheight = abs(P_GetSlopeZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz); - fixed_t rxoffs = xoffs; - fixed_t ryoffs = yoffs; R_PlaneBounds(pl); - for (i = pl->high; i < pl->low; i++) + for (x = pl->high; x < pl->low; x++) { - R_PlaneRipple(pl, i, plheight); - xoffs = rxoffs + ripple_xfrac; - yoffs = ryoffs + ripple_yfrac; - R_SlopeVectors(pl, i, fudgecanyon); + R_CalculatePlaneRipple(pl, x, plheight, true); + R_SetSlopePlaneVectors(pl, x, (xoffs + planeripple.xfrac), (yoffs + planeripple.yfrac), fudgecanyon); } - - xoffs = rxoffs; - yoffs = ryoffs; } else -#endif - R_SlopeVectors(pl, 0, fudgecanyon); + R_SetSlopePlaneVectors(pl, 0, xoffs, yoffs, fudgecanyon); -#ifndef NOWATER - if (itswater && (spanfunctype == SPANDRAWFUNC_WATER)) - spanfunctype = SPANDRAWFUNC_TILTEDWATER; - else -#endif - if (spanfunctype == SPANDRAWFUNC_TRANS) - spanfunctype = SPANDRAWFUNC_TILTEDTRANS; - else if (spanfunctype == SPANDRAWFUNC_SPLAT) - spanfunctype = SPANDRAWFUNC_TILTEDSPLAT; - else - spanfunctype = SPANDRAWFUNC_TILTED; + switch (spanfunctype) + { + case SPANDRAWFUNC_WATER: + spanfunctype = SPANDRAWFUNC_TILTEDWATER; + break; + case SPANDRAWFUNC_TRANS: + spanfunctype = SPANDRAWFUNC_TILTEDTRANS; + break; + case SPANDRAWFUNC_SPLAT: + spanfunctype = SPANDRAWFUNC_TILTEDSPLAT; + break; + default: + spanfunctype = SPANDRAWFUNC_TILTED; + break; + } planezlight = scalelight[light]; } @@ -1081,7 +1103,7 @@ using the palette colors. if (spanfunc == spanfuncs[BASEDRAWFUNC]) { INT32 i; - ds_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans50); spanfunc = spanfuncs[SPANDRAWFUNC_TRANS]; for (i=0; i<4; i++) { @@ -1131,6 +1153,8 @@ using the palette colors. } } #endif + + viewangle = viewang; } void R_PlaneBounds(visplane_t *plane) diff --git a/src/r_plane.h b/src/r_plane.h index 8d5ce9ee42330149e2b39255e580831dfd752f7f..0d11c5b721c2ffadcaee26f4fbd830a6b2698c0a 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -87,11 +87,18 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop); void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop); void R_PlaneBounds(visplane_t *plane); -// Draws a single visplane. -void R_DrawSinglePlane(visplane_t *pl); void R_CheckFlatLength(size_t size); boolean R_CheckPowersOfTwo(void); +// Draws a single visplane. +void R_DrawSinglePlane(visplane_t *pl); + +// Calculates the slope vectors needed for tilted span drawing. +void R_CalculateSlopeVectors(pslope_t *slope, fixed_t planeviewx, fixed_t planeviewy, fixed_t planeviewz, fixed_t planexscale, fixed_t planeyscale, fixed_t planexoffset, fixed_t planeyoffset, angle_t planeviewangle, angle_t planeangle, float fudge); + +// Sets the slope vector pointers for the current tilted span. +void R_SetTiltedSpan(INT32 span); + typedef struct planemgr_s { visplane_t *plane; diff --git a/src/r_segs.c b/src/r_segs.c index aa04777c6c4f06bb63021e947380d5e8c7711a3d..1ed1f0285f785465ea3a307c0a6250b4db0d5c49 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -73,170 +73,6 @@ static lighttable_t **walllights; static INT16 *maskedtexturecol; static fixed_t *maskedtextureheight = NULL; -// ========================================================================== -// R_Splats Wall Splats Drawer -// ========================================================================== - -#ifdef WALLSPLATS -static INT16 last_ceilingclip[MAXVIDWIDTH]; -static INT16 last_floorclip[MAXVIDWIDTH]; - -static void R_DrawSplatColumn(column_t *column) -{ - INT32 topscreen, bottomscreen; - fixed_t basetexturemid; - INT32 topdelta, prevdelta = -1; - - basetexturemid = dc_texturemid; - - for (; column->topdelta != 0xff ;) - { - // calculate unclipped screen coordinates for post - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - topscreen = sprtopscreen + spryscale*topdelta; - bottomscreen = topscreen + spryscale*column->length; - - dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; - dc_yh = (bottomscreen-1)>>FRACBITS; - - if (dc_yh >= last_floorclip[dc_x]) - dc_yh = last_floorclip[dc_x] - 1; - if (dc_yl <= last_ceilingclip[dc_x]) - dc_yl = last_ceilingclip[dc_x] + 1; - if (dc_yl <= dc_yh && dl_yh < vid.height && yh > 0) - { - dc_source = (UINT8 *)column + 3; - dc_texturemid = basetexturemid - (topdelta<<FRACBITS); - - // Drawn by R_DrawColumn. - colfunc(); - } - column = (column_t *)((UINT8 *)column + column->length + 4); - } - - dc_texturemid = basetexturemid; -} - -static void R_DrawWallSplats(void) -{ - wallsplat_t *splat; - seg_t *seg; - angle_t angle, angle1, angle2; - INT32 x1, x2; - size_t pindex; - column_t *col; - patch_t *patch; - fixed_t texturecolumn; - - splat = (wallsplat_t *)linedef->splats; - - I_Assert(splat != NULL); - - seg = ds_p->curline; - - // draw all splats from the line that touches the range of the seg - for (; splat; splat = splat->next) - { - angle1 = R_PointToAngle(splat->v1.x, splat->v1.y); - angle2 = R_PointToAngle(splat->v2.x, splat->v2.y); - angle1 = (angle1 - viewangle + ANGLE_90)>>ANGLETOFINESHIFT; - angle2 = (angle2 - viewangle + ANGLE_90)>>ANGLETOFINESHIFT; - // out of the viewangletox lut - /// \todo clip it to the screen - if (angle1 > FINEANGLES/2 || angle2 > FINEANGLES/2) - continue; - x1 = viewangletox[angle1]; - x2 = viewangletox[angle2]; - - if (x1 >= x2) - continue; // does not cross a pixel - - // splat is not in this seg range - if (x2 < ds_p->x1 || x1 > ds_p->x2) - continue; - - if (x1 < ds_p->x1) - x1 = ds_p->x1; - if (x2 > ds_p->x2) - x2 = ds_p->x2; - if (x2 <= x1) - continue; - - // calculate incremental stepping values for texture edges - rw_scalestep = ds_p->scalestep; - spryscale = ds_p->scale1 + (x1 - ds_p->x1)*rw_scalestep; - mfloorclip = floorclip; - mceilingclip = ceilingclip; - - patch = W_CachePatchNum(splat->patch, PU_PATCH); - - dc_texturemid = splat->top + (SHORT(patch->height)<<(FRACBITS-1)) - viewz; - if (splat->yoffset) - dc_texturemid += *splat->yoffset; - - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - - // set drawing mode - switch (splat->flags & SPLATDRAWMODE_MASK) - { - case SPLATDRAWMODE_OPAQUE: - colfunc = colfuncs[BASEDRAWFUNC]; - break; - case SPLATDRAWMODE_TRANS: - if (!cv_translucency.value) - colfunc = colfuncs[BASEDRAWFUNC]; - else - { - dc_transmap = transtables + ((tr_trans50 - 1)<<FF_TRANSSHIFT); - colfunc = colfuncs[COLDRAWFUNC_FUZZY]; - } - - break; - case SPLATDRAWMODE_SHADE: - colfunc = colfuncs[COLDRAWFUNC_SHADE]; - break; - } - - dc_texheight = 0; - - // draw the columns - for (dc_x = x1; dc_x <= x2; dc_x++, spryscale += rw_scalestep) - { - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; - if (pindex >= MAXLIGHTSCALE) - pindex = MAXLIGHTSCALE - 1; - dc_colormap = walllights[pindex]; - - if (frontsector->extra_colormap) - dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); - - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - dc_iscale = 0xffffffffu / (unsigned)spryscale; - - // find column of patch, from perspective - angle = (rw_centerangle + xtoviewangle[dc_x])>>ANGLETOFINESHIFT; - texturecolumn = rw_offset2 - splat->offset - - FixedMul(FINETANGENT(angle), rw_distance); - - // FIXME! - texturecolumn >>= FRACBITS; - if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) - continue; - - // draw the texture - col = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); - R_DrawSplatColumn(col); - } - } // next splat - - colfunc = colfuncs[BASEDRAWFUNC]; -} - -#endif //WALLSPLATS - // ========================================================================== // R_RenderMaskedSegRange // ========================================================================== @@ -321,7 +157,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (ldef->alpha > 0 && ldef->alpha < FRACUNIT) { - dc_transmap = transtables + ((R_GetLinedefTransTable(ldef->alpha) - 1) << FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(R_GetLinedefTransTable(ldef->alpha)); colfunc = colfuncs[COLDRAWFUNC_FUZZY]; } @@ -339,7 +175,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (curline->polyseg->translucency >= NUMTRANSMAPS) return; - dc_transmap = transtables + ((curline->polyseg->translucency-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(curline->polyseg->translucency); colfunc = colfuncs[COLDRAWFUNC_FUZZY]; } @@ -767,23 +603,23 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (pfloor->alpha < 12) return; // Don't even draw it else if (pfloor->alpha < 38) - dc_transmap = transtables + ((tr_trans90-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans90); else if (pfloor->alpha < 64) - dc_transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans80); else if (pfloor->alpha < 89) - dc_transmap = transtables + ((tr_trans70-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans70); else if (pfloor->alpha < 115) - dc_transmap = transtables + ((tr_trans60-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans60); else if (pfloor->alpha < 140) - dc_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans50); else if (pfloor->alpha < 166) - dc_transmap = transtables + ((tr_trans40-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans40); else if (pfloor->alpha < 192) - dc_transmap = transtables + ((tr_trans30-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans30); else if (pfloor->alpha < 217) - dc_transmap = transtables + ((tr_trans20-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans20); else if (pfloor->alpha < 243) - dc_transmap = transtables + ((tr_trans10-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans10); else fuzzy = false; // Opaque @@ -2887,20 +2723,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_tsilheight = &(ds_p->tsilheight); rw_bsilheight = &(ds_p->bsilheight); -#ifdef WALLSPLATS - if (linedef->splats && cv_splats.value) - { - // Isn't a bit wasteful to copy the ENTIRE array for every drawseg? - M_Memcpy(last_ceilingclip + ds_p->x1, ceilingclip + ds_p->x1, - sizeof (INT16) * (ds_p->x2 - ds_p->x1 + 1)); - M_Memcpy(last_floorclip + ds_p->x1, floorclip + ds_p->x1, - sizeof (INT16) * (ds_p->x2 - ds_p->x1 + 1)); - R_RenderSegLoop(); - R_DrawWallSplats(); - } - else -#endif - R_RenderSegLoop(); + R_RenderSegLoop(); colfunc = colfuncs[BASEDRAWFUNC]; if (portalline) // if curline is a portal, set portalrender for drawseg diff --git a/src/r_skins.h b/src/r_skins.h index 04ce459a37889d9455be439da72e3cbd34318966..fbbb38743d84704d3373aafd9e5cc1a7135a46d2 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -17,6 +17,7 @@ #include "info.h" #include "sounds.h" #include "d_player.h" // skinflags +#include "r_patch.h" #include "r_picformats.h" // spriteinfo_t #include "r_defs.h" // spritedef_t diff --git a/src/r_splats.c b/src/r_splats.c index dfec185a11ef2f4d6fc30ca532bd3de003d61942..a3fad82d81730ff1d0ff967f0a4419c60791e59a 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -8,619 +8,590 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file r_splats.c -/// \brief floor and wall splats +/// \brief Floor splats #include "r_draw.h" #include "r_main.h" -#include "r_plane.h" #include "r_splats.h" +#include "r_bsp.h" +#include "p_local.h" +#include "p_slopes.h" #include "w_wad.h" #include "z_zone.h" -#include "d_netcmd.h" -#ifdef WALLSPLATS -static wallsplat_t wallsplats[MAXLEVELSPLATS]; // WALL splats -static INT32 freewallsplat; -#endif - -#ifdef USEASM -/// \brief for floorsplats \note accessed by asm code -struct rastery_s *prastertab; -#endif +struct rastery_s *prastertab; // for ASM code -#ifdef FLOORSPLATS -static floorsplat_t floorsplats[1]; // FLOOR splats -static INT32 freefloorsplat; - -struct rastery_s -{ - fixed_t minx, maxx; // for each raster line starting at line 0 - fixed_t tx1, ty1; - fixed_t tx2, ty2; // start/end points in texture at this line -}; static struct rastery_s rastertab[MAXVIDHEIGHT]; - static void prepare_rastertab(void); -#endif -// -------------------------------------------------------------------------- -// setup splat cache -// -------------------------------------------------------------------------- -void R_ClearLevelSplats(void) -{ -#ifdef WALLSPLATS - freewallsplat = 0; - memset(wallsplats, 0, sizeof (wallsplats)); -#endif -#ifdef FLOORSPLATS - freefloorsplat = 0; - memset(floorsplats, 0, sizeof (floorsplats)); +// ========================================================================== +// FLOOR SPLATS +// ========================================================================== - // setup to draw floorsplats - prastertab = rastertab; - prepare_rastertab(); +#ifdef USEASM +void ASMCALL rasterize_segment_tex_asm(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, INT32 tc, INT32 dir); #endif -} -// ========================================================================== -// WALL SPLATS -// ========================================================================== -#ifdef WALLSPLATS -// -------------------------------------------------------------------------- -// Return a pointer to a splat free for use, or NULL if no more splats are -// available -// -------------------------------------------------------------------------- -static wallsplat_t *R_AllocWallSplat(void) +// Lactozilla +static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, INT32 tc, INT32 dir) { - wallsplat_t *splat; - wallsplat_t *p_splat; - line_t *li; - - // clear the splat from the line if it was in use - splat = &wallsplats[freewallsplat]; - li = splat->line; - if (li) +#ifdef USEASM + if (R_ASM) { - // remove splat from line splats list - if (li->splats == splat) - li->splats = splat->next; // remove from head - else - { - I_Assert(li->splats != NULL); - for (p_splat = li->splats; p_splat->next; p_splat = p_splat->next) - if (p_splat->next == splat) - { - p_splat->next = splat->next; - break; - } - } + rasterize_segment_tex_asm(x1, y1, x2, y2, tv1, tv2, tc, dir); + return; } + else +#endif + { + fixed_t xs, xe, count; + fixed_t dx0, dx1; - memset(splat, 0, sizeof (wallsplat_t)); + if (y1 == y2) + return; - // for next allocation - freewallsplat++; - if (freewallsplat >= 20) - freewallsplat = 0; + if (y2 > y1) + { + count = (y2-y1)+1; - return splat; -} + dx0 = FixedDiv((x2-x1)<<FRACBITS, count<<FRACBITS); + dx1 = FixedDiv((tv2-tv1)<<FRACBITS, count<<FRACBITS); -// Add a new splat to the linedef: -// top: top z coord -// wallfrac: frac along the linedef vector (0 to FRACUNIT) -// splatpatchname: name of patch to draw -void R_AddWallSplat(line_t *wallline, INT16 sectorside, const char *patchname, fixed_t top, - fixed_t wallfrac, INT32 flags) -{ - fixed_t fracsplat, linelength; - wallsplat_t *splat = NULL; - wallsplat_t *p_splat; - patch_t *patch; - sector_t *backsector = NULL; - - if (W_CheckNumForName(patchname) != LUMPERROR) - splat = R_AllocWallSplat(); - if (!splat) - return; + xs = x1 << FRACBITS; + xe = tv1 << FRACBITS; + tc <<= FRACBITS; - // set the splat - splat->patch = W_GetNumForName(patchname); - sectorside ^= 1; - if (wallline->sidenum[sectorside] != 0xffff) - { - backsector = sides[wallline->sidenum[sectorside]].sector; + if (dir == 0) + { + for (;;) + { + rastertab[y1].maxx = xs; + rastertab[y1].tx2 = xe; + rastertab[y1].ty2 = tc; - if (top < backsector->floorheight) - { - splat->yoffset = &backsector->floorheight; - top -= backsector->floorheight; - } - else if (top > backsector->ceilingheight) - { - splat->yoffset = &backsector->ceilingheight; - top -= backsector->ceilingheight; - } - } + xs += dx0; + xe += dx1; + y1++; - splat->top = top; - splat->flags = flags; + if (count-- < 1) break; + } + } + else + { + for (;;) + { + rastertab[y1].maxx = xs; + rastertab[y1].tx2 = tc; + rastertab[y1].ty2 = xe; - // bad.. but will be needed for drawing anyway.. - patch = W_CachePatchNum(splat->patch, PU_PATCH); + xs += dx0; + xe += dx1; + y1++; - // offset needed by draw code for texture mapping - linelength = P_SegLength((seg_t *)wallline); - splat->offset = FixedMul(wallfrac, linelength) - (SHORT(patch->width)<<(FRACBITS-1)); - fracsplat = FixedDiv(((SHORT(patch->width)<<FRACBITS)>>1), linelength); + if (count-- < 1) break; + } + } + } + else + { + count = (y1-y2)+1; - wallfrac -= fracsplat; - if (wallfrac > linelength) - return; - splat->v1.x = wallline->v1->x + FixedMul(wallline->dx, wallfrac); - splat->v1.y = wallline->v1->y + FixedMul(wallline->dy, wallfrac); - wallfrac += fracsplat + fracsplat; - if (wallfrac < 0) - return; - splat->v2.x = wallline->v1->x + FixedMul(wallline->dx, wallfrac); - splat->v2.y = wallline->v1->y + FixedMul(wallline->dy, wallfrac); + dx0 = FixedDiv((x1-x2)<<FRACBITS, count<<FRACBITS); + dx1 = FixedDiv((tv1-tv2)<<FRACBITS, count<<FRACBITS); - if (wallline->frontsector && wallline->frontsector == backsector) - return; + xs = x2 << FRACBITS; + xe = tv2 << FRACBITS; + tc <<= FRACBITS; - // insert splat in the linedef splat list - // BP: why not insert in head is much more simple? - // BP: because for remove it is more simple! - splat->line = wallline; - splat->next = NULL; - if (wallline->splats) - { - p_splat = wallline->splats; - while (p_splat->next) - p_splat = p_splat->next; - p_splat->next = splat; - } - else - wallline->splats = splat; -} -#endif // WALLSPLATS + if (dir == 0) + { + for (;;) + { + rastertab[y2].minx = xs; + rastertab[y2].tx1 = xe; + rastertab[y2].ty1 = tc; -// ========================================================================== -// FLOOR SPLATS -// ========================================================================== -#ifdef FLOORSPLATS + xs += dx0; + xe += dx1; + y2++; -// -------------------------------------------------------------------------- -// Return a pointer to a splat free for use, or NULL if no more splats are -// available -// -------------------------------------------------------------------------- -static floorsplat_t *R_AllocFloorSplat(void) -{ - floorsplat_t *splat; - floorsplat_t *p_splat; - subsector_t *sub; - - // find splat to use - freefloorsplat++; - if (freefloorsplat >= 1) - freefloorsplat = 0; - - // clear the splat from the line if it was in use - splat = &floorsplats[freefloorsplat]; - sub = splat->subsector; - if (sub) - { - // remove splat from subsector splats list - if (sub->splats == splat) - sub->splats = splat->next; // remove from head - else - { - p_splat = sub->splats; - while (p_splat->next) + if (count-- < 1) break; + } + } + else { - if (p_splat->next == splat) - p_splat->next = splat->next; + for (;;) + { + rastertab[y2].minx = xs; + rastertab[y2].tx1 = tc; + rastertab[y2].ty1 = xe; + + xs += dx0; + xe += dx1; + y2++; + + if (count-- < 1) break; + } } } } - - memset(splat, 0, sizeof (floorsplat_t)); - return splat; } -// -------------------------------------------------------------------------- -// Add a floor splat to the subsector -// -------------------------------------------------------------------------- -void R_AddFloorSplat(subsector_t *subsec, mobj_t *mobj, const char *picname, fixed_t x, fixed_t y, fixed_t z, - INT32 flags) +void R_DrawFloorSprite(vissprite_t *spr) { - floorsplat_t *splat = NULL; - floorsplat_t *p_splat; - INT32 size; + floorsplat_t splat; + mobj_t *mobj = spr->mobj; + fixed_t tr_x, tr_y, rot_x, rot_y, rot_z; + + vector3_t *v3d; + vector2_t v2d[4]; + vector2_t rotated[4]; + + fixed_t x, y; + fixed_t w, h; + angle_t angle, splatangle; + fixed_t ca, sa; + fixed_t xscale, yscale; + fixed_t xoffset, yoffset; + fixed_t leftoffset, topoffset; + pslope_t *slope = NULL; + INT32 i; + + boolean hflip = (spr->xiscale < 0); + boolean vflip = (spr->cut & SC_VFLIP); + UINT8 flipflags = 0; + + renderflags_t renderflags = spr->renderflags; + + if (hflip) + flipflags |= PICFLAGS_XFLIP; + if (vflip) + flipflags |= PICFLAGS_YFLIP; + + if (!mobj || P_MobjWasRemoved(mobj)) + return; - if (W_CheckNumForName(picname) != LUMPERROR) - splat = R_AllocFloorSplat(); - if (!splat) + Patch_GenerateFlat(spr->patch, flipflags); + splat.pic = spr->patch->flats[flipflags]; + if (splat.pic == NULL) return; - // set the splat - splat->pic = W_GetNumForName(picname); - splat->flags = flags; - splat->mobj = mobj; + splat.mobj = mobj; + splat.width = spr->patch->width; + splat.height = spr->patch->height; + splat.scale = mobj->scale; - splat->z = z; + if (mobj->skin && ((skin_t *)mobj->skin)->flags & SF_HIRES) + splat.scale = FixedMul(splat.scale, ((skin_t *)mobj->skin)->highresscale); - size = W_LumpLength(splat->pic); + if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) + splatangle = mobj->angle; + else + splatangle = viewangle; - switch (size) - { - case 4194304: // 2048x2048 lump - splat->size = 1024; - break; - case 1048576: // 1024x1024 lump - splat->size = 512; - break; - case 262144:// 512x512 lump - splat->size = 256; - break; - case 65536: // 256x256 lump - splat->size = 128; - break; - case 16384: // 128x128 lump - splat->size = 64; - break; - case 1024: // 32x32 lump - splat->size = 16; - break; - default: // 64x64 lump - splat->size = 32; - break; - } + if (!(spr->cut & SC_ISROTATED)) + splatangle += mobj->rollangle; + + splat.angle = -splatangle; + splat.angle += ANGLE_90; + + topoffset = spr->spriteyoffset; + leftoffset = spr->spritexoffset; + if (hflip) + leftoffset = ((splat.width * FRACUNIT) - leftoffset); + + xscale = spr->spritexscale; + yscale = spr->spriteyscale; + + splat.xscale = FixedMul(splat.scale, xscale); + splat.yscale = FixedMul(splat.scale, yscale); + + xoffset = FixedMul(leftoffset, splat.xscale); + yoffset = FixedMul(topoffset, splat.yscale); + + x = mobj->x; + y = mobj->y; + w = (splat.width * splat.xscale); + h = (splat.height * splat.yscale); + + splat.x = x; + splat.y = y; + splat.z = mobj->z; + splat.tilted = false; + + // Set positions // 3--2 // | | // 0--1 - // - splat->verts[0].x = splat->verts[3].x = x - (splat->size<<FRACBITS); - splat->verts[2].x = splat->verts[1].x = x + ((splat->size-1)<<FRACBITS); - splat->verts[3].y = splat->verts[2].y = y + ((splat->size-1)<<FRACBITS); - splat->verts[0].y = splat->verts[1].y = y - (splat->size<<FRACBITS); - - // insert splat in the subsector splat list - splat->subsector = subsec; - splat->next = NULL; - if (subsec->splats) + + splat.verts[0].x = w - xoffset; + splat.verts[0].y = yoffset; + + splat.verts[1].x = -xoffset; + splat.verts[1].y = yoffset; + + splat.verts[2].x = -xoffset; + splat.verts[2].y = -h + yoffset; + + splat.verts[3].x = w - xoffset; + splat.verts[3].y = -h + yoffset; + + angle = -splat.angle; + ca = FINECOSINE(angle>>ANGLETOFINESHIFT); + sa = FINESINE(angle>>ANGLETOFINESHIFT); + + // Rotate + for (i = 0; i < 4; i++) { - p_splat = subsec->splats; - while (p_splat->next) - p_splat = p_splat->next; - p_splat->next = splat; + rotated[i].x = FixedMul(splat.verts[i].x, ca) - FixedMul(splat.verts[i].y, sa); + rotated[i].y = FixedMul(splat.verts[i].x, sa) + FixedMul(splat.verts[i].y, ca); } - else - subsec->splats = splat; -} -// -------------------------------------------------------------------------- -// Before each frame being rendered, clear the visible floorsplats list -// -------------------------------------------------------------------------- -static floorsplat_t *visfloorsplats; + if (renderflags & (RF_SLOPESPLAT | RF_OBJECTSLOPESPLAT)) + { + pslope_t *standingslope = mobj->standingslope; // The slope that the object is standing on. -void R_ClearVisibleFloorSplats(void) -{ - visfloorsplats = NULL; -} + // The slope that was defined for the sprite. + if (renderflags & RF_SLOPESPLAT) + slope = mobj->floorspriteslope; -// -------------------------------------------------------------------------- -// Add a floorsplat to the visible floorsplats list, for the current frame -// -------------------------------------------------------------------------- -void R_AddVisibleFloorSplats(subsector_t *subsec) -{ - floorsplat_t *pSplat; - I_Assert(subsec->splats != NULL); - - pSplat = subsec->splats; - // the splat is not visible from below - // FIXME: depending on some flag in pSplat->flags, some splats may be visible from 2 sides - // (above/below) - if (pSplat->z < viewz) + if (standingslope && (renderflags & RF_OBJECTSLOPESPLAT)) + slope = standingslope; + + // Set splat as tilted + splat.tilted = (slope != NULL); + } + + if (splat.tilted) { - pSplat->nextvis = visfloorsplats; - visfloorsplats = pSplat; + // Lactozilla: Just copy the entire slope LMFAOOOO + pslope_t *s = &splat.slope; + + s->o.x = slope->o.x; + s->o.y = slope->o.y; + s->o.z = slope->o.z; + + s->d.x = slope->d.x; + s->d.y = slope->d.y; + + s->normal.x = slope->normal.x; + s->normal.y = slope->normal.y; + s->normal.z = slope->normal.z; + + s->zdelta = slope->zdelta; + s->zangle = slope->zangle; + s->xydirection = slope->xydirection; + + s->next = NULL; + s->flags = 0; } - while (pSplat->next) + // Translate + for (i = 0; i < 4; i++) { - pSplat = pSplat->next; - if (pSplat->z < viewz) + tr_x = rotated[i].x + x; + tr_y = rotated[i].y + y; + + if (slope) { - pSplat->nextvis = visfloorsplats; - visfloorsplats = pSplat; + rot_z = P_GetSlopeZAt(slope, tr_x, tr_y); + splat.verts[i].z = rot_z; } + else + splat.verts[i].z = splat.z; + + splat.verts[i].x = tr_x; + splat.verts[i].y = tr_y; } -} -#ifdef USEASM -// tv1, tv2 = x/y qui varie dans la texture, tc = x/y qui est constant. -void ASMCALL rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, - INT32 tc, INT32 dir); -#endif + for (i = 0; i < 4; i++) + { + v3d = &splat.verts[i]; + + // transform the origin point + tr_x = v3d->x - viewx; + tr_y = v3d->y - viewy; -// current test with floor tile -//#define FLOORSPLATSOLIDCOLOR + // rotation around vertical y axis + rot_x = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); + rot_y = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); + rot_z = v3d->z - viewz; + + if (rot_y < FRACUNIT) + return; + + // note: y from view above of map, is distance far away + xscale = FixedDiv(projection, rot_y); + yscale = -FixedDiv(projectiony, rot_y); + + // projection + v2d[i].x = (centerxfrac + FixedMul(rot_x, xscale))>>FRACBITS; + v2d[i].y = (centeryfrac + FixedMul(rot_z, yscale))>>FRACBITS; + } + + R_RenderFloorSplat(&splat, v2d, spr); +} // -------------------------------------------------------------------------- // Rasterize the four edges of a floor splat polygon, // fill the polygon with linear interpolation, call span drawer for each // scan line // -------------------------------------------------------------------------- -static void R_RenderFloorSplat(floorsplat_t *pSplat, vertex_t *verts, UINT8 *pTex) +void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis) { // rasterizing - INT32 miny = vid.height + 1, maxy = 0, y, x1, ry1, x2, y2; - fixed_t offsetx, offsety; - -#ifdef FLOORSPLATSOLIDCOLOR - UINT8 *pDest; - INT32 tdx, tdy, ty, tx, x; -#else - lighttable_t **planezlight; - fixed_t planeheight; - angle_t angle, planecos, planesin; - fixed_t distance, span; - size_t indexr; - INT32 light; -#endif - (void)pTex; + INT32 miny = viewheight + 1, maxy = 0; + INT32 y, x1, ry1, x2, y2, i; + fixed_t offsetx = 0, offsety = 0; + fixed_t planeheight = 0; + fixed_t step; - offsetx = pSplat->verts[0].x & ((pSplat->size << FRACBITS)-1); - offsety = pSplat->verts[0].y & ((pSplat->size << FRACBITS)-1); + int spanfunctype = SPANDRAWFUNC_SPRITE; - // do segment a -> top of texture - x1 = verts[3].x; - ry1 = verts[3].y; - x2 = verts[2].x; - y2 = verts[2].y; - if (ry1 < 0) - ry1 = 0; - if (ry1 >= vid.height) - ry1 = vid.height - 1; - if (y2 < 0) - y2 = 0; - if (y2 >= vid.height) - y2 = vid.height - 1; - rasterize_segment_tex(x1, ry1, x2, y2, 0, pSplat->size - 1, 0, 0); - if (ry1 < miny) - miny = ry1; - if (ry1 > maxy) - maxy = ry1; + prepare_rastertab(); - // do segment b -> right side of texture - x1 = x2; - ry1 = y2; - x2 = verts[1].x; - y2 = verts[1].y; - if (ry1 < 0) - ry1 = 0; - if (ry1 >= vid.height) - ry1 = vid.height - 1; - if (y2 < 0) - y2 = 0; - if (y2 >= vid.height) - y2 = vid.height - 1; - rasterize_segment_tex(x1, ry1, x2, y2, 0, pSplat->size - 1, pSplat->size - 1, 1); - if (ry1 < miny) - miny = ry1; - if (ry1 > maxy) - maxy = ry1; +#define RASTERPARAMS(vnum1, vnum2, tv1, tv2, tc, dir) \ + x1 = verts[vnum1].x; \ + ry1 = verts[vnum1].y; \ + x2 = verts[vnum2].x; \ + y2 = verts[vnum2].y; \ + if (y2 > ry1) \ + step = FixedDiv(x2-x1, y2-ry1+1); \ + else if (y2 == ry1) \ + step = 0; \ + else \ + step = FixedDiv(x2-x1, ry1-y2+1); \ + if (ry1 < 0) { \ + if (step) { \ + x1 <<= FRACBITS; \ + x1 += (-ry1)*step; \ + x1 >>= FRACBITS; \ + } \ + ry1 = 0; \ + } \ + if (ry1 >= vid.height) { \ + if (step) { \ + x1 <<= FRACBITS; \ + x1 -= (vid.height-1-ry1)*step; \ + x1 >>= FRACBITS; \ + } \ + ry1 = vid.height - 1; \ + } \ + if (y2 < 0) { \ + if (step) { \ + x2 <<= FRACBITS; \ + x2 -= (-y2)*step; \ + x2 >>= FRACBITS; \ + } \ + y2 = 0; \ + } \ + if (y2 >= vid.height) { \ + if (step) { \ + x2 <<= FRACBITS; \ + x2 += (vid.height-1-y2)*step; \ + x2 >>= FRACBITS; \ + } \ + y2 = vid.height - 1; \ + } \ + rasterize_segment_tex(x1, ry1, x2, y2, tv1, tv2, tc, dir); \ + if (ry1 < miny) \ + miny = ry1; \ + if (ry1 > maxy) \ + maxy = ry1; + // do segment a -> top of texture + RASTERPARAMS(3,2,0,pSplat->width-1,0,0); + // do segment b -> right side of texture + RASTERPARAMS(2,1,0,pSplat->width-1,pSplat->height-1,0); // do segment c -> bottom of texture - x1 = x2; - ry1 = y2; - x2 = verts[0].x; - y2 = verts[0].y; - if (ry1 < 0) - ry1 = 0; - if (ry1 >= vid.height) - ry1 = vid.height - 1; - if (y2 < 0) - y2 = 0; - if (y2 >= vid.height) - y2 = vid.height - 1; - rasterize_segment_tex(x1, ry1, x2, y2, pSplat->size - 1, 0, pSplat->size - 1, 0); - if (ry1 < miny) - miny = ry1; - if (ry1 > maxy) - maxy = ry1; - + RASTERPARAMS(1,0,pSplat->width-1,0,pSplat->height-1,0); // do segment d -> left side of texture - x1 = x2; - ry1 = y2; - x2 = verts[3].x; - y2 = verts[3].y; - if (ry1 < 0) - ry1 = 0; - if (ry1 >= vid.height) - ry1 = vid.height - 1; - if (y2 < 0) - y2 = 0; - if (y2 >= vid.height) - y2 = vid.height - 1; - rasterize_segment_tex(x1, ry1, x2, y2, pSplat->size - 1, 0, 0, 1); - if (ry1 < miny) - miny = ry1; - if (ry1 > maxy) - maxy = ry1; - -#ifndef FLOORSPLATSOLIDCOLOR - // prepare values for all the splat - ds_source = W_CacheLumpNum(pSplat->pic, PU_CACHE); - planeheight = abs(pSplat->z - viewz); - light = (pSplat->subsector->sector->lightlevel >> LIGHTSEGSHIFT); - if (light >= LIGHTLEVELS) - light = LIGHTLEVELS - 1; - if (light < 0) - light = 0; - planezlight = zlight[light]; + RASTERPARAMS(0,3,pSplat->width-1,0,0,1); - for (y = miny; y <= maxy; y++) - { - x1 = rastertab[y].minx>>FRACBITS; - x2 = rastertab[y].maxx>>FRACBITS; + ds_source = (UINT8 *)pSplat->pic; + ds_flatwidth = pSplat->width; + ds_flatheight = pSplat->height; - if (x1 < 0) - x1 = 0; - if (x2 >= vid.width) - x2 = vid.width - 1; + if (R_CheckPowersOfTwo()) + R_CheckFlatLength(ds_flatwidth * ds_flatheight); - angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; - planecos = FINECOSINE(angle); - planesin = FINESINE(angle); + // Lactozilla: I don't know what I'm doing + if (pSplat->tilted) + { + R_SetTiltedSpan(0); + R_CalculateSlopeVectors(&pSplat->slope, viewx, viewy, viewz, pSplat->xscale, pSplat->yscale, -pSplat->verts[0].x, pSplat->verts[0].y, viewangle, pSplat->angle, 1.0f); + spanfunctype = SPANDRAWFUNC_TILTEDSPRITE; + } + else + { + planeheight = abs(pSplat->z - viewz); - if (planeheight != cachedheight[y]) + if (pSplat->angle) { - cachedheight[y] = planeheight; - distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); - ds_xstep = cachedxstep[y] = FixedMul(distance,basexscale); - ds_ystep = cachedystep[y] = FixedMul(distance,baseyscale); - - if ((span = abs(centery-y))) - { - ds_xstep = cachedxstep[y] = FixedMul(planesin, planeheight) / span; - ds_ystep = cachedystep[y] = FixedMul(planecos, planeheight) / span; - } + // Add the view offset, rotated by the plane angle. + fixed_t a = -pSplat->verts[0].x + viewx; + fixed_t b = -pSplat->verts[0].y + viewy; + angle_t angle = (pSplat->angle >> ANGLETOFINESHIFT); + offsetx = FixedMul(a, FINECOSINE(angle)) - FixedMul(b,FINESINE(angle)); + offsety = -FixedMul(a, FINESINE(angle)) - FixedMul(b,FINECOSINE(angle)); + memset(cachedheight, 0, sizeof(cachedheight)); } else { - distance = cacheddistance[y]; - ds_xstep = cachedxstep[y]; - ds_ystep = cachedystep[y]; + offsetx = viewx - pSplat->verts[0].x; + offsety = pSplat->verts[0].y - viewy; } + } - ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; - ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; - ds_xfrac -= offsetx; - ds_yfrac += offsety; + ds_colormap = vis->colormap; + ds_translation = R_GetSpriteTranslation(vis); + if (ds_translation == NULL) + ds_translation = colormaps; - indexr = distance >> LIGHTZSHIFT; - if (indexr >= MAXLIGHTZ) - indexr = MAXLIGHTZ - 1; - ds_colormap = planezlight[indexr]; + if (vis->extra_colormap) + { + if (!ds_colormap) + ds_colormap = vis->extra_colormap->colormap; + else + ds_colormap = &vis->extra_colormap->colormap[ds_colormap - colormaps]; + } - ds_y = y; - if (x2 >= x1) // sanity check - { - ds_x1 = x1; - ds_x2 = x2; - ds_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT); - (spanfuncs[SPANDRAWFUNC_SPLAT])(); - } + if (vis->transmap) + { + ds_transmap = vis->transmap; - // reset for next calls to edge rasterizer - rastertab[y].minx = INT32_MAX; - rastertab[y].maxx = INT32_MIN; + if (pSplat->tilted) + spanfunctype = SPANDRAWFUNC_TILTEDTRANSSPRITE; + else + spanfunctype = SPANDRAWFUNC_TRANSSPRITE; } + else + ds_transmap = NULL; + + if (ds_powersoftwo) + spanfunc = spanfuncs[spanfunctype]; + else + spanfunc = spanfuncs_npo2[spanfunctype]; + + if (maxy >= vid.height) + maxy = vid.height-1; -#else for (y = miny; y <= maxy; y++) { + boolean cliptab[MAXVIDWIDTH+1]; + x1 = rastertab[y].minx>>FRACBITS; x2 = rastertab[y].maxx>>FRACBITS; + + if (x1 > x2) + { + INT32 swap = x1; + x1 = x2; + x2 = swap; + } + + if (x1 == INT16_MIN || x2 == INT16_MAX) + continue; + if (x1 < 0) x1 = 0; - if (x2 >= vid.width) - x2 = vid.width - 1; + if (x2 >= viewwidth) + x2 = viewwidth - 1; -// pDest = ylookup[y] + columnofs[x1]; - pDest = &topleft[y*vid.width + x1]; + if (x1 >= viewwidth || x2 < 0) + continue; - x = x2 - x1 + 1; + for (i = x1; i <= x2; i++) + cliptab[i] = (y >= mfloorclip[i]); - // starting point of the texture - tx = rastertab[y].tx1; - ty = rastertab[y].ty1; - - // HORRIBLE BUG!!! - if (x > 0) + // clip left + while (cliptab[x1]) { - tdx = (rastertab[y].tx2 - tx) / x; - tdy = (rastertab[y].ty2 - ty) / x; - - while (x-- > 0) - { - *(pDest++) = (UINT8)(y&1); - tx += tdx; - ty += tdy; - } + x1++; + if (x1 >= viewwidth) + break; } - // reinitialise the minimum and maximum for the next approach - rastertab[y].minx = INT32_MAX; - rastertab[y].maxx = INT32_MIN; - } -#endif -} + // clip right + i = x2; -// -------------------------------------------------------------------------- -// R_DrawVisibleFloorSplats -// draw the flat floor/ceiling splats -// -------------------------------------------------------------------------- -void R_DrawVisibleFloorSplats(void) -{ - floorsplat_t *pSplat; - INT32 iCount = 0, i; - fixed_t tr_x, tr_y, rot_x, rot_y, rot_z, xscale, yscale; - vertex_t *v3d; - vertex_t v2d[4]; - - pSplat = visfloorsplats; - while (pSplat) - { - iCount++; + while (i > x1) + { + if (cliptab[i]) + x2 = i-1; + i--; + if (i < 0) + break; + } - // Draw a floor splat - // 3--2 - // | | - // 0--1 + if (x2 < x1) + continue; - rot_z = pSplat->z - viewz; - for (i = 0; i < 4; i++) + if (!pSplat->tilted) { - v3d = &pSplat->verts[i]; + fixed_t xstep, ystep; + fixed_t distance, span; - // transform the origin point - tr_x = v3d->x - viewx; - tr_y = v3d->y - viewy; + angle_t angle = (viewangle + pSplat->angle)>>ANGLETOFINESHIFT; + angle_t planecos = FINECOSINE(angle); + angle_t planesin = FINESINE(angle); - // rotation around vertical y axis - rot_x = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); - rot_y = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); + if (planeheight != cachedheight[y]) + { + cachedheight[y] = planeheight; + distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); + span = abs(centery - y); - if (rot_y < 4*FRACUNIT) - goto skipit; + if (span) // don't divide by zero + { + xstep = FixedMul(planesin, planeheight) / span; + ystep = FixedMul(planecos, planeheight) / span; + } + else + { + // ah + xstep = FRACUNIT; + ystep = FRACUNIT; + } + + cachedxstep[y] = xstep; + cachedystep[y] = ystep; + } + else + { + distance = cacheddistance[y]; + xstep = cachedxstep[y]; + ystep = cachedystep[y]; + } - // note: y from view above of map, is distance far away - xscale = FixedDiv(projection, rot_y); - yscale = -FixedDiv(projectiony, rot_y); + ds_xstep = FixedDiv(xstep, pSplat->xscale); + ds_ystep = FixedDiv(ystep, pSplat->yscale); - // projection - v2d[i].x = (centerxfrac + FixedMul (rot_x, xscale))>>FRACBITS; - v2d[i].y = (centeryfrac + FixedMul (rot_z, yscale))>>FRACBITS; + ds_xfrac = FixedDiv(offsetx + FixedMul(planecos, distance) + (x1 - centerx) * xstep, pSplat->xscale); + ds_yfrac = FixedDiv(offsety - FixedMul(planesin, distance) + (x1 - centerx) * ystep, pSplat->yscale); } - R_RenderFloorSplat(pSplat, v2d, NULL); -skipit: - pSplat = pSplat->nextvis; + ds_y = y; + ds_x1 = x1; + ds_x2 = x2; + spanfunc(); + + rastertab[y].minx = INT32_MAX; + rastertab[y].maxx = INT32_MIN; } + + if (pSplat->angle && !pSplat->tilted) + memset(cachedheight, 0, sizeof(cachedheight)); } static void prepare_rastertab(void) { - INT32 iLine; - for (iLine = 0; iLine < vid.height; iLine++) + INT32 i; + prastertab = rastertab; + for (i = 0; i < vid.height; i++) { - rastertab[iLine].minx = INT32_MAX; - rastertab[iLine].maxx = INT32_MIN; + rastertab[i].minx = INT32_MAX; + rastertab[i].maxx = INT32_MIN; } } - -#endif // FLOORSPLATS diff --git a/src/r_splats.h b/src/r_splats.h index 4ad893abbb2db5dcde78116fd94b65cf8f373aa4..e1f836f489bab54513dafd5b867ebfd7dbc79f44 100644 --- a/src/r_splats.h +++ b/src/r_splats.h @@ -14,68 +14,35 @@ #define __R_SPLATS_H__ #include "r_defs.h" - -//#define WALLSPLATS // comment this out to compile without splat effects -/*#ifdef USEASM -#define FLOORSPLATS -#endif*/ - -#define MAXLEVELSPLATS 1024 - -// splat flags -#define SPLATDRAWMODE_MASK 0x03 // mask to get drawmode from flags -#define SPLATDRAWMODE_OPAQUE 0x00 -#define SPLATDRAWMODE_SHADE 0x01 -#define SPLATDRAWMODE_TRANS 0x02 +#include "r_things.h" // ========================================================================== // DEFINITIONS // ========================================================================== -// WALL SPLATS are patches drawn on top of wall segs -typedef struct wallsplat_s +struct rastery_s { - lumpnum_t patch; // lump id. - vertex_t v1, v2; // vertices along the linedef - fixed_t top; - fixed_t offset; // offset in columns<<FRACBITS from start of linedef to start of splat - INT32 flags; - fixed_t *yoffset; - line_t *line; // the parent line of the splat seg - struct wallsplat_s *next; -} wallsplat_t; + fixed_t minx, maxx; // for each raster line starting at line 0 + fixed_t tx1, ty1; // start points in texture at this line + fixed_t tx2, ty2; // end points in texture at this line +}; +extern struct rastery_s *prastertab; // for ASM code -// FLOOR SPLATS are pic_t (raw horizontally stored) drawn on top of the floor or ceiling typedef struct floorsplat_s { - lumpnum_t pic; // a pic_t lump id - INT32 flags; - INT32 size; // 64, 128, 256, etc. - vertex_t verts[4]; // (x,y) as viewn from above on map - fixed_t z; // z (height) is constant for all the floorsplats - subsector_t *subsector; // the parent subsector + UINT16 *pic; + INT32 width, height; + fixed_t scale, xscale, yscale; + angle_t angle; + boolean tilted; // Uses the tilted drawer + pslope_t slope; + + vector3_t verts[4]; // (x,y,z) as viewed from above on map + fixed_t x, y, z; // position mobj_t *mobj; // Mobj it is tied to - struct floorsplat_s *next; - struct floorsplat_s *nextvis; } floorsplat_t; -// p_setup.c -fixed_t P_SegLength(seg_t *seg); - -// call at P_SetupLevel() -void R_ClearLevelSplats(void); - -#ifdef WALLSPLATS -void R_AddWallSplat(line_t *wallline, INT16 sectorside, const char *patchname, fixed_t top, - fixed_t wallfrac, INT32 flags); -#endif -#ifdef FLOORSPLATS -void R_AddFloorSplat(subsector_t *subsec, mobj_t *mobj, const char *picname, fixed_t x, fixed_t y, fixed_t z, - INT32 flags); -#endif - -void R_ClearVisibleFloorSplats(void); -void R_AddVisibleFloorSplats(subsector_t *subsec); -void R_DrawVisibleFloorSplats(void); +void R_DrawFloorSprite(vissprite_t *spr); +void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis); #endif /*__R_SPLATS_H__*/ diff --git a/src/r_textures.c b/src/r_textures.c index a34c29c728c79395d56ad93864b32c575032d5aa..9de9649e222a9628f0917592570c899917e62722 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -20,6 +20,7 @@ #include "m_misc.h" #include "r_data.h" #include "r_textures.h" +#include "r_patch.h" #include "r_picformats.h" #include "w_wad.h" #include "z_zone.h" @@ -33,7 +34,7 @@ #endif #ifdef HWRENDER -#include "hardware/hw_main.h" // HWR_LoadTextures +#include "hardware/hw_glob.h" // HWR_LoadMapTextures #endif #include <errno.h> @@ -266,7 +267,7 @@ UINT8 *R_GenerateTexture(size_t texnum) UINT8 *blocktex; texture_t *texture; texpatch_t *patch; - patch_t *realpatch; + softwarepatch_t *realpatch; UINT8 *pdata; int x, x1, x2, i, width, height; size_t blocksize; @@ -296,7 +297,7 @@ UINT8 *R_GenerateTexture(size_t texnum) lumpnum = patch->lump; lumplength = W_LumpLengthPwad(wadnum, lumpnum); pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); - realpatch = (patch_t *)pdata; + realpatch = (softwarepatch_t *)pdata; #ifndef NO_PNG_LUMPS if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) @@ -392,17 +393,17 @@ UINT8 *R_GenerateTexture(size_t texnum) lumpnum = patch->lump; pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); lumplength = W_LumpLengthPwad(wadnum, lumpnum); - realpatch = (patch_t *)pdata; + realpatch = (softwarepatch_t *)pdata; dealloc = true; #ifndef NO_PNG_LUMPS if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) - realpatch = (patch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0); + realpatch = (softwarepatch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0); else #endif #ifdef WALLFLATS if (texture->type == TEXTURETYPE_FLAT) - realpatch = (patch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_PATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); + realpatch = (softwarepatch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_DOOMPATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); else #endif { @@ -597,13 +598,13 @@ void *R_GetLevelFlat(levelflat_t *levelflat) { UINT8 *converted; size_t size; - patch_t *patch = W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE); + softwarepatch_t *patch = W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE); levelflat->width = ds_flatwidth = SHORT(patch->width); levelflat->height = ds_flatheight = SHORT(patch->height); levelflat->picture = Z_Malloc(levelflat->width * levelflat->height, PU_LEVEL, NULL); - converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); + converted = Picture_FlatConvert(PICFMT_DOOMPATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); M_Memcpy(levelflat->picture, converted, size); Z_Free(converted); } @@ -839,7 +840,7 @@ Rloadtextures (INT32 i, INT32 w) UINT16 j; UINT16 texstart, texend, texturesLumpPos; texture_t *texture; - patch_t *patchlump; + softwarepatch_t *patchlump; texpatch_t *patch; // Get the lump numbers for the markers in the WAD, if they exist. @@ -1062,7 +1063,7 @@ void R_LoadTextures(void) #ifdef HWRENDER if (rendermode == render_opengl) - HWR_LoadTextures(numtextures); + HWR_LoadMapTextures(numtextures); #endif } diff --git a/src/r_things.c b/src/r_things.c index cc205f9eab51aa97d7030f7262cff0b3c2059cc5..08337392742fe3775f3faa2d1f0a073937736fc6 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -24,9 +24,12 @@ #include "i_video.h" // rendermode #include "i_system.h" #include "r_things.h" +#include "r_patch.h" +#include "r_patchrotation.h" #include "r_picformats.h" #include "r_plane.h" #include "r_portal.h" +#include "r_splats.h" #include "p_tick.h" #include "p_local.h" #include "p_slopes.h" @@ -96,7 +99,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch { char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging - INT32 r, ang; + INT32 r; lumpnum_t lumppat = wad; lumppat <<= 16; lumppat += lump; @@ -104,15 +107,13 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch if (maxframe ==(size_t)-1 || frame > maxframe) maxframe = frame; - // rotsprite #ifdef ROTSPRITE - sprtemp[frame].rotsprite.cached = 0; for (r = 0; r < 16; r++) { - for (ang = 0; ang < ROTANGLES; ang++) - sprtemp[frame].rotsprite.patch[r][ang] = NULL; + sprtemp[frame].rotated[0][r] = NULL; + sprtemp[frame].rotated[1][r] = NULL; } -#endif/*ROTSPRITE*/ +#endif if (rotation == 0) { @@ -228,7 +229,7 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 UINT8 frame; UINT8 rotation; lumpinfo_t *lumpinfo; - patch_t patch; + softwarepatch_t patch; UINT8 numadded = 0; memset(sprtemp,0xFF, sizeof (sprtemp)); @@ -240,9 +241,6 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 // if so, it might patch only certain frames, not all if (spritedef->numframes) // (then spriteframes is not null) { -#ifdef ROTSPRITE - R_FreeSingleRotSprite(spritedef); -#endif // copy the already defined sprite frames M_Memcpy(sprtemp, spritedef->spriteframes, spritedef->numframes * sizeof (spriteframe_t)); @@ -283,7 +281,7 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 #ifndef NO_PNG_LUMPS { - patch_t *png = W_CacheLumpNumPwad(wadnum, l, PU_STATIC); + softwarepatch_t *png = W_CacheLumpNumPwad(wadnum, l, PU_STATIC); size_t len = W_LumpLengthPwad(wadnum, l); if (Picture_IsLumpPNG((UINT8 *)png, len)) @@ -298,11 +296,11 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 if (!isPNG) #endif { - W_ReadLumpHeaderPwad(wadnum, l, &patch, sizeof (patch_t), 0); - width = SHORT(patch.width); - height = SHORT(patch.height); - topoffset = SHORT(patch.topoffset); - leftoffset = SHORT(patch.leftoffset); + W_ReadLumpHeaderPwad(wadnum, l, &patch, sizeof(INT16) * 4, 0); + width = (INT32)(SHORT(patch.width)); + height = (INT32)(SHORT(patch.height)); + topoffset = (INT16)(SHORT(patch.topoffset)); + leftoffset = (INT16)(SHORT(patch.leftoffset)); } spritecachedinfo[numspritelumps].width = width<<FRACBITS; @@ -310,14 +308,8 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 spritecachedinfo[numspritelumps].topoffset = topoffset<<FRACBITS; spritecachedinfo[numspritelumps].height = height<<FRACBITS; - //BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer - if (rendermode != render_none) // not for psprite - spritecachedinfo[numspritelumps].topoffset += FEETADJUST; - // Being selective with this causes bad things. :( Like the special stage tokens breaking apart. - /*if (rendermode != render_none // not for psprite - && SHORT(patch.topoffset)>0 && SHORT(patch.topoffset)<SHORT(patch.height)) - // perfect is patch.height but sometime it is too high - spritecachedinfo[numspritelumps].topoffset = min(SHORT(patch.topoffset)+(FEETADJUST>>FRACBITS),SHORT(patch.height))<<FRACBITS;*/ + // BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer + spritecachedinfo[numspritelumps].topoffset += FEETADJUST; //---------------------------------------------------- @@ -414,9 +406,6 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 if (spritedef->numframes && // has been allocated spritedef->numframes < maxframe) // more frames are defined ? { -#ifdef ROTSPRITE - R_FreeSingleRotSprite(spritedef); -#endif Z_Free(spritedef->spriteframes); spritedef->spriteframes = NULL; } @@ -746,6 +735,55 @@ void R_DrawFlippedMaskedColumn(column_t *column) dc_texturemid = basetexturemid; } +boolean R_SpriteIsFlashing(vissprite_t *vis) +{ + return (!(vis->cut & SC_PRECIP) + && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) + && (vis->mobj->flags2 & MF2_FRET) + && !(vis->mobj->flags & MF_GRENADEBOUNCE) + && (leveltime & 1)); +} + +UINT8 *R_GetSpriteTranslation(vissprite_t *vis) +{ + if (R_SpriteIsFlashing(vis)) // Bosses "flash" + { + if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) + return R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); + else if (vis->mobj->type == MT_METALSONIC_BATTLE) + return R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); + else + return R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE); + } + else if (vis->mobj->color) + { + // New colormap stuff for skins Tails 06-07-2002 + if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) + return R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); + else if (!(vis->cut & SC_PRECIP) + && vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD + && (vis->mobj->player->charflags & SF_DASHMODE) + && ((leveltime/2) & 1)) + { + if (vis->mobj->player->charflags & SF_MACHINE) + return R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE); + else + return R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); + } + else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! + { + size_t skinnum = (skin_t*)vis->mobj->skin-skins; + return R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE); + } + else // Use the defaults + return R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE); + } + else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome. + return R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLUE, GTC_CACHE); + + return NULL; +} + // // R_DrawVisSprite // mfloorclip and mceilingclip should also be set. @@ -779,79 +817,26 @@ static void R_DrawVisSprite(vissprite_t *vis) colfunc = colfuncs[BASEDRAWFUNC]; // hack: this isn't resetting properly somewhere. dc_colormap = vis->colormap; - if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" - { - // translate certain pixels to white - colfunc = colfuncs[COLDRAWFUNC_TRANS]; - if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) - dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); - else if (vis->mobj->type == MT_METALSONIC_BATTLE) - dc_translation = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); - else - dc_translation = R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE); - } + dc_translation = R_GetSpriteTranslation(vis); + + if (R_SpriteIsFlashing(vis)) // Bosses "flash" + colfunc = colfuncs[COLDRAWFUNC_TRANS]; // translate certain pixels to white else if (vis->mobj->color && vis->transmap) // Color mapping { colfunc = colfuncs[COLDRAWFUNC_TRANSTRANS]; dc_transmap = vis->transmap; - if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) - dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); - else if (!(vis->cut & SC_PRECIP) - && vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD - && (vis->mobj->player->charflags & SF_DASHMODE) - && ((leveltime/2) & 1)) - { - if (vis->mobj->player->charflags & SF_MACHINE) - dc_translation = R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE); - else - dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); - } - else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_> - { - size_t skinnum = (skin_t*)vis->mobj->skin-skins; - dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE); - } - else // Use the defaults - dc_translation = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE); } else if (vis->transmap) { colfunc = colfuncs[COLDRAWFUNC_FUZZY]; dc_transmap = vis->transmap; //Fab : 29-04-98: translucency table } - else if (vis->mobj->color) - { - // translate green skin to another color + else if (vis->mobj->color) // translate green skin to another color colfunc = colfuncs[COLDRAWFUNC_TRANS]; - - // New colormap stuff for skins Tails 06-07-2002 - if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) - dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); - else if (!(vis->cut & SC_PRECIP) - && vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD - && (vis->mobj->player->charflags & SF_DASHMODE) - && ((leveltime/2) & 1)) - { - if (vis->mobj->player->charflags & SF_MACHINE) - dc_translation = R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE); - else - dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); - } - else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! - { - size_t skinnum = (skin_t*)vis->mobj->skin-skins; - dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE); - } - else // Use the defaults - dc_translation = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE); - } else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome. - { colfunc = colfuncs[COLDRAWFUNC_TRANS]; - dc_translation = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLUE, GTC_CACHE); - } - if (vis->extra_colormap) + if (vis->extra_colormap && !(vis->renderflags & RF_NOCOLORMAPS)) { if (!dc_colormap) dc_colormap = vis->extra_colormap->colormap; @@ -905,18 +890,21 @@ static void R_DrawVisSprite(vissprite_t *vis) vis->x2 = vid.width-1; localcolfunc = (vis->cut & SC_VFLIP) ? R_DrawFlippedMaskedColumn : R_DrawMaskedColumn; - lengthcol = SHORT(patch->height); + lengthcol = patch->height; // Split drawing loops for paper and non-paper to reduce conditional checks per sprite if (vis->scalestep) { - pwidth = SHORT(patch->width); + fixed_t horzscale = FixedMul(vis->spritexscale, this_scale); + fixed_t scalestep = FixedMul(vis->scalestep, vis->spriteyscale); + + pwidth = patch->width; // Papersprite drawing loop - for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += vis->scalestep) + for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += scalestep) { angle_t angle = ((vis->centerangle + xtoviewangle[dc_x]) >> ANGLETOFINESHIFT) & 0xFFF; - texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / this_scale; + texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / horzscale; if (texturecolumn < 0 || texturecolumn >= pwidth) continue; @@ -927,15 +915,37 @@ static void R_DrawVisSprite(vissprite_t *vis) sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); dc_iscale = (0xffffffffu / (unsigned)spryscale); - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); localcolfunc (column); } } + else if (vis->cut & SC_SHEAR) + { +#ifdef RANGECHECK + pwidth = patch->width; +#endif + + // Vertically sheared sprite + for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale, dc_texturemid -= vis->shear.tan) + { +#ifdef RANGECHECK + texturecolumn = frac>>FRACBITS; + if (texturecolumn < 0 || texturecolumn >= pwidth) + I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); +#else + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS])); +#endif + + sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); + localcolfunc (column); + } + } else { #ifdef RANGECHECK - pwidth = SHORT(patch->width); + pwidth = patch->width; #endif // Non-paper drawing loop @@ -945,9 +955,9 @@ static void R_DrawVisSprite(vissprite_t *vis) texturecolumn = frac>>FRACBITS; if (texturecolumn < 0 || texturecolumn >= pwidth) I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x); - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); #else - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS])); #endif localcolfunc (column); } @@ -1009,12 +1019,12 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) #ifdef RANGECHECK texturecolumn = frac>>FRACBITS; - if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) + if (texturecolumn < 0 || texturecolumn >= patch->width) I_Error("R_DrawPrecipitationSpriteRange: bad texturecolumn"); - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); #else - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS])); #endif R_DrawMaskedColumn(column); } @@ -1068,14 +1078,6 @@ static void R_SplitSprite(vissprite_t *sprite) sprite->sz = cutfrac; newsprite->szt = (INT16)(sprite->sz - 1); - if (testheight < sprite->pzt && testheight > sprite->pz) - sprite->pz = newsprite->pzt = testheight; - else - { - newsprite->pz = newsprite->gz; - newsprite->pzt = newsprite->gzt; - } - newsprite->szt -= 8; newsprite->cut |= SC_TOP; @@ -1226,6 +1228,29 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) #undef CHECKZ } +static void R_SkewShadowSprite( + mobj_t *thing, pslope_t *groundslope, + fixed_t groundz, INT32 spriteheight, fixed_t scalemul, + fixed_t *shadowyscale, fixed_t *shadowskew) +{ + // haha let's try some dumb stuff + fixed_t xslope, zslope; + angle_t sloperelang = (R_PointToAngle(thing->x, thing->y) - groundslope->xydirection) >> ANGLETOFINESHIFT; + + xslope = FixedMul(FINESINE(sloperelang), groundslope->zdelta); + zslope = FixedMul(FINECOSINE(sloperelang), groundslope->zdelta); + + //CONS_Printf("Shadow is sloped by %d %d\n", xslope, zslope); + + if (viewz < groundz) + *shadowyscale += FixedMul(FixedMul(thing->radius*2 / spriteheight, scalemul), zslope); + else + *shadowyscale -= FixedMul(FixedMul(thing->radius*2 / spriteheight, scalemul), zslope); + + *shadowyscale = abs((*shadowyscale)); + *shadowskew = xslope; +} + static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, fixed_t tx, fixed_t tz) { vissprite_t *shadow; @@ -1249,61 +1274,39 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, scalemul = FixedMul(FRACUNIT - floordiff/640, scale); - patch = W_CachePatchName("DSHADOW", PU_CACHE); + patch = W_CachePatchName("DSHADOW", PU_SPRITE); xscale = FixedDiv(projection, tz); yscale = FixedDiv(projectiony, tz); shadowxscale = FixedMul(thing->radius*2, scalemul); shadowyscale = FixedMul(FixedMul(thing->radius*2, scalemul), FixedDiv(abs(groundz - viewz), tz)); - shadowyscale = min(shadowyscale, shadowxscale) / SHORT(patch->height); - shadowxscale /= SHORT(patch->width); + shadowyscale = min(shadowyscale, shadowxscale) / patch->height; + shadowxscale /= patch->width; shadowskew = 0; if (groundslope) - { - // haha let's try some dumb stuff - fixed_t xslope, zslope; - angle_t sloperelang = (R_PointToAngle(thing->x, thing->y) - groundslope->xydirection) >> ANGLETOFINESHIFT; - - xslope = FixedMul(FINESINE(sloperelang), groundslope->zdelta); - zslope = FixedMul(FINECOSINE(sloperelang), groundslope->zdelta); - - //CONS_Printf("Shadow is sloped by %d %d\n", xslope, zslope); - - if (viewz < groundz) - shadowyscale += FixedMul(FixedMul(thing->radius*2 / SHORT(patch->height), scalemul), zslope); - else - shadowyscale -= FixedMul(FixedMul(thing->radius*2 / SHORT(patch->height), scalemul), zslope); + R_SkewShadowSprite(thing, groundslope, groundz, patch->height, scalemul, &shadowyscale, &shadowskew); - shadowyscale = abs(shadowyscale); - - shadowskew = xslope; - } - - tx -= SHORT(patch->width) * shadowxscale/2; + tx -= patch->width * shadowxscale/2; x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; if (x1 >= viewwidth) return; - tx += SHORT(patch->width) * shadowxscale; + tx += patch->width * shadowxscale; x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--; if (x2 < 0 || x2 <= x1) return; - if (shadowyscale < FRACUNIT/SHORT(patch->height)) return; // fix some crashes? + if (shadowyscale < FRACUNIT/patch->height) return; // fix some crashes? shadow = R_NewVisSprite(); shadow->patch = patch; shadow->heightsec = vis->heightsec; - shadow->thingheight = FRACUNIT; - shadow->pz = groundz + (isflipped ? -shadow->thingheight : 0); - shadow->pzt = shadow->pz + shadow->thingheight; - shadow->mobjflags = 0; shadow->sortscale = vis->sortscale; shadow->dispoffset = vis->dispoffset - 5; shadow->gx = thing->x; shadow->gy = thing->y; - shadow->gzt = (isflipped ? shadow->pzt : shadow->pz) + SHORT(patch->height) * shadowyscale / 2; - shadow->gz = shadow->gzt - SHORT(patch->height) * shadowyscale; + shadow->gzt = groundz + patch->height * shadowyscale / 2; + shadow->gz = shadow->gzt - patch->height * shadowyscale; shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale)); if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) shadow->texturemid = FixedMul(shadow->texturemid, ((skin_t *)thing->skin)->highresscale); @@ -1324,7 +1327,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->startfrac = 0; //shadow->xiscale = 0x7ffffff0 / (shadow->xscale/2); - shadow->xiscale = (SHORT(patch->width)<<FRACBITS)/(x2-x1+1); // fuck it + shadow->xiscale = (patch->width<<FRACBITS)/(x2-x1+1); // fuck it if (shadow->x1 > x1) shadow->startfrac += shadow->xiscale*(shadow->x1-x1); @@ -1333,28 +1336,32 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, x1 += (x2-x1)/2; shadow->shear.offset = shadow->x1-x1; - if (thing->subsector->sector->numlights) + if (thing->renderflags & RF_NOCOLORMAPS) + shadow->extra_colormap = NULL; + else { - INT32 lightnum; - light = thing->subsector->sector->numlights - 1; - - // R_GetPlaneLight won't work on sloped lights! - for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { - fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y); - if (h <= shadow->gzt) { - light = lightnum - 1; - break; + if (thing->subsector->sector->numlights) + { + INT32 lightnum; + light = thing->subsector->sector->numlights - 1; + + // R_GetPlaneLight won't work on sloped lights! + for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { + fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y); + if (h <= shadow->gzt) { + light = lightnum - 1; + break; + } } } - //light = R_GetPlaneLight(thing->subsector->sector, shadow->gzt, false); - } - if (thing->subsector->sector->numlights) - shadow->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap; - else - shadow->extra_colormap = thing->subsector->sector->extra_colormap; + if (thing->subsector->sector->numlights) + shadow->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap; + else + shadow->extra_colormap = thing->subsector->sector->extra_colormap; + } - shadow->transmap = transtables + (trans<<FF_TRANSSHIFT); + shadow->transmap = R_GetTranslucencyTable(trans + 1); shadow->colormap = scalelight[0][0]; // full dark! objectsdrawn++; @@ -1370,7 +1377,9 @@ static void R_ProjectSprite(mobj_t *thing) mobj_t *oldthing = thing; fixed_t tr_x, tr_y; fixed_t tx, tz; - fixed_t xscale, yscale, sortscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! + fixed_t xscale, yscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! + fixed_t sortscale, sortsplat = 0; + fixed_t sort_x = 0, sort_y = 0, sort_z; INT32 x1, x2; @@ -1383,13 +1392,15 @@ static void R_ProjectSprite(mobj_t *thing) size_t frame, rot; UINT16 flip; - boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); + boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(thing)); boolean mirrored = thing->mirrored; - boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored); + boolean hflip = (!R_ThingHorizontallyFlipped(thing) != !mirrored); INT32 lindex; + INT32 trans; vissprite_t *vis; + patch_t *patch; spritecut_e cut = SC_NONE; @@ -1398,22 +1409,29 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t scalestep; fixed_t offset, offset2; + fixed_t sheartan = 0; + fixed_t shadowscale = FRACUNIT; fixed_t basetx; // drop shadows - boolean papersprite = !!(thing->frame & FF_PAPERSPRITE); - fixed_t paperoffset = 0, paperdistance = 0; angle_t centerangle = 0; + boolean shadowdraw, shadoweffects, shadowskew; + boolean splat = R_ThingIsFloorSprite(thing); + boolean papersprite = (R_ThingIsPaperSprite(thing) && !splat); + fixed_t paperoffset = 0, paperdistance = 0; + angle_t centerangle = 0; INT32 dispoffset = thing->info->dispoffset; //SoM: 3/17/2000 - fixed_t gz, gzt; + fixed_t gz = 0, gzt = 0; INT32 heightsec, phs; INT32 light = 0; fixed_t this_scale = thing->scale; + fixed_t spritexscale, spriteyscale; // rotsprite fixed_t spr_width, spr_height; fixed_t spr_offset, spr_topoffset; + #ifdef ROTSPRITE patch_t *rotsprite = NULL; INT32 rollangle = 0; @@ -1460,7 +1478,7 @@ static void R_ProjectSprite(mobj_t *thing) thing->frame = states[S_UNKNOWN].frame; sprdef = &sprites[thing->sprite]; #ifdef ROTSPRITE - sprinfo = NULL; + sprinfo = &spriteinfo[thing->sprite]; #endif frame = thing->frame&FF_FRAMEMASK; } @@ -1469,7 +1487,7 @@ static void R_ProjectSprite(mobj_t *thing) { sprdef = &sprites[thing->sprite]; #ifdef ROTSPRITE - sprinfo = NULL; + sprinfo = &spriteinfo[thing->sprite]; #endif if (frame >= sprdef->numframes) @@ -1484,6 +1502,7 @@ static void R_ProjectSprite(mobj_t *thing) thing->sprite = states[S_UNKNOWN].sprite; thing->frame = states[S_UNKNOWN].frame; sprdef = &sprites[thing->sprite]; + sprinfo = &spriteinfo[thing->sprite]; frame = thing->frame&FF_FRAMEMASK; } } @@ -1541,19 +1560,28 @@ static void R_ProjectSprite(mobj_t *thing) spr_offset = spritecachedinfo[lump].offset; spr_topoffset = spritecachedinfo[lump].topoffset; + //Fab: lumppat is the lump number of the patch to use, this is different + // than lumpid for sprites-in-pwad : the graphics are patched + patch = W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE); + #ifdef ROTSPRITE - if (thing->rollangle) + if (thing->rollangle + && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE))) { rollangle = R_GetRollAngle(thing->rollangle); - if (!(sprframe->rotsprite.cached & (1<<rot))) - R_CacheRotSprite(thing->sprite, frame, sprinfo, sprframe, rot, flip); - rotsprite = sprframe->rotsprite.patch[rot][rollangle]; + rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); + if (rotsprite != NULL) { - spr_width = SHORT(rotsprite->width) << FRACBITS; - spr_height = SHORT(rotsprite->height) << FRACBITS; - spr_offset = SHORT(rotsprite->leftoffset) << FRACBITS; - spr_topoffset = SHORT(rotsprite->topoffset) << FRACBITS; + patch = rotsprite; + cut |= SC_ISROTATED; + + spr_width = rotsprite->width << FRACBITS; + spr_height = rotsprite->height << FRACBITS; + spr_offset = rotsprite->leftoffset << FRACBITS; + spr_topoffset = rotsprite->topoffset << FRACBITS; + spr_topoffset += FEETADJUST; + // flip -> rotate, not rotate -> flip flip = 0; } @@ -1563,12 +1591,34 @@ static void R_ProjectSprite(mobj_t *thing) flip = !flip != !hflip; // calculate edges of the shape + spritexscale = thing->spritexscale; + spriteyscale = thing->spriteyscale; + if (spritexscale < 1 || spriteyscale < 1) + return; + + if (thing->renderflags & RF_ABSOLUTEOFFSETS) + { + spr_offset = thing->spritexoffset; + spr_topoffset = thing->spriteyoffset; + } + else + { + SINT8 flipoffset = 1; + + if ((thing->renderflags & RF_FLIPOFFSETS) && flip) + flipoffset = -1; + + spr_offset += thing->spritexoffset * flipoffset; + spr_topoffset += thing->spriteyoffset * flipoffset; + } + if (flip) offset = spr_offset - spr_width; else offset = -spr_offset; - offset = FixedMul(offset, this_scale); - offset2 = FixedMul(spr_width, this_scale); + + offset = FixedMul(offset, FixedMul(spritexscale, this_scale)); + offset2 = FixedMul(spr_width, FixedMul(spritexscale, this_scale)); if (papersprite) { @@ -1675,6 +1725,15 @@ static void R_ProjectSprite(mobj_t *thing) return; } + // Adjust the sort scale if needed + if (splat) + { + sort_z = (patch->height - patch->topoffset) * FRACUNIT; + ang = (viewangle >> ANGLETOFINESHIFT); + sort_x = FixedMul(FixedMul(FixedMul(spritexscale, this_scale), sort_z), FINECOSINE(ang)); + sort_y = FixedMul(FixedMul(FixedMul(spriteyscale, this_scale), sort_z), FINESINE(ang)); + } + if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY) { fixed_t linkscale; @@ -1684,8 +1743,8 @@ static void R_ProjectSprite(mobj_t *thing) if (! R_ThingVisible(thing)) return; - tr_x = thing->x - viewx; - tr_y = thing->y - viewy; + tr_x = (thing->x + sort_x) - viewx; + tr_y = (thing->y + sort_y) - viewy; tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); linkscale = FixedDiv(projectiony, tz); @@ -1696,7 +1755,23 @@ static void R_ProjectSprite(mobj_t *thing) dispoffset *= -1; // if it's physically behind, make sure it's ordered behind (if dispoffset > 0) sortscale = linkscale; // now make sure it's linked - cut = SC_LINKDRAW; + cut |= SC_LINKDRAW; + } + else if (splat) + { + tr_x = (thing->x + sort_x) - viewx; + tr_y = (thing->y + sort_y) - viewy; + sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); + sortscale = FixedDiv(projectiony, sort_z); + } + + // Calculate the splat's sortscale + if (splat) + { + tr_x = (thing->x - sort_x) - viewx; + tr_y = (thing->y - sort_y) - viewy; + sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); + sortsplat = FixedDiv(projectiony, sort_z); } // PORTAL SPRITE CLIPPING @@ -1709,19 +1784,93 @@ static void R_ProjectSprite(mobj_t *thing) return; } - //SoM: 3/17/2000: Disregard sprites that are out of view.. - if (vflip) + // Determine the translucency value. + if (oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility) + trans = tr_trans80; // because now the translucency is set through FF_TRANSMASK + else if (oldthing->frame & FF_TRANSMASK) { - // When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned. - // sprite height - sprite topoffset is the proper inverse of the vertical offset, of course. - // remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes! - gz = oldthing->z + oldthing->height - FixedMul(spr_topoffset, this_scale); - gzt = gz + FixedMul(spr_height, this_scale); + trans = (oldthing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT; + if (oldthing->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) + return; } else + trans = 0; + + // Check if this sprite needs to be rendered like a shadow + shadowdraw = (!!(thing->renderflags & RF_SHADOWDRAW) && !(papersprite || splat)); + shadoweffects = (thing->renderflags & RF_SHADOWEFFECTS); + shadowskew = (shadowdraw && thing->standingslope); + + if (shadowdraw || shadoweffects) { - gzt = oldthing->z + FixedMul(spr_topoffset, this_scale); - gz = gzt - FixedMul(spr_height, this_scale); + fixed_t groundz = R_GetShadowZ(thing, NULL); + boolean isflipped = (thing->eflags & MFE_VERTICALFLIP); + + if (shadoweffects) + { + mobj_t *caster = thing->target; + + if (caster && !P_MobjWasRemoved(caster)) + { + fixed_t floordiff; + + if (abs(groundz-viewz)/tz > 4) + return; // Prevent stretchy shadows and possible crashes + + floordiff = abs((isflipped ? caster->height : 0) + caster->z - groundz); + trans += ((floordiff / (100*FRACUNIT)) + 3); + shadowscale = FixedMul(FRACUNIT - floordiff/640, caster->scale); + } + else + trans += 3; + + if (trans >= NUMTRANSMAPS) + return; + + trans--; + } + + if (shadowdraw) + { + spritexscale = FixedMul(thing->radius * 2, FixedMul(shadowscale, spritexscale)); + spriteyscale = FixedMul(thing->radius * 2, FixedMul(shadowscale, spriteyscale)); + spriteyscale = FixedMul(spriteyscale, FixedDiv(abs(groundz - viewz), tz)); + spriteyscale = min(spriteyscale, spritexscale) / patch->height; + spritexscale /= patch->width; + } + else + { + spritexscale = FixedMul(shadowscale, spritexscale); + spriteyscale = FixedMul(shadowscale, spriteyscale); + } + + if (shadowskew) + { + R_SkewShadowSprite(thing, thing->standingslope, groundz, patch->height, shadowscale, &spriteyscale, &sheartan); + + gzt = (isflipped ? (thing->z + thing->height) : thing->z) + patch->height * spriteyscale / 2; + gz = gzt - patch->height * spriteyscale; + + cut |= SC_SHEAR; + } + } + + if (!shadowskew) + { + //SoM: 3/17/2000: Disregard sprites that are out of view.. + if (vflip) + { + // When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned. + // sprite height - sprite topoffset is the proper inverse of the vertical offset, of course. + // remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes! + gz = oldthing->z + oldthing->height - FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); + gzt = gz + FixedMul(spr_height, FixedMul(spriteyscale, this_scale)); + } + else + { + gzt = oldthing->z + FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); + gz = gzt - FixedMul(spr_height, FixedMul(spriteyscale, this_scale)); + } } if (thing->subsector->sector->cullheight) @@ -1733,12 +1882,13 @@ static void R_ProjectSprite(mobj_t *thing) if (thing->subsector->sector->numlights) { INT32 lightnum; + fixed_t top = (splat) ? gz : gzt; light = thing->subsector->sector->numlights - 1; // R_GetPlaneLight won't work on sloped lights! for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y); - if (h <= gzt) { + if (h <= top) { light = lightnum - 1; break; } @@ -1774,24 +1924,23 @@ static void R_ProjectSprite(mobj_t *thing) // store information in a vissprite vis = R_NewVisSprite(); + vis->renderflags = thing->renderflags; + vis->rotateflags = sprframe->rotate; vis->heightsec = heightsec; //SoM: 3/17/2000 vis->mobjflags = thing->flags; - vis->scale = yscale; //<<detailshift; vis->sortscale = sortscale; + vis->sortsplat = sortsplat; vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15 vis->gx = thing->x; vis->gy = thing->y; vis->gz = gz; vis->gzt = gzt; - vis->thingheight = thing->height; - vis->pz = thing->z; - vis->pzt = vis->pz + vis->thingheight; - vis->texturemid = vis->gzt - viewz; + vis->texturemid = FixedDiv(gzt - viewz, spriteyscale); vis->scalestep = scalestep; vis->paperoffset = paperoffset; vis->paperdistance = paperdistance; vis->centerangle = centerangle; - vis->shear.tan = 0; + vis->shear.tan = sheartan; vis->shear.offset = 0; vis->mobj = thing; // Easy access! Tails 06-07-2002 @@ -1799,17 +1948,34 @@ static void R_ProjectSprite(mobj_t *thing) vis->x1 = x1 < portalclipstart ? portalclipstart : x1; vis->x2 = x2 >= portalclipend ? portalclipend-1 : x2; - vis->xscale = xscale; //SoM: 4/17/2000 vis->sector = thing->subsector->sector; vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS); vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS); vis->cut = cut; + if (thing->subsector->sector->numlights) vis->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap; else vis->extra_colormap = thing->subsector->sector->extra_colormap; - iscale = FixedDiv(FRACUNIT, xscale); + vis->xscale = FixedMul(spritexscale, xscale); //SoM: 4/17/2000 + vis->scale = FixedMul(spriteyscale, yscale); //<<detailshift; + + vis->spritexscale = spritexscale; + vis->spriteyscale = spriteyscale; + vis->spritexoffset = spr_offset; + vis->spriteyoffset = spr_topoffset; + + if (shadowdraw || shadoweffects) + { + iscale = (patch->width<<FRACBITS)/(x2-x1+1); // fuck it + x1 += (x2-x1)/2; // reusing x1 variable + vis->shear.offset = vis->x1-x1; + } + else + iscale = FixedDiv(FRACUNIT, vis->xscale); + + vis->shadowscale = shadowscale; if (flip) { @@ -1824,41 +1990,31 @@ static void R_ProjectSprite(mobj_t *thing) if (vis->x1 > x1) { - vis->startfrac += FixedDiv(vis->xiscale, this_scale)*(vis->x1-x1); - vis->scale += scalestep*(vis->x1 - x1); + vis->startfrac += FixedDiv(vis->xiscale, this_scale) * (vis->x1 - x1); + vis->scale += FixedMul(scalestep, spriteyscale) * (vis->x1 - x1); } - //Fab: lumppat is the lump number of the patch to use, this is different - // than lumpid for sprites-in-pwad : the graphics are patched -#ifdef ROTSPRITE - if (rotsprite != NULL) - vis->patch = rotsprite; + if ((oldthing->blendmode != AST_COPY) && cv_translucency.value) + vis->transmap = R_GetBlendTable(oldthing->blendmode, trans); else -#endif - vis->patch = W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE); - -// -// determine the colormap (lightlevel & special effects) -// - vis->transmap = NULL; - - // specific translucency - if (!cv_translucency.value) - ; // no translucency - else if (oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility) - vis->transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT); // because now the translucency is set through FF_TRANSMASK - else if (oldthing->frame & FF_TRANSMASK) - vis->transmap = transtables + (oldthing->frame & FF_TRANSMASK) - 0x10000; + vis->transmap = NULL; - if (oldthing->frame & FF_FULLBRIGHT || oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) + if (R_ThingIsFullBright(oldthing) || oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) vis->cut |= SC_FULLBRIGHT; + else if (R_ThingIsFullDark(oldthing)) + vis->cut |= SC_FULLDARK; + // + // determine the colormap (lightlevel & special effects) + // if (vis->cut & SC_FULLBRIGHT && (!vis->extra_colormap || !(vis->extra_colormap->flags & CMF_FADEFULLBRIGHTSPRITES))) { // full bright: goggles vis->colormap = colormaps; } + else if (vis->cut & SC_FULLDARK) + vis->colormap = scalelight[0][0]; else { // diminished light @@ -1872,8 +2028,12 @@ static void R_ProjectSprite(mobj_t *thing) if (vflip) vis->cut |= SC_VFLIP; + if (splat) + vis->cut |= SC_SPLAT; // I like ya cut g - if (thing->subsector->sector->numlights) + vis->patch = patch; + + if (thing->subsector->sector->numlights && !(shadowdraw || splat)) R_SplitSprite(vis); if (oldthing->shadowscale && cv_shadow.value) @@ -1991,9 +2151,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->gy = thing->y; vis->gz = gz; vis->gzt = gzt; - vis->thingheight = 4*FRACUNIT; - vis->pz = thing->z; - vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; vis->scalestep = 0; vis->paperdistance = 0; @@ -2018,7 +2175,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) //Fab: lumppat is the lump number of the patch to use, this is different // than lumpid for sprites-in-pwad : the graphics are patched - vis->patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + vis->patch = W_CachePatchNum(sprframe->lumppat[0], PU_SPRITE); // specific translucency if (thing->frame & FF_TRANSMASK) @@ -2387,19 +2544,15 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy, r2->plane->height); planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy, r2->plane->height); - if (rover->mobjflags & MF_NOCLIPHEIGHT) + // bird: if any part of the sprite peeks in front the plane + if (planecameraz < viewz) { - //Objects with NOCLIPHEIGHT can appear halfway in. - if (planecameraz < viewz && rover->pz+(rover->thingheight/2) >= planeobjectz) - continue; - if (planecameraz > viewz && rover->pzt-(rover->thingheight/2) <= planeobjectz) + if (rover->gzt >= planeobjectz) continue; } - else + else if (planecameraz > viewz) { - if (planecameraz < viewz && rover->pz >= planeobjectz) - continue; - if (planecameraz > viewz && rover->pzt <= planeobjectz) + if (rover->gz <= planeobjectz) continue; } @@ -2432,7 +2585,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps } else if (r2->thickseg) { - fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz; + //fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz; if (rover->x1 > r2->thickseg->x2 || rover->x2 < r2->thickseg->x1) continue; @@ -2443,6 +2596,11 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps if (scale <= rover->sortscale) continue; + // bird: Always sort sprites behind segs. This helps the plane + // sorting above too. Basically if the sprite gets sorted behind + // the seg here, it will be behind the plane too, since planes + // are added after segs in the list. +#if 0 topplaneobjectz = P_GetFFloorTopZAt (r2->ffloor, rover->gx, rover->gy); topplanecameraz = P_GetFFloorTopZAt (r2->ffloor, viewx, viewy); botplaneobjectz = P_GetFFloorBottomZAt(r2->ffloor, rover->gx, rover->gy); @@ -2451,6 +2609,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps if ((topplanecameraz > viewz && botplanecameraz < viewz) || (topplanecameraz < viewz && rover->gzt < topplaneobjectz) || (botplanecameraz > viewz && rover->gz > botplaneobjectz)) +#endif { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; @@ -2480,13 +2639,33 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps } else if (r2->sprite) { - if (r2->sprite->x1 > rover->x2 || r2->sprite->x2 < rover->x1) - continue; - if (r2->sprite->szt > rover->sz || r2->sprite->sz < rover->szt) - continue; + boolean infront = (r2->sprite->sortscale > rover->sortscale + || (r2->sprite->sortscale == rover->sortscale && r2->sprite->dispoffset > rover->dispoffset)); + + if (rover->cut & SC_SPLAT || r2->sprite->cut & SC_SPLAT) + { + fixed_t scale1 = (rover->cut & SC_SPLAT ? rover->sortsplat : rover->sortscale); + fixed_t scale2 = (r2->sprite->cut & SC_SPLAT ? r2->sprite->sortsplat : r2->sprite->sortscale); + boolean behind = (scale2 > scale1 || (scale2 == scale1 && r2->sprite->dispoffset > rover->dispoffset)); - if (r2->sprite->sortscale > rover->sortscale - || (r2->sprite->sortscale == rover->sortscale && r2->sprite->dispoffset > rover->dispoffset)) + if (!behind) + { + // FIXME: calculate gz and gzt for splats properly and use that + if (rover->mobj->z < viewz) + infront = (r2->sprite->mobj->z >= rover->mobj->z); + else + infront = (r2->sprite->mobj->z <= rover->mobj->z); + } + } + else + { + if (r2->sprite->x1 > rover->x2 || r2->sprite->x2 < rover->x1) + continue; + if (r2->sprite->szt > rover->sz || r2->sprite->sz < rover->szt) + continue; + } + + if (infront) { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; @@ -2572,7 +2751,11 @@ static void R_DrawSprite(vissprite_t *spr) { mfloorclip = spr->clipbot; mceilingclip = spr->cliptop; - R_DrawVisSprite(spr); + + if (spr->cut & SC_SPLAT) + R_DrawFloorSprite(spr); + else + R_DrawVisSprite(spr); } // Special drawer for precipitation sprites Tails 08-18-2002 @@ -2583,207 +2766,212 @@ static void R_DrawPrecipitationSprite(vissprite_t *spr) R_DrawPrecipitationVisSprite(spr); } -// R_ClipSprites +// R_ClipVisSprite // Clips vissprites without drawing, so that portals can work. -Red -void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) +void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal) { - vissprite_t *spr; - for (; clippedvissprites < visspritecount; clippedvissprites++) - { - drawseg_t *ds; - INT32 x; - INT32 r1; - INT32 r2; - fixed_t scale; - fixed_t lowscale; - INT32 silhouette; - - spr = R_GetVisSprite(clippedvissprites); - - for (x = spr->x1; x <= spr->x2; x++) - spr->clipbot[x] = spr->cliptop[x] = -2; - - // Scan drawsegs from end to start for obscuring segs. - // The first drawseg that has a greater scale - // is the clip seg. - //SoM: 4/8/2000: - // Pointer check was originally nonportable - // and buggy, by going past LEFT end of array: + drawseg_t *ds; + INT32 x; + INT32 r1; + INT32 r2; + fixed_t scale; + fixed_t lowscale; + INT32 silhouette; + + for (x = x1; x <= x2; x++) + spr->clipbot[x] = spr->cliptop[x] = -2; + + // Scan drawsegs from end to start for obscuring segs. + // The first drawseg that has a greater scale + // is the clip seg. + //SoM: 4/8/2000: + // Pointer check was originally nonportable + // and buggy, by going past LEFT end of array: + + // for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code + for (ds = ds_p; ds-- > dsstart;) + { + // determine if the drawseg obscures the sprite + if (ds->x1 > x2 || + ds->x2 < x1 || + (!ds->silhouette + && !ds->maskedtexturecol)) + { + // does not cover sprite + continue; + } - // for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code - for (ds = ds_p; ds-- > dsstart;) + if (ds->portalpass != 66) { - // determine if the drawseg obscures the sprite - if (ds->x1 > spr->x2 || - ds->x2 < spr->x1 || - (!ds->silhouette - && !ds->maskedtexturecol)) + if (ds->portalpass > 0 && ds->portalpass <= portalrender) + continue; // is a portal + + if (ds->scale1 > ds->scale2) { - // does not cover sprite - continue; + lowscale = ds->scale2; + scale = ds->scale1; } - - if (ds->portalpass != 66) + else { - if (ds->portalpass > 0 && ds->portalpass <= portalrender) - continue; // is a portal - - if (ds->scale1 > ds->scale2) - { - lowscale = ds->scale2; - scale = ds->scale1; - } - else - { - lowscale = ds->scale1; - scale = ds->scale2; - } + lowscale = ds->scale1; + scale = ds->scale2; + } - if (scale < spr->sortscale || - (lowscale < spr->sortscale && - !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) - { - // masked mid texture? - /*if (ds->maskedtexturecol) - R_RenderMaskedSegRange (ds, r1, r2);*/ - // seg is behind sprite - continue; - } + if (scale < spr->sortscale || + (lowscale < spr->sortscale && + !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) + { + // masked mid texture? + /*if (ds->maskedtexturecol) + R_RenderMaskedSegRange (ds, r1, r2);*/ + // seg is behind sprite + continue; } + } - r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; - r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; + r1 = ds->x1 < x1 ? x1 : ds->x1; + r2 = ds->x2 > x2 ? x2 : ds->x2; - // clip this piece of the sprite - silhouette = ds->silhouette; + // clip this piece of the sprite + silhouette = ds->silhouette; - if (spr->gz >= ds->bsilheight) - silhouette &= ~SIL_BOTTOM; + if (spr->gz >= ds->bsilheight) + silhouette &= ~SIL_BOTTOM; - if (spr->gzt <= ds->tsilheight) - silhouette &= ~SIL_TOP; + if (spr->gzt <= ds->tsilheight) + silhouette &= ~SIL_TOP; - if (silhouette == SIL_BOTTOM) + if (silhouette == SIL_BOTTOM) + { + // bottom sil + for (x = r1; x <= r2; x++) + if (spr->clipbot[x] == -2) + spr->clipbot[x] = ds->sprbottomclip[x]; + } + else if (silhouette == SIL_TOP) + { + // top sil + for (x = r1; x <= r2; x++) + if (spr->cliptop[x] == -2) + spr->cliptop[x] = ds->sprtopclip[x]; + } + else if (silhouette == (SIL_TOP|SIL_BOTTOM)) + { + // both + for (x = r1; x <= r2; x++) { - // bottom sil - for (x = r1; x <= r2; x++) - if (spr->clipbot[x] == -2) - spr->clipbot[x] = ds->sprbottomclip[x]; + if (spr->clipbot[x] == -2) + spr->clipbot[x] = ds->sprbottomclip[x]; + if (spr->cliptop[x] == -2) + spr->cliptop[x] = ds->sprtopclip[x]; } - else if (silhouette == SIL_TOP) - { - // top sil - for (x = r1; x <= r2; x++) - if (spr->cliptop[x] == -2) - spr->cliptop[x] = ds->sprtopclip[x]; + } + } + //SoM: 3/17/2000: Clip sprites in water. + if (spr->heightsec != -1) // only things in specially marked sectors + { + fixed_t mh, h; + INT32 phs = viewplayer->mo->subsector->sector->heightsec; + if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && + (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 && + (h >>= FRACBITS) < viewheight) + { + if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) + { // clip bottom + for (x = x1; x <= x2; x++) + if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) + spr->clipbot[x] = (INT16)h; } - else if (silhouette == (SIL_TOP|SIL_BOTTOM)) + else // clip top { - // both - for (x = r1; x <= r2; x++) - { - if (spr->clipbot[x] == -2) - spr->clipbot[x] = ds->sprbottomclip[x]; - if (spr->cliptop[x] == -2) - spr->cliptop[x] = ds->sprtopclip[x]; - } + for (x = x1; x <= x2; x++) + if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) + spr->cliptop[x] = (INT16)h; } } - //SoM: 3/17/2000: Clip sprites in water. - if (spr->heightsec != -1) // only things in specially marked sectors + + if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && + (h = centeryfrac - FixedMul(mh-viewz, spr->sortscale)) >= 0 && + (h >>= FRACBITS) < viewheight) { - fixed_t mh, h; - INT32 phs = viewplayer->mo->subsector->sector->heightsec; - if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && - (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 && - (h >>= FRACBITS) < viewheight) - { - if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) - { // clip bottom - for (x = spr->x1; x <= spr->x2; x++) - if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) - spr->clipbot[x] = (INT16)h; - } - else // clip top - { - for (x = spr->x1; x <= spr->x2; x++) - if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) - spr->cliptop[x] = (INT16)h; - } + if (phs != -1 && viewz >= sectors[phs].ceilingheight) + { // clip bottom + for (x = x1; x <= x2; x++) + if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) + spr->clipbot[x] = (INT16)h; } - - if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && - (h = centeryfrac - FixedMul(mh-viewz, spr->sortscale)) >= 0 && - (h >>= FRACBITS) < viewheight) + else // clip top { - if (phs != -1 && viewz >= sectors[phs].ceilingheight) - { // clip bottom - for (x = spr->x1; x <= spr->x2; x++) - if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) - spr->clipbot[x] = (INT16)h; - } - else // clip top - { - for (x = spr->x1; x <= spr->x2; x++) - if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) - spr->cliptop[x] = (INT16)h; - } + for (x = x1; x <= x2; x++) + if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) + spr->cliptop[x] = (INT16)h; } } - if (spr->cut & SC_TOP && spr->cut & SC_BOTTOM) + } + if (spr->cut & SC_TOP && spr->cut & SC_BOTTOM) + { + for (x = x1; x <= x2; x++) { - for (x = spr->x1; x <= spr->x2; x++) - { - if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) - spr->cliptop[x] = spr->szt; + if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) + spr->cliptop[x] = spr->szt; - if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) - spr->clipbot[x] = spr->sz; - } + if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) + spr->clipbot[x] = spr->sz; } - else if (spr->cut & SC_TOP) + } + else if (spr->cut & SC_TOP) + { + for (x = x1; x <= x2; x++) { - for (x = spr->x1; x <= spr->x2; x++) - { - if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) - spr->cliptop[x] = spr->szt; - } + if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) + spr->cliptop[x] = spr->szt; } - else if (spr->cut & SC_BOTTOM) + } + else if (spr->cut & SC_BOTTOM) + { + for (x = x1; x <= x2; x++) { - for (x = spr->x1; x <= spr->x2; x++) - { - if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) - spr->clipbot[x] = spr->sz; - } + if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) + spr->clipbot[x] = spr->sz; } + } - // all clipping has been performed, so store the values - what, did you think we were drawing them NOW? + // all clipping has been performed, so store the values - what, did you think we were drawing them NOW? - // check for unclipped columns - for (x = spr->x1; x <= spr->x2; x++) - { - if (spr->clipbot[x] == -2) - spr->clipbot[x] = (INT16)viewheight; + // check for unclipped columns + for (x = x1; x <= x2; x++) + { + if (spr->clipbot[x] == -2) + spr->clipbot[x] = (INT16)viewheight; - if (spr->cliptop[x] == -2) - //Fab : 26-04-98: was -1, now clips against console bottom - spr->cliptop[x] = (INT16)con_clipviewtop; - } + if (spr->cliptop[x] == -2) + //Fab : 26-04-98: was -1, now clips against console bottom + spr->cliptop[x] = (INT16)con_clipviewtop; + } - if (portal) + if (portal) + { + for (x = x1; x <= x2; x++) { - for (x = spr->x1; x <= spr->x2; x++) - { - if (spr->clipbot[x] > portal->floorclip[x - portal->start]) - spr->clipbot[x] = portal->floorclip[x - portal->start]; - if (spr->cliptop[x] < portal->ceilingclip[x - portal->start]) - spr->cliptop[x] = portal->ceilingclip[x - portal->start]; - } + if (spr->clipbot[x] > portal->floorclip[x - portal->start]) + spr->clipbot[x] = portal->floorclip[x - portal->start]; + if (spr->cliptop[x] < portal->ceilingclip[x - portal->start]) + spr->cliptop[x] = portal->ceilingclip[x - portal->start]; } } } +void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) +{ + for (; clippedvissprites < visspritecount; clippedvissprites++) + { + vissprite_t *spr = R_GetVisSprite(clippedvissprites); + INT32 x1 = (spr->cut & SC_SPLAT) ? 0 : spr->x1; + INT32 x2 = (spr->cut & SC_SPLAT) ? viewwidth : spr->x2; + R_ClipVisSprite(spr, x1, x2, dsstart, portal); + } +} + /* Check if thing may be drawn from our current view. */ boolean R_ThingVisible (mobj_t *thing) { @@ -2833,6 +3021,36 @@ boolean R_PrecipThingVisible (precipmobj_t *precipthing, return ( approx_dist <= limit_dist ); } +boolean R_ThingHorizontallyFlipped(mobj_t *thing) +{ + return (thing->frame & FF_HORIZONTALFLIP || thing->renderflags & RF_HORIZONTALFLIP); +} + +boolean R_ThingVerticallyFlipped(mobj_t *thing) +{ + return (thing->frame & FF_VERTICALFLIP || thing->renderflags & RF_VERTICALFLIP); +} + +boolean R_ThingIsPaperSprite(mobj_t *thing) +{ + return (thing->frame & FF_PAPERSPRITE || thing->renderflags & RF_PAPERSPRITE); +} + +boolean R_ThingIsFloorSprite(mobj_t *thing) +{ + return (thing->flags2 & MF2_SPLAT || thing->renderflags & RF_FLOORSPRITE); +} + +boolean R_ThingIsFullBright(mobj_t *thing) +{ + return (thing->frame & FF_FULLBRIGHT || thing->renderflags & RF_FULLBRIGHT); +} + +boolean R_ThingIsFullDark(mobj_t *thing) +{ + return (thing->renderflags & RF_FULLDARK); +} + // // R_DrawMasked // diff --git a/src/r_things.h b/src/r_things.h index b13c5dc55ccc208c52c01a04376af98c11eda375..d15ae818c4c273dee396fe9c6b7919a95c87b98b 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -15,6 +15,7 @@ #define __R_THINGS__ #include "r_plane.h" +#include "r_patch.h" #include "r_picformats.h" #include "r_portal.h" #include "r_defs.h" @@ -64,7 +65,6 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope); void R_AddSprites(sector_t *sec, INT32 lightlevel); void R_InitSprites(void); void R_ClearSprites(void); -void R_ClipSprites(drawseg_t* dsstart, portal_t* portal); boolean R_ThingVisible (mobj_t *thing); @@ -75,6 +75,15 @@ boolean R_ThingVisibleWithinDist (mobj_t *thing, boolean R_PrecipThingVisible (precipmobj_t *precipthing, fixed_t precip_draw_dist); +boolean R_ThingHorizontallyFlipped (mobj_t *thing); +boolean R_ThingVerticallyFlipped (mobj_t *thing); + +boolean R_ThingIsPaperSprite (mobj_t *thing); +boolean R_ThingIsFloorSprite (mobj_t *thing); + +boolean R_ThingIsFullBright (mobj_t *thing); +boolean R_ThingIsFullDark (mobj_t *thing); + // -------------- // MASKED DRAWING // -------------- @@ -107,19 +116,23 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks); typedef enum { // actual cuts - SC_NONE = 0, - SC_TOP = 1, - SC_BOTTOM = 1<<1, + SC_NONE = 0, + SC_TOP = 1, + SC_BOTTOM = 1<<1, // other flags - SC_PRECIP = 1<<2, - SC_LINKDRAW = 1<<3, + SC_PRECIP = 1<<2, + SC_LINKDRAW = 1<<3, SC_FULLBRIGHT = 1<<4, - SC_VFLIP = 1<<5, - SC_ISSCALED = 1<<6, - SC_SHADOW = 1<<7, + SC_FULLDARK = 1<<5, + SC_VFLIP = 1<<6, + SC_ISSCALED = 1<<7, + SC_ISROTATED = 1<<8, + SC_SHADOW = 1<<9, + SC_SHEAR = 1<<10, + SC_SPLAT = 1<<11, // masks - SC_CUTMASK = SC_TOP|SC_BOTTOM, - SC_FLAGMASK = ~SC_CUTMASK + SC_CUTMASK = SC_TOP|SC_BOTTOM, + SC_FLAGMASK = ~SC_CUTMASK } spritecut_e; // A vissprite_t is a thing that will be drawn during a refresh, @@ -138,11 +151,12 @@ typedef struct vissprite_s INT32 x1, x2; fixed_t gx, gy; // for line side calculation - fixed_t gz, gzt; // global bottom/top for silhouette clipping - fixed_t pz, pzt; // physical bottom/top for sorting with 3D floors + fixed_t gz, gzt; // global bottom/top for silhouette clipping and sorting with 3D floors fixed_t startfrac; // horizontal position of x1 - fixed_t scale, sortscale; // sortscale only differs from scale for paper sprites and MF2_LINKDRAW + fixed_t scale; + fixed_t sortscale; // sortscale only differs from scale for paper sprites, floor sprites, and MF2_LINKDRAW + fixed_t sortsplat; // the sortscale from behind the floor sprite fixed_t scalestep; // only for paper sprites, 0 otherwise fixed_t paperoffset, paperdistance; // for paper sprites, offset/dist relative to the angle fixed_t xiscale; // negative if flipped @@ -171,11 +185,17 @@ typedef struct vissprite_s fixed_t xscale; // Precalculated top and bottom screen coords for the sprite. - fixed_t thingheight; // The actual height of the thing (for 3D floors) sector_t *sector; // The sector containing the thing. INT16 sz, szt; spritecut_e cut; + UINT32 renderflags; + UINT8 rotateflags; + + fixed_t spritexscale, spriteyscale; + fixed_t spritexoffset, spriteyoffset; + + fixed_t shadowscale; INT16 clipbot[MAXVIDWIDTH], cliptop[MAXVIDWIDTH]; @@ -184,6 +204,12 @@ typedef struct vissprite_s extern UINT32 visspritecount; +void R_ClipSprites(drawseg_t* dsstart, portal_t* portal); +void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal); + +boolean R_SpriteIsFlashing(vissprite_t *vis); +UINT8 *R_GetSpriteTranslation(vissprite_t *vis); + // ---------- // DRAW NODES // ---------- diff --git a/src/s_sound.c b/src/s_sound.c index 793794aa7c70bcabbcd02e7fade906e108e39bb1..36bd454c104b02867c29d3f16f22f639ed06dc97 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -29,10 +29,7 @@ #include "fastcmp.h" #include "m_misc.h" // for tunes command #include "m_cond.h" // for conditionsets - -#ifdef HAVE_LUA_MUSICPLUS #include "lua_hook.h" // MusicChange hook -#endif #ifdef HW3SOUND // 3D Sound Interface @@ -2272,10 +2269,8 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 return; strncpy(newmusic, mmusic, 7); -#ifdef HAVE_LUA_MUSICPLUS - if(LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms)) + if (LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms)) return; -#endif newmusic[6] = 0; // No Music (empty string) diff --git a/src/screen.c b/src/screen.c index 048480fb27d8d6a54024cac0ff5664f72862e711..9d36eee39cb1da8c2ce14e5fc1392344a9dbefc9 100644 --- a/src/screen.c +++ b/src/screen.c @@ -28,6 +28,7 @@ #include "d_main.h" #include "d_clisrv.h" #include "f_finale.h" +#include "y_inter.h" // usebuffer #include "i_sound.h" // closed captions #include "s_sound.h" // ditto #include "g_game.h" // ditto @@ -63,14 +64,14 @@ consvar_t cv_scr_height = CVAR_INIT ("scr_height", "800", CV_SAVE, CV_Unsigned, consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL); consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL); -static void SCR_ActuallyChangeRenderer(void); -static CV_PossibleValue_t cv_renderer_t[] = { +CV_PossibleValue_t cv_renderer_t[] = { {1, "Software"}, #ifdef HWRENDER {2, "OpenGL"}, #endif {0, NULL} }; + consvar_t cv_renderer = CVAR_INIT ("renderer", "Software", CV_SAVE|CV_NOLUA|CV_CALL, cv_renderer_t, SCR_ChangeRenderer); static void SCR_ChangeFullscreen(void); @@ -121,34 +122,34 @@ void SCR_SetDrawFuncs(void) colfuncs[COLDRAWFUNC_FOG] = R_DrawFogColumn_8; spanfuncs[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_8; + spanfuncs[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_8; + spanfuncs[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_8; spanfuncs[SPANDRAWFUNC_SPLAT] = R_DrawSplat_8; spanfuncs[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_8; - spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8; -#ifndef NOWATER + spanfuncs[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_8; + spanfuncs[SPANDRAWFUNC_SPRITE] = R_DrawFloorSprite_8; + spanfuncs[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_8; + spanfuncs[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_8; + spanfuncs[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_8; spanfuncs[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_8; -#endif - spanfuncs[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_8; - spanfuncs[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_8; -#ifndef NOWATER spanfuncs[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_8; -#endif - spanfuncs[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_8; + spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8; // Lactozilla: Non-powers-of-two spanfuncs_npo2[BASEDRAWFUNC] = R_DrawSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_SPLAT] = R_DrawSplat_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_NPO2_8; - spanfuncs_npo2[SPANDRAWFUNC_FOG] = NULL; // Not needed -#ifndef NOWATER + spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_SPRITE] = R_DrawFloorSprite_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_NPO2_8; -#endif - spanfuncs_npo2[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_NPO2_8; - spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_NPO2_8; -#ifndef NOWATER spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_NPO2_8; -#endif - spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_FOG] = NULL; // Not needed #ifdef RUSEASM if (R_ASM) @@ -202,14 +203,19 @@ void SCR_SetMode(void) // Lactozilla: Renderer switching if (setrenderneeded) { - Z_PreparePatchFlush(); - needpatchflush = true; - needpatchrecache = true; - VID_CheckRenderer(); + // stop recording movies (APNG only) + if (setrenderneeded && (moviemode == MM_APNG)) + M_StopMovie(); + + // VID_SetMode will call VID_CheckRenderer itself, + // so no need to do this in here. if (!setmodeneeded) - VID_SetMode(vid.modenum); + VID_CheckRenderer(); + + vid.recalc = 1; } + // Set the video mode in the video interface. if (setmodeneeded) VID_SetMode(--setmodeneeded); @@ -279,34 +285,9 @@ void SCR_Startup(void) vid.modenum = 0; - vid.dupx = vid.width / BASEVIDWIDTH; - vid.dupy = vid.height / BASEVIDHEIGHT; - vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT); - vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT); - -#ifdef HWRENDER - if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions in opengl -#endif - vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); - - vid.meddupx = (UINT8)(vid.dupx >> 1) + 1; - vid.meddupy = (UINT8)(vid.dupy >> 1) + 1; -#ifdef HWRENDER - vid.fmeddupx = vid.meddupx*FRACUNIT; - vid.fmeddupy = vid.meddupy*FRACUNIT; -#endif - - vid.smalldupx = (UINT8)(vid.dupx / 3) + 1; - vid.smalldupy = (UINT8)(vid.dupy / 3) + 1; -#ifdef HWRENDER - vid.fsmalldupx = vid.smalldupx*FRACUNIT; - vid.fsmalldupy = vid.smalldupy*FRACUNIT; -#endif - - vid.baseratio = FRACUNIT; - V_Init(); + V_Recalc(); + CV_RegisterVar(&cv_ticrate); CV_RegisterVar(&cv_constextsize); @@ -323,38 +304,7 @@ void SCR_Recalc(void) // bytes per pixel quick access scr_bpp = vid.bpp; - // scale 1,2,3 times in x and y the patches for the menus and overlays... - // calculated once and for all, used by routines in v_video.c - vid.dupx = vid.width / BASEVIDWIDTH; - vid.dupy = vid.height / BASEVIDHEIGHT; - vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT); - vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT); - -#ifdef HWRENDER - //if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions in opengl - // 13/11/18: - // The above is no longer necessary, since we want OpenGL to be just like software now - // -- Monster Iestyn -#endif - vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); - - //vid.baseratio = FixedDiv(vid.height << FRACBITS, BASEVIDHEIGHT << FRACBITS); - vid.baseratio = FRACUNIT; - - vid.meddupx = (UINT8)(vid.dupx >> 1) + 1; - vid.meddupy = (UINT8)(vid.dupy >> 1) + 1; -#ifdef HWRENDER - vid.fmeddupx = vid.meddupx*FRACUNIT; - vid.fmeddupy = vid.meddupy*FRACUNIT; -#endif - - vid.smalldupx = (UINT8)(vid.dupx / 3) + 1; - vid.smalldupy = (UINT8)(vid.dupy / 3) + 1; -#ifdef HWRENDER - vid.fsmalldupx = vid.smalldupx*FRACUNIT; - vid.fsmalldupy = vid.smalldupy*FRACUNIT; -#endif + V_Recalc(); // toggle off (then back on) the automap because some screensize-dependent values will // be calculated next time the automap is activated. @@ -374,6 +324,12 @@ void SCR_Recalc(void) // vid.recalc lasts only for the next refresh... con_recalc = true; am_recalc = true; + +#ifdef HWRENDER + // Shoot! The screen texture was flushed! + if ((rendermode == render_opengl) && (gamestate == GS_INTERMISSION)) + usebuffer = false; +#endif } // Check for screen cmd-line parms: to force a resolution. @@ -411,7 +367,16 @@ void SCR_CheckDefaultMode(void) setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1; } - SCR_ActuallyChangeRenderer(); + if (cv_renderer.value != (signed)rendermode) + { + if (chosenrendermode == render_none) // nothing set at command line + SCR_ChangeRenderer(); + else + { + // Set cv_renderer to the current render mode + CV_StealthSetValue(&cv_renderer, rendermode); + } + } } // sets the modenum as the new default video mode to be saved in the config file @@ -441,64 +406,27 @@ void SCR_ChangeFullscreen(void) #endif } -static int target_renderer = 0; - -void SCR_ActuallyChangeRenderer(void) +void SCR_ChangeRenderer(void) { - setrenderneeded = target_renderer; + if (chosenrendermode != render_none + || (signed)rendermode == cv_renderer.value) + return; #ifdef HWRENDER - // Well, it didn't even load anyway. - if ((vid_opengl_state == -1) && (setrenderneeded == render_opengl)) + // Check if OpenGL loaded successfully (or wasn't disabled) before switching to it. + if ((vid.glstate == VID_GL_LIBRARY_ERROR) + && (cv_renderer.value == render_opengl)) { if (M_CheckParm("-nogl")) CONS_Alert(CONS_ERROR, "OpenGL rendering was disabled!\n"); else CONS_Alert(CONS_ERROR, "OpenGL never loaded\n"); - setrenderneeded = 0; return; } #endif - // 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") && (vid_opengl_state == 1)) - 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); + // Set the new render mode + setrenderneeded = cv_renderer.value; } boolean SCR_IsAspectCorrect(INT32 width, INT32 height) diff --git a/src/screen.h b/src/screen.h index 2cb2cf839160ab6e73e1544d6f7f6869ac4bdbb9..e4944775d952249c785c14262960daa8f58bc796 100644 --- a/src/screen.h +++ b/src/screen.h @@ -72,10 +72,16 @@ typedef struct viddef_s #ifdef HWRENDER INT32/*fixed_t*/ fsmalldupx, fsmalldupy; INT32/*fixed_t*/ fmeddupx, fmeddupy; + INT32 glstate; #endif } viddef_t; -#define VIDWIDTH vid.width -#define VIDHEIGHT vid.height + +enum +{ + VID_GL_LIBRARY_NOTLOADED = 0, + VID_GL_LIBRARY_LOADED = 1, + VID_GL_LIBRARY_ERROR = -1, +}; // internal additional info for vesa modes only typedef struct @@ -134,18 +140,22 @@ enum { SPANDRAWFUNC_BASE = BASEDRAWFUNC, SPANDRAWFUNC_TRANS, - SPANDRAWFUNC_SPLAT, - SPANDRAWFUNC_TRANSSPLAT, - SPANDRAWFUNC_FOG, -#ifndef NOWATER - SPANDRAWFUNC_WATER, -#endif SPANDRAWFUNC_TILTED, SPANDRAWFUNC_TILTEDTRANS, + + SPANDRAWFUNC_SPLAT, + SPANDRAWFUNC_TRANSSPLAT, SPANDRAWFUNC_TILTEDSPLAT, -#ifndef NOWATER + + SPANDRAWFUNC_SPRITE, + SPANDRAWFUNC_TRANSSPRITE, + SPANDRAWFUNC_TILTEDSPRITE, + SPANDRAWFUNC_TILTEDTRANSSPRITE, + + SPANDRAWFUNC_WATER, SPANDRAWFUNC_TILTEDWATER, -#endif + + SPANDRAWFUNC_FOG, SPANDRAWFUNC_MAX }; @@ -170,10 +180,11 @@ extern boolean R_SSE2; // ---------------- extern viddef_t vid; extern INT32 setmodeneeded; // mode number to set if needed, or 0 +extern UINT8 setrenderneeded; void SCR_ChangeRenderer(void); -void SCR_ChangeRendererCVars(INT32 mode); -extern UINT8 setrenderneeded; + +extern CV_PossibleValue_t cv_renderer_t[]; extern INT32 scr_bpp; extern UINT8 *scr_borderpatch; // patch used to fill the view borders @@ -182,17 +193,23 @@ extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_re // wait for page flipping to end or not extern consvar_t cv_vidwait; +// Initialize the screen +void SCR_Startup(void); + // Change video mode, only at the start of a refresh. void SCR_SetMode(void); + +// Set drawer functions for Software void SCR_SetDrawFuncs(void); + // Recalc screen size dependent stuff void SCR_Recalc(void); + // Check parms once at startup void SCR_CheckDefaultMode(void); -// Set the mode number which is saved in the config -void SCR_SetDefaultMode (void); -void SCR_Startup (void); +// Set the mode number which is saved in the config +void SCR_SetDefaultMode(void); FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height); diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index c2d6456e462bbf67bca399703e5b30b63d773d0a..d46a4af2b0d89ea1dc93b0573e4ef1d6a32665b4 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -196,6 +196,9 @@ <ClInclude Include="..\comptime.h" /> <ClInclude Include="..\console.h" /> <ClInclude Include="..\dehacked.h" /> + <ClInclude Include="..\deh_soc.h" /> + <ClInclude Include="..\deh_lua.h" /> + <ClInclude Include="..\deh_tables.h" /> <ClInclude Include="..\doomdata.h" /> <ClInclude Include="..\doomdef.h" /> <ClInclude Include="..\doomstat.h" /> @@ -283,6 +286,8 @@ <ClInclude Include="..\r_draw.h" /> <ClInclude Include="..\r_local.h" /> <ClInclude Include="..\r_main.h" /> + <ClInclude Include="..\r_patch.h" /> + <ClInclude Include="..\r_patchrotation.h" /> <ClInclude Include="..\r_picformats.h" /> <ClInclude Include="..\r_plane.h" /> <ClInclude Include="..\r_portal.h" /> @@ -361,6 +366,9 @@ <ClCompile Include="..\comptime.c" /> <ClCompile Include="..\console.c" /> <ClCompile Include="..\dehacked.c" /> + <ClCompile Include="..\deh_soc.c" /> + <ClCompile Include="..\deh_lua.c" /> + <ClCompile Include="..\deh_tables.c" /> <ClCompile Include="..\d_clisrv.c" /> <ClCompile Include="..\d_main.c" /> <ClCompile Include="..\d_net.c" /> @@ -452,6 +460,8 @@ <ExcludedFromBuild>true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\r_main.c" /> + <ClCompile Include="..\r_patch.c" /> + <ClCompile Include="..\r_patchrotation.c" /> <ClCompile Include="..\r_picformats.c" /> <ClCompile Include="..\r_plane.c" /> <ClCompile Include="..\r_portal.c" /> diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index 438746ac7f02a01745f3785c9bf60b1e969e8de1..adae2f446dbde8267e375bb794eacc50bed9c663 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -477,12 +477,18 @@ <ClInclude Include="..\hardware\hw_clip.h"> <Filter>Hw_Hardware</Filter> </ClInclude> - <ClInclude Include="..\r_textures.h"> + <ClInclude Include="..\r_patch.h"> + <Filter>R_Rend</Filter> + </ClInclude> + <ClInclude Include="..\r_patchrotation.h"> <Filter>R_Rend</Filter> </ClInclude> <ClInclude Include="..\r_picformats.h"> <Filter>R_Rend</Filter> </ClInclude> + <ClInclude Include="..\r_textures.h"> + <Filter>R_Rend</Filter> + </ClInclude> <ClInclude Include="..\r_portal.h"> <Filter>R_Rend</Filter> </ClInclude> @@ -961,12 +967,18 @@ <Filter>Hw_Hardware</Filter> </ClCompile> <ClCompile Include="..\apng.c" /> - <ClCompile Include="..\r_textures.c"> + <ClCompile Include="..\r_patch.c"> + <Filter>R_Rend</Filter> + </ClCompile> + <ClCompile Include="..\r_patchrotation.c"> <Filter>R_Rend</Filter> </ClCompile> <ClCompile Include="..\r_picformats.c"> <Filter>R_Rend</Filter> </ClCompile> + <ClCompile Include="..\r_textures.c"> + <Filter>R_Rend</Filter> + </ClCompile> <ClCompile Include="..\r_portal.c"> <Filter>R_Rend</Filter> </ClCompile> diff --git a/src/sdl/Srb2SDL-vc9.vcproj b/src/sdl/Srb2SDL-vc9.vcproj index 3c430b2b4af5a85ca641d0df1557ff9e90215604..95f035267026215279b91d1d309b08be34e6e29e 100644 --- a/src/sdl/Srb2SDL-vc9.vcproj +++ b/src/sdl/Srb2SDL-vc9.vcproj @@ -1710,6 +1710,138 @@ RelativePath="..\dehacked.h" > </File> + <File + RelativePath="..\deh_soc.c" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug|x64" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|x64" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\deh_soc.h" + > + </File> + <File + RelativePath="..\deh_lua.c" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug|x64" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|x64" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\deh_lua.h" + > + </File> + <File + RelativePath="..\deh_tables.c" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug|x64" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|x64" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\deh_tables.h" + > + </File> <File RelativePath="..\doomdata.h" > diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index e545bbb6363a72210fdb25aeffb4de35a638b491..3985086626c4d17f157a63668627d210737d1546 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -86,9 +86,11 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(ClearBuffer); GETFUNC(SetTexture); GETFUNC(UpdateTexture); + GETFUNC(DeleteTexture); GETFUNC(ReadRect); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); + GETFUNC(ClearCacheList); GETFUNC(SetSpecialState); GETFUNC(GetTextureUsed); GETFUNC(DrawModel); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index a49adb50866cb5fa9e096d599cabc8fd8af30421..b8b3b9d34e8ae97648d3f1f6178511c251b9253e 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -42,7 +42,7 @@ #ifdef HAVE_IMAGE #include "SDL_image.h" -#elif defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) // Windows doesn't need this, as SDL will do it for us. +#elif defined (__unix__) || (!defined(__APPLE__) && defined (UNIXCOMMON)) // Windows & Mac don't need this, as SDL will do it for us. #define LOAD_XPM //I want XPM! #include "IMG_xpm.c" //Alam: I don't want to add SDL_Image.dll/so #define HAVE_IMAGE //I have SDL_Image, sortof @@ -95,7 +95,7 @@ static INT32 numVidModes = -1; static char vidModeName[33][32]; // allow 33 different modes rendermode_t rendermode = render_soft; -static rendermode_t chosenrendermode = render_soft; // set by command line arguments +rendermode_t chosenrendermode = render_none; // set by command line arguments boolean highcolor = false; @@ -105,7 +105,6 @@ static consvar_t cv_stretch = CVAR_INIT ("stretch", "Off", CV_SAVE|CV_NOSHOWHELP static consvar_t cv_alwaysgrabmouse = CVAR_INIT ("alwaysgrabmouse", "Off", CV_SAVE, CV_OnOff, NULL); UINT8 graphics_started = 0; // Is used in console.c and screen.c -INT32 vid_opengl_state = 0; // To disable fullscreen at startup; is set in VID_PrepareModeList boolean allow_fullscreen = false; @@ -1443,7 +1442,8 @@ static SDL_bool Impl_CreateContext(void) { // Renderer-specific stuff #ifdef HWRENDER - if ((rendermode == render_opengl) && (vid_opengl_state != -1)) + if ((rendermode == render_opengl) + && (vid.glstate != VID_GL_LIBRARY_ERROR)) { if (!sdlglcontext) sdlglcontext = SDL_GL_CreateContext(window); @@ -1480,7 +1480,7 @@ void VID_CheckGLLoaded(rendermode_t oldrender) { (void)oldrender; #ifdef HWRENDER - if (vid_opengl_state == -1) // Well, it didn't work the first time anyway. + if (vid.glstate == VID_GL_LIBRARY_ERROR) // Well, it didn't work the first time anyway. { CONS_Alert(CONS_ERROR, "OpenGL never loaded\n"); rendermode = oldrender; @@ -1495,14 +1495,16 @@ void VID_CheckGLLoaded(rendermode_t oldrender) #endif } -void VID_CheckRenderer(void) +boolean VID_CheckRenderer(void) { boolean rendererchanged = false; boolean contextcreated = false; +#ifdef HWRENDER rendermode_t oldrenderer = rendermode; +#endif if (dedicated) - return; + return false; if (setrenderneeded) { @@ -1516,11 +1518,12 @@ void VID_CheckRenderer(void) // Initialise OpenGL before calling SDLSetMode!!! // This is because SDLSetMode calls OglSdlSurface. - if (vid_opengl_state == 0) + if (vid.glstate == VID_GL_LIBRARY_NOTLOADED) { VID_StartupOpenGL(); + // Loaded successfully! - if (vid_opengl_state == 1) + if (vid.glstate == VID_GL_LIBRARY_LOADED) { // Destroy the current window, if it exists. if (window) @@ -1543,7 +1546,7 @@ void VID_CheckRenderer(void) contextcreated = true; } } - else if (vid_opengl_state == -1) + else if (vid.glstate == VID_GL_LIBRARY_ERROR) rendererchanged = false; } #endif @@ -1554,7 +1557,7 @@ void VID_CheckRenderer(void) setrenderneeded = 0; } - SDLSetMode(vid.width, vid.height, USE_FULLSCREEN, (rendererchanged ? SDL_FALSE : SDL_TRUE)); + SDLSetMode(vid.width, vid.height, USE_FULLSCREEN, (setmodeneeded ? SDL_TRUE : SDL_FALSE)); Impl_VideoSetupBuffer(); if (rendermode == render_soft) @@ -1565,27 +1568,17 @@ void VID_CheckRenderer(void) bufSurface = NULL; } - if (rendererchanged) - { -#ifdef HWRENDER - if (vid_opengl_state == 1) // Only if OpenGL ever loaded! - HWR_FreeTextureCache(); -#endif - SCR_SetDrawFuncs(); - } + SCR_SetDrawFuncs(); } #ifdef HWRENDER - else if (rendermode == render_opengl) + else if (rendermode == render_opengl && rendererchanged) { - if (rendererchanged) - { - R_InitHardwareMode(); - V_SetPalette(0); - } + HWR_Switch(); + V_SetPalette(0); } -#else - (void)oldrenderer; #endif + + return rendererchanged; } INT32 VID_SetMode(INT32 modeNum) @@ -1626,7 +1619,7 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) flags |= SDL_WINDOW_BORDERLESS; #ifdef HWRENDER - if (vid_opengl_state == 1) + if (vid.glstate == VID_GL_LIBRARY_LOADED) flags |= SDL_WINDOW_OPENGL; #endif @@ -1747,12 +1740,44 @@ void I_StartupGraphics(void) framebuffer = SDL_TRUE; } -#ifdef HWRENDER - if (M_CheckParm("-opengl")) - chosenrendermode = rendermode = render_opengl; + // Renderer choices + // Takes priority over the config. + if (M_CheckParm("-renderer")) + { + INT32 i = 0; + CV_PossibleValue_t *renderer_list = cv_renderer_t; + const char *modeparm = M_GetNextParm(); + while (renderer_list[i].strvalue) + { + if (!stricmp(modeparm, renderer_list[i].strvalue)) + { + chosenrendermode = renderer_list[i].value; + break; + } + i++; + } + } + + // Choose Software renderer else if (M_CheckParm("-software")) + chosenrendermode = render_soft; + +#ifdef HWRENDER + // Choose OpenGL renderer + else if (M_CheckParm("-opengl")) + chosenrendermode = render_opengl; + + // Don't startup OpenGL + if (M_CheckParm("-nogl")) + { + vid.glstate = VID_GL_LIBRARY_ERROR; + if (chosenrendermode == render_opengl) + chosenrendermode = render_none; + } #endif - chosenrendermode = rendermode = render_soft; + + if (chosenrendermode != render_none) + rendermode = chosenrendermode; usesdl2soft = M_CheckParm("-softblit"); borderlesswindow = M_CheckParm("-borderless"); @@ -1761,9 +1786,7 @@ void I_StartupGraphics(void) VID_Command_ModeList_f(); #ifdef HWRENDER - if (M_CheckParm("-nogl")) - vid_opengl_state = -1; // Don't startup OpenGL - else if (chosenrendermode == render_opengl) + if (rendermode == render_opengl) VID_StartupOpenGL(); #endif @@ -1836,9 +1859,11 @@ void VID_StartupOpenGL(void) HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); HWD.pfnSetTexture = hwSym("SetTexture",NULL); HWD.pfnUpdateTexture = hwSym("UpdateTexture",NULL); + HWD.pfnDeleteTexture = hwSym("DeleteTexture",NULL); HWD.pfnReadRect = hwSym("ReadRect",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); + HWD.pfnClearCacheList = hwSym("ClearCacheList",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); HWD.pfnSetPalette = hwSym("SetPalette",NULL); HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); @@ -1863,9 +1888,9 @@ void VID_StartupOpenGL(void) HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL); HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL); - vid_opengl_state = HWD.pfnInit() ? 1 : -1; // let load the OpenGL library + vid.glstate = HWD.pfnInit() ? VID_GL_LIBRARY_LOADED : VID_GL_LIBRARY_ERROR; // let load the OpenGL library - if (vid_opengl_state == -1) + if (vid.glstate == VID_GL_LIBRARY_ERROR) { rendermode = render_soft; setrenderneeded = 0; diff --git a/src/st_stuff.c b/src/st_stuff.c index 86e0b37542224bc780017c44449ef0fb3e55d306..b25538d883276cdac46784489462b2c32f349fc9 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -203,9 +203,7 @@ void ST_doPaletteStuff(void) { INT32 palette; - if (paused || P_AutoPause()) - palette = 0; - else if (stplyr && stplyr->flashcount) + if (stplyr && stplyr->flashcount) palette = stplyr->flashpal; else palette = 0; @@ -215,8 +213,6 @@ void ST_doPaletteStuff(void) palette = 0; // No flashpals here in OpenGL #endif - palette = min(max(palette, 0), 13); - if (palette != st_palette) { st_palette = palette; @@ -232,7 +228,7 @@ void ST_doPaletteStuff(void) void ST_UnloadGraphics(void) { - Z_FreeTag(PU_HUDGFX); + Patch_FreeTag(PU_HUDGFX); } void ST_LoadGraphics(void) @@ -458,7 +454,7 @@ boolean st_overlay; static void ST_DrawNightsOverlayNum(fixed_t x /* right border */, fixed_t y, fixed_t s, INT32 a, UINT32 num, patch_t **numpat, skincolornum_t colornum) { - fixed_t w = SHORT(numpat[0]->width)*s; + fixed_t w = numpat[0]->width * s; const UINT8 *colormap; // I want my V_SNAPTOx flags. :< -Red @@ -676,7 +672,7 @@ static void ST_drawRaceNum(INT32 time) if (!(P_AutoPause() || paused) && !bounce) S_StartSound(0, ((racenum == racego) ? sfx_s3kad : sfx_s3ka7)); } - V_DrawScaledPatch(((BASEVIDWIDTH - SHORT(racenum->width))/2), height, V_PERPLAYER, racenum); + V_DrawScaledPatch(((BASEVIDWIDTH - racenum->width)/2), height, V_PERPLAYER, racenum); } static void ST_drawTime(void) @@ -1625,8 +1621,8 @@ static void ST_drawFirstPersonHUD(void) p = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); // Display the countdown drown numbers! - if (p && !F_GetPromptHideHud(60 - SHORT(p->topoffset))) - V_DrawScaledPatch((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset), 60 - SHORT(p->topoffset), + if (p && !F_GetPromptHideHud(60 - p->topoffset)) + V_DrawScaledPatch((BASEVIDWIDTH/2) - (p->width / 2) + SHORT(p->leftoffset), 60 - SHORT(p->topoffset), V_PERPLAYER|V_PERPLAYER|V_TRANSLUCENT, p); } @@ -2080,21 +2076,21 @@ static void ST_drawNiGHTSHUD(void) if (stplyr->powers[pw_nights_superloop]) { pwr = stplyr->powers[pw_nights_superloop]; - V_DrawSmallScaledPatch(110, 44, 0, W_CachePatchName("NPRUA0",PU_CACHE)); + V_DrawSmallScaledPatch(110, 44, 0, W_CachePatchName("NPRUA0",PU_SPRITE)); V_DrawThinString(106, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } if (stplyr->powers[pw_nights_helper]) { pwr = stplyr->powers[pw_nights_helper]; - V_DrawSmallScaledPatch(150, 44, 0, W_CachePatchName("NPRUC0",PU_CACHE)); + V_DrawSmallScaledPatch(150, 44, 0, W_CachePatchName("NPRUC0",PU_SPRITE)); V_DrawThinString(146, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } if (stplyr->powers[pw_nights_linkfreeze]) { pwr = stplyr->powers[pw_nights_linkfreeze]; - V_DrawSmallScaledPatch(190, 44, 0, W_CachePatchName("NPRUE0",PU_CACHE)); + V_DrawSmallScaledPatch(190, 44, 0, W_CachePatchName("NPRUE0",PU_SPRITE)); V_DrawThinString(186, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } } @@ -2379,7 +2375,7 @@ static void ST_drawTeamHUD(void) p = bmatcico; if (LUA_HudEnabled(hud_teamscores)) - V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); + V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - (p->width / 4), 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); if (gametyperules & GTR_TEAMFLAGS) p = rflagico; @@ -2387,7 +2383,7 @@ static void ST_drawTeamHUD(void) p = rmatcico; if (LUA_HudEnabled(hud_teamscores)) - V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); + V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - (p->width / 4), 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); if (!(gametyperules & GTR_TEAMFLAGS)) goto num; @@ -2400,11 +2396,11 @@ static void ST_drawTeamHUD(void) { // Blue flag isn't at base if (players[i].gotflag & GF_BLUEFLAG && LUA_HudEnabled(hud_teamscores)) - V_DrawScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(nonicon->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon); + V_DrawScaledPatch(BASEVIDWIDTH/2 - SEP - (nonicon->width / 2), 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon); // Red flag isn't at base if (players[i].gotflag & GF_REDFLAG && LUA_HudEnabled(hud_teamscores)) - V_DrawScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(nonicon2->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon2); + V_DrawScaledPatch(BASEVIDWIDTH/2 + SEP - (nonicon2->width / 2), 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon2); whichflag |= players[i].gotflag; @@ -2677,7 +2673,7 @@ static void ST_overlayDrawer(void) else { tic_t num = time; - INT32 sz = SHORT(tallnum[0]->width)/2, width = 0; + INT32 sz = tallnum[0]->width / 2, width = 0; do { width += sz; @@ -2755,9 +2751,6 @@ 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/taglist.c b/src/taglist.c index e0bb86c97410938972ed1c060909489316c0c827..b11216b6cf7b3e7c709b73750c2d46e8e9155c40 100644 --- a/src/taglist.c +++ b/src/taglist.c @@ -15,10 +15,15 @@ #include "z_zone.h" #include "r_data.h" +// Taggroups are used to list elements of the same tag, for iteration. +// Since elements can now have multiple tags, it means an element may appear +// in several taggroups at the same time. These are built on level load. taggroup_t* tags_sectors[MAXTAGS + 1]; taggroup_t* tags_lines[MAXTAGS + 1]; taggroup_t* tags_mapthings[MAXTAGS + 1]; +/// Adds a tag to a given element's taglist. +/// \warning This does not rebuild the global taggroups, which are used for iteration. void Tag_Add (taglist_t* list, const mtag_t tag) { list->tags = Z_Realloc(list->tags, (list->count + 1) * sizeof(list->tags), PU_LEVEL, NULL); @@ -26,6 +31,7 @@ void Tag_Add (taglist_t* list, const mtag_t tag) } /// Sets the first tag entry in a taglist. +/// Replicates the old way of accessing element->tag. void Tag_FSet (taglist_t* list, const mtag_t tag) { if (!list->count) @@ -38,6 +44,7 @@ void Tag_FSet (taglist_t* list, const mtag_t tag) } /// Gets the first tag entry in a taglist. +/// Replicates the old way of accessing element->tag. mtag_t Tag_FGet (const taglist_t* list) { if (list->count) @@ -46,6 +53,7 @@ mtag_t Tag_FGet (const taglist_t* list) return 0; } +/// Returns true if the given tag exist inside the list. boolean Tag_Find (const taglist_t* list, const mtag_t tag) { size_t i; @@ -56,6 +64,7 @@ boolean Tag_Find (const taglist_t* list, const mtag_t tag) return false; } +/// Returns true if at least one tag is shared between two given lists. boolean Tag_Share (const taglist_t* list1, const taglist_t* list2) { size_t i; @@ -66,6 +75,7 @@ boolean Tag_Share (const taglist_t* list1, const taglist_t* list2) return false; } +/// Returns true if both lists are identical. boolean Tag_Compare (const taglist_t* list1, const taglist_t* list2) { size_t i; @@ -80,7 +90,7 @@ boolean Tag_Compare (const taglist_t* list1, const taglist_t* list2) return true; } - +/// Search for an element inside a global taggroup. size_t Taggroup_Find (const taggroup_t *group, const size_t id) { size_t i; @@ -95,6 +105,7 @@ size_t Taggroup_Find (const taggroup_t *group, const size_t id) return -1; } +/// Add an element to a global taggroup. void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id) { taggroup_t *group; @@ -135,6 +146,7 @@ void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id) group->elements[i] = id; } +/// Remove an element from a global taggroup. void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id) { taggroup_t *group; @@ -191,6 +203,8 @@ static void Taglist_AddToMapthings (const mtag_t tag, const size_t itemid) Taggroup_Add(tags_mapthings, tag, itemid); } +/// After all taglists have been built for each element (sectors, lines, things), +/// the global taggroups, made for iteration, are built here. void Taglist_InitGlobalTables(void) { size_t i, j; @@ -338,6 +352,7 @@ INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start) // Ingame list manipulation. +/// Changes the first tag for a given sector, and updates the global taggroups. void Tag_SectorFSet (const size_t id, const mtag_t tag) { sector_t* sec = §ors[id]; diff --git a/src/taglist.h b/src/taglist.h index 3a724aef37a601818ac3cae32cfc2b7e0b83a069..0e6d9f8422bbc150dbbabe3c6048d6e66c448f05 100644 --- a/src/taglist.h +++ b/src/taglist.h @@ -20,7 +20,7 @@ typedef INT16 mtag_t; #define MAXTAGS UINT16_MAX #define MTAG_GLOBAL -1 -/// Multitag list. +/// Multitag list. Each taggable element will have its own taglist. typedef struct { mtag_t* tags; @@ -28,16 +28,15 @@ typedef struct } taglist_t; void Tag_Add (taglist_t* list, const mtag_t tag); - void Tag_FSet (taglist_t* list, const mtag_t tag); mtag_t Tag_FGet (const taglist_t* list); boolean Tag_Find (const taglist_t* list, const mtag_t tag); boolean Tag_Share (const taglist_t* list1, const taglist_t* list2); - boolean Tag_Compare (const taglist_t* list1, const taglist_t* list2); void Tag_SectorFSet (const size_t id, const mtag_t tag); +/// Taggroup list. It is essentially just an element id list. typedef struct { size_t *elements; @@ -61,14 +60,68 @@ INT32 Tag_Iterate_Things (const mtag_t tag, const size_t p); INT32 Tag_FindLineSpecial(const INT16 special, const mtag_t tag); INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start); -// Use this macro to declare the iterator position variable. +// Use this macro to declare an iterator position variable. #define TAG_ITER_DECLARECOUNTER(level) size_t ICNT_##level -#define TAG_ITER(level, fn, tag, id) for(ICNT_##level = 0; (id = fn(tag, ICNT_##level)) >= 0; ICNT_##level++) +#define TAG_ITER(level, fn, tag, return_varname) for(ICNT_##level = 0; (return_varname = fn(tag, ICNT_##level)) >= 0; ICNT_##level++) + +// Use these macros as wrappers for a taglist iteration. +#define TAG_ITER_SECTORS(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Sectors, tag, return_varname) +#define TAG_ITER_LINES(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Lines, tag, return_varname) +#define TAG_ITER_THINGS(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Things, tag, return_varname) + +/* ITERATION MACROS +TAG_ITER_DECLARECOUNTER must be used before using the iterators. + +'level': +For each nested iteration, an additional TAG_ITER_DECLARECOUNTER +must be used with a different level number to avoid conflict with +the outer iterations. +Most cases don't have nested iterations and thus the level is just 0. + +'tag': +Pretty much the elements' tag to iterate through. + +'return_varname': +Target variable's name to return the iteration results to. + + +EXAMPLE: +{ + TAG_ITER_DECLARECOUNTER(0); + TAG_ITER_DECLARECOUNTER(1); // For the nested iteration. + + size_t li; + size_t sec; + + INT32 tag1 = 4; + + ... + + TAG_ITER_LINES(0, tag1, li) + { + line_t *line = lines + li; + + ... + + if (something) + { + mtag_t tag2 = 8; + + // Nested iteration; just make sure the level is higher + // and that it has its own counter declared in scope. + TAG_ITER_SECTORS(1, tag2, sec) + { + sector_t *sector = sectors + sec; + + ... + } + } + } +} -// Use these macros as wrappers for the taglist iterations. -#define TAG_ITER_SECTORS(level, tag, id) TAG_ITER(level, Tag_Iterate_Sectors, tag, id) -#define TAG_ITER_LINES(level, tag, id) TAG_ITER(level, Tag_Iterate_Lines, tag, id) -#define TAG_ITER_THINGS(level, tag, id) TAG_ITER(level, Tag_Iterate_Things, tag, id) +Notes: +If no elements are found for a given tag, the loop inside won't be executed. +*/ #endif //__R_TAGLIST__ diff --git a/src/tmap.nas b/src/tmap.nas index 106f38e962b03fef0f0edc9e93dbd71112449ced..69282d0b471dd2c86802df544f4a346e4b96baa9 100644 --- a/src/tmap.nas +++ b/src/tmap.nas @@ -763,8 +763,8 @@ TX2 EQU 16 TY2 EQU 20 RASTERY_SIZEOF EQU 24 -cglobal rasterize_segment_tex -rasterize_segment_tex: +cglobal rasterize_segment_tex_asm +rasterize_segment_tex_asm: push ebp mov ebp,esp diff --git a/src/v_video.c b/src/v_video.c index 9c91261de6eb3247945e33eec33384145e99ea6a..4713db0d89dda23a656f3df9ace63db9fba52902 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -529,7 +529,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca //if (rendermode != render_soft && !con_startup) // Why? if (rendermode == render_opengl) { - HWR_DrawStretchyFixedPatch((GLPatch_t *)patch, x, y, pscale, vscale, scrn, colormap); + HWR_DrawStretchyFixedPatch(patch, x, y, pscale, vscale, scrn, colormap); return; } #endif @@ -551,7 +551,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca if (alphalevel) { - v_translevel = transtables + ((alphalevel-1)<<FF_TRANSSHIFT); + v_translevel = R_GetTranslucencyTable(alphalevel); patchdrawfunc = translucentpdraw; } } @@ -599,13 +599,13 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca // left offset if (scrn & V_FLIP) - offsetx = FixedMul((SHORT(patch->width) - SHORT(patch->leftoffset))<<FRACBITS, pscale) + 1; + offsetx = FixedMul((patch->width - patch->leftoffset)<<FRACBITS, pscale) + 1; else - offsetx = FixedMul(SHORT(patch->leftoffset)<<FRACBITS, pscale); + offsetx = FixedMul(patch->leftoffset<<FRACBITS, pscale); // top offset // TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!? - offsety = FixedMul(SHORT(patch->topoffset)<<FRACBITS, vscale); + offsety = FixedMul(patch->topoffset<<FRACBITS, vscale); if ((scrn & (V_NOSCALESTART|V_OFFSET)) == (V_NOSCALESTART|V_OFFSET)) // Multiply by dupx/dupy for crosshairs { @@ -712,9 +712,9 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca if (!(scrn & V_SCALEPATCHMASK)) { // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT) - if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) + if (x == 0 && patch->width == BASEVIDWIDTH && y == 0 && patch->height == BASEVIDHEIGHT) { - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); + column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[0])); if (!column->topdelta) { source = (const UINT8 *)(column) + 3; @@ -754,18 +754,18 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca if (pscale != FRACUNIT) // scale width properly { - pwidth = SHORT(patch->width)<<FRACBITS; + pwidth = patch->width<<FRACBITS; pwidth = FixedMul(pwidth, pscale); pwidth = FixedMul(pwidth, dupx<<FRACBITS); pwidth >>= FRACBITS; } else - pwidth = SHORT(patch->width) * dupx; + pwidth = patch->width * dupx; deststart = desttop; destend = desttop + pwidth; - for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, ++offx, desttop++) + for (col = 0; (col>>FRACBITS) < patch->width; col += colfrac, ++offx, desttop++) { INT32 topdelta, prevdelta = -1; if (scrn & V_FLIP) // offx is measured from right edge instead of left @@ -782,7 +782,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca if (x+offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION) break; } - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); + column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS])); while (column->topdelta != 0xff) { @@ -829,7 +829,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ //if (rendermode != render_soft && !con_startup) // Not this again if (rendermode == render_opengl) { - HWR_DrawCroppedPatch((GLPatch_t*)patch,x,y,pscale,scrn,sx,sy,w,h); + HWR_DrawCroppedPatch(patch,x,y,pscale,scrn,sx,sy,w,h); return; } #endif @@ -851,7 +851,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ if (alphalevel) { - v_translevel = transtables + ((alphalevel-1)<<FF_TRANSSHIFT); + v_translevel = R_GetTranslucencyTable(alphalevel); patchdrawfunc = translucentpdraw; } } @@ -862,8 +862,8 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ colfrac = FixedDiv(FRACUNIT, fdup); rowfrac = FixedDiv(FRACUNIT, fdup); - y -= FixedMul(SHORT(patch->topoffset)<<FRACBITS, pscale); - x -= FixedMul(SHORT(patch->leftoffset)<<FRACBITS, pscale); + y -= FixedMul(patch->topoffset<<FRACBITS, pscale); + x -= FixedMul(patch->leftoffset<<FRACBITS, pscale); if (splitscreen && (scrn & V_PERPLAYER)) { @@ -998,14 +998,14 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ desttop += (y*vid.width) + x; } - for (col = sx<<FRACBITS; (col>>FRACBITS) < SHORT(patch->width) && ((col>>FRACBITS) - sx) < w; col += colfrac, ++x, desttop++) + for (col = sx<<FRACBITS; (col>>FRACBITS) < patch->width && ((col>>FRACBITS) - sx) < w; col += colfrac, ++x, desttop++) { INT32 topdelta, prevdelta = -1; if (x < 0) // don't draw off the left of the screen (WRAP PREVENTION) continue; if (x >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION) break; - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); + column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS])); while (column->topdelta != 0xff) { @@ -1500,7 +1500,7 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) // Jimita (12-04-2018) if (alphalevel) { - fadetable = ((UINT8 *)transtables + ((alphalevel-1)<<FF_TRANSSHIFT) + (c*256)); + fadetable = R_GetTranslucencyTable(alphalevel) + (c*256); for (;(--h >= 0) && dest < deststop; dest += vid.width) { u = 0; @@ -1683,7 +1683,7 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U fadetable = ((color & 0xFF00) // Color is not palette index? ? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade. - : ((UINT8 *)transtables + ((9-strength)<<FF_TRANSSHIFT) + color*256)); // Else, do TRANSMAP** fade. + : ((UINT8 *)R_GetTranslucencyTable((9-strength)+1) + color*256)); // Else, do TRANSMAP** fade. for (;(--h >= 0) && dest < deststop; dest += vid.width) { u = 0; @@ -1796,7 +1796,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum) void V_DrawPatchFill(patch_t *pat) { INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - INT32 x, y, pw = SHORT(pat->width) * dupz, ph = SHORT(pat->height) * dupz; + INT32 x, y, pw = pat->width * dupz, ph = pat->height * dupz; for (x = 0; x < vid.width; x += pw) { @@ -1829,7 +1829,7 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength) ? ((UINT8 *)(((color & 0x0F00) == 0x0A00) ? fadecolormap // Do fadecolormap fade. : (((color & 0x0F00) == 0x0B00) ? fadecolormap + (256 * FADECOLORMAPROWS) // Do white fadecolormap fade. : colormaps)) + strength*256) // Do COLORMAP fade. - : ((UINT8 *)transtables + ((9-strength)<<FF_TRANSSHIFT) + color*256)); // Else, do TRANSMAP** fade. + : ((UINT8 *)R_GetTranslucencyTable((9-strength)+1) + color*256)); // Else, do TRANSMAP** fade. const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; UINT8 *buf = screens[0]; @@ -1984,7 +1984,7 @@ void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed) if (c < 0 || c >= HU_FONTSIZE || !hu_font[c]) return; - w = SHORT(hu_font[c]->width); + w = hu_font[c]->width; if (x + w > vid.width) return; @@ -2011,7 +2011,7 @@ void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UI if (c < 0 || c >= HU_FONTSIZE || !hu_font[c]) return; - w = (vid.width < 640 ) ? (SHORT(hu_font[c]->width)/2) : (SHORT(hu_font[c]->width)); // use normal sized characters if we're using a terribly low resolution. + w = (vid.width < 640 ) ? ((hu_font[c]->width / 2)) : (hu_font[c]->width); // use normal sized characters if we're using a terribly low resolution. if (x + w > vid.width) return; @@ -2173,10 +2173,10 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) if (charwidth) { w = charwidth * dupx; - center = w/2 - SHORT(hu_font[c]->width)*dupx/2; + center = w/2 - hu_font[c]->width*dupx/2; } else - w = SHORT(hu_font[c]->width) * dupx; + w = hu_font[c]->width * dupx; if (cx > scrwidth) continue; @@ -2290,10 +2290,10 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) if (charwidth) { w = charwidth * dupx; - center = w/2 - SHORT(hu_font[c]->width)*dupx/4; + center = w/2 - hu_font[c]->width*dupx/4; } else - w = SHORT(hu_font[c]->width) * dupx / 2; + w = hu_font[c]->width * dupx / 2; if (cx > scrwidth) continue; @@ -2408,7 +2408,7 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) if (charwidth) w = charwidth * dupx; else - w = (SHORT(tny_font[c]->width) * dupx); + w = tny_font[c]->width * dupx; if (cx > scrwidth) continue; @@ -2547,10 +2547,10 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) if (charwidth) { w = charwidth * dupx; - center = w/2 - SHORT(hu_font[c]->width)*(dupx/2); + center = w/2 - hu_font[c]->width*(dupx/2); } else - w = SHORT(hu_font[c]->width) * dupx; + w = hu_font[c]->width * dupx; if ((cx>>FRACBITS) > scrwidth) continue; @@ -2663,10 +2663,10 @@ void V_DrawSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *st if (charwidth) { w = charwidth * dupx; - center = w/2 - SHORT(hu_font[c]->width)*(dupx/4); + center = w/2 - hu_font[c]->width*(dupx/4); } else - w = SHORT(hu_font[c]->width) * dupx / 2; + w = hu_font[c]->width * dupx / 2; if ((cx>>FRACBITS) > scrwidth) break; @@ -2780,10 +2780,10 @@ void V_DrawThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *str if (charwidth) { w = charwidth * dupx; - center = w/2 - SHORT(tny_font[c]->width)*(dupx/2); + center = w/2 - tny_font[c]->width*(dupx/2); } else - w = SHORT(tny_font[c]->width) * dupx; + w = tny_font[c]->width * dupx; if ((cx>>FRACBITS) > scrwidth) break; @@ -2897,10 +2897,10 @@ void V_DrawSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char if (charwidth) { w = FixedMul(charwidth, dupx); - center = w/2 - SHORT(tny_font[c]->width)*(dupx/4); + center = w/2 - tny_font[c]->width*(dupx/4); } else - w = SHORT(tny_font[c]->width) * dupx / 2; + w = tny_font[c]->width * dupx / 2; if (cx > scrwidth) break; @@ -2933,7 +2933,7 @@ void V_DrawRightAlignedSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option // Draws a tallnum. Replaces two functions in y_inter and st_stuff void V_DrawTallNum(INT32 x, INT32 y, INT32 flags, INT32 num) { - INT32 w = SHORT(tallnum[0]->width); + INT32 w = tallnum[0]->width; boolean neg; if (flags & (V_NOSCALESTART|V_NOSCALEPATCH)) @@ -2959,7 +2959,7 @@ void V_DrawTallNum(INT32 x, INT32 y, INT32 flags, INT32 num) // Does not handle negative numbers in a special way, don't try to feed it any. void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits) { - INT32 w = SHORT(tallnum[0]->width); + INT32 w = tallnum[0]->width; if (flags & (V_NOSCALESTART|V_NOSCALEPATCH)) w *= vid.dupx; @@ -3036,7 +3036,7 @@ void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string) continue; } - w = SHORT(cred_font[c]->width) * dupx; + w = cred_font[c]->width * dupx; if ((cx>>FRACBITS) > scrwidth) continue; @@ -3098,7 +3098,7 @@ static void V_DrawNameTagLine(INT32 x, INT32 y, INT32 option, fixed_t scale, UIN continue; } - w = FixedMul((SHORT(ntb_font[c]->width)+2 * dupx) * FRACUNIT, scale); + w = FixedMul(((ntb_font[c]->width)+2 * dupx) * FRACUNIT, scale); if (FixedInt(cx) > scrwidth) continue; @@ -3239,7 +3239,7 @@ INT32 V_NameTagWidth(const char *string) if (c < 0 || c >= NT_FONTSIZE || !ntb_font[c] || !nto_font[c]) w += 4; else - w += SHORT(ntb_font[c]->width)+2; + w += (ntb_font[c]->width)+2; } return w; @@ -3262,7 +3262,7 @@ INT32 V_CreditStringWidth(const char *string) if (c < 0 || c >= CRED_FONTSIZE) w += 16; else - w += SHORT(cred_font[c]->width); + w += cred_font[c]->width; } return w; @@ -3320,7 +3320,7 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string) continue; } - w = SHORT(lt_font[c]->width) * dupx; + w = lt_font[c]->width * dupx; if (cx > scrwidth) continue; @@ -3352,7 +3352,7 @@ INT32 V_LevelNameWidth(const char *string) if (c < 0 || c >= LT_FONTSIZE || !lt_font[c]) w += 16; else - w += SHORT(lt_font[c]->width); + w += lt_font[c]->width; } return w; @@ -3371,8 +3371,8 @@ INT32 V_LevelNameHeight(const char *string) if (c < 0 || c >= LT_FONTSIZE || !lt_font[c]) continue; - if (SHORT(lt_font[c]->height) > w) - w = SHORT(lt_font[c]->height); + if (lt_font[c]->height > w) + w = lt_font[c]->height; } return w; @@ -3385,11 +3385,11 @@ INT16 V_LevelActNumWidth(UINT8 num) INT16 result = 0; if (num == 0) - result = SHORT(ttlnum[num]->width); + result = ttlnum[num]->width; while (num > 0 && num <= 99) { - result = result + SHORT(ttlnum[num%10]->width); + result = result + ttlnum[num%10]->width; num = num/10; } @@ -3427,7 +3427,7 @@ INT32 V_StringWidth(const char *string, INT32 option) if (c < 0 || c >= HU_FONTSIZE || !hu_font[c]) w += spacewidth; else - w += (charwidth ? charwidth : SHORT(hu_font[c]->width)); + w += (charwidth ? charwidth : hu_font[c]->width); } if (option & (V_NOSCALESTART|V_NOSCALEPATCH)) @@ -3467,7 +3467,7 @@ INT32 V_SmallStringWidth(const char *string, INT32 option) if (c < 0 || c >= HU_FONTSIZE || !hu_font[c]) w += spacewidth; else - w += (charwidth ? charwidth : SHORT(hu_font[c]->width)/2); + w += (charwidth ? charwidth : (hu_font[c]->width / 2)); } return w; @@ -3504,7 +3504,7 @@ INT32 V_ThinStringWidth(const char *string, INT32 option) if (c < 0 || c >= HU_FONTSIZE || !tny_font[c]) w += spacewidth; else - w += (charwidth ? charwidth : SHORT(tny_font[c]->width)); + w += (charwidth ? charwidth : tny_font[c]->width); } return w; @@ -3565,7 +3565,7 @@ void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param) angle_t disStart = (leveltime * 128) & FINEMASK; // in 0 to FINEANGLE INT32 newpix; INT32 sine; - //UINT8 *transme = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT); + //UINT8 *transme = R_GetTranslucencyTable(tr_trans50); for (y = yoffset; y < yoffset+height; y++) { @@ -3622,7 +3622,7 @@ Unoptimized version INT32 x, y; // TODO: Add a postimg_param so that we can pick the translucency level... - UINT8 *transme = transtables + ((param-1)<<FF_TRANSSHIFT); + UINT8 *transme = R_GetTranslucencyTable(param); for (y = yoffset; y < yoffset+height; y++) { @@ -3770,3 +3770,36 @@ void V_Init(void) CONS_Debug(DBG_RENDER, " screens[%d] = %x\n", i, screens[i]); #endif } + +void V_Recalc(void) +{ + // scale 1,2,3 times in x and y the patches for the menus and overlays... + // calculated once and for all, used by routines in v_video.c and v_draw.c + vid.dupx = vid.width / BASEVIDWIDTH; + vid.dupy = vid.height / BASEVIDHEIGHT; + vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); + vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT); + vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT); + +#ifdef HWRENDER + //if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions in opengl + // 13/11/18: + // The above is no longer necessary, since we want OpenGL to be just like software now + // -- Monster Iestyn +#endif + vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); + + vid.meddupx = (UINT8)(vid.dupx >> 1) + 1; + vid.meddupy = (UINT8)(vid.dupy >> 1) + 1; +#ifdef HWRENDER + vid.fmeddupx = vid.meddupx*FRACUNIT; + vid.fmeddupy = vid.meddupy*FRACUNIT; +#endif + + vid.smalldupx = (UINT8)(vid.dupx / 3) + 1; + vid.smalldupy = (UINT8)(vid.dupy / 3) + 1; +#ifdef HWRENDER + vid.fsmalldupx = vid.smalldupx*FRACUNIT; + vid.fsmalldupy = vid.smalldupy*FRACUNIT; +#endif +} diff --git a/src/v_video.h b/src/v_video.h index 2af4fe29313055edab8478dfcb912ca28a8435aa..8a18f82ad7ab834988e672e3f5c21189764876b6 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -36,6 +36,9 @@ cv_rsaturation, cv_ysaturation, cv_gsaturation, cv_csaturation, cv_bsaturation, // Allocates buffer screens, call before R_Init. void V_Init(void); +// Recalculates the viddef (dupx, dupy, etc.) according to the current screen resolution. +void V_Recalc(void); + // Color look-up table #define CLUTINDEX(r, g, b) (((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3) diff --git a/src/w_wad.c b/src/w_wad.c index 42417a4b9485b2e96d044ac93a87d1b7f64eb183..aca530fa518c7134636349b769f6760590cc79e3 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -57,6 +57,7 @@ #include "r_defs.h" #include "r_data.h" #include "r_textures.h" +#include "r_patch.h" #include "r_picformats.h" #include "i_system.h" #include "md5.h" @@ -833,11 +834,6 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache); Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache); -#ifdef HWRENDER - // allocates GLPatch info structures and store them in a tree - wadfile->hwrcache = M_AATreeAlloc(AATREE_ZUSER); -#endif - // // add the wadfile // @@ -847,7 +843,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) #ifdef HWRENDER // Read shaders from file - if (rendermode == render_opengl && (vid_opengl_state == 1)) + if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) { HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3)); HWR_CompileShaders(); @@ -1670,13 +1666,7 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) if (!lumpcache[lump]) { size_t len = W_LumpLengthPwad(wad, lump); - void *ptr, *lumpdata; -#ifndef NO_PNG_LUMPS - void *srcdata = NULL; -#endif - - ptr = Z_Malloc(len, tag, &lumpcache[lump]); - lumpdata = Z_Malloc(len, tag, NULL); + void *ptr, *dest, *lumpdata = Z_Malloc(len, PU_STATIC, NULL); // read the lump in full W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); @@ -1686,14 +1676,25 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) if (Picture_IsLumpPNG((UINT8 *)lumpdata, len)) { size_t newlen; - srcdata = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_PATCH, NULL, NULL, NULL, NULL, len, &newlen, 0); - ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]); - M_Memcpy(ptr, srcdata, newlen); - Z_Free(srcdata); + void *converted = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &newlen, 0); + ptr = Z_Malloc(newlen, PU_STATIC, NULL); + M_Memcpy(ptr, converted, newlen); + Z_Free(converted); + len = newlen; } else // just copy it into the patch cache #endif + { + ptr = Z_Malloc(len, PU_STATIC, NULL); M_Memcpy(ptr, lumpdata, len); + } + + Z_Free(lumpdata); + + dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]); + Patch_Create(ptr, len, dest); + + Z_Free(ptr); } else Z_ChangeTag(lumpcache[lump], tag); @@ -1708,45 +1709,22 @@ void *W_CacheSoftwarePatchNum(lumpnum_t lumpnum, INT32 tag) void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) { -#ifdef HWRENDER - GLPatch_t *grPatch; -#endif + patch_t *patch; if (!TestValidLump(wad, lump)) return NULL; + patch = W_CacheSoftwarePatchNumPwad(wad, lump, tag); + #ifdef HWRENDER // Software-only compile cache the data without conversion if (rendermode == render_soft || rendermode == render_none) #endif - { - return W_CacheSoftwarePatchNumPwad(wad, lump, tag); - } -#ifdef HWRENDER - - grPatch = HWR_GetCachedGLPatchPwad(wad, lump); - - if (grPatch->mipmap->data) - { - if (tag == PU_CACHE) - tag = PU_HWRCACHE; - Z_ChangeTag(grPatch->mipmap->data, tag); - } - else - { - patch_t *ptr = NULL; + return (void *)patch; - // Only load the patch if we haven't initialised the grPatch yet - if (grPatch->mipmap->width == 0) - ptr = W_CacheLumpNumPwad(grPatch->wadnum, grPatch->lumpnum, PU_STATIC); - - // Run HWR_MakePatch in all cases, to recalculate some things - HWR_MakePatch(ptr, grPatch, grPatch->mipmap, false); - Z_Free(ptr); - } - - // return GLPatch_t, which can be casted to (patch_t) with valid patch header info - return (void *)grPatch; +#ifdef HWRENDER + Patch_CreateGL(patch); + return (void *)patch; #endif } @@ -1761,7 +1739,7 @@ void W_UnlockCachedPatch(void *patch) // have different lifetimes from software's. #ifdef HWRENDER if (rendermode == render_opengl) - HWR_UnlockCachedPatch((GLPatch_t*)patch); + HWR_UnlockCachedPatch((GLPatch_t *)((patch_t *)patch)->hardware); else #endif Z_Unlock(patch); diff --git a/src/w_wad.h b/src/w_wad.h index 41232cba1c5f5e006c33ed8496462c98a1ccf2f4..1e86eea5a6b2ac991d26d47b98cf3416f4de5b2b 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -102,10 +102,6 @@ virtlump_t* vres_Find(const virtres_t*, const char*); #define lumpcache_t void * -#ifdef HWRENDER -#include "m_aatree.h" -#endif - // Resource type of the WAD. Yeah, I know this sounds dumb, but I'll leave it like this until I clean up the code further. typedef enum restype { @@ -123,9 +119,6 @@ typedef struct wadfile_s lumpinfo_t *lumpinfo; lumpcache_t *lumpcache; lumpcache_t *patchcache; -#ifdef HWRENDER - aatree_t *hwrcache; // patches are cached in renderer's native format -#endif UINT16 numlumps; // this wad's number of resources FILE *handle; UINT32 filesize; // for network diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg index bf68f8c9793d7baeca356a8ee5fba71d116a257b..486616f2d79b477ec7474c5f9982b72d8d663ae3 100644 --- a/src/win32/Makefile.cfg +++ b/src/win32/Makefile.cfg @@ -59,7 +59,6 @@ endif ifndef SDL OPTS+=-D_WINDOWS endif - OPTS+=-D__USE_MINGW_ANSI_STDIO=0 ifndef SDL LIBS+=-lmingw32 -mwindows -ldinput -ldxguid -lgdi32 -lwinmm diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj index 52617037b210f0eb913daf9a4e7eab6d1bee973f..3e8af3b0ed866b9039879abbc4b4e28b1d623ba4 100644 --- a/src/win32/Srb2win-vc10.vcxproj +++ b/src/win32/Srb2win-vc10.vcxproj @@ -298,6 +298,8 @@ <ExcludedFromBuild>true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\r_main.c" /> + <ClCompile Include="..\r_patch.c" /> + <ClCompile Include="..\r_patchrotation.c" /> <ClCompile Include="..\r_picformats.c" /> <ClCompile Include="..\r_plane.c" /> <ClCompile Include="..\r_portal.c" /> @@ -454,6 +456,8 @@ <ClInclude Include="..\r_draw.h" /> <ClInclude Include="..\r_local.h" /> <ClInclude Include="..\r_main.h" /> + <ClInclude Include="..\r_patch.h" /> + <ClInclude Include="..\r_patchrotation.h" /> <ClInclude Include="..\r_picformats.h" /> <ClInclude Include="..\r_plane.h" /> <ClInclude Include="..\r_portal.h" /> diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters index 0689a4ac0893e10c660a72ed32c9bb0c3c054c82..7279368f1423f4a02e962395e8d4b451a30e44cd 100644 --- a/src/win32/Srb2win-vc10.vcxproj.filters +++ b/src/win32/Srb2win-vc10.vcxproj.filters @@ -469,9 +469,18 @@ <Filter>Hw_Hardware</Filter> </ClCompile> <ClCompile Include="..\apng.c" /> + <ClCompile Include="..\r_patch.c"> + <Filter>R_Rend</Filter> + </ClCompile> + <ClCompile Include="..\r_patchrotation.c"> + <Filter>R_Rend</Filter> + </ClCompile> <ClCompile Include="..\r_picformats.c"> <Filter>R_Rend</Filter> </ClCompile> + <ClCompile Include="..\r_textures.c"> + <Filter>R_Rend</Filter> + </ClCompile> <ClCompile Include="..\r_portal.c"> <Filter>R_Rend</Filter> </ClCompile> @@ -886,12 +895,18 @@ <Filter>Hw_Hardware</Filter> </ClInclude> <ClInclude Include="..\apng.h" /> - <ClInclude Include="..\r_textures.h"> + <ClInclude Include="..\r_patch.h"> + <Filter>R_Rend</Filter> + </ClInclude> + <ClInclude Include="..\r_patchrotation.h"> <Filter>R_Rend</Filter> </ClInclude> <ClInclude Include="..\r_picformats.h"> <Filter>R_Rend</Filter> </ClInclude> + <ClInclude Include="..\r_textures.h"> + <Filter>R_Rend</Filter> + </ClInclude> <ClInclude Include="..\r_portal.h"> <Filter>R_Rend</Filter> </ClInclude> diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c index fa648a89c77d2f889799b5b31ebbba7507c1cf0b..d942d8cd406ad55b85b0e1bdd768631588f244ec 100644 --- a/src/win32/win_dll.c +++ b/src/win32/win_dll.c @@ -107,9 +107,11 @@ static loadfunc_t hwdFuncTable[] = { {"ClearBuffer@12", &hwdriver.pfnClearBuffer}, {"SetTexture@4", &hwdriver.pfnSetTexture}, {"UpdateTexture@4", &hwdriver.pfnUpdateTexture}, + {"DeleteTexture@4", &hwdriver.pfnDeleteTexture}, {"ReadRect@24", &hwdriver.pfnReadRect}, {"GClipRect@20", &hwdriver.pfnGClipRect}, {"ClearMipMapCache@0", &hwdriver.pfnClearMipMapCache}, + {"ClearCacheList@0", &hwdriver.pfnClearCacheList}, {"SetSpecialState@8", &hwdriver.pfnSetSpecialState}, {"DrawModel@16", &hwdriver.pfnDrawModel}, {"SetTransform@4", &hwdriver.pfnSetTransform}, @@ -139,9 +141,11 @@ static loadfunc_t hwdFuncTable[] = { {"ClearBuffer", &hwdriver.pfnClearBuffer}, {"SetTexture", &hwdriver.pfnSetTexture}, {"UpdateTexture", &hwdriver.pfnUpdateTexture}, + {"DeleteTexture", &hwdriver.pfnDeleteTexture}, {"ReadRect", &hwdriver.pfnReadRect}, {"GClipRect", &hwdriver.pfnGClipRect}, {"ClearMipMapCache", &hwdriver.pfnClearMipMapCache}, + {"ClearCacheList", &hwdriver.pfnClearCacheList}, {"SetSpecialState", &hwdriver.pfnSetSpecialState}, {"DrawModel", &hwdriver.pfnDrawModel}, {"SetTransform", &hwdriver.pfnSetTransform}, diff --git a/src/win32/win_vid.c b/src/win32/win_vid.c index 931e006eb35416dc251e5fbf7bd2ade432154f5c..7a33e19311f876fe595b72f7552fcf55f0af23fd 100644 --- a/src/win32/win_vid.c +++ b/src/win32/win_vid.c @@ -48,6 +48,7 @@ // this is the CURRENT rendermode!! very important: used by w_wad, and much other code rendermode_t rendermode = render_soft; +rendermode_t chosenrendermode = render_none; // set by command line arguments static void OnTop_OnChange(void); // synchronize page flipping with screen refresh static CV_PossibleValue_t CV_NeverOnOff[] = {{-1, "Never"}, {0, "Off"}, {1, "On"}, {0, NULL}}; @@ -56,7 +57,6 @@ static consvar_t cv_stretch = CVAR_INIT ("stretch", "On", CV_SAVE|CV_NOSHOWHELP, static consvar_t cv_ontop = CVAR_INIT ("ontop", "Never", 0, CV_NeverOnOff, NULL); boolean highcolor; -int vid_opengl_state = 0; static BOOL bDIBMode; // means we are using DIB instead of DirectDraw surfaces static LPBITMAPINFO bmiMain = NULL; @@ -952,7 +952,11 @@ INT32 VID_SetMode(INT32 modenum) return 1; } -void VID_CheckRenderer(void) {} +boolean VID_CheckRenderer(void) +{ + return false; +} + void VID_CheckGLLoaded(rendermode_t oldrender) { (void)oldrender; diff --git a/src/y_inter.c b/src/y_inter.c index d263bf6357c186e30c4d44612ec16c27ddb2d03c..061cbb5e1d45ed5659593b3f88944bba74e82e4d 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -152,7 +152,6 @@ typedef struct boolean usebuffer = false; static boolean useinterpic; -static boolean safetorender = true; static y_buffer_t *y_buffer; static INT32 intertic; @@ -169,7 +168,6 @@ 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) @@ -185,7 +183,7 @@ static void Y_IntermissionTokenDrawer(void) offs = 0; lowy = BASEVIDHEIGHT - 32 - 8; - temp = SHORT(tokenicon->height)/2; + temp = tokenicon->height / 2; em = 0; while (emeralds & (1 << em)) @@ -214,7 +212,7 @@ static void Y_IntermissionTokenDrawer(void) calc = (lowy - y)*2; if (calc > 0) - V_DrawCroppedPatch(32<<FRACBITS, y<<FRACBITS, FRACUNIT/2, 0, tokenicon, 0, 0, SHORT(tokenicon->width), calc); + V_DrawCroppedPatch(32<<FRACBITS, y<<FRACBITS, FRACUNIT/2, 0, tokenicon, 0, 0, tokenicon->width, calc); } // @@ -316,19 +314,6 @@ void Y_IntermissionDrawer(void) if (intertype == int_none || rendermode == render_none) return; - // Lactozilla: Renderer switching - if (needpatchrecache) - { - Y_CleanupData(); - safetorender = false; - } - - if (!safetorender) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - - if (!safetorender) - goto dontdrawbg; - if (useinterpic) V_DrawScaledPatch(0, 0, 0, interpic); else if (!usetile) @@ -366,7 +351,6 @@ void Y_IntermissionDrawer(void) if (!LUA_HudEnabled(hud_intermissiontally)) goto skiptallydrawer; -dontdrawbg: if (intertype == int_coop) { INT32 bonusy; @@ -416,22 +400,19 @@ dontdrawbg: bonusy = 150; // 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; + V_DrawScaledPatch(152, bonusy, 0, data.coop.ptotal); + V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.total); + bonusy -= (3*(tallnum[0]->height)/2) + 1; // Draw bonuses for (i = 3; i >= 0; --i) { - if (data.coop.bonuses[i].display && safetorender) + if (data.coop.bonuses[i].display) { V_DrawScaledPatch(152, bonusy, 0, data.coop.bonuspatches[i]); V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.bonuses[i].points); } - bonusy -= (3*SHORT(tallnum[0]->height)/2) + 1; + bonusy -= (3*(tallnum[0]->height)/2) + 1; } } else if (intertype == int_spec) @@ -655,8 +636,7 @@ dontdrawbg: char strtime[10]; // draw the header - if (safetorender) - V_DrawScaledPatch(112, 2, 0, data.match.result); + V_DrawScaledPatch(112, 2, 0, data.match.result); // draw the level name V_DrawCenteredString(BASEVIDWIDTH/2, 20, 0, data.match.levelstring); @@ -769,10 +749,10 @@ dontdrawbg: char name[MAXPLAYERNAME+1]; // Show the team flags and the team score at the top instead of "RESULTS" - V_DrawSmallScaledPatch(128 - SHORT(data.match.blueflag->width)/4, 2, 0, data.match.blueflag); + V_DrawSmallScaledPatch(128 - (data.match.blueflag->width / 4), 2, 0, data.match.blueflag); V_DrawCenteredString(128, 16, 0, va("%u", bluescore)); - V_DrawSmallScaledPatch(192 - SHORT(data.match.redflag->width)/4, 2, 0, data.match.redflag); + V_DrawSmallScaledPatch(192 - (data.match.redflag->width / 4), 2, 0, data.match.redflag); V_DrawCenteredString(192, 16, 0, va("%u", redscore)); // draw the level name @@ -1212,8 +1192,6 @@ void Y_StartIntermission(void) I_Error("endtic is dirty"); #endif - safetorender = true; - if (!multiplayer) { timer = 0; @@ -2060,19 +2038,13 @@ void Y_EndIntermission(void) usebuffer = false; } -#define UNLOAD(x) if (x) {Z_ChangeTag(x, PU_CACHE);} x = NULL; -#define CLEANUP(x) x = NULL; +#define UNLOAD(x) if (x) {Patch_Free(x);} x = NULL; // // Y_UnloadData // static void Y_UnloadData(void) { - // In hardware mode, don't Z_ChangeTag a pointer returned by W_CachePatchName(). - // It doesn't work and is unnecessary. - if (rendermode != render_soft) - return; - // unload the background patches UNLOAD(bgpatch); UNLOAD(bgtile); @@ -2112,45 +2084,3 @@ static void Y_UnloadData(void) break; } } - -static void Y_CleanupData(void) -{ - // unload the background patches - CLEANUP(bgpatch); - 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 2c7384c3da22fead194f365dc8fea0a4768949b9..ad64a3a07f04f01d40ac291cfa4e77f26bd37e88 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 "r_picformats.h" #include "i_system.h" // I_GetFreeMem #include "i_video.h" // rendermode @@ -495,36 +496,37 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag) } } -// ----------------- -// Utility functions -// ----------------- +/** Iterates through all memory for a given set of tags. + * + * \param lowtag The lowest tag to consider. + * \param hightag The highest tag to consider. + * \param iterfunc The iterator function. + */ +void Z_IterateTags(INT32 lowtag, INT32 hightag, boolean (*iterfunc)(void *)) +{ + memblock_t *block, *next; -// for renderer switching -boolean needpatchflush = false; -boolean needpatchrecache = false; + if (!iterfunc) + I_Error("Z_IterateTags: no iterator function was given"); -// flush all patches from memory -void Z_FlushCachedPatches(void) -{ - CONS_Debug(DBG_RENDER, "Z_FlushCachedPatches()...\n"); - 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); - Z_FreeTag(PU_HWRMODELTEXTURE_UNLOCKED); -} + for (block = head.next; block != &head; block = next) + { + next = block->next; // get link before possibly freeing -void Z_PreparePatchFlush(void) -{ - CONS_Debug(DBG_RENDER, "Z_PreparePatchFlush()...\n"); -#ifdef ROTSPRITE - R_FreeAllRotSprite(); -#endif + if (block->tag >= lowtag && block->tag <= hightag) + { + void *mem = (UINT8 *)block->hdr + sizeof *block->hdr; + boolean free = iterfunc(mem); + if (free) + Z_Free(mem); + } + } } +// ----------------- +// Utility functions +// ----------------- + // starting value of nextcleanup #define CLEANUPCOUNT 2000 @@ -793,14 +795,19 @@ static void Command_Memfree_f(void) Z_CheckHeap(-1); CONS_Printf("\x82%s", M_GetText("Memory Info\n")); - CONS_Printf(M_GetText("Total heap used : %7s KB\n"), sizeu1(Z_TotalUsage()>>10)); - CONS_Printf(M_GetText("Static : %7s KB\n"), sizeu1(Z_TagUsage(PU_STATIC)>>10)); - CONS_Printf(M_GetText("Static (sound) : %7s KB\n"), sizeu1(Z_TagUsage(PU_SOUND)>>10)); - CONS_Printf(M_GetText("Static (music) : %7s KB\n"), sizeu1(Z_TagUsage(PU_MUSIC)>>10)); - CONS_Printf(M_GetText("Locked cache : %7s KB\n"), sizeu1(Z_TagUsage(PU_CACHE)>>10)); - CONS_Printf(M_GetText("Level : %7s KB\n"), sizeu1(Z_TagUsage(PU_LEVEL)>>10)); - CONS_Printf(M_GetText("Special thinker : %7s KB\n"), sizeu1(Z_TagUsage(PU_LEVSPEC)>>10)); - CONS_Printf(M_GetText("All purgable : %7s KB\n"), + CONS_Printf(M_GetText("Total heap used : %7s KB\n"), sizeu1(Z_TotalUsage()>>10)); + CONS_Printf(M_GetText("Static : %7s KB\n"), sizeu1(Z_TagUsage(PU_STATIC)>>10)); + CONS_Printf(M_GetText("Static (sound) : %7s KB\n"), sizeu1(Z_TagUsage(PU_SOUND)>>10)); + CONS_Printf(M_GetText("Static (music) : %7s KB\n"), sizeu1(Z_TagUsage(PU_MUSIC)>>10)); + CONS_Printf(M_GetText("Patches : %7s KB\n"), sizeu1(Z_TagUsage(PU_PATCH)>>10)); + CONS_Printf(M_GetText("Patches (low priority) : %7s KB\n"), sizeu1(Z_TagUsage(PU_PATCH_LOWPRIORITY)>>10)); + CONS_Printf(M_GetText("Patches (rotated) : %7s KB\n"), sizeu1(Z_TagUsage(PU_PATCH_ROTATED)>>10)); + CONS_Printf(M_GetText("Sprites : %7s KB\n"), sizeu1(Z_TagUsage(PU_SPRITE)>>10)); + CONS_Printf(M_GetText("HUD graphics : %7s KB\n"), sizeu1(Z_TagUsage(PU_HUDGFX)>>10)); + CONS_Printf(M_GetText("Locked cache : %7s KB\n"), sizeu1(Z_TagUsage(PU_CACHE)>>10)); + CONS_Printf(M_GetText("Level : %7s KB\n"), sizeu1(Z_TagUsage(PU_LEVEL)>>10)); + CONS_Printf(M_GetText("Special thinker : %7s KB\n"), sizeu1(Z_TagUsage(PU_LEVSPEC)>>10)); + CONS_Printf(M_GetText("All purgable : %7s KB\n"), sizeu1(Z_TagsUsage(PU_PURGELEVEL, INT32_MAX)>>10)); #ifdef HWRENDER diff --git a/src/z_zone.h b/src/z_zone.h index 5cbcc6655bc24eb2208627f4cf57e31b48c88a1a..e80a45e7fb4f2ed6223868fc78d18649e75ab4ad 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -42,8 +42,13 @@ 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_PATCH = 14, // static entire execution time + PU_PATCH_LOWPRIORITY = 15, // lower priority patch, static until level exited + PU_PATCH_ROTATED = 16, // rotated patch, static until level exited or WAD added + PU_PATCH_DATA = 17, // patch data, lifetime depends on the patch that owns it + PU_SPRITE = 18, // sprite patch, static until WAD added + PU_HUDGFX = 19, // HUD patch, static until WAD added PU_HWRPATCHINFO = 21, // Hardware GLPatch_t struct for OpenGL texture cache PU_HWRPATCHCOLMIPMAP = 22, // Hardware GLMipmap_t struct colormap variation of patch @@ -63,7 +68,7 @@ enum PU_HWRCACHE_UNLOCKED = 102, // 'unlocked' PU_HWRCACHE memory: // 'second-level' cache for graphics // stored in hardware format and downloaded as needed - PU_HWRPATCHINFO_UNLOCKED = 103, // 'unlocked' PU_HWRPATCHINFO memory + PU_HWRPATCHINFO_UNLOCKED = 103, // 'unlocked' PU_HWRPATCHINFO memory PU_HWRMODELTEXTURE_UNLOCKED = 104, // 'unlocked' PU_HWRMODELTEXTURE memory }; @@ -107,6 +112,10 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb #define Z_FreeTag(tagnum) Z_FreeTags(tagnum, tagnum) void Z_FreeTags(INT32 lowtag, INT32 hightag); +// Iterate memory by tag +#define Z_IterateTag(tagnum, func) Z_IterateTags(tagnum, tagnum, func) +void Z_IterateTags(INT32 lowtag, INT32 hightag, boolean (*iterfunc)(void *)); + // // Utility functions // @@ -144,10 +153,4 @@ 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