diff --git a/docs/console.html b/docs/console.html index d5ca0a735..7fb5d4c8c 100644 --- a/docs/console.html +++ b/docs/console.html @@ -2361,6 +2361,11 @@ alias -creep "joy_speedmultiplier 1.0" of a music lump or file on disk (which need not have been specified with the -file parameter). +
changeskill skill
+
Changes the current skill of the game. The skill change will take + effect at the next map change. The skill must be a number. The default skill + levels range from 0 to 4 inclusive. +
chase
Turns the chasecom on and off. This command also works while watching demos, so you can bind it to a key and watch demos in the third @@ -3177,6 +3182,7 @@ alias -creep "joy_speedmultiplier 1.0" centerview
changemap
changemus
+ changeskill
chase
chase_dist
chase_height
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dafcb994e..0bf6b7103 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,6 +56,7 @@ if( WIN32 ) add_definitions( -D_WIN32 ) set( PROJECT_LIBRARIES + psapi wsock32 winmm dinput8 diff --git a/src/common/2d/v_2ddrawer.h b/src/common/2d/v_2ddrawer.h index 48b18496a..5a6111225 100644 --- a/src/common/2d/v_2ddrawer.h +++ b/src/common/2d/v_2ddrawer.h @@ -217,7 +217,7 @@ public: double originx, double originy, double scalex, double scaley, DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double lightlevel, uint32_t *indices, size_t indexcount); void AddPoly(FGameTexture* img, FVector4 *vt, size_t vtcount, const unsigned int *ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, const IntRect* clip); - void FillPolygon(int* rx1, int* ry1, int* xb1, int32_t npoints, int picnum, int palette, int shade, int props, const FVector2& xtex, const FVector2& ytex, const FVector2& otex, + void FillPolygon(int* rx1, int* ry1, int* xb1, int32_t npoints, int pic, int palette, int shade, int props, const FVector2& xtex, const FVector2& ytex, const FVector2& otex, int clipx1, int clipy1, int clipx2, int clipy2); void AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin = false, double flatscale = 1.0, PalEntry color = 0xffffffff, ERenderStyle rs = STYLE_Normal); diff --git a/src/common/2d/v_draw.cpp b/src/common/2d/v_draw.cpp index 7c1beb0c8..85ed31517 100644 --- a/src/common/2d/v_draw.cpp +++ b/src/common/2d/v_draw.cpp @@ -1786,12 +1786,12 @@ DEFINE_ACTION_FUNCTION(FCanvas, Dim) // //========================================================================== -void DrawBorder (F2DDrawer *drawer, FTextureID picnum, int x1, int y1, int x2, int y2) +void DrawBorder (F2DDrawer *drawer, FTextureID texid, int x1, int y1, int x2, int y2) { int filltype = (ui_screenborder_classic_scaling) ? -1 : 0; - if (picnum.isValid()) + if (texid.isValid()) { - drawer->AddFlatFill (x1, y1, x2, y2, TexMan.GetGameTexture(picnum, false), filltype); + drawer->AddFlatFill (x1, y1, x2, y2, TexMan.GetGameTexture(texid, false), filltype); } else { diff --git a/src/common/audio/music/i_music.cpp b/src/common/audio/music/i_music.cpp index 0bc858292..6b8580724 100644 --- a/src/common/audio/music/i_music.cpp +++ b/src/common/audio/music/i_music.cpp @@ -40,7 +40,6 @@ #include #include -#include "m_argv.h" #include "filesystem.h" #include "c_dispatch.h" @@ -218,13 +217,13 @@ static void SetupDMXGUS() // //========================================================================== -void I_InitMusic(void) +void I_InitMusic(int musicstate) { I_InitSoundFonts(); snd_musicvolume->Callback (); - nomusic = !!Args->CheckParm("-nomusic") || !!Args->CheckParm("-nosound"); + nomusic = musicstate; snd_mididevice->Callback(); diff --git a/src/common/audio/music/i_music.h b/src/common/audio/music/i_music.h index a6609eadb..aa2d48e62 100644 --- a/src/common/audio/music/i_music.h +++ b/src/common/audio/music/i_music.h @@ -34,27 +34,16 @@ #ifndef __I_MUSIC_H__ #define __I_MUSIC_H__ -#include "c_cvars.h" - -class FileReader; -struct FOptionValues; - // // MUSIC I/O // -void I_InitMusic (); -void I_BuildMIDIMenuList (FOptionValues *); +void I_InitMusic (int); // Volume. void I_SetRelativeVolume(float); void I_SetMusicVolume (double volume); -extern int nomusic; - -EXTERN_CVAR(Bool, mus_enabled) -EXTERN_CVAR(Float, snd_musicvolume) - inline float AmplitudeTodB(float amplitude) { diff --git a/src/common/audio/music/music.cpp b/src/common/audio/music/music.cpp index 610f0368f..6101dc1cc 100644 --- a/src/common/audio/music/music.cpp +++ b/src/common/audio/music/music.cpp @@ -53,9 +53,11 @@ #include "gain_analysis.h" #include "i_specialpaths.h" #include "configfile.h" +#include "c_cvars.h" // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- +extern int nomusic; extern float S_GetMusicVolume (const char *music); static void S_ActivatePlayList(bool goBack); @@ -81,6 +83,8 @@ static MusicCallbacks mus_cb = { nullptr, DefaultOpenMusic }; // PUBLIC DATA DEFINITIONS ------------------------------------------------- +EXTERN_CVAR(Bool, mus_enabled) +EXTERN_CVAR(Float, snd_musicvolume) EXTERN_CVAR(Int, snd_mididevice) EXTERN_CVAR(Float, mod_dumb_mastervolume) EXTERN_CVAR(Float, fluid_gain) diff --git a/src/common/audio/sound/i_soundinternal.h b/src/common/audio/sound/i_soundinternal.h index 1ef4178d4..52dabeea3 100644 --- a/src/common/audio/sound/i_soundinternal.h +++ b/src/common/audio/sound/i_soundinternal.h @@ -5,7 +5,6 @@ #include #include "vectors.h" -#include "tarray.h" #include "tflags.h" enum EChanFlag @@ -32,13 +31,12 @@ enum EChanFlag CHANF_LOCAL = 16384, // only plays locally for the calling actor CHANF_TRANSIENT = 32768, // Do not record in savegames - used for sounds that get restarted outside the sound system (e.g. ambients in SW and Blood) CHANF_FORCE = 65536, // Start, even if sound is paused. + CHANF_SINGULAR = 0x20000, // Only start if no sound of this name is already playing. }; typedef TFlags EChanFlags; DEFINE_TFLAGS_OPERATORS(EChanFlags) -class FileReader; - // For convenience, this structure matches FMOD_REVERB_PROPERTIES. // Since I can't very well #include system-specific stuff in the // main game files, I duplicate it here. @@ -77,14 +75,17 @@ struct REVERB_PROPERTIES unsigned int Flags; }; -#define REVERB_FLAGS_DECAYTIMESCALE 0x00000001 -#define REVERB_FLAGS_REFLECTIONSSCALE 0x00000002 -#define REVERB_FLAGS_REFLECTIONSDELAYSCALE 0x00000004 -#define REVERB_FLAGS_REVERBSCALE 0x00000008 -#define REVERB_FLAGS_REVERBDELAYSCALE 0x00000010 -#define REVERB_FLAGS_DECAYHFLIMIT 0x00000020 -#define REVERB_FLAGS_ECHOTIMESCALE 0x00000040 -#define REVERB_FLAGS_MODULATIONTIMESCALE 0x00000080 +enum EReverbFlags +{ + REVERB_FLAGS_DECAYTIMESCALE = 0x00000001, + REVERB_FLAGS_REFLECTIONSSCALE = 0x00000002, + REVERB_FLAGS_REFLECTIONSDELAYSCALE = 0x00000004, + REVERB_FLAGS_REVERBSCALE = 0x00000008, + REVERB_FLAGS_REVERBDELAYSCALE = 0x00000010, + REVERB_FLAGS_DECAYHFLIMIT = 0x00000020, + REVERB_FLAGS_ECHOTIMESCALE = 0x00000040, + REVERB_FLAGS_MODULATIONTIMESCALE = 0x00000080, +}; struct ReverbContainer { @@ -143,8 +144,6 @@ struct FISoundChannel EChanFlags ChanFlags; }; -class SoundStream; - void S_SetSoundPaused(int state); diff --git a/src/common/audio/sound/s_sound.cpp b/src/common/audio/sound/s_sound.cpp index f3b0fb412..2544d1f87 100644 --- a/src/common/audio/sound/s_sound.cpp +++ b/src/common/audio/sound/s_sound.cpp @@ -488,7 +488,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, } // If this is a singular sound, don't play it if it's already playing. - if (sfx->bSingular && CheckSingular(sound_id)) + if ((sfx->bSingular || (flags & CHANF_SINGULAR)) && CheckSingular(sound_id)) { chanflags |= CHANF_EVICTED; } diff --git a/src/common/audio/sound/s_soundinternal.h b/src/common/audio/sound/s_soundinternal.h index dae8a0ee2..782fbe325 100644 --- a/src/common/audio/sound/s_soundinternal.h +++ b/src/common/audio/sound/s_soundinternal.h @@ -90,6 +90,7 @@ constexpr FSoundID INVALID_SOUND = FSoundID::fromInt(-1); float DefPitchMax = 0.f; // Randomized range with stronger control over pitch itself. int16_t NearLimit = 4; // 0 means unlimited. + int16_t UserVal = 0; // repurpose this gap for something useful uint8_t PitchMask = 0; bool bRandomHeader = false; bool bLoadRAW = false; @@ -99,17 +100,16 @@ constexpr FSoundID INVALID_SOUND = FSoundID::fromInt(-1); bool bTentative = true; bool bExternal = false; - TArray UserData; - int RawRate = 0; // Sample rate to use when bLoadRAW is true int LoopStart = -1; // -1 means no specific loop defined int LoopEnd = -1; // -1 means no specific loop defined + float Attenuation = 1.f; // Multiplies the attenuation passed to S_Sound. FSoundID link = NO_LINK; constexpr static FSoundID NO_LINK = FSoundID::fromInt(-1); + TArray UserData; FRolloffInfo Rolloff{}; - float Attenuation = 1.f; // Multiplies the attenuation passed to S_Sound. }; diff --git a/src/common/console/c_commandbuffer.h b/src/common/console/c_commandbuffer.h index 179651c45..637027b27 100644 --- a/src/common/console/c_commandbuffer.h +++ b/src/common/console/c_commandbuffer.h @@ -1,3 +1,4 @@ +#pragma once #include #include "zstring.h" diff --git a/src/common/console/c_consolebuffer.h b/src/common/console/c_consolebuffer.h index 58bc0edea..8d4e235d5 100644 --- a/src/common/console/c_consolebuffer.h +++ b/src/common/console/c_consolebuffer.h @@ -32,6 +32,7 @@ **--------------------------------------------------------------------------- ** */ +#pragma once #include #include diff --git a/src/common/cutscenes/playmve.cpp b/src/common/cutscenes/playmve.cpp index 70b56b43a..3c49e9610 100644 --- a/src/common/cutscenes/playmve.cpp +++ b/src/common/cutscenes/playmve.cpp @@ -546,7 +546,7 @@ bool InterplayDecoder::Open(FileReader &fr_) int chunkType = LE_16(&chunkPreamble[2]); if (chunkType == CHUNK_VIDEO) bAudioEnabled = false; - else + else if (bAudioEnabled) { if (ProcessNextChunk() != CHUNK_INIT_AUDIO) { diff --git a/src/common/engine/namedef.h b/src/common/engine/namedef.h index d11cbffe3..800667c06 100644 --- a/src/common/engine/namedef.h +++ b/src/common/engine/namedef.h @@ -268,3 +268,4 @@ xx(BuiltinNameToClass) xx(BuiltinClassCast) xx(ScreenJobRunner) +xx(Action) diff --git a/src/common/engine/palettecontainer.cpp b/src/common/engine/palettecontainer.cpp index 9648f2528..800dc31c6 100644 --- a/src/common/engine/palettecontainer.cpp +++ b/src/common/engine/palettecontainer.cpp @@ -367,7 +367,7 @@ static bool IndexOutOfRange(const int start1, const int end1, const int start2, // //---------------------------------------------------------------------------- -bool FRemapTable::operator==(const FRemapTable& o) +bool FRemapTable::operator==(const FRemapTable& o) const { // Two translations are identical when they have the same amount of colors // and the palette values for both are identical. diff --git a/src/common/engine/palettecontainer.h b/src/common/engine/palettecontainer.h index e1d0befd3..a220873a6 100644 --- a/src/common/engine/palettecontainer.h +++ b/src/common/engine/palettecontainer.h @@ -19,7 +19,7 @@ struct FRemapTable FRemapTable(const FRemapTable& o) = default; FRemapTable& operator=(const FRemapTable& o) = default; - bool operator==(const FRemapTable& o); + bool operator==(const FRemapTable& o) const; void MakeIdentity(); bool IsIdentity() const; bool AddIndexRange(int start, int end, int pal1, int pal2); diff --git a/src/common/engine/sc_man_scanner.re b/src/common/engine/sc_man_scanner.re index 59c3c7712..b5cce6d09 100644 --- a/src/common/engine/sc_man_scanner.re +++ b/src/common/engine/sc_man_scanner.re @@ -220,6 +220,7 @@ std2: 'bright' { RET(StateOptions ? TK_Bright : TK_Identifier); } 'fast' { RET(StateOptions ? TK_Fast : TK_Identifier); } 'slow' { RET(StateOptions ? TK_Slow : TK_Identifier); } + 'ticadjust' { RET(StateOptions ? TK_NoDelay : TK_Identifier); } 'nodelay' { RET(StateOptions ? TK_NoDelay : TK_Identifier); } 'canraise' { RET(StateOptions ? TK_CanRaise : TK_Identifier); } 'offset' { RET(StateOptions ? TK_Offset : TK_Identifier); } diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h index 63bfb3529..93c7ef5a1 100644 --- a/src/common/engine/serializer.h +++ b/src/common/engine/serializer.h @@ -234,6 +234,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def); FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def); FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def); +FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &sid, struct ModelOverride *def); template >*/> FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) @@ -244,7 +245,6 @@ FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) return arc; } - template FSerializer &Serialize(FSerializer &arc, const char *key, TArray &value, TArray *def) { diff --git a/src/common/engine/serializer_internal.h b/src/common/engine/serializer_internal.h index 31cf76c1a..05b6dcad0 100644 --- a/src/common/engine/serializer_internal.h +++ b/src/common/engine/serializer_internal.h @@ -1,3 +1,4 @@ +#pragma once const char* UnicodeToString(const char* cc); const char* StringToUnicode(const char* cc, int size = -1); diff --git a/src/common/filesystem/ancientzip.h b/src/common/filesystem/ancientzip.h index 621505504..6241f775d 100644 --- a/src/common/filesystem/ancientzip.h +++ b/src/common/filesystem/ancientzip.h @@ -1,3 +1,4 @@ +#pragma once #include "files.h" #include "engineerrors.h" diff --git a/src/common/fonts/singlepicfont.cpp b/src/common/fonts/singlepicfont.cpp index 687602876..30fdf8711 100644 --- a/src/common/fonts/singlepicfont.cpp +++ b/src/common/fonts/singlepicfont.cpp @@ -65,21 +65,21 @@ protected: FSinglePicFont::FSinglePicFont(const char *picname) : FFont(-1) // Since lump is only needed for priority information we don't need to worry about this here. { - FTextureID picnum = TexMan.CheckForTexture (picname, ETextureType::Any); + FTextureID texid = TexMan.CheckForTexture (picname, ETextureType::Any); - if (!picnum.isValid()) + if (!texid.isValid()) { I_FatalError ("%s is not a font or texture", picname); } - auto pic = TexMan.GetGameTexture(picnum); + auto pic = TexMan.GetGameTexture(texid); FontName = picname; FontHeight = (int)pic->GetDisplayHeight(); SpaceWidth = (int)pic->GetDisplayWidth(); GlobalKerning = 0; FirstChar = LastChar = 'A'; - PicNum = picnum; + PicNum = texid; } //========================================================================== diff --git a/src/common/fonts/v_font.cpp b/src/common/fonts/v_font.cpp index f51813aeb..cb206a4ec 100644 --- a/src/common/fonts/v_font.cpp +++ b/src/common/fonts/v_font.cpp @@ -138,10 +138,10 @@ FFont *V_GetFont(const char *name, const char *fontlumpname) return font; } } - FTextureID picnum = TexMan.CheckForTexture (name, ETextureType::Any); - if (picnum.isValid()) + FTextureID texid = TexMan.CheckForTexture (name, ETextureType::Any); + if (texid.isValid()) { - auto tex = TexMan.GetGameTexture(picnum); + auto tex = TexMan.GetGameTexture(texid); if (tex && tex->GetSourceLump() >= folderfile) { FFont *CreateSinglePicFont(const char *name); diff --git a/src/common/menu/menudef.cpp b/src/common/menu/menudef.cpp index 4fbeeb0bb..e81bda2d2 100644 --- a/src/common/menu/menudef.cpp +++ b/src/common/menu/menudef.cpp @@ -1662,6 +1662,7 @@ static void InitMusicMenus() // Special menus will be created once all engine data is loaded // //============================================================================= +void I_BuildMIDIMenuList(FOptionValues*); void M_CreateMenus() { diff --git a/src/common/objects/dobjtype.cpp b/src/common/objects/dobjtype.cpp index b39c930f8..f9ccc4c77 100644 --- a/src/common/objects/dobjtype.cpp +++ b/src/common/objects/dobjtype.cpp @@ -231,6 +231,8 @@ void PClass::StaticInit () // //========================================================================== +void ClearServices(); + void PClass::StaticShutdown () { if (WP_NOCHANGE != nullptr) @@ -238,6 +240,7 @@ void PClass::StaticShutdown () delete WP_NOCHANGE; } + ClearServices(); // delete all variables containing pointers to script functions. for (auto p : FunctionPtrList) { diff --git a/src/common/platform/posix/cocoa/i_main.mm b/src/common/platform/posix/cocoa/i_main.mm index 3e257a5ce..8a9d96b07 100644 --- a/src/common/platform/posix/cocoa/i_main.mm +++ b/src/common/platform/posix/cocoa/i_main.mm @@ -151,21 +151,24 @@ void I_DetectOS() case 10: switch (version.minorVersion) { - case 12: name = "macOS Sierra"; break; - case 13: name = "macOS High Sierra"; break; - case 14: name = "macOS Mojave"; break; - case 15: name = "macOS Catalina"; break; - case 16: name = "macOS Big Sur"; break; + case 12: name = "Sierra"; break; + case 13: name = "High Sierra"; break; + case 14: name = "Mojave"; break; + case 15: name = "Catalina"; break; + case 16: name = "Big Sur"; break; } break; case 11: - name = "macOS Big Sur"; + name = "Big Sur"; break; case 12: - name = "macOS Monterey"; + name = "Monterey"; break; case 13: - name = "macOS Ventura"; + name = "Ventura"; + break; + case 14: + name = "Sonoma"; break; } @@ -186,7 +189,7 @@ void I_DetectOS() "Unknown"; #endif - Printf("%s running %s %d.%d.%d (%s) %s\n", model, name, + Printf("%s running macOS %s %d.%d.%d (%s) %s\n", model, name, int(version.majorVersion), int(version.minorVersion), int(version.patchVersion), release, architecture); } diff --git a/src/common/platform/posix/sdl/i_system.cpp b/src/common/platform/posix/sdl/i_system.cpp index e81c97f68..ab0c6bd7d 100644 --- a/src/common/platform/posix/sdl/i_system.cpp +++ b/src/common/platform/posix/sdl/i_system.cpp @@ -51,7 +51,6 @@ #include #include #include -#include "printf.h" #endif #include @@ -65,6 +64,7 @@ #include "c_cvars.h" #include "palutil.h" #include "st_start.h" +#include "printf.h" #ifndef NO_GTK @@ -408,7 +408,7 @@ FString I_GetFromClipboard (bool use_primary_selection) FString I_GetCWD() { - char* curdir = get_current_dir_name(); + char* curdir = getcwd(NULL,0); if (!curdir) { return ""; @@ -447,7 +447,7 @@ unsigned int I_MakeRNGSeed() void I_OpenShellFolder(const char* infolder) { - char* curdir = get_current_dir_name(); + char* curdir = getcwd(NULL,0); if (!chdir(infolder)) { diff --git a/src/common/platform/win32/i_mouse.cpp b/src/common/platform/win32/i_mouse.cpp index 908452916..37ee35709 100644 --- a/src/common/platform/win32/i_mouse.cpp +++ b/src/common/platform/win32/i_mouse.cpp @@ -189,6 +189,8 @@ CUSTOM_CVAR (Int, in_mouse, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) // //========================================================================== +static bool mouse_shown = true; + static void SetCursorState(bool visible) { CursorState = visible || !m_hidepointer; @@ -196,13 +198,19 @@ static void SetCursorState(bool visible) { if (CursorState) { - ShowCursor(1); - SetCursor((HCURSOR)(intptr_t)GetClassLongPtr(mainwindow.GetHandle(), GCLP_HCURSOR)); + if(!mouse_shown) + { + ShowCursor(true); + mouse_shown = true; + } } else { - ShowCursor(0); - SetCursor(NULL); + if(mouse_shown) + { + ShowCursor(false); + mouse_shown = false; + } } } } diff --git a/src/common/platform/win32/winres.h b/src/common/platform/win32/winres.h index 6d78230d8..a2b8711a6 100644 --- a/src/common/platform/win32/winres.h +++ b/src/common/platform/win32/winres.h @@ -10,6 +10,7 @@ // winres.h - Windows resource definitions // extracted from WINUSER.H and COMMCTRL.H +#pragma once #ifdef _AFX_MINREBUILD #pragma component(minrebuild, off) diff --git a/src/common/rendering/hwrenderer/data/hw_mesh.cpp b/src/common/rendering/hwrenderer/data/hw_mesh.cpp index 427620037..e061da43f 100644 --- a/src/common/rendering/hwrenderer/data/hw_mesh.cpp +++ b/src/common/rendering/hwrenderer/data/hw_mesh.cpp @@ -1,6 +1,7 @@ #include "hw_mesh.h" #include "v_video.h" +#include "cmdlib.h" #define USE_MESH_VERTEX_BUFFER diff --git a/src/common/rendering/vulkan/buffers/vk_rsbuffers.cpp b/src/common/rendering/vulkan/buffers/vk_rsbuffers.cpp index b24d18c7f..0d13983a2 100644 --- a/src/common/rendering/vulkan/buffers/vk_rsbuffers.cpp +++ b/src/common/rendering/vulkan/buffers/vk_rsbuffers.cpp @@ -26,6 +26,7 @@ #include "vulkan/buffers/vk_buffer.h" #include #include "flatvertices.h" +#include "cmdlib.h" VkRSBuffers::VkRSBuffers(VulkanRenderDevice* fb) { diff --git a/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp b/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp index 095dc3393..46ffea39a 100644 --- a/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp +++ b/src/common/rendering/vulkan/pipelines/vk_renderpass.cpp @@ -35,6 +35,7 @@ #include "hw_viewpointuniforms.h" #include "v_2ddrawer.h" #include "i_specialpaths.h" +#include "cmdlib.h" VkRenderPassManager::VkRenderPassManager(VulkanRenderDevice* fb) : fb(fb) { diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index 0fb297458..1fdf92b9b 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -64,7 +64,6 @@ FString JitCaptureStackTrace(int framesToSkip, bool includeNativeFrames, int maxFrames = -1); -EXTERN_CVAR(Bool, r_drawvoxels) EXTERN_CVAR(Int, gl_tonemap) EXTERN_CVAR(Int, screenblocks) EXTERN_CVAR(Bool, cl_capfps) diff --git a/src/common/scripting/frontend/zcc-parse.lemon b/src/common/scripting/frontend/zcc-parse.lemon index 1a9146f37..71385c582 100644 --- a/src/common/scripting/frontend/zcc-parse.lemon +++ b/src/common/scripting/frontend/zcc-parse.lemon @@ -272,6 +272,13 @@ dottable_id(X) ::= IDENTIFIER(A). id->Id = A.Name(); X = id; } +// this is needed for defining properties named 'action'. +dottable_id(X) ::= ACTION(A). +{ + NEW_AST_NODE(Identifier,id,A); + id->Id = NAME_Action; + X = id; +} dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). { NEW_AST_NODE(Identifier,id2,A); diff --git a/src/common/scripting/interface/vmnatives.cpp b/src/common/scripting/interface/vmnatives.cpp index 2c7df6fb7..54cc0d2a9 100644 --- a/src/common/scripting/interface/vmnatives.cpp +++ b/src/common/scripting/interface/vmnatives.cpp @@ -57,8 +57,8 @@ static ZSMap AllServices; -static void MarkServices() { - +static void MarkServices() +{ ZSMap::Iterator it(AllServices); ZSMap::Pair* pair; while (it.NextPair(pair)) @@ -82,6 +82,11 @@ void InitServices() GC::AddMarkerFunc(&MarkServices); } +void ClearServices() +{ + AllServices.Clear(); +} + //========================================================================== diff --git a/src/common/scripting/jit/jitintern.h b/src/common/scripting/jit/jitintern.h index aaf8d70a6..05dfd62df 100644 --- a/src/common/scripting/jit/jitintern.h +++ b/src/common/scripting/jit/jitintern.h @@ -1,4 +1,4 @@ - +#pragma once #include "jit.h" #include "types.h" diff --git a/src/common/scripting/vm/vm.h b/src/common/scripting/vm/vm.h index 3766e9d31..9529cf5c0 100644 --- a/src/common/scripting/vm/vm.h +++ b/src/common/scripting/vm/vm.h @@ -45,6 +45,7 @@ #include "memarena.h" #include "name.h" #include "scopebarrier.h" +#include class DObject; union VMOP; @@ -194,6 +195,12 @@ struct VMReturn *(void **)Location = val; } + void SetConstPointer(const void *val) + { + assert(RegType == REGT_POINTER); + *(const void **)Location = val; + } + void SetObject(DObject *val) { assert(RegType == REGT_POINTER); @@ -611,6 +618,8 @@ namespace template struct native_is_valid { static const bool value = true; static const bool retval = true; }; template<> struct native_is_valid { static const bool value = true; static const bool retval = true; }; template<> struct native_is_valid { static const bool value = true; static const bool retval = true; }; + // [RL0] this is disabled for now due to graf's concerns + // template<> struct native_is_valid { static const bool value = true; static const bool retval = true; static_assert(sizeof(FName) == sizeof(int)); static_assert(std::is_pod_v);}; template<> struct native_is_valid { static const bool value = true; static const bool retval = true; }; template<> struct native_is_valid { static const bool value = true; static const bool retval = true; }; template<> struct native_is_valid { static const bool value = true; static const bool retval = false;}; // Bool as return does not work! @@ -621,26 +630,7 @@ struct DirectNativeDesc { DirectNativeDesc() = default; - #define TP(n) typename P##n - #define VP(n) ValidateType() - template DirectNativeDesc(Ret(*func)()) : Ptr(reinterpret_cast(func)) { ValidateRet(); } - template DirectNativeDesc(Ret(*func)(P1)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); } - template DirectNativeDesc(Ret(*func)(P1,P2)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); } - template DirectNativeDesc(Ret(*func)(P1,P2,P3)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); VP(12); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); VP(12); VP(13); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); VP(12); VP(13), VP(14); } - template DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14)) : Ptr(reinterpret_cast(func)) { ValidateRet(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); VP(12); VP(13), VP(14), VP(15); } -#undef TP - #undef VP + template DirectNativeDesc(Ret(*func)(Params...)) : Ptr(reinterpret_cast(func)) { ValidateRet(); (ValidateType(), ...); } template void ValidateType() { static_assert(native_is_valid::value, "Argument type is not valid as a direct native parameter or return type"); } template void ValidateRet() { static_assert(native_is_valid::retval, "Return type is not valid as a direct native parameter or return type"); } @@ -759,6 +749,7 @@ struct AFuncDesc class AActor; #define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state); return 1; } return 0; } while(0) +#define ACTION_RETURN_CONST_POINTER(v) do { const void *state = v; if (numret > 0) { assert(ret != NULL); ret->SetConstPointer(state); return 1; } return 0; } while(0) #define ACTION_RETURN_POINTER(v) do { void *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state); return 1; } return 0; } while(0) #define ACTION_RETURN_OBJECT(v) do { auto state = v; if (numret > 0) { assert(ret != NULL); ret->SetObject(state); return 1; } return 0; } while(0) #define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0) diff --git a/src/common/textures/animlib.h b/src/common/textures/animlib.h index 23d0d89da..661f00fb2 100644 --- a/src/common/textures/animlib.h +++ b/src/common/textures/animlib.h @@ -24,6 +24,7 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au) */ //------------------------------------------------------------------------- +#pragma once #include ///////////////////////////////////////////////////////////////////////////// diff --git a/src/common/textures/hires/hqnx_asm/hqnx_asm_Image.h b/src/common/textures/hires/hqnx_asm/hqnx_asm_Image.h index 918b904fe..6e2a93108 100644 --- a/src/common/textures/hires/hqnx_asm/hqnx_asm_Image.h +++ b/src/common/textures/hires/hqnx_asm/hqnx_asm_Image.h @@ -19,6 +19,7 @@ //#ifdef WIN32 //#define DLL __declspec(dllexport) //#else +#pragma once #define DLL //#endif diff --git a/src/common/textures/textureid.h b/src/common/textures/textureid.h index e30b4e86a..c441cb9d5 100644 --- a/src/common/textures/textureid.h +++ b/src/common/textures/textureid.h @@ -45,7 +45,7 @@ public: bool operator > (FTextureID other) const { return texnum > other.texnum; } protected: - FTextureID(int num) { texnum = num; } + constexpr FTextureID(int num) : texnum(num) { } private: int texnum; }; @@ -53,13 +53,13 @@ private: class FNullTextureID : public FTextureID { public: - FNullTextureID() : FTextureID(0) {} + constexpr FNullTextureID() : FTextureID(0) {} }; // This is for the script interface which needs to do casts from int to texture. class FSetTextureID : public FTextureID { public: - FSetTextureID(int v) : FTextureID(v) {} + constexpr FSetTextureID(int v) : FTextureID(v) {} }; diff --git a/src/common/textures/texturemanager.cpp b/src/common/textures/texturemanager.cpp index 94aa40de1..988498408 100644 --- a/src/common/textures/texturemanager.cpp +++ b/src/common/textures/texturemanager.cpp @@ -498,9 +498,9 @@ FTextureID FTextureManager::CreateTexture (int lumpnum, ETextureType usetype) // //========================================================================== -void FTextureManager::ReplaceTexture (FTextureID picnum, FGameTexture *newtexture, bool free) +void FTextureManager::ReplaceTexture (FTextureID texid, FGameTexture *newtexture, bool free) { - int index = picnum.GetIndex(); + int index = texid.GetIndex(); if (unsigned(index) >= Textures.Size()) return; diff --git a/src/common/textures/texturemanager.h b/src/common/textures/texturemanager.h index 575e838ea..3f80514f3 100644 --- a/src/common/textures/texturemanager.h +++ b/src/common/textures/texturemanager.h @@ -137,7 +137,7 @@ public: void AddTextures(void (*progressFunc_)(), void (*checkForHacks)(BuildInfo&), void (*customtexturehandler)() = nullptr); void DeleteAll(); - void ReplaceTexture (FTextureID picnum, FGameTexture *newtexture, bool free); + void ReplaceTexture (FTextureID texid, FGameTexture *newtexture, bool free); int NumTextures () const { return (int)Textures.Size(); } diff --git a/src/common/textures/v_collection.cpp b/src/common/textures/v_collection.cpp index 2b51885bf..975287680 100644 --- a/src/common/textures/v_collection.cpp +++ b/src/common/textures/v_collection.cpp @@ -62,8 +62,8 @@ void FImageCollection::Add (const char **patchNames, int numPatches, ETextureTyp for (int i = 0; i < numPatches; ++i) { - FTextureID picnum = TexMan.CheckForTexture(patchNames[i], namespc); - ImageMap[OldCount + i] = picnum; + FTextureID texid = TexMan.CheckForTexture(patchNames[i], namespc); + ImageMap[OldCount + i] = texid; } } diff --git a/src/common/utility/files.h b/src/common/utility/files.h index 66fa9a354..24d66e1d7 100644 --- a/src/common/utility/files.h +++ b/src/common/utility/files.h @@ -184,7 +184,7 @@ public: return mReader->Seek((long)offset, origin); } - Size Read(void *buffer, Size len) + Size Read(void *buffer, Size len) const { return mReader->Read(buffer, (long)len); } diff --git a/src/common/utility/tarray.h b/src/common/utility/tarray.h index 29d62289c..3d49f1868 100644 --- a/src/common/utility/tarray.h +++ b/src/common/utility/tarray.h @@ -54,6 +54,7 @@ #include #include #include +#include #if !defined(_WIN32) #include // for intptr_t @@ -327,9 +328,10 @@ public: } // returns address of first element - T *Data() const + T *Data(size_t index = 0) const { - return &Array[0]; + assert(index <= Count); + return &Array[index]; } unsigned IndexOf(const T& elem) const @@ -419,6 +421,26 @@ public: return start; } + unsigned AppendFill(const T& val, unsigned append_count) + { + unsigned start = Count; + + Grow(append_count); + Count += append_count; + if constexpr (std::is_trivially_copyable::value) + { + std::fill(Array + start, Array + Count, val); + } + else + { + for (unsigned i = 0; i < append_count; i++) + { + new(&Array[start + i]) T(val); + } + } + return start; + } + bool Pop () { if (Count > 0) diff --git a/src/common/utility/vectors.h b/src/common/utility/vectors.h index f392f561f..ea5cb5250 100644 --- a/src/common/utility/vectors.h +++ b/src/common/utility/vectors.h @@ -44,23 +44,32 @@ #include #include #include + +// this is needed to properly normalize angles. We cannot do that with compiler provided conversions because they differ too much #include "xs_Float.h" -#include "math/cmath.h" -#include "basics.h" -#include "cmdlib.h" - - -#define EQUAL_EPSILON (1/65536.) // make this a local inline function to avoid any dependencies on other headers and not pollute the global namespace namespace pi { inline constexpr double pi() { return 3.14159265358979323846; } - inline constexpr double pif() { return 3.14159265358979323846f; } + inline constexpr float pif() { return 3.14159265358979323846f; } } +// optionally use reliable math routines if reproducability across hardware is important., but let this still compile without them. +#if __has_include("math/cmath.h") +#include "math/cmath.h" +#else +double g_cosdeg(double v) { return cos(v * (pi::pi() / 180.)); } +double g_sindeg(double v) { return sin(v * (pi::pi() / 180.)); } +double g_cos(double v) { return cos(v); } +double g_sin(double v) { return sin(v); } +double g_sqrt(double v) { return sqrt(v); } +double g_atan2(double v, double w) { return atan2(v, w); } +#endif +#define EQUAL_EPSILON (1/65536.) + template struct TVector3; template struct TRotator; template struct TAngle; @@ -1450,8 +1459,13 @@ public: double Tan() const { + // use an optimized approach if we have a sine table. If not just call the CRT's tan function. +#if __has_include("math/cmath.h") const auto bam = BAMs(); return g_sinbam(bam) / g_cosbam(bam); +#else + return vec_t(tan(Radians())); +#endif } // This is for calculating vertical velocity. For high pitches the tangent will become too large to be useful. @@ -1460,9 +1474,11 @@ public: return clamp(Tan(), -max, max); } + // returns sign of the NORMALIZED angle. int Sgn() const { - return ::Sgn(int(BAMs())); + auto val = int(BAMs()); + return (val > 0) - (val < 0); } }; diff --git a/src/common/utility/weightedlist.h b/src/common/utility/weightedlist.h index cd6a4ba0e..fb956a462 100644 --- a/src/common/utility/weightedlist.h +++ b/src/common/utility/weightedlist.h @@ -31,6 +31,7 @@ **--------------------------------------------------------------------------- ** */ +#pragma once #include #include diff --git a/src/console/c_cmds.cpp b/src/console/c_cmds.cpp index 011f16140..2b77bfeed 100644 --- a/src/console/c_cmds.cpp +++ b/src/console/c_cmds.cpp @@ -408,6 +408,39 @@ CCMD (changemap) } } +CCMD (changeskill) +{ + if (!players[consoleplayer].mo || !usergame) + { + Printf ("Use the skill command when not in a game.\n"); + return; + } + + if (!players[consoleplayer].settings_controller && netgame) + { + Printf ("Only setting controllers can change the skill.\n"); + return; + } + + if (argv.argc() == 2) + { + int skill = atoi(argv[1]); + if ((unsigned)skill >= AllSkills.Size()) + { + Printf ("Skill %d is out of range.\n", skill); + } + else + { + NextSkill = skill; + Printf ("Skill %d will take effect on the next map.\n", skill); + } + } + else + { + Printf ("Usage: changeskill \n"); + } +} + CCMD (give) { if (CheckCheatmode () || argv.argc() < 2) diff --git a/src/d_defcvars.h b/src/d_defcvars.h index 73f110c70..8bf3d7c18 100644 --- a/src/d_defcvars.h +++ b/src/d_defcvars.h @@ -19,6 +19,7 @@ // defcvars loader split from d_main.cpp // //----------------------------------------------------------------------------- +#pragma once #define SHOULD_BLACKLIST(name) \ if (#name[0]==CurrentFindCVar[0]) \ diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 431c37813..4266b75a7 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -148,6 +148,7 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize, else if(sc.Compare("Extended")) iwad->flags |= GI_MENUHACK_EXTENDED; else if(sc.Compare("Shorttex")) iwad->flags |= GI_COMPATSHORTTEX; else if(sc.Compare("Stairs")) iwad->flags |= GI_COMPATSTAIRS; + else if (sc.Compare("nosectionmerge")) iwad->flags |= GI_NOSECTIONMERGE; else sc.ScriptError(NULL); } while (sc.CheckString(",")); diff --git a/src/d_main.cpp b/src/d_main.cpp index ae9608ad1..77cfa7d3d 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -625,7 +625,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) COMPATF_TRACE | COMPATF_MISSILECLIP | COMPATF_SOUNDTARGET | COMPATF_NO_PASSMOBJ | COMPATF_LIMITPAIN | COMPATF_DEHHEALTH | COMPATF_INVISIBILITY | COMPATF_CROSSDROPOFF | COMPATF_VILEGHOSTS | COMPATF_HITSCAN | COMPATF_WALLRUN | COMPATF_NOTOSSDROPS | COMPATF_LIGHT | COMPATF_MASKEDMIDTEX; - w = COMPATF2_BADANGLES | COMPATF2_FLOORMOVE | COMPATF2_POINTONLINE | COMPATF2_EXPLODE2 | COMPATF2_NOMBF21; + w = COMPATF2_BADANGLES | COMPATF2_FLOORMOVE | COMPATF2_POINTONLINE | COMPATF2_EXPLODE2 | COMPATF2_NOMBF21 | COMPATF2_VOODOO_ZOMBIES; break; case 3: // Boom compat mode diff --git a/src/doomdef.h b/src/doomdef.h index 8dd96ea70..bdeb81611 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -233,6 +233,7 @@ enum : unsigned int COMPATF2_AVOID_HAZARDS = 1 << 12, // another MBF thing. COMPATF2_STAYONLIFT = 1 << 13, // yet another MBF thing. COMPATF2_NOMBF21 = 1 << 14, // disable MBF21 features that may clash with certain maps + COMPATF2_VOODOO_ZOMBIES = 1 << 15, // [RL0] allow playerinfo, playerpawn, and voodoo health to all be different, and skip killing the player's mobj if a voodoo doll dies to allow voodoo zombies }; diff --git a/src/g_pch.h b/src/g_pch.h index bad3eda56..cf3dfdbd5 100644 --- a/src/g_pch.h +++ b/src/g_pch.h @@ -1,3 +1,4 @@ +#pragma once #include #include #include diff --git a/src/g_pch2.h b/src/g_pch2.h index 4cd69197e..f5871488a 100644 --- a/src/g_pch2.h +++ b/src/g_pch2.h @@ -1,4 +1,5 @@ // This is separate because the files being compiled with it use different compiler settings which may affect how the header is compiled +#pragma once #include #include #include diff --git a/src/gamedata/doomfont.h b/src/gamedata/doomfont.h index 9b44a480f..b9d14db7d 100644 --- a/src/gamedata/doomfont.h +++ b/src/gamedata/doomfont.h @@ -1,6 +1,7 @@ // // Globally visible constants. // +#pragma once #define HU_FONTSTART uint8_t('!') // the first font characters #define HU_FONTEND uint8_t('\377') // the last font characters diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index 6d7a7f512..59f37bc52 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -1847,6 +1847,7 @@ MapFlagHandlers[] = { "compat_avoidhazards", MITYPE_COMPATFLAG, 0, COMPATF2_AVOID_HAZARDS }, { "compat_stayonlift", MITYPE_COMPATFLAG, 0, COMPATF2_STAYONLIFT }, { "compat_nombf21", MITYPE_COMPATFLAG, 0, COMPATF2_NOMBF21 }, + { "compat_voodoozombies", MITYPE_COMPATFLAG, 0, COMPATF2_VOODOO_ZOMBIES }, { "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, diff --git a/src/gamedata/gi.h b/src/gamedata/gi.h index 5f11ecfa5..5e713628d 100644 --- a/src/gamedata/gi.h +++ b/src/gamedata/gi.h @@ -51,6 +51,7 @@ enum GI_COMPATPOLY1 = 0x00000040, // Hexen's MAP36 needs old polyobject drawing GI_COMPATPOLY2 = 0x00000080, // so does HEXDD's MAP47 GI_IGNORETITLEPATCHES = 0x00000200, // Ignore the map name graphics when not runnning in English language + GI_NOSECTIONMERGE = 0x00000400, // For the original id IWADs: avoid merging sections due to how idbsp created its sectors. }; #include "gametype.h" diff --git a/src/gamedata/umapinfo.cpp b/src/gamedata/umapinfo.cpp index d6b391039..006e4629a 100644 --- a/src/gamedata/umapinfo.cpp +++ b/src/gamedata/umapinfo.cpp @@ -42,6 +42,7 @@ struct UMapEntry FString InterText; FString InterTextSecret; TArray BossActions; + bool BossCleared = false; char levelpic[9] = ""; char nextmap[9] = ""; @@ -268,6 +269,7 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape) // mark level free of boss actions classnum = special = tag = -1; mape->BossActions.Clear(); + mape->BossCleared = true; } else { @@ -446,11 +448,12 @@ void CommitUMapinfo(level_info_t *defaultinfo) levelinfo->InterMusic = map.intermusic; levelinfo->intermusicorder = 0; } - if (map.BossActions.Size() > 0) + if (map.BossActions.Size() > 0 || map.BossCleared) { // Setting a boss action will deactivate the flag based monster actions. levelinfo->specialactions = std::move(map.BossActions); levelinfo->flags &= ~(LEVEL_BRUISERSPECIAL | LEVEL_CYBORGSPECIAL | LEVEL_SPIDERSPECIAL | LEVEL_MAP07SPECIAL | LEVEL_MINOTAURSPECIAL | LEVEL_HEADSPECIAL | LEVEL_SORCERER2SPECIAL | LEVEL_SPECACTIONSMASK | LEVEL_SPECKILLMONSTERS); + levelinfo->flags3 &= ~(LEVEL3_E1M8SPECIAL | LEVEL3_E2M8SPECIAL | LEVEL3_E3M8SPECIAL | LEVEL3_E4M8SPECIAL | LEVEL3_E4M6SPECIAL); } const int exflags = FExitText::DEF_TEXT | FExitText::DEF_BACKDROP | FExitText::DEF_MUSIC; diff --git a/src/maploader/compatibility.cpp b/src/maploader/compatibility.cpp index a9d9ca0e5..f85d89b19 100644 --- a/src/maploader/compatibility.cpp +++ b/src/maploader/compatibility.cpp @@ -171,6 +171,7 @@ static FCompatOption Options[] = { "railing", COMPATF2_RAILING, SLOT_COMPAT2 }, { "scriptwait", COMPATF2_SCRIPTWAIT, SLOT_COMPAT2 }, { "nombf21", COMPATF2_NOMBF21, SLOT_COMPAT2 }, + { "voodoozombies", COMPATF2_VOODOO_ZOMBIES, SLOT_COMPAT2 }, { NULL, 0, 0 } }; @@ -291,13 +292,19 @@ FName MapLoader::CheckCompatibility(MapData *map) Level->ib_compatflags = 0; // When playing Doom IWAD levels force BCOMPATF_NOSECTIONMERGE, COMPAT_SHORTTEX and COMPATF_LIGHT. - // I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt. BCOMPATF_NOSECTIONMERGE is mainly for MAP18's sector 0 + // I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt. // TNT's MAP31 also needs COMPATF_STAIRINDEX but that only gets activated for TNT.WAD. - if (fileSystem.GetFileContainer(map->lumpnum) == fileSystem.GetIwadNum() && (gameinfo.flags & GI_COMPATSHORTTEX) && Level->maptype == MAPTYPE_DOOM) + if (fileSystem.GetFileContainer(map->lumpnum) == fileSystem.GetIwadNum()) { - Level->ii_compatflags = COMPATF_SHORTTEX|COMPATF_LIGHT; - Level->ib_compatflags = BCOMPATF_NOSECTIONMERGE; - if (gameinfo.flags & GI_COMPATSTAIRS) Level->ii_compatflags |= COMPATF_STAIRINDEX; + if ((gameinfo.flags & GI_COMPATSHORTTEX) && Level->maptype == MAPTYPE_DOOM) + { + Level->ii_compatflags = COMPATF_SHORTTEX | COMPATF_LIGHT; + if (gameinfo.flags & GI_COMPATSTAIRS) Level->ii_compatflags |= COMPATF_STAIRINDEX; + } + if (gameinfo.flags & GI_NOSECTIONMERGE) + { + Level->ib_compatflags |= BCOMPATF_NOSECTIONMERGE; + } } map->GetChecksum(md5.Bytes); diff --git a/src/playsim/actor.h b/src/playsim/actor.h index fa78ca84a..c89a6ec4e 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -677,20 +677,26 @@ enum EViewPosFlags // [MC] Flags for SetViewPos. VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position. }; +struct ModelOverride +{ + int modelID; + TArray surfaceSkinIDs; +}; + class DActorModelData : public DObject { DECLARE_CLASS(DActorModelData, DObject); public: - FName modelDef; - bool hasModel; - TArray modelIDs; - TArray skinIDs; - TArray surfaceSkinIDs; - TArray animationIDs; - TArray modelFrameGenerators; + FName modelDef; + bool hasModel; + TArray models; + TArray skinIDs; + TArray animationIDs; + TArray modelFrameGenerators; DActorModelData() = default; virtual void Serialize(FSerializer& arc) override; + virtual void OnDestroy() override; }; class DViewPosition : public DObject diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 157ef9336..2d9e488a1 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -5107,7 +5107,212 @@ enum ChangeModelFlags CMDL_USESURFACESKIN = 1 << 2, }; -DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel) +void ChangeModelNative( + AActor * self, + AActor * invoker, + FStateParamInfo * stateinfo, + int i_modeldef, + int i_modelindex, + const FString &p_modelpath, + int i_model, + int i_skinindex, + const FString &p_skinpath, + int i_skin, + int flags, + int generatorindex, + int i_animationindex, + const FString &p_animationpath, + int i_animation +) { + if(!self) ThrowAbortException(X_READ_NIL, "In function parameter self"); + + FName modeldef { ENamedName(i_modeldef) }; + FName model { ENamedName(i_model) }; + FName skin { ENamedName(i_skin) }; + FName animation { ENamedName(i_animation) }; + + if (modeldef != NAME_None && PClass::FindClass(modeldef.GetChars()) == nullptr) + { + Printf("Attempt to pass invalid modeldef name %s in %s.", modeldef.GetChars(), self->GetCharacterName()); + return; + } + + unsigned modelindex = i_modelindex < 0 ? 0 : i_modelindex; + unsigned skinindex = i_skinindex < 0 ? 0 : i_skinindex; + unsigned animationindex = i_animationindex < 0 ? 0 : i_animationindex; + + AActor* mobj = (ACTION_CALL_FROM_PSPRITE() && (flags & CMDL_WEAPONTOPLAYER)) || ACTION_CALL_FROM_INVENTORY() ? self : invoker; + + FString modelpath = p_modelpath; + FString skinpath = p_skinpath; + FString animationpath = p_animationpath; + + if (modelpath.Len() != 0 && modelpath[(int)modelpath.Len() - 1] != '/') modelpath += '/'; + if (skinpath.Len() != 0 && skinpath[(int)skinpath.Len() - 1] != '/') skinpath += '/'; + if (animationpath.Len() != 0 && animationpath[(int)animationpath.Len() - 1] != '/') animationpath += '/'; + + if (mobj->modelData == nullptr) + { + auto ptr = Create(); + + ptr->hasModel = mobj->hasmodel; + ptr->modelDef = NAME_None; + + mobj->modelData = ptr; + mobj->hasmodel = true; + GC::WriteBarrier(mobj, ptr); + }; + + int queryModel = !(flags & CMDL_HIDEMODEL) ? model != NAME_None ? FindModel(modelpath.GetChars(), model.GetChars()) : -1 : -2; + int queryAnimation = animation != NAME_None ? FindModel(animationpath.GetChars(), animation.GetChars()) : -1; + + mobj->modelData->modelDef = modeldef; + + assert(mobj->modelData->models.Size() == mobj->modelData->modelFrameGenerators.Size()); + + if(mobj->modelData->models.Size() < modelindex) + { + mobj->modelData->models.AppendFill({-1, {}}, modelindex - mobj->modelData->models.Size()); + mobj->modelData->modelFrameGenerators.AppendFill(-1, modelindex - mobj->modelData->modelFrameGenerators.Size()); + } + + if(mobj->modelData->animationIDs.Size() < animationindex) + { + mobj->modelData->animationIDs.AppendFill(-1, animationindex - mobj->modelData->animationIDs.Size()); + } + + auto skindata = skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID(); + + if(mobj->modelData->models.Size() == modelindex) + { + + if(flags & CMDL_USESURFACESKIN && skinindex >= 0) + { + TArray surfaceSkins; + if(skinindex > 0) + { + surfaceSkins.AppendFill(FNullTextureID(), skinindex); + } + surfaceSkins.Push(skindata); + mobj->modelData->models.Push({queryModel, std::move(surfaceSkins)}); + mobj->modelData->modelFrameGenerators.Push(generatorindex); + } + else + { + mobj->modelData->models.Push({queryModel, {}}); + mobj->modelData->modelFrameGenerators.Push(generatorindex); + } + } + else + { + if(flags & CMDL_USESURFACESKIN && skinindex >= 0) + { + if(skinindex > mobj->modelData->models[modelindex].surfaceSkinIDs.Size()) + { + mobj->modelData->models[modelindex].surfaceSkinIDs.AppendFill(FNullTextureID(), skinindex - mobj->modelData->models[modelindex].surfaceSkinIDs.Size()); + } + + if(skinindex == mobj->modelData->models[modelindex].surfaceSkinIDs.Size()) + { + mobj->modelData->models[modelindex].surfaceSkinIDs.Push(skindata); + } + else + { + mobj->modelData->models[modelindex].surfaceSkinIDs[skinindex] = skindata; + } + } + if(queryModel != -1) mobj->modelData->models[modelindex].modelID = queryModel; + if(generatorindex != -1) mobj->modelData->modelFrameGenerators[modelindex] = generatorindex; + } + + if(mobj->modelData->animationIDs.Size() == animationindex) + { + mobj->modelData->animationIDs.Push(queryAnimation); + } + else + { + mobj->modelData->animationIDs[animationindex] = queryAnimation; + } + + if (!(flags & CMDL_USESURFACESKIN)) + { + if(mobj->modelData->skinIDs.Size() < skinindex) + { + mobj->modelData->skinIDs.AppendFill(FNullTextureID(), skinindex - mobj->modelData->skinIDs.Size()); + } + + if(mobj->modelData->skinIDs.Size() == skinindex) + { + mobj->modelData->skinIDs.Push(skindata); + } + else + { + mobj->modelData->skinIDs[skinindex] = skindata; + } + } + + //[SM] - We need to serialize file paths and model names so that they are pushed on loading save files. Likewise, let's not include models that were already parsed when initialized. + if (queryModel >= 0) + { + FString fullName; + fullName.Format("%s%s", modelpath.GetChars(), model.GetChars()); + bool found = false; + + for (auto &m : savedModelFiles) + { + if(m.CompareNoCase(fullName) == 0) + { + found = true; + break; + } + } + if(!found) for (auto &m : Models) + { + if (m->mFileName.CompareNoCase(fullName) == 0) + { + found = true; + break; + } + } + if(!found) savedModelFiles.Push(fullName); + } + //Same for animations + if (queryAnimation >= 0) + { + FString fullName; + fullName.Format("%s%s", animationpath.GetChars(), animation.GetChars()); + bool found = false; + + for (auto &m : savedModelFiles) + { + if(m.CompareNoCase(fullName) == 0) + { + found = true; + break; + } + } + if(!found) for (auto &m : Models) + { + if (m->mFileName.CompareNoCase(fullName) == 0) + { + found = true; + break; + } + } + if(!found) savedModelFiles.Push(fullName); + } + + if (mobj->modelData->models.Size() == 0 && mobj->modelData->modelFrameGenerators.Size() == 0 && mobj->modelData->skinIDs.Size() == 0 && mobj->modelData->animationIDs.Size() == 0 && modeldef == NAME_None) + { + mobj->hasmodel = mobj->modelData->hasModel; + mobj->modelData->Destroy(); + mobj->modelData = nullptr; + } + + return; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_ChangeModel, ChangeModelNative) { PARAM_ACTION_PROLOGUE(AActor); PARAM_NAME(modeldef); @@ -5122,141 +5327,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel) PARAM_INT(animationindex); PARAM_STRING_VAL(animationpath); PARAM_NAME(animation); - - if (self == nullptr) - ACTION_RETURN_BOOL(false); - else if (modeldef != NAME_None && PClass::FindClass(modeldef.GetChars()) == nullptr) - { - Printf("Attempt to pass invalid modeldef name %s in %s.", modeldef.GetChars(), self->GetCharacterName()); - ACTION_RETURN_BOOL(false); - } - else if (modelindex < 0) - { - Printf("Attempt to pass invalid model index %d in %s, index must be non-negative.", modelindex, self->GetCharacterName()); - ACTION_RETURN_BOOL(false); - } - else if (skinindex < 0) - { - Printf("Attempt to pass invalid skin index %d in %s, index must be non-negative.", skinindex, self->GetCharacterName()); - ACTION_RETURN_BOOL(false); - } - else if (animationindex < 0) - { - Printf("Attempt to pass invalid animation index %d in %s, index must be non-negative.", animationindex, self->GetCharacterName()); - ACTION_RETURN_BOOL(false); - } - - AActor* mobj = (ACTION_CALL_FROM_PSPRITE() && (flags & CMDL_WEAPONTOPLAYER)) || ACTION_CALL_FROM_INVENTORY() ? self : stateowner; - - if (modelpath[(int)modelpath.Len() - 1] != '/') modelpath += '/'; - if (skinpath[(int)skinpath.Len() - 1] != '/') skinpath += '/'; - if (animationpath[(int)animationpath.Len() - 1] != '/') animationpath += '/'; - - if (mobj->modelData == nullptr) - { - auto ptr = Create(); - ptr->hasModel = mobj->hasmodel ? 1 : 0; - ptr->modelIDs = *new TArray(); - ptr->skinIDs = *new TArray(); - ptr->surfaceSkinIDs = *new TArray(); - ptr->animationIDs = *new TArray(); - ptr->modelFrameGenerators = *new TArray(); - ptr->modelDef = NAME_None; - mobj->modelData = ptr; - mobj->hasmodel = 1; - GC::WriteBarrier(mobj, ptr); - } - - int maxModels = mobj->modelData->modelIDs.Size(); - int maxSkins = mobj->modelData->skinIDs.Size(); - int maxSurfaceSkins = mobj->modelData->surfaceSkinIDs.Size(); - int maxAnimations = mobj->modelData->animationIDs.Size(); - int maxGenerators = mobj->modelData->modelFrameGenerators.Size(); - - int skinPosition = skinindex + modelindex * MD3_MAX_SURFACES; - - int queryModel = !(flags & CMDL_HIDEMODEL) ? model != NAME_None ? FindModel(modelpath.GetChars(), model.GetChars()) : -1 : -2; - int queryAnimation = animation != NAME_None ? FindModel(animationpath.GetChars(), animation.GetChars()) : -1; - - //[SM] - Let's clear out any potential entries at the specified indices - mobj->modelData->modelDef = modeldef; - if(maxModels > modelindex) mobj->modelData->modelIDs.Pop(mobj->modelData->modelIDs[modelindex]); - if(maxAnimations > animationindex) mobj->modelData->animationIDs.Pop(mobj->modelData->animationIDs[animationindex]); - if(maxGenerators > modelindex) mobj->modelData->modelFrameGenerators.Pop(mobj->modelData->modelFrameGenerators[modelindex]); - - if (flags & CMDL_USESURFACESKIN) - { - if (maxSurfaceSkins > skinPosition) - mobj->modelData->surfaceSkinIDs.Delete(skinPosition); //[SM] - It seems the only way to make sure this does what it's told is from Delete, not Pop - } - else - { - if (maxSkins > skinindex) - mobj->modelData->skinIDs.Pop(mobj->modelData->skinIDs[skinindex]); - } - - //[SM] - We need to fill up any holes this new index will make so that it doesn't leave behind any undefined behavior - while ((int)mobj->modelData->modelIDs.Size() < modelindex) mobj->modelData->modelIDs.Push(-1); - while ((int)mobj->modelData->modelFrameGenerators.Size() < modelindex) mobj->modelData->modelFrameGenerators.Push(-1); - while ((int)mobj->modelData->animationIDs.Size() < modelindex) mobj->modelData->animationIDs.Push(-1); - if (flags & CMDL_USESURFACESKIN) - while ((int)mobj->modelData->surfaceSkinIDs.Size() < skinPosition) mobj->modelData->surfaceSkinIDs.Push(FNullTextureID()); - else - while ((int)mobj->modelData->skinIDs.Size() < skinindex) mobj->modelData->skinIDs.Push(FNullTextureID()); - mobj->modelData->modelIDs.Insert(modelindex, queryModel); - mobj->modelData->modelFrameGenerators.Insert(modelindex, generatorindex); - mobj->modelData->animationIDs.Insert(animationindex, queryAnimation); - if (flags & CMDL_USESURFACESKIN) - mobj->modelData->surfaceSkinIDs.Insert(skinPosition, skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID()); - else - mobj->modelData->skinIDs.Insert(skinindex, skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID()); - - //[SM] - We need to serialize file paths and model names so that they are pushed on loading save files. Likewise, let's not include models that were already parsed when initialized. - if (queryModel >= 0) - { - FString fullName; - fullName.Format("%s%s", modelpath.GetChars(), model.GetChars()); - bool allowPush = true; - for (unsigned i = 0; i < savedModelFiles.Size(); i++) if (!savedModelFiles[i].CompareNoCase(fullName)) allowPush = false; - for (unsigned i = 0; i < Models.Size()-1; i++) if (!Models[i]->mFileName.CompareNoCase(fullName)) allowPush = false; - - if(allowPush) savedModelFiles.Push(fullName); - } - //Same for animations - if (queryAnimation >= 0) - { - FString fullName; - fullName.Format("%s%s", animationpath.GetChars(), animation.GetChars()); - bool allowPush = true; - for (unsigned i = 0; i < savedModelFiles.Size(); i++) if (!savedModelFiles[i].CompareNoCase(fullName)) allowPush = false; - for (unsigned i = 0; i < Models.Size() - 1; i++) if (!Models[i]->mFileName.CompareNoCase(fullName)) allowPush = false; - - if (allowPush) savedModelFiles.Push(fullName); - } - - //[SM] - if an indice of modelIDs or skinIDs comes up blank and it's the last one, just delete it. For using very large amounts of indices, common sense says to just not run this repeatedly. - while (mobj->modelData->modelIDs.Size() > 0 && mobj->modelData->modelIDs.Last() == -1) - mobj->modelData->modelIDs.Pop(mobj->modelData->modelIDs.Last()); - while (mobj->modelData->modelFrameGenerators.Size() > 0 && mobj->modelData->modelFrameGenerators.Last() == -1) - mobj->modelData->modelFrameGenerators.Pop(mobj->modelData->modelFrameGenerators.Last()); - while (mobj->modelData->skinIDs.Size() > 0 && mobj->modelData->skinIDs.Last() == FNullTextureID()) - mobj->modelData->skinIDs.Pop(mobj->modelData->skinIDs.Last()); - while (mobj->modelData->surfaceSkinIDs.Size() > 0 && mobj->modelData->surfaceSkinIDs.Last() == FNullTextureID()) - mobj->modelData->surfaceSkinIDs.Pop(mobj->modelData->surfaceSkinIDs.Last()); - while (mobj->modelData->animationIDs.Size() > 0 && mobj->modelData->animationIDs.Last() == -1) - mobj->modelData->animationIDs.Pop(mobj->modelData->animationIDs.Last()); - - if (mobj->modelData->modelIDs.Size() == 0 && mobj->modelData->modelFrameGenerators.Size() == 0 && mobj->modelData->skinIDs.Size() == 0 && mobj->modelData->surfaceSkinIDs.Size() == 0 && mobj->modelData->animationIDs.Size() == 0 && modeldef == NAME_None) - { - mobj->hasmodel = mobj->modelData->hasModel; - mobj->modelData->modelIDs.Reset(); - mobj->modelData->modelFrameGenerators.Reset(); - mobj->modelData->skinIDs.Reset(); - mobj->modelData->surfaceSkinIDs.Reset(); - mobj->modelData->animationIDs.Reset(); - mobj->modelData->Destroy(); - } + ChangeModelNative(self,stateowner,stateinfo,modeldef.GetIndex(),modelindex,modelpath,model.GetIndex(),skinindex,skinpath,skin.GetIndex(),flags,generatorindex,animationindex,animationpath,animation.GetIndex()); return 0; } diff --git a/src/playsim/p_interaction.cpp b/src/playsim/p_interaction.cpp index 2c89e3cc1..4baac07a4 100644 --- a/src/playsim/p_interaction.cpp +++ b/src/playsim/p_interaction.cpp @@ -1335,13 +1335,24 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da } } + bool compat_voodoo_zombie = target->Level->i_compatflags2 & COMPATF2_VOODOO_ZOMBIES; + player->health -= damage; // mirror mobj health here for Dave - // [RH] Make voodoo dolls and real players record the same health - target->health = player->mo->health -= damage; + if(compat_voodoo_zombie) + { // [RL0] To allow voodoo zombies, don't set the voodoo doll to the player mobj's health and don't change the player mobj's health on damage + target->health -= damage; + } + else + { // [RH] Make voodoo dolls and real players record the same health + target->health = player->mo->health -= damage; + } if (player->health < 50 && !deathmatch && !(flags & DMG_FORCED)) { P_AutoUseStrifeHealth (player); - player->mo->health = player->health; + if(!compat_voodoo_zombie) + { // [RL0] To match vanilla behavior, don't set the player mo's health to 0 if voodoo zombies compat is enabled + player->mo->health = player->health; + } } if (player->health <= 0) { diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index be38b528d..e9be195f2 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -1324,18 +1324,36 @@ bool AActor::Massacre () // //---------------------------------------------------------------------------- +FSerializer &Serialize(FSerializer &arc, const char *key, ModelOverride &sid, ModelOverride *def) +{ + arc.BeginObject(key); + arc("modelID", sid.modelID); + arc("surfaceSkinIDs", sid.surfaceSkinIDs); + arc.EndObject(); + return arc; +} + void DActorModelData::Serialize(FSerializer& arc) { Super::Serialize(arc); arc("modelDef", modelDef) - ("modelIDs", modelIDs) + ("models", models) ("skinIDs", skinIDs) - ("surfaceSkinIDs", surfaceSkinIDs) + //("surfaceSkinIDs", surfaceSkinIDs) ("animationIDs", animationIDs) ("modelFrameGenerators", modelFrameGenerators) ("hasModel", hasModel); } +void DActorModelData::OnDestroy() +{ + models.Reset(); + modelFrameGenerators.Reset(); + skinIDs.Reset(); + //surfaceSkinIDs.Reset(); + animationIDs.Reset(); +} + //---------------------------------------------------------------------------- // // PROC P_ExplodeMissile diff --git a/src/posix/i_steam.cpp b/src/posix/i_steam.cpp index 15265a6e0..82c2c9d98 100644 --- a/src/posix/i_steam.cpp +++ b/src/posix/i_steam.cpp @@ -187,7 +187,7 @@ TArray I_GetSteamPath() return result; } - SteamInstallFolders.Push(appSupportPath + "/Steam/SteamApps/common"); + SteamInstallFolders.Push(appSupportPath + "/Steam/steamapps/common"); #else char* home = getenv("HOME"); if(home != NULL && *home != '\0') @@ -198,7 +198,7 @@ TArray I_GetSteamPath() // .steam at some point. Not sure if it's just my setup so I guess we // can fall back on it? if(!FileExists(regPath)) - regPath.Format("%s/.local/share/Steam/config/config.vdf", home); + regPath.Format("%s/.steam/steam/config/config.vdf", home); try { @@ -210,7 +210,7 @@ TArray I_GetSteamPath() return result; } - regPath.Format("%s/.local/share/Steam/SteamApps/common", home); + regPath.Format("%s/.steam/steam/steamapps/common", home); SteamInstallFolders.Push(regPath); } #endif diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 84eb9aada..ca77c9c8d 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -316,12 +316,12 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr } } - int modelsamount = smf->modelsAmount; + unsigned modelsamount = smf->modelsAmount; //[SM] - if we added any models for the frame to also render, then we also need to update modelsAmount for this smf if (actor->modelData != nullptr) { - if (actor->modelData->modelIDs.Size() > (unsigned)modelsamount) - modelsamount = actor->modelData->modelIDs.Size(); + if (actor->modelData->models.Size() > modelsamount) + modelsamount = actor->modelData->models.Size(); } TArray surfaceskinids; @@ -330,57 +330,112 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr int boneStartingPosition = 0; bool evaluatedSingle = false; - for (int i = 0; i < modelsamount; i++) + for (unsigned i = 0; i < modelsamount; i++) { int modelid = -1; int animationid = -1; int modelframe = -1; int modelframenext = -1; - FTextureID skinid; skinid.SetInvalid(); + FTextureID skinid; skinid.SetNull(); surfaceskinids.Clear(); + if (actor->modelData != nullptr) { - if (i < (int)actor->modelData->modelIDs.Size()) - modelid = actor->modelData->modelIDs[i]; - - if (i < (int)actor->modelData->animationIDs.Size()) - animationid = actor->modelData->animationIDs[i]; - - if (i < (int)actor->modelData->modelFrameGenerators.Size()) + //modelID + if (actor->modelData->models.Size() > i && actor->modelData->models[i].modelID >= 0) { - //[SM] - We will use this little snippet to allow a modder to specify a model index to clone. It's also pointless to clone something that clones something else in this case. And causes me headaches. - if (actor->modelData->modelFrameGenerators[i] >= 0 && actor->modelData->modelFrameGenerators[i] <= modelsamount && smf->modelframes[actor->modelData->modelFrameGenerators[i]] != -1) + modelid = actor->modelData->models[i].modelID; + } + else if(actor->modelData->models.Size() > i && actor->modelData->models[i].modelID == -2) + { + continue; + } + else if(smf->modelsAmount > i) + { + modelid = smf->modelIDs[i]; + } + + //animationID + if (actor->modelData->animationIDs.Size() > i && actor->modelData->animationIDs[i] >= 0) + { + animationid = actor->modelData->animationIDs[i]; + } + else if(smf->modelsAmount > i) + { + animationid = smf->animationIDs[i]; + } + + //modelFrame + if (actor->modelData->modelFrameGenerators.Size() > i + && actor->modelData->modelFrameGenerators[i] >= 0 + && actor->modelData->modelFrameGenerators[i] < modelsamount + && smf->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0 + ) { + modelframe = smf->modelframes[actor->modelData->modelFrameGenerators[i]]; + + if (smfNext) { - modelframe = smf->modelframes[actor->modelData->modelFrameGenerators[i]]; - if (smfNext) modelframenext = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]]; + if(smfNext->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0) + { + modelframenext = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]]; + } + else + { + modelframenext = smfNext->modelframes[i]; + } } } - if (i < (int)actor->modelData->skinIDs.Size()) + else if(smf->modelsAmount > i) { - if (actor->modelData->skinIDs[i].isValid()) - skinid = actor->modelData->skinIDs[i]; + modelframe = smf->modelframes[i]; + if (smfNext) modelframenext = smfNext->modelframes[i]; } - for (int surface = i * MD3_MAX_SURFACES; surface < (i + 1) * MD3_MAX_SURFACES; surface++) + + //skinID + if (actor->modelData->skinIDs.Size() > i && actor->modelData->skinIDs[i].isValid()) { - if (surface < (int)actor->modelData->surfaceSkinIDs.Size()) + skinid = actor->modelData->skinIDs[i]; + } + else if(smf->modelsAmount > i) + { + skinid = smf->skinIDs[i]; + } + + //surfaceSkinIDs + if(actor->modelData->models.Size() > i && actor->modelData->models[i].surfaceSkinIDs.Size() > 0) + { + unsigned sz1 = smf->surfaceskinIDs.Size(); + unsigned sz2 = actor->modelData->models[i].surfaceSkinIDs.Size(); + unsigned start = i * MD3_MAX_SURFACES; + + surfaceskinids = actor->modelData->models[i].surfaceSkinIDs; + surfaceskinids.Resize(MD3_MAX_SURFACES); + + for (unsigned surface = 0; surface < MD3_MAX_SURFACES; surface++) { - if (actor->modelData->surfaceSkinIDs[surface].isValid()) + if (sz2 > surface && (actor->modelData->models[i].surfaceSkinIDs[surface].isValid())) { - // only make a copy of the surfaceskinIDs array if really needed - if (surfaceskinids.Size() == 0) surfaceskinids = smf->surfaceskinIDs; - surfaceskinids[surface] = actor->modelData->surfaceSkinIDs[surface]; + continue; + } + if((surface + start) < sz1) + { + surfaceskinids[surface] = smf->surfaceskinIDs[surface + start]; + } + else + { + surfaceskinids[surface].SetNull(); } } } } - if (i < smf->modelsAmount) + else { - if (modelid == -1) modelid = smf->modelIDs[i]; - if (animationid == -1) animationid = smf->animationIDs[i]; - if (modelframe == -1) modelframe = smf->modelframes[i]; - if (modelframenext == -1 && smfNext) modelframenext = smfNext->modelframes[i]; - if (!skinid.isValid()) skinid = smf->skinIDs[i]; + modelid = smf->modelIDs[i]; + animationid = smf->animationIDs[i]; + modelframe = smf->modelframes[i]; + if (smfNext) modelframenext = smfNext->modelframes[i]; + skinid = smf->skinIDs[i]; } if (modelid >= 0) @@ -389,8 +444,9 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr auto tex = skinid.isValid() ? TexMan.GetGameTexture(skinid, true) : nullptr; mdl->BuildVertexBuffer(renderer); - auto& ssids = surfaceskinids.Size() > 0 ? surfaceskinids : smf->surfaceskinIDs; - auto ssidp = (unsigned)(i * MD3_MAX_SURFACES) < ssids.Size() ? &ssids[i * MD3_MAX_SURFACES] : nullptr; + auto ssidp = surfaceskinids.Size() > 0 + ? surfaceskinids.Data() + : (((i * MD3_MAX_SURFACES) < smf->surfaceskinIDs.Size()) ? &smf->surfaceskinIDs[i * MD3_MAX_SURFACES] : nullptr); bool nextFrame = smfNext && modelframe != modelframenext; diff --git a/src/r_data/r_vanillatrans.h b/src/r_data/r_vanillatrans.h index 702fc8212..d6b6a5d9e 100644 --- a/src/r_data/r_vanillatrans.h +++ b/src/r_data/r_vanillatrans.h @@ -30,6 +30,7 @@ **--------------------------------------------------------------------------- ** */ +#pragma once void UpdateVanillaTransparency(); diff --git a/src/rendering/hwrenderer/hw_vertexbuilder.h b/src/rendering/hwrenderer/hw_vertexbuilder.h index 7d04df3f0..6bfe10709 100644 --- a/src/rendering/hwrenderer/hw_vertexbuilder.h +++ b/src/rendering/hwrenderer/hw_vertexbuilder.h @@ -1,4 +1,4 @@ - +#pragma once #include "tarray.h" #include "r_defs.h" diff --git a/src/rendering/swrenderer/textures/warpbuffer.h b/src/rendering/swrenderer/textures/warpbuffer.h index 778706850..594903a53 100644 --- a/src/rendering/swrenderer/textures/warpbuffer.h +++ b/src/rendering/swrenderer/textures/warpbuffer.h @@ -31,6 +31,7 @@ **--------------------------------------------------------------------------- ** */ +#pragma once #include "textures.h" #include "texturemanager.h" diff --git a/src/sound/s_doomsound.cpp b/src/sound/s_doomsound.cpp index bc5c092b0..50509eb3d 100644 --- a/src/sound/s_doomsound.cpp +++ b/src/sound/s_doomsound.cpp @@ -66,6 +66,7 @@ #include "g_game.h" #include "s_music.h" #include "v_draw.h" +#include "m_argv.h" // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -229,7 +230,7 @@ void S_Init() } I_InitSound(); - I_InitMusic(); + I_InitMusic(Args->CheckParm("-nomusic") || Args->CheckParm("-nosound")); // Heretic and Hexen have sound curve lookup tables. Doom does not. int curvelump = fileSystem.CheckNumForName("SNDCURVE"); diff --git a/src/win32/i_steam.cpp b/src/win32/i_steam.cpp index 056b59364..5b62ae435 100644 --- a/src/win32/i_steam.cpp +++ b/src/win32/i_steam.cpp @@ -80,6 +80,112 @@ #include "cmdlib.h" #include "i_interface.h" + +//TODO maybe move this code to a separate cpp file, so that there isn't code duplication between the win32 and posix backends +static void PSR_FindEndBlock(FScanner &sc) +{ + int depth = 1; + do + { + if(sc.CheckToken('}')) + --depth; + else if(sc.CheckToken('{')) + ++depth; + else + sc.MustGetAnyToken(); + } + while(depth); +} +static void PSR_SkipBlock(FScanner &sc) +{ + sc.MustGetToken('{'); + PSR_FindEndBlock(sc); +} +static bool PSR_FindAndEnterBlock(FScanner &sc, const char* keyword) +{ + // Finds a block with a given keyword and then enter it (opening brace) + // Should be closed with PSR_FindEndBlock + while(sc.GetToken()) + { + if(sc.TokenType == '}') + { + sc.UnGet(); + return false; + } + + sc.TokenMustBe(TK_StringConst); + if(!sc.Compare(keyword)) + { + if(!sc.CheckToken(TK_StringConst)) + PSR_SkipBlock(sc); + } + else + { + sc.MustGetToken('{'); + return true; + } + } + return false; +} +static TArray PSR_ReadBaseInstalls(FScanner &sc) +{ + TArray result; + + // Get a list of possible install directories. + while(sc.GetToken()) + { + if(sc.TokenType == '}') + break; + + sc.TokenMustBe(TK_StringConst); + FString key(sc.String); + if(key.Left(18).CompareNoCase("BaseInstallFolder_") == 0) + { + sc.MustGetToken(TK_StringConst); + result.Push(FString(sc.String) + "/steamapps/common"); + } + else + { + if(sc.CheckToken('{')) + PSR_FindEndBlock(sc); + else + sc.MustGetToken(TK_StringConst); + } + } + + return result; +} +static TArray ParseSteamRegistry(const char* path) +{ + TArray dirs; + + // Read registry data + FScanner sc; + if (sc.OpenFile(path)) + { + sc.SetCMode(true); + + // Find the SteamApps listing + if (PSR_FindAndEnterBlock(sc, "InstallConfigStore")) + { + if (PSR_FindAndEnterBlock(sc, "Software")) + { + if (PSR_FindAndEnterBlock(sc, "Valve")) + { + if (PSR_FindAndEnterBlock(sc, "Steam")) + { + dirs = PSR_ReadBaseInstalls(sc); + } + PSR_FindEndBlock(sc); + } + PSR_FindEndBlock(sc); + } + PSR_FindEndBlock(sc); + } + } + return dirs; +} + //========================================================================== // // QueryPathKey @@ -240,18 +346,30 @@ TArray I_GetSteamPath() "Doom 2/finaldoombase" }; - FString path; + FString steamPath; - if (!QueryPathKey(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", L"SteamPath", path)) + if (!QueryPathKey(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", L"SteamPath", steamPath)) { - if (!QueryPathKey(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", L"InstallPath", path)) + if (!QueryPathKey(HKEY_LOCAL_MACHINE, L"Software\\Valve\\Steam", L"InstallPath", steamPath)) return result; } - path += "/SteamApps/common/"; + + TArray paths = ParseSteamRegistry(steamPath + "/config/config.vdf"); + + for(FString &path : paths) + { + path.ReplaceChars('\\','/'); + path+="/"; + } + + paths.Push(steamPath + "/steamapps/common/"); for(unsigned int i = 0; i < countof(steam_dirs); ++i) { - result.Push(path + steam_dirs[i]); + for(const FString &path : paths) + { + result.Push(path + steam_dirs[i]); + } } return result; diff --git a/wadsrc/static/language.def b/wadsrc/static/language.def index 9af43dbce..f27921290 100644 --- a/wadsrc/static/language.def +++ b/wadsrc/static/language.def @@ -326,7 +326,9 @@ HE3TEXT = ""; HE4TEXT = ""; HE5TEXT = ""; +// // mappings for duplicate texts +// CNTRLMNU_TITLE = "$$OPTMNU_CONTROLS"; MOUSEMNU_TITLE = "$$OPTMNU_MOUSE"; @@ -337,9 +339,49 @@ OPENALMNU_TITLE = "$$SNDMNU_OPENAL"; SNDMNU_TITLE = "$$OPTMNU_SOUND"; MODMNU_TITLE = "$$SNDMNU_MODREPLAYER"; MISCMNU_TITLE = "$$OPTMNU_MISCELLANEOUS"; - GLMNU_TEXOPT = "$$GLTEXMNU_TITLE"; +SCORE_ITEMS = "$$TXT_IMITEMS"; +SCORE_KILLS = "$$TXT_IMKILLS"; + +FN_ZOMBIE = "$$CC_ZOMBIE"; +FN_IMP = "$$CC_IMP"; +FN_DEMON = "$$CC_DEMON"; +FN_LOST = "$$CC_LOST"; +FN_CACO = "$$CC_CACO"; +FN_HELL = "$$CC_HELL"; +FN_BARON = "$$CC_BARON"; +FN_ARACH = "$$CC_ARACH"; +FN_PAIN = "$$CC_PAIN"; +FN_REVEN = "$$CC_REVEN"; +FN_MANCU = "$$CC_MANCU"; +FN_ARCH = "$$CC_ARCH"; + +TAG_GAUNTLETS = "$$TXT_WPNGAUNTLETS"; +TAG_GAUNTLETSP = "$$TXT_WPNGAUNTLETS"; +TAG_CROSSBOW = "$$TXT_WPNCROSSBOW"; +TAG_CROSSBOWP = "$$TXT_WPNCROSSBOW"; +TAG_STAFFP = "$$TAG_STAFF"; +TAG_GOLDWANDP = "$$TAG_GOLDWAND"; +TAG_BLASTER = "$$TXT_WPNBLASTER"; +TAG_BLASTERP = "$$TXT_WPNBLASTER"; +TAG_SKULLROD = "$$TXT_WPNSKULLROD"; +TAG_SKULLRODP = "$$TXT_WPNSKULLROD"; +TAG_PHOENIXROD = "$$TXT_WPNPHOENIXROD"; +TAG_PHOENIXRODP = "$$TXT_WPNPHOENIXROD"; +TAG_MACE = "$$TXT_WPNMACE"; +TAG_MACEP = "$$TXT_WPNMACE"; + +TAG_ARTIEGG = "$$TXT_ARTIEGG"; +TAG_ARTIFIREBOMB = "$$TXT_ARTIFIREBOMB"; +TAG_ARTIFLY = "$$TXT_ARTIFLY"; +TAG_ARTIHEALTH = "$$TXT_ARTIHEALTH"; +TAG_ARTIINVISIBILITY = "$$TXT_ARTIINVISIBILITY"; +TAG_ARTIINVULNERABILITY = "$$TXT_ARTIINVULNERABILITY"; +TAG_ARTITELEPORT = "$$TXT_ARTITELEPORT"; +TAG_ARTITOMEOFPOWER = "$$TXT_ARTITOMEOFPOWER"; +TAG_ARTITORCH = "$$TXT_ARTITORCH"; + // newly added text not in the string table OPTMNU_SWRENDERER = "Software Renderer"; diff --git a/wadsrc/static/zscript/actors/inventory/weapons.zs b/wadsrc/static/zscript/actors/inventory/weapons.zs index d4aa0e57d..72f31b1f9 100644 --- a/wadsrc/static/zscript/actors/inventory/weapons.zs +++ b/wadsrc/static/zscript/actors/inventory/weapons.zs @@ -932,6 +932,7 @@ class Weapon : StateProvider int count1, count2; int enough, enoughmask; int lAmmoUse1; + int lAmmoUse2 = AmmoUse2; if (sv_infiniteammo || (Owner.FindInventory ('PowerInfiniteAmmo', true) != null)) { @@ -957,20 +958,21 @@ class Weapon : StateProvider count1 = (Ammo1 != null) ? Ammo1.Amount : 0; count2 = (Ammo2 != null) ? Ammo2.Amount : 0; - if (bDehAmmo && Ammo1 == null) - { - lAmmoUse1 = 0; - } - else if (ammocount >= 0 && bDehAmmo) + if (ammocount >= 0) { lAmmoUse1 = ammocount; + lAmmoUse2 = ammocount; + } + else if (bDehAmmo && Ammo1 == null) + { + lAmmoUse1 = 0; } else { lAmmoUse1 = AmmoUse1; } - enough = (count1 >= lAmmoUse1) | ((count2 >= AmmoUse2) << 1); + enough = (count1 >= lAmmoUse1) | ((count2 >= lAmmoUse2) << 1); if (useboth) { enoughmask = 3; diff --git a/wadsrc/static/zscript/actors/player/player.zs b/wadsrc/static/zscript/actors/player/player.zs index 7039f9436..5f6d0f616 100644 --- a/wadsrc/static/zscript/actors/player/player.zs +++ b/wadsrc/static/zscript/actors/player/player.zs @@ -85,6 +85,11 @@ class PlayerPawn : Actor flagdef CanSuperMorph: PlayerFlags, 1; flagdef CrouchableMorph: PlayerFlags, 2; flagdef WeaponLevel2Ended: PlayerFlags, 3; + + enum EPrivatePlayerFlags + { + PF_VOODOO_ZOMBIE = 1<<4, + } Default { @@ -777,14 +782,16 @@ class PlayerPawn : Actor Super.Die (source, inflictor, dmgflags, MeansOfDeath); if (player != NULL && player.mo == self) player.bonuscount = 0; - - if (player != NULL && player.mo != self) + + // [RL0] To allow voodoo zombies, don't kill the player together with voodoo dolls if the compat flag is enabled + if (player != NULL && player.mo != self && !(Level.compatflags2 & COMPATF2_VOODOO_ZOMBIES)) { // Make the real player die, too player.mo.Die (source, inflictor, dmgflags, MeansOfDeath); } else { - if (player != NULL && sv_weapondrop) + // [RL0] player.mo == self will always be true if COMPATF2_VOODOO_ZOMBIES is false, so there's no need to check the compatflag here too, just self + if (player != NULL && sv_weapondrop && player.mo == self) { // Voodoo dolls don't drop weapons let weap = player.ReadyWeapon; if (weap != NULL) @@ -1609,6 +1616,12 @@ class PlayerPawn : Actor { let player = self.player; UserCmd cmd = player.cmd; + + // [RL0] Mark players that became zombies (this stays even if they 'revive' by healing, until a level change) + if((Level.compatflags2 & COMPATF2_VOODOO_ZOMBIES) && player.health <= 0 && player.mo.health > 0) + { + PlayerFlags |= PF_VOODOO_ZOMBIE; + } CheckFOV(); @@ -1692,6 +1705,9 @@ class PlayerPawn : Actor void BringUpWeapon () { + // [RL0] Don't bring up weapon when in a voodoo zombie state + if(PlayerFlags & PF_VOODOO_ZOMBIE) return; + let player = self.player; if (player.PendingWeapon == WP_NOCHANGE) { @@ -2007,6 +2023,19 @@ class PlayerPawn : Actor void PlayerFinishLevel (int mode, int flags) { + // [RL0] Handle player exit behavior for voodoo zombies + if(PlayerFlags & PF_VOODOO_ZOMBIE) + { + if(player.health > 0) + { + PlayerFlags &= ~PF_VOODOO_ZOMBIE; + } + else + { + bShootable = false; + bKilled = true; + } + } Inventory item, next; let p = player; diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index 66426a125..fe44f2c3d 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -1429,6 +1429,11 @@ enum ECompatFlags COMPATF2_EXPLODE1 = 1 << 8, // No vertical explosion thrust COMPATF2_EXPLODE2 = 1 << 9, // Use original explosion code throughout. COMPATF2_RAILING = 1 << 10, // Bugged Strife railings. + COMPATF2_SCRIPTWAIT = 1 << 11, // Use old scriptwait implementation where it doesn't wait on a non-running script. + COMPATF2_AVOID_HAZARDS = 1 << 12, // another MBF thing. + COMPATF2_STAYONLIFT = 1 << 13, // yet another MBF thing. + COMPATF2_NOMBF21 = 1 << 14, // disable MBF21 features that may clash with certain maps + COMPATF2_VOODOO_ZOMBIES = 1 << 15, // allow playerinfo, playerpawn, and voodoo health to all be different, and allow monster targetting of 'dead' players that have positive health }; const M_E = 2.7182818284590452354; // e diff --git a/wadsrc_extra/static/iwadinfo.txt b/wadsrc_extra/static/iwadinfo.txt index a1c419d4e..11387e29c 100644 --- a/wadsrc_extra/static/iwadinfo.txt +++ b/wadsrc_extra/static/iwadinfo.txt @@ -326,7 +326,7 @@ IWad Config = "Doom" IWADName = "doom.wad", 2 Mapinfo = "mapinfo/ultdoom.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2", @@ -343,7 +343,7 @@ IWad Config = "Doom" IWADName = "doomunity.wad", 2 Mapinfo = "mapinfo/ultdoom.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2", @@ -375,7 +375,7 @@ IWad Config = "Doom" IWADName = "doom.wad" Mapinfo = "mapinfo/doomxbox.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2", "E1M10", "SEWERS" @@ -391,7 +391,7 @@ IWad Config = "Doom" IWADName = "doom.wad" Mapinfo = "mapinfo/ultdoom.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1", "E4M2" @@ -407,7 +407,7 @@ IWad Config = "Doom" IWADName = "doom.wad", 1 Mapinfo = "mapinfo/doom1.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", "DPHOOF","BFGGA0","HEADA1","CYBRA1","SPIDA1D1" @@ -422,7 +422,7 @@ IWad Game = "Doom" Config = "Doom" Mapinfo = "mapinfo/doom1.txt" - Compatibility = "Shareware", "Shorttex" + Compatibility = "Shareware", "Shorttex", "nosectionmerge" MustContain = "E1M1" BannerColors = "54 54 54", "a8 a8 a8" IgnoreTitlePatches = 1 @@ -492,7 +492,7 @@ IWad Config = "Doom" IWADName = "doom2.wad" Mapinfo = "mapinfo/doom2bfg.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "MAP01", "DMENUPIC", "M_ACPT", "M_CAN", "M_EXITO", "M_CHG" BannerColors = "a8 00 00", "a8 a8 a8" Load = "nerve.wad" @@ -507,7 +507,7 @@ IWad Config = "Doom" IWADName = "doom2unity.wad" Mapinfo = "mapinfo/doom2unity.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "MAP01", "DMENUPIC" BannerColors = "00 7c 00", "a8 a8 a8" IgnoreTitlePatches = 1 @@ -522,7 +522,7 @@ IWad Config = "Doom" IWADName = "doom2.wad", 1 Mapinfo = "mapinfo/doom2xbox.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "MAP01", "MAP33", "CWILV32" BannerColors = "18 18 18", "a8 a8 a8" IgnoreTitlePatches = 1 @@ -538,7 +538,7 @@ IWad Config = "Doom" IWADName = "doom2f.wad", 1 Mapinfo = "mapinfo/doom2.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "MAP01", "WIOBJ" BannerColors = "ff ff ff", "a8 00 00" } @@ -552,7 +552,7 @@ IWad Config = "Doom" IWADName = "doom2.wad", 1 Mapinfo = "mapinfo/doom2.txt" - Compatibility = "Shorttex" + Compatibility = "Shorttex", "nosectionmerge" MustContain = "MAP01" BannerColors = "a8 00 00", "a8 a8 a8" IgnoreTitlePatches = 1