Merge pull request #13 from nashmuhandes/GZDoomUpdate-12-07-2023

GZDoom master update
This commit is contained in:
Magnus Norddahl 2023-07-12 15:38:40 +02:00 committed by GitHub
commit 7706fc7692
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
74 changed files with 773 additions and 294 deletions

View file

@ -2361,6 +2361,11 @@ alias -creep "joy_speedmultiplier 1.0"</pre>
of a music lump or file on disk (which need not have been specified with the
-file parameter).
</div>
<div class="c" id="changeskill">changeskill <i>skill</i></div>
<div class="b">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.
</div>
<div class="c" id="chase">chase</div>
<div class="b">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"</pre>
<a href="#centerview">centerview</a><br />
<a href="#changemap">changemap</a><br />
<a href="#changemus">changemus</a><br />
<a href="#changeskill">changeskill</a><br />
<a href="#chase">chase</a><br />
<a href="#chase_dist">chase_dist</a><br />
<a href="#chase_height">chase_height</a><br />

View file

@ -56,6 +56,7 @@ if( WIN32 )
add_definitions( -D_WIN32 )
set( PROJECT_LIBRARIES
psapi
wsock32
winmm
dinput8

View file

@ -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);

View file

@ -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
{

View file

@ -40,7 +40,6 @@
#include <zlib.h>
#include <zmusic.h>
#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();

View file

@ -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)
{

View file

@ -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)

View file

@ -5,7 +5,6 @@
#include <stdint.h>
#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<EChanFlag> 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);

View file

@ -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;
}

View file

@ -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<int> 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<int> UserData;
FRolloffInfo Rolloff{};
float Attenuation = 1.f; // Multiplies the attenuation passed to S_Sound.
};

View file

@ -1,3 +1,4 @@
#pragma once
#include <string>
#include "zstring.h"

View file

@ -32,6 +32,7 @@
**---------------------------------------------------------------------------
**
*/
#pragma once
#include <limits.h>
#include <stdio.h>

View file

@ -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)
{

View file

@ -268,3 +268,4 @@ xx(BuiltinNameToClass)
xx(BuiltinClassCast)
xx(ScreenJobRunner)
xx(Action)

View file

@ -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.

View file

@ -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);

View file

@ -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); }

View file

@ -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 <typename T/*, typename = std::enable_if_t<std::is_base_of_v<DObject, T>>*/>
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<class T, class TT>
FSerializer &Serialize(FSerializer &arc, const char *key, TArray<T, TT> &value, TArray<T, TT> *def)
{

View file

@ -1,3 +1,4 @@
#pragma once
const char* UnicodeToString(const char* cc);
const char* StringToUnicode(const char* cc, int size = -1);

View file

@ -1,3 +1,4 @@
#pragma once
#include "files.h"
#include "engineerrors.h"

View file

@ -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;
}
//==========================================================================

View file

@ -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);

View file

@ -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()
{

View file

@ -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)
{

View file

@ -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);
}

View file

@ -51,7 +51,6 @@
#include <asm/unistd.h>
#include <linux/perf_event.h>
#include <sys/mman.h>
#include "printf.h"
#endif
#include <SDL.h>
@ -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))
{

View file

@ -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;
}
}
}
}

View file

@ -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)

View file

@ -1,6 +1,7 @@
#include "hw_mesh.h"
#include "v_video.h"
#include "cmdlib.h"
#define USE_MESH_VERTEX_BUFFER

View file

@ -26,6 +26,7 @@
#include "vulkan/buffers/vk_buffer.h"
#include <zvulkan/vulkanbuilders.h>
#include "flatvertices.h"
#include "cmdlib.h"
VkRSBuffers::VkRSBuffers(VulkanRenderDevice* fb)
{

View file

@ -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)
{

View file

@ -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)

View file

@ -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);

View file

@ -57,8 +57,8 @@
static ZSMap<FName, DObject*> AllServices;
static void MarkServices() {
static void MarkServices()
{
ZSMap<FName, DObject*>::Iterator it(AllServices);
ZSMap<FName, DObject*>::Pair* pair;
while (it.NextPair(pair))
@ -82,6 +82,11 @@ void InitServices()
GC::AddMarkerFunc(&MarkServices);
}
void ClearServices()
{
AllServices.Clear();
}
//==========================================================================

View file

@ -1,4 +1,4 @@
#pragma once
#include "jit.h"
#include "types.h"

View file

@ -45,6 +45,7 @@
#include "memarena.h"
#include "name.h"
#include "scopebarrier.h"
#include <type_traits>
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<typename T> struct native_is_valid<T&> { static const bool value = true; static const bool retval = true; };
template<> struct native_is_valid<void> { static const bool value = true; static const bool retval = true; };
template<> struct native_is_valid<int> { 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<FName> { static const bool value = true; static const bool retval = true; static_assert(sizeof(FName) == sizeof(int)); static_assert(std::is_pod_v<FName>);};
template<> struct native_is_valid<unsigned int> { static const bool value = true; static const bool retval = true; };
template<> struct native_is_valid<double> { static const bool value = true; static const bool retval = true; };
template<> struct native_is_valid<bool> { 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<P##n>()
template<typename Ret> DirectNativeDesc(Ret(*func)()) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); }
template<typename Ret, TP(1)> DirectNativeDesc(Ret(*func)(P1)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); }
template<typename Ret, TP(1), TP(2)> DirectNativeDesc(Ret(*func)(P1,P2)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); }
template<typename Ret, TP(1), TP(2), TP(3)> DirectNativeDesc(Ret(*func)(P1,P2,P3)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9), TP(10)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9), TP(10), TP(11)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); VP(1); VP(2); VP(3); VP(4); VP(5); VP(6); VP(7); VP(8); VP(9); VP(10); VP(11); }
template<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9), TP(10), TP(11), TP(12)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); 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<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9), TP(10), TP(11), TP(12), TP(13)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); 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<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9), TP(10), TP(11), TP(12), TP(13), TP(14)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); 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<typename Ret, TP(1), TP(2), TP(3), TP(4), TP(5), TP(6), TP(7), TP(8), TP(9), TP(10), TP(11), TP(12), TP(13), TP(14), TP(15)> DirectNativeDesc(Ret(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); 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<typename Ret, typename... Params> DirectNativeDesc(Ret(*func)(Params...)) : Ptr(reinterpret_cast<void*>(func)) { ValidateRet<Ret>(); (ValidateType<Params>(), ...); }
template<typename T> void ValidateType() { static_assert(native_is_valid<T>::value, "Argument type is not valid as a direct native parameter or return type"); }
template<typename T> void ValidateRet() { static_assert(native_is_valid<T>::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)

View file

@ -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 <stdint.h>
/////////////////////////////////////////////////////////////////////////////

View file

@ -19,6 +19,7 @@
//#ifdef WIN32
//#define DLL __declspec(dllexport)
//#else
#pragma once
#define DLL
//#endif

View file

@ -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) {}
};

View file

@ -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;

View file

@ -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(); }

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -54,6 +54,7 @@
#include <new>
#include <utility>
#include <iterator>
#include <algorithm>
#if !defined(_WIN32)
#include <inttypes.h> // 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<T>::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)

View file

@ -44,23 +44,32 @@
#include <math.h>
#include <float.h>
#include <string.h>
// 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<class vec_t> struct TVector3;
template<class vec_t> struct TRotator;
template<class vec_t> 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);
}
};

View file

@ -31,6 +31,7 @@
**---------------------------------------------------------------------------
**
*/
#pragma once
#include <stdlib.h>
#include <stdint.h>

View file

@ -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 <skill>\n");
}
}
CCMD (give)
{
if (CheckCheatmode () || argv.argc() < 2)

View file

@ -19,6 +19,7 @@
// defcvars loader split from d_main.cpp
//
//-----------------------------------------------------------------------------
#pragma once
#define SHOULD_BLACKLIST(name) \
if (#name[0]==CurrentFindCVar[0]) \

View file

@ -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(","));

View file

@ -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

View file

@ -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
};

View file

@ -1,3 +1,4 @@
#pragma once
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

View file

@ -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 <stddef.h>
#include <stdlib.h>
#include <stdio.h>

View file

@ -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

View file

@ -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 },

View file

@ -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"

View file

@ -42,6 +42,7 @@ struct UMapEntry
FString InterText;
FString InterTextSecret;
TArray<FSpecialAction> 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;

View file

@ -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);

View file

@ -677,20 +677,26 @@ enum EViewPosFlags // [MC] Flags for SetViewPos.
VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position.
};
struct ModelOverride
{
int modelID;
TArray<FTextureID> surfaceSkinIDs;
};
class DActorModelData : public DObject
{
DECLARE_CLASS(DActorModelData, DObject);
public:
FName modelDef;
bool hasModel;
TArray<int> modelIDs;
TArray<FTextureID> skinIDs;
TArray<FTextureID> surfaceSkinIDs;
TArray<int> animationIDs;
TArray<int> modelFrameGenerators;
FName modelDef;
bool hasModel;
TArray<ModelOverride> models;
TArray<FTextureID> skinIDs;
TArray<int> animationIDs;
TArray<int> modelFrameGenerators;
DActorModelData() = default;
virtual void Serialize(FSerializer& arc) override;
virtual void OnDestroy() override;
};
class DViewPosition : public DObject

View file

@ -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<DActorModelData>();
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<FTextureID> 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<DActorModelData>();
ptr->hasModel = mobj->hasmodel ? 1 : 0;
ptr->modelIDs = *new TArray<int>();
ptr->skinIDs = *new TArray<FTextureID>();
ptr->surfaceSkinIDs = *new TArray<FTextureID>();
ptr->animationIDs = *new TArray<int>();
ptr->modelFrameGenerators = *new TArray<int>();
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;
}

View file

@ -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)
{

View file

@ -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

View file

@ -187,7 +187,7 @@ TArray<FString> 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<FString> 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<FString> 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

View file

@ -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<FTextureID> 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;

View file

@ -30,6 +30,7 @@
**---------------------------------------------------------------------------
**
*/
#pragma once
void UpdateVanillaTransparency();

View file

@ -1,4 +1,4 @@
#pragma once
#include "tarray.h"
#include "r_defs.h"

View file

@ -31,6 +31,7 @@
**---------------------------------------------------------------------------
**
*/
#pragma once
#include "textures.h"
#include "texturemanager.h"

View file

@ -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");

View file

@ -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<FString> PSR_ReadBaseInstalls(FScanner &sc)
{
TArray<FString> 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<FString> ParseSteamRegistry(const char* path)
{
TArray<FString> 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<FString> 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<FString> 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;

View file

@ -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";

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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