From 90b8dbb096c1f44df96d9e579c4a587fd3883dcd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 12:47:16 +0100 Subject: [PATCH 01/25] - removed the separate SSE2 version of the node builder's ClassifyLine function and all code associated with it. Like everything else related to doing standard math with SSE2 vs. x87, there's nothing to be gained here with anything but first generation SSE2 systems which are irrelevant these days. Taking 'thespir2.wad' from https://forum.zdoom.org/viewtopic.php?f=1&t=10655 the SSE2 version is reproducably ~3% slower than the x87 version on my Core i7, which quite closely mirrors all my previous tests since 2007. Overall this just looks like an optimization not worth doing. --- src/CMakeLists.txt | 32 ------- src/nodebuild.cpp | 92 ------------------- src/nodebuild.h | 43 +-------- src/nodebuild_classify_nosse2.cpp | 2 +- src/nodebuild_classify_sse2.cpp | 144 ------------------------------ 5 files changed, 2 insertions(+), 311 deletions(-) delete mode 100644 src/nodebuild_classify_sse2.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c5149121c..4ff73e32c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -397,22 +397,6 @@ if (NOT ZDOOM_USE_SSE2) endif() endif() -if( SSE_MATTERS ) - if( WIN32 ) - set( BACKPATCH 1 CACHE BOOL "Enable backpatching." ) - else() - CHECK_FUNCTION_EXISTS(mprotect HAVE_MPROTECT) - if( HAVE_MPROTECT ) - set( BACKPATCH 1 CACHE BOOL "Enable backpatching." ) - else() - set( BACKPATCH 0 ) - endif() - endif() - set( SSE 1 CACHE BOOL "Build SSE and SSE2 versions of key code." ) -else() - set( BACKPATCH 0 ) -endif() - if( X64 ) set( HAVE_MMX 1 ) else( X64 ) @@ -577,10 +561,6 @@ endif() # Flags -if( BACKPATCH ) - add_definitions( -DBACKPATCH ) -endif() - # Update gitinfo.h add_custom_target( revision_check ALL @@ -726,18 +706,6 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) -if( SSE_MATTERS ) - if( SSE ) - set( X86_SOURCES nodebuild_classify_sse2.cpp ) - set_source_files_properties( nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "${SSE2_ENABLE}" ) - else() - add_definitions( -DDISABLE_SSE ) - endif() -else() - add_definitions( -DDISABLE_SSE ) - set( X86_SOURCES ) -endif() - if( SNDFILE_FOUND ) add_definitions( -DHAVE_SNDFILE ) endif() diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 19dc16b61..6b17c9629 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -1062,95 +1062,3 @@ void FNodeBuilder::PrintSet (int l, DWORD set) } Printf (PRINT_LOG, "*\n"); } - - - -#ifdef BACKPATCH -#ifdef _WIN32 -extern "C" { -__declspec(dllimport) int __stdcall VirtualProtect(void *, unsigned long, unsigned long, unsigned long *); -} -#define PAGE_EXECUTE_READWRITE 64 -#else -#include -#include -#include -#endif - -#ifdef __GNUC__ -extern "C" int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) -#else -static int *CallerOffset; -int ClassifyLineBackpatchC (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) -#endif -{ - // Select the routine based on SSE2 availability and patch the caller so that - // they call that routine directly next time instead of going through here. - int *calleroffset; - int diff; - int (*func)(node_t &, const FSimpleVert *, const FSimpleVert *, int[2]); - -#ifdef __GNUC__ - calleroffset = (int *)__builtin_return_address(0); -#else - calleroffset = CallerOffset; -#endif -// printf ("Patching for SSE %d @ %p %d\n", SSELevel, calleroffset, *calleroffset); - -#ifndef DISABLE_SSE - if (CPU.bSSE2) - { - func = ClassifyLineSSE2; - diff = int((char *)ClassifyLineSSE2 - (char *)calleroffset); - } - else -#endif - { - func = ClassifyLine2; - diff = int((char *)ClassifyLine2 - (char *)calleroffset); - } - - calleroffset--; - // Patch the caller. -#ifdef _WIN32 - unsigned long oldprotect; - if (VirtualProtect (calleroffset, 4, PAGE_EXECUTE_READWRITE, &oldprotect)) -#else - // must make this page-aligned for mprotect - long pagesize = sysconf(_SC_PAGESIZE); - char *callerpage = (char *)((intptr_t)calleroffset & ~(pagesize - 1)); - size_t protectlen = (intptr_t)calleroffset + sizeof(void*) - (intptr_t)callerpage; - int ptect; - if (!(ptect = mprotect(callerpage, protectlen, PROT_READ|PROT_WRITE|PROT_EXEC))) -#endif - { - *calleroffset = diff; -#ifdef _WIN32 - VirtualProtect (calleroffset, sizeof(void*), oldprotect, &oldprotect); -#else - mprotect(callerpage, protectlen, PROT_READ|PROT_EXEC); -#endif - } - - // And return by calling the real function. - return func (node, v1, v2, sidev); -} - -#ifndef __GNUC__ -// The ClassifyLineBackpatch() function here is a stub that uses inline assembly and nakedness -// to retrieve the return address of the stack before sending control to the real -// ClassifyLineBackpatchC() function. Since BACKPATCH shouldn't be defined on 64-bit builds, -// we're okay that VC++ can't do inline assembly on that target. - -extern "C" __declspec(noinline) __declspec(naked) int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) -{ - // We store the return address in a global, so as not to need to mess with the parameter list. - __asm - { - mov eax, [esp] - mov CallerOffset, eax - jmp ClassifyLineBackpatchC - } -} -#endif -#endif diff --git a/src/nodebuild.h b/src/nodebuild.h index 9599bc0d2..6d730644e 100644 --- a/src/nodebuild.h +++ b/src/nodebuild.h @@ -53,22 +53,6 @@ struct FSimpleVert fixed_t x, y; }; -extern "C" -{ - int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); -#ifndef DISABLE_SSE - int ClassifyLineSSE1 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); - int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); -#ifdef BACKPATCH -#ifdef __GNUC__ - int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) __attribute__((noinline)); -#else - int __declspec(noinline) ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]); -#endif -#endif -#endif -} - class FNodeBuilder { struct FPrivSeg @@ -282,7 +266,7 @@ private: // 1 = seg is in back // -1 = seg cuts the node - inline int ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]); + int ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]); void FixSplitSharers (const node_t &node); double AddIntersection (const node_t &node, int vertex); @@ -341,28 +325,3 @@ inline int FNodeBuilder::PointOnSide (int x, int y, int x1, int y1, int dx, int } return s_num > 0.0 ? -1 : 1; } - -inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]) -{ -#ifdef DISABLE_SSE - return ClassifyLine2 (node, v1, v2, sidev); -#else -#if defined(__SSE2__) || defined(_M_X64) - // If compiling with SSE2 support everywhere, just use the SSE2 version. - return ClassifyLineSSE2 (node, v1, v2, sidev); -#elif defined(_MSC_VER) && _MSC_VER < 1300 - // VC 6 does not support SSE optimizations. - return ClassifyLine2 (node, v1, v2, sidev); -#else - // Select the routine based on our flag. -#ifdef BACKPATCH - return ClassifyLineBackpatch (node, v1, v2, sidev); -#else - if (CPU.bSSE2) - return ClassifyLineSSE2 (node, v1, v2, sidev); - else - return ClassifyLine2 (node, v1, v2, sidev); -#endif -#endif -#endif -} diff --git a/src/nodebuild_classify_nosse2.cpp b/src/nodebuild_classify_nosse2.cpp index 2d2c8edea..44f7e709f 100644 --- a/src/nodebuild_classify_nosse2.cpp +++ b/src/nodebuild_classify_nosse2.cpp @@ -3,7 +3,7 @@ #define FAR_ENOUGH 17179869184.f // 4<<32 -extern "C" int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) +int FNodeBuilder::ClassifyLine(node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]) { double d_x1 = double(node.x); double d_y1 = double(node.y); diff --git a/src/nodebuild_classify_sse2.cpp b/src/nodebuild_classify_sse2.cpp deleted file mode 100644 index 52429ecb8..000000000 --- a/src/nodebuild_classify_sse2.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef DISABLE_SSE - -#include "doomtype.h" -#include "nodebuild.h" - -#define FAR_ENOUGH 17179869184.f // 4<<32 - -// You may notice that this function is identical to ClassifyLine2. -// The reason it is SSE2 is because this file is explicitly compiled -// with SSE2 math enabled, but the other files are not. - -extern "C" int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) -{ - double d_x1 = double(node.x); - double d_y1 = double(node.y); - double d_dx = double(node.dx); - double d_dy = double(node.dy); - double d_xv1 = double(v1->x); - double d_xv2 = double(v2->x); - double d_yv1 = double(v1->y); - double d_yv2 = double(v2->y); - - double s_num1 = (d_y1 - d_yv1) * d_dx - (d_x1 - d_xv1) * d_dy; - double s_num2 = (d_y1 - d_yv2) * d_dx - (d_x1 - d_xv2) * d_dy; - - int nears = 0; - - if (s_num1 <= -FAR_ENOUGH) - { - if (s_num2 <= -FAR_ENOUGH) - { - sidev[0] = sidev[1] = 1; - return 1; - } - if (s_num2 >= FAR_ENOUGH) - { - sidev[0] = 1; - sidev[1] = -1; - return -1; - } - nears = 1; - } - else if (s_num1 >= FAR_ENOUGH) - { - if (s_num2 >= FAR_ENOUGH) - { - sidev[0] = sidev[1] = -1; - return 0; - } - if (s_num2 <= -FAR_ENOUGH) - { - sidev[0] = -1; - sidev[1] = 1; - return -1; - } - nears = 1; - } - else - { - nears = 2 | int(fabs(s_num2) < FAR_ENOUGH); - } - - if (nears) - { - double l = 1.f / (d_dx*d_dx + d_dy*d_dy); - if (nears & 2) - { - double dist = s_num1 * s_num1 * l; - if (dist < SIDE_EPSILON*SIDE_EPSILON) - { - sidev[0] = 0; - } - else - { - sidev[0] = s_num1 > 0.0 ? -1 : 1; - } - } - else - { - sidev[0] = s_num1 > 0.0 ? -1 : 1; - } - if (nears & 1) - { - double dist = s_num2 * s_num2 * l; - if (dist < SIDE_EPSILON*SIDE_EPSILON) - { - sidev[1] = 0; - } - else - { - sidev[1] = s_num2 > 0.0 ? -1 : 1; - } - } - else - { - sidev[1] = s_num2 > 0.0 ? -1 : 1; - } - } - else - { - sidev[0] = s_num1 > 0.0 ? -1 : 1; - sidev[1] = s_num2 > 0.0 ? -1 : 1; - } - - if ((sidev[0] | sidev[1]) == 0) - { // seg is coplanar with the splitter, so use its orientation to determine - // which child it ends up in. If it faces the same direction as the splitter, - // it goes in front. Otherwise, it goes in back. - - if (node.dx != 0) - { - if ((node.dx > 0 && v2->x > v1->x) || (node.dx < 0 && v2->x < v1->x)) - { - return 0; - } - else - { - return 1; - } - } - else - { - if ((node.dy > 0 && v2->y > v1->y) || (node.dy < 0 && v2->y < v1->y)) - { - return 0; - } - else - { - return 1; - } - } - } - else if (sidev[0] <= 0 && sidev[1] <= 0) - { - return 0; - } - else if (sidev[0] >= 0 && sidev[1] >= 0) - { - return 1; - } - return -1; -} - -#endif From 6210a67f855c664fef01a792fadc1c38d7aedc0d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 12:50:11 +0100 Subject: [PATCH 02/25] - fixed messagebox correctly. --- wadsrc/static/zscript/menu/messagebox.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/menu/messagebox.txt b/wadsrc/static/zscript/menu/messagebox.txt index b7b611f41..f5a60d9d4 100644 --- a/wadsrc/static/zscript/menu/messagebox.txt +++ b/wadsrc/static/zscript/menu/messagebox.txt @@ -61,7 +61,7 @@ class MessageBoxMenu : Menu int mr2 = 170 + SmallFont.StringWidth(Stringtable.Localize("$TXT_NO")); mMouseRight = MAX(mr1, mr2); mParentMenu = parent; - mMessage = SmallFont.BreakLines(message, 300); + mMessage = SmallFont.BreakLines(Stringtable.Localize(message), 300); mMessageMode = messagemode; if (playsound) { From 3412bdf5dc8e01afa7fb84b059d8fe1cc2759d67 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 12:51:24 +0100 Subject: [PATCH 03/25] Revert "Fixed splitting of long lines in message box menu" This reverts commit 76a44ebf9cdef82a3d1dc08bd43e5a960163de54. Fix was done in the wrong place, it should be inside the script so that script-side calls to open a confirmation screen also get proper treatment. --- src/menu/messagebox.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index a68bbc5f1..a1a0fda76 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -67,8 +67,7 @@ DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, { auto c = PClass::FindClass("MessageBoxMenu"); auto p = c->CreateNew(); - const FString msg = '$' == message[0] ? GStrings(message + 1) : message; - VMValue params[] = { p, parent, msg, messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; + VMValue params[] = { p, parent, FString(message), messagemode, playsound, action.GetIndex(), reinterpret_cast(handler) }; auto f = dyn_cast(c->Symbols.FindSymbol("Init", false)); GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0); From 03ac816e83dded357d9f72be969b1cee64e97dfe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 14:04:30 +0100 Subject: [PATCH 04/25] - added a gme_stereodepth CVAR. --- src/sound/i_music.cpp | 4 ++++ src/sound/i_music.h | 1 + src/sound/music_gme.cpp | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 1cbca0863..a896aeee7 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -279,6 +279,10 @@ void MusInfo::TimidityVolumeChanged() { } +void MusInfo::GMEDepthChanged(float val) +{ +} + void MusInfo::FluidSettingInt(const char *, int) { } diff --git a/src/sound/i_music.h b/src/sound/i_music.h index aaa00b020..069d2f142 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -84,6 +84,7 @@ public: virtual void FluidSettingNum(const char *setting, double value); // " virtual void FluidSettingStr(const char *setting, const char *value); // " virtual void WildMidiSetOption(int opt, int set); + virtual void GMEDepthChanged(float val); void Start(bool loop, float rel_vol = -1.f, int subsong = 0); diff --git a/src/sound/music_gme.cpp b/src/sound/music_gme.cpp index 6038f2349..d00728ec6 100644 --- a/src/sound/music_gme.cpp +++ b/src/sound/music_gme.cpp @@ -43,6 +43,7 @@ #include #include "v_text.h" #include "files.h" +#include "templates.h" // MACROS ------------------------------------------------------------------ @@ -67,6 +68,7 @@ protected: bool StartTrack(int track, bool getcritsec=true); bool GetTrackInfo(); int CalcSongLength(); + void GMEDepthChanged(float val); static bool Read(SoundStream *stream, void *buff, int len, void *userdata); }; @@ -84,6 +86,12 @@ protected: // Currently not used. CVAR (Float, spc_amp, 1.875f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, gme_stereodepth, 0.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (currSong != nullptr) + currSong->GMEDepthChanged(self); +} + // PRIVATE DATA DEFINITIONS ------------------------------------------------ // CODE -------------------------------------------------------------------- @@ -146,6 +154,7 @@ MusInfo *GME_OpenSong(FileReader &reader, const char *fmt) reader.Seek(fpos, SEEK_SET); return NULL; } + gme_set_stereo_depth(emu, clamp(*gme_stereodepth, 0.f, 1.f)); return new GMESong(emu, sample_rate); } @@ -189,6 +198,19 @@ GMESong::~GMESong() } +//========================================================================== +// +// GMESong :: GMEDepthChanged +// +//========================================================================== + +void GMESong::GMEDepthChanged(float val) +{ + if (Emu != nullptr) + gme_set_stereo_depth(Emu, clamp(val, 0.f, 1.f)); +} + + //========================================================================== // // GMESong :: Play From bb7e19120826837c65c3b6b37bffa940967bbefe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 14:50:02 +0100 Subject: [PATCH 05/25] - allow specification of intermission music based on the destination map. --- src/g_level.h | 1 + src/g_mapinfo.cpp | 12 ++++++++++++ src/wi_stuff.cpp | 5 ++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/g_level.h b/src/g_level.h index d59a4fc09..c356476a4 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -324,6 +324,7 @@ struct level_info_t FString ExitPic; FString InterMusic; int intermusicorder; + TMap > MapInterMusic; FString SoundInfo; FString SndSeq; diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index f83e18ece..89fe27ddf 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -915,6 +915,18 @@ DEFINE_MAP_OPTION(intermusic, true) parse.ParseMusic(info->InterMusic, info->intermusicorder); } +DEFINE_MAP_OPTION(mapintermusic, true) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + FString mapname = parse.sc.String; + FString music; + int order; + parse.ParseComma(); + parse.ParseMusic(music, order); + info->MapInterMusic[FName(mapname)] = std::make_pair(music, order); +} + DEFINE_MAP_OPTION(fadetable, true) { parse.ParseAssign(); diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index d5c5554da..736384e62 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -2020,7 +2020,10 @@ public: if (bcnt == 1) { // intermission music - use the defaults if none specified - if (level.info->InterMusic.IsNotEmpty()) + auto mus = level.info->MapInterMusic.CheckKey(wbs->next); + if (mus != nullptr) + S_ChangeMusic(mus->first, mus->second); + else if (level.info->InterMusic.IsNotEmpty()) S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder); else S_ChangeMusic (gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder); From a6761463af1b1cce85cc598652270150785f2f4b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 15:01:55 +0100 Subject: [PATCH 06/25] - added a new showtriggerlines mode that doesn't exclude doors. - use lambdas for the AM checker functions. --- src/am_map.cpp | 85 ++++++++++++++++++-------------------- wadsrc/static/language.eng | 1 + wadsrc/static/menudef.txt | 9 +++- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 9968f4ac4..8df074182 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -90,7 +90,7 @@ CVAR (Bool, am_customcolors, true, CVAR_ARCHIVE); CVAR (Int, am_map_secrets, 1, CVAR_ARCHIVE); CVAR (Int, am_drawmapback, 1, CVAR_ARCHIVE); CVAR (Bool, am_showkeys, true, CVAR_ARCHIVE); -CVAR (Bool, am_showtriggerlines, false, CVAR_ARCHIVE); +CVAR (Int, am_showtriggerlines, 0, CVAR_ARCHIVE); CVAR (Int, am_showthingsprites, 0, CVAR_ARCHIVE); //============================================================================= @@ -2281,58 +2281,47 @@ bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int *), int *s return (line.backsector && AM_checkSectorActions(line.backsector, function, specialptr, argsptr, false)); } -bool AM_isTeleportSpecial (int special, int *) -{ - return (special == Teleport || - special == Teleport_NoFog || - special == Teleport_ZombieChanger || - special == Teleport_Line); -} - bool AM_isTeleportBoundary (line_t &line) { - return AM_checkSpecialBoundary(line, &AM_isTeleportSpecial); -} - -bool AM_isExitSpecial (int special, int *) -{ - return (special == Teleport_NewMap || - special == Teleport_EndGame || - special == Exit_Normal || - special == Exit_Secret); + return AM_checkSpecialBoundary(line, [](int special, int *) + { + return (special == Teleport || + special == Teleport_NoFog || + special == Teleport_ZombieChanger || + special == Teleport_Line); + }); } bool AM_isExitBoundary (line_t& line) { - return AM_checkSpecialBoundary(line, &AM_isExitSpecial); -} - -bool AM_isTriggerSpecial (int special, int *) -{ - FLineSpecial *spec = P_GetLineSpecialInfo(special); - return spec != NULL - && spec->max_args >= 0 - && special != Door_Open - && special != Door_Close - && special != Door_CloseWaitOpen - && special != Door_Raise - && special != Door_Animated - && special != Generic_Door; + return AM_checkSpecialBoundary(line, [](int special, int *) + { + return (special == Teleport_NewMap || + special == Teleport_EndGame || + special == Exit_Normal || + special == Exit_Secret); + }); } bool AM_isTriggerBoundary (line_t &line) { - return AM_checkSpecialBoundary(line, &AM_isTriggerSpecial); -} - -bool AM_isLockSpecial (int special, int* args) -{ - return special == Door_LockedRaise - || special == ACS_LockedExecute - || special == ACS_LockedExecuteDoor - || (special == Door_Animated && args[3] != 0) - || (special == Generic_Door && args[4] != 0) - || (special == FS_Execute && args[2] != 0); + return am_showtriggerlines == 1? AM_checkSpecialBoundary(line, [](int special, int *) + { + FLineSpecial *spec = P_GetLineSpecialInfo(special); + return spec != NULL + && spec->max_args >= 0 + && special != Door_Open + && special != Door_Close + && special != Door_CloseWaitOpen + && special != Door_Raise + && special != Door_Animated + && special != Generic_Door; + }) : AM_checkSpecialBoundary(line, [](int special, int *) + { + FLineSpecial *spec = P_GetLineSpecialInfo(special); + return spec != NULL + && spec->max_args >= 0; + }); } bool AM_isLockBoundary (line_t &line, int *lockptr = NULL) @@ -2351,7 +2340,15 @@ bool AM_isLockBoundary (line_t &line, int *lockptr = NULL) int special; int *args; - bool result = AM_checkSpecialBoundary(line, &AM_isLockSpecial, &special, &args); + bool result = AM_checkSpecialBoundary(line, [](int special, int* args) + { + return special == Door_LockedRaise + || special == ACS_LockedExecute + || special == ACS_LockedExecuteDoor + || (special == Door_Animated && args[3] != 0) + || (special == Generic_Door && args[4] != 0) + || (special == FS_Execute && args[2] != 0); + }, &special, &args); if (result) { diff --git a/wadsrc/static/language.eng b/wadsrc/static/language.eng index bf0a0a91d..66757cee7 100644 --- a/wadsrc/static/language.eng +++ b/wadsrc/static/language.eng @@ -106,6 +106,7 @@ CMPTMNU_RENDERINGBEHAVIOR = "Rendering Behaviour"; CMPTMNU_SOUNDBEHAVIOR = "Sound Behaviour"; CMPTMNU_SECTORSOUNDS = "Sector sounds use centre as source"; OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colours only"; +OPTVAL_NODOORS = "All except doors"; C_GRAY = "\ccgrey"; C_DARKGRAY = "\cudark grey"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index d90d1851c..db2adcdfd 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1008,6 +1008,13 @@ OptionValue MapBackTypes 2, "$OPTVAL_MAPDEFINEDCOLORSONLY" } +OptionValue MapTriggers +{ + 0, "$OPTVAL_OFF" + 1, "$OPTVAL_NO_DOORS" + 2, "$OPTVAL_ON" +} + OptionMenu AutomapOptions { Title "$AUTOMAPMNU_TITLE" @@ -1031,7 +1038,7 @@ OptionMenu AutomapOptions Option "$AUTOMAPMNU_SHOWMAPLABEL", "am_showmaplabel", "MaplabelTypes" Option "$AUTOMAPMNU_DRAWMAPBACK", "am_drawmapback", "MapBackTypes" Option "$AUTOMAPMNU_SHOWKEYS", "am_showkeys", "OnOff" - Option "$AUTOMAPMNU_SHOWTRIGGERLINES", "am_showtriggerlines", "OnOff" + Option "$AUTOMAPMNU_SHOWTRIGGERLINES", "am_showtriggerlines", "MapTriggers" Option "$AUTOMAPMNU_SHOWTHINGSPRITES", "am_showthingsprites", "STSTypes" } From a0b830c1989b035b89373eeaf0fcda8c50d7d62b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 15:20:43 +0100 Subject: [PATCH 07/25] - allow all actor list CCMDs to filter by tid. --- src/c_cmds.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index ff83d8342..7e0a66c4b 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -937,14 +937,20 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha AActor *mo; const PClass *FilterClass = NULL; int counter = 0; + int tid = 0; if (FilterName != NULL) { FilterClass = PClass::FindActor(FilterName); if (FilterClass == NULL) { - Printf("%s is not an actor class.\n", FilterName); - return; + char *endp; + tid = (int)strtol(FilterName, &endp, 10); + if (*endp != 0) + { + Printf("%s is not an actor class.\n", FilterName); + return; + } } } TThinkerIterator it; @@ -953,10 +959,13 @@ static void PrintFilteredActorList(const ActorTypeChecker IsActorType, const cha { if ((FilterClass == NULL || mo->IsA(FilterClass)) && IsActorType(mo)) { - counter++; - if (!countOnly) - Printf ("%s at (%f,%f,%f)\n", - mo->GetClass()->TypeName.GetChars(), mo->X(), mo->Y(), mo->Z()); + if (tid == 0 || tid == mo->tid) + { + counter++; + if (!countOnly) + Printf("%s at (%f,%f,%f)\n", + mo->GetClass()->TypeName.GetChars(), mo->X(), mo->Y(), mo->Z()); + } } } Printf("%i match(s) found.\n", counter); From 8b2a5c75a1cc6a6e85b0e2da5dcce0a33d6a450b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 15:47:37 +0100 Subject: [PATCH 08/25] - added an old submission for PowerReflection, although it had to be seriously reworked and improved. --- src/namedef.h | 2 ++ src/p_interaction.cpp | 22 ++++++++++++++++++++ wadsrc/static/zscript/inventory/powerups.txt | 15 +++++++++++++ 3 files changed, 39 insertions(+) diff --git a/src/namedef.h b/src/namedef.h index 13e9096bc..5aa7e82db 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -197,6 +197,8 @@ xx(PowerWeaponLevel2) xx(PowerFlight) xx(PowerSpeed) xx(PowerTorch) +xx(PowerReflection) +xx(Reflection) xx(CustomInventory) xx(Inventory) xx(CallTryPickup) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index e940c259f..2e2dd5682 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1162,6 +1162,28 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da // any negative value means that something in the above chain has cancelled out all damage and all damage effects, including pain. return 0; } + + + AInventory *reflect; + //[RC] Backported from the Zandronum source.. Mostly. + if( target->player && + damage > 0 && + source && + (reflect = target->FindInventory(NAME_PowerReflection)) && + mod != NAME_Reflection) + { + if ( target != source ) + { + // use the reflect item's damage factors to get the final value here. + int reflectdamage = reflect->ApplyDamageFactor(mod, damage); + P_DamageMobj(source, nullptr, target, reflectdamage, NAME_Reflection ); + + // Reset means of death flag. + MeansOfDeath = mod; + } + } + + // Push the target unless the source's weapon's kickback is 0. // (i.e. Gauntlets/Chainsaw) if (!plrDontThrust && inflictor && inflictor != target // [RH] Not if hurting own self diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 346f3d1a7..897fe80e3 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -1939,6 +1939,21 @@ class PowerInfiniteAmmo : Powerup } } + +//=========================================================================== +// +// InfiniteAmmo +// +//=========================================================================== + +class PowerReflection : Powerup +{ + Default + { + Powerup.Duration -30; + } +} + //=========================================================================== // // PowerMorph From c7668952d9c0b5e7af6b124b5b24d172474172e1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 15:50:03 +0100 Subject: [PATCH 09/25] - set sensible defaults for PowerReflection. --- wadsrc/static/zscript/inventory/powerups.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 897fe80e3..1fc63cfbe 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -1950,7 +1950,8 @@ class PowerReflection : Powerup { Default { - Powerup.Duration -30; + Powerup.Duration -60; + DamageFactor 0.5; } } From e6b31dde27b47f484c4d1073cc3760cab5b4b2a3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 16:23:22 +0100 Subject: [PATCH 10/25] - added some flexibility to some Skulltag powerups. - handle these powerups by actual item checks instead of cheat flags. (The same should also be done for the Frightener and Buddha but those are a bit more complex because they are also real cheats.) --- src/d_player.h | 6 -- src/namedef.h | 2 + src/p_interaction.cpp | 37 ++++++-- src/p_mobj.cpp | 3 +- src/p_user.cpp | 12 ++- wadsrc/static/zscript/constants.txt | 16 ++-- wadsrc/static/zscript/inventory/powerups.txt | 92 ++------------------ 7 files changed, 58 insertions(+), 110 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index b16af3611..2d7d439c5 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -209,13 +209,7 @@ typedef enum CF_TOTALLYFROZEN = 1 << 12, // [RH] All players can do is press +use CF_PREDICTING = 1 << 13, // [RH] Player movement is being predicted CF_INTERPVIEW = 1 << 14, // [RH] view was changed outside of input, so interpolate one frame - CF_DRAIN = 1 << 16, // Player owns a drain powerup - CF_HIGHJUMP = 1 << 18, // more Skulltag flags. Implementation not guaranteed though. ;) - CF_REFLECTION = 1 << 19, - CF_PROSPERITY = 1 << 20, - CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. - CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either. CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either. CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die diff --git a/src/namedef.h b/src/namedef.h index 5aa7e82db..dd4a4f5e3 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -197,7 +197,9 @@ xx(PowerWeaponLevel2) xx(PowerFlight) xx(PowerSpeed) xx(PowerTorch) +xx(PowerHighJump) xx(PowerReflection) +xx(PowerDrain) xx(Reflection) xx(CustomInventory) xx(Inventory) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 2e2dd5682..33605e4e3 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1164,18 +1164,28 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da } - AInventory *reflect; //[RC] Backported from the Zandronum source.. Mostly. if( target->player && damage > 0 && source && - (reflect = target->FindInventory(NAME_PowerReflection)) && - mod != NAME_Reflection) + mod != NAME_Reflection && + target != source) + { - if ( target != source ) + int reflectdamage = 0; + for (auto p = target->player->mo->Inventory; p != nullptr; p = p->Inventory) + { + // This picks the reflection item with the maximum efficiency for the given damage type. + if (p->IsKindOf(NAME_PowerReflection)) + { + int mydamage = p->ApplyDamageFactor(mod, damage); + if (mydamage > reflectdamage) reflectdamage = mydamage; + } + } + + if (reflectdamage > 0) { // use the reflect item's damage factors to get the final value here. - int reflectdamage = reflect->ApplyDamageFactor(mod, damage); P_DamageMobj(source, nullptr, target, reflectdamage, NAME_Reflection ); // Reset means of death flag. @@ -1439,13 +1449,24 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da // If the damaging player has the power of drain, give the player 50% of the damage // done in health. - if ( source && source->player && source->player->cheats & CF_DRAIN && !(target->flags5 & MF5_DONTDRAIN)) + if ( source && source->player && !(target->flags5 & MF5_DONTDRAIN)) { if (!target->player || target->player != source->player) { - if ( P_GiveBody( source, damage / 2 )) + double draindamage = 0; + for (auto p = source->player->mo->Inventory; p != nullptr; p = p->Inventory) { - S_Sound( source, CHAN_ITEM, "*drainhealth", 1, ATTN_NORM ); + // This picks the item with the maximum efficiency. + if (p->IsKindOf(NAME_PowerDrain)) + { + double mydamage = p->FloatVar(NAME_Strength); + if (mydamage > draindamage) draindamage = mydamage; + } + } + + if ( P_GiveBody( source, int(draindamage * damage))) + { + S_Sound(source, CHAN_ITEM, "*drainhealth", 1, ATTN_NORM ); } } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a908e115e..d14c69aad 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -902,8 +902,7 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate // Do not take ammo if the "no take infinite/take as ammo depletion" flag is set // and infinite ammo is on if (notakeinfinite && - ((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) && - item->IsKindOf(NAME_Ammo)) + ((dmflags & DF_INFINITE_AMMO) || (player && FindInventory(NAME_PowerInfiniteAmmo))) && item->IsKindOf(NAME_Ammo)) { // Nothing to do here, except maybe res = false;? Would it make sense? result = false; diff --git a/src/p_user.cpp b/src/p_user.cpp index 53e27c0f5..5bb0e2127 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2689,9 +2689,19 @@ void P_PlayerThink (player_t *player) else if (level.IsJumpingAllowed() && player->onground && player->jumpTics == 0) { double jumpvelz = player->mo->JumpZ * 35 / TICRATE; + double jumpfac = 0; // [BC] If the player has the high jump power, double his jump velocity. - if ( player->cheats & CF_HIGHJUMP ) jumpvelz *= 2; + // (actually, pick the best factors from all active items.) + for (auto p = player->mo->Inventory; p != nullptr; p = p->Inventory) + { + if (p->IsKindOf(NAME_PowerHighJump)) + { + double f = p->FloatVar(NAME_Strength); + if (f > jumpfac) jumpfac = f; + } + } + if (jumpfac > 0) jumpvelz *= jumpfac; player->mo->Vel.Z += jumpvelz; player->mo->flags2 &= ~MF2_ONMOBJ; diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index e2390cfd1..422853ea6 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -1088,17 +1088,21 @@ enum EPlayerCheats CF_TOTALLYFROZEN = 1 << 12, // [RH] All players can do is press +use CF_PREDICTING = 1 << 13, // [RH] Player movement is being predicted CF_INTERPVIEW = 1 << 14, // [RH] view was changed outside of input, so interpolate one frame - CF_DRAIN = 1 << 16, // Player owns a drain powerup - CF_HIGHJUMP = 1 << 18, // more Skulltag flags. Implementation not guaranteed though. ;) - CF_REFLECTION = 1 << 19, - CF_PROSPERITY = 1 << 20, - CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact + CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. - CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact + CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either. CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either. CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip + + // These flags no longer exist, but keep the names for some stray mod that might have used them. + CF_DRAIN = 0, + CF_HIGHJUMP = 0, + CF_REFLECTION = 0, + CF_PROSPERITY = 0, + CF_DOUBLEFIRINGSPEED= 0, + CF_INFINITEAMMO = 0, }; const TEXTCOLOR_BRICK = "\034A"; diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 1fc63cfbe..3b01c97b3 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -1783,32 +1783,9 @@ class PowerDrain : Powerup { Default { + Powerup.Strength 0.5; Powerup.Duration -60; } - - override void InitEffect() - { - Super.InitEffect(); - - if (Owner!= null && Owner.player != null) - { - // Give the player the power to drain life from opponents when he damages them. - Owner.player.cheats |= CF_DRAIN; - } - } - - override void EndEffect() - { - Super.EndEffect(); - - // Nothing to do if there's no owner. - if (Owner!= null && Owner.player != null) - { - // Take away the drain power. - Owner.player.cheats &= ~CF_DRAIN; - } - } - } //=========================================================================== @@ -1846,27 +1823,9 @@ class PowerRegeneration : Powerup class PowerHighJump : Powerup { - override void InitEffect() + Default { - Super.InitEffect(); - - if (Owner!= null && Owner.player != null) - { - // Give the player the power to jump much higher. - Owner.player.cheats |= CF_HIGHJUMP; - } - } - - override void EndEffect() - { - Super.EndEffect(); - - // Nothing to do if there's no owner. - if (Owner!= null && Owner.player != null) - { - // Take away the high jump power. - Owner.player.cheats &= ~CF_HIGHJUMP; - } + Powerup.Strength 2; } } @@ -1878,27 +1837,9 @@ class PowerHighJump : Powerup class PowerDoubleFiringSpeed : Powerup { - override void InitEffect() + Default { - Super.InitEffect(); - - if (Owner!= null && Owner.player != null) - { - // Give the player the power to shoot twice as fast. - Owner.player.cheats |= CF_DOUBLEFIRINGSPEED; - } - } - - override void EndEffect() - { - Super.EndEffect(); - - // Nothing to do if there's no owner. - if (Owner!= null && Owner.player != null) - { - // Take away the shooting twice as fast power. - Owner.player.cheats &= ~CF_DOUBLEFIRINGSPEED; - } + Powerup.Duration -40; } } @@ -1914,29 +1855,6 @@ class PowerInfiniteAmmo : Powerup { Powerup.Duration -30; } - - override void InitEffect() - { - Super.InitEffect(); - - if (Owner!= null && Owner.player != null) - { - // Give the player infinite ammo - Owner.player.cheats |= CF_INFINITEAMMO; - } - } - - override void EndEffect() - { - Super.EndEffect(); - - // Nothing to do if there's no owner. - if (Owner!= null && Owner.player != null) - { - // Take away the limitless ammo - Owner.player.cheats &= ~CF_INFINITEAMMO; - } - } } From d80dc098bd1a37aa70234f20e62a10a7b8206e22 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 16:48:24 +0100 Subject: [PATCH 11/25] - added a RESETITEMS MAPINFO flag. --- src/g_game.cpp | 12 ++++++++++++ src/g_level.h | 1 + src/g_mapinfo.cpp | 1 + 3 files changed, 14 insertions(+) diff --git a/src/g_game.cpp b/src/g_game.cpp index b4e497311..b39ee52a8 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1343,12 +1343,24 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags) if (mode == FINISH_NoHub && !(level.flags2 & LEVEL2_KEEPFULLINVENTORY)) { // Reduce all owned (visible) inventory to defined maximum interhub amount + TArray todelete; for (item = p->mo->Inventory; item != NULL; item = item->Inventory) { // If the player is carrying more samples of an item than allowed, reduce amount accordingly if (item->ItemFlags & IF_INVBAR && item->Amount > item->InterHubAmount) { item->Amount = item->InterHubAmount; + if ((level.flags3 & LEVEL3_RESETINVENTORY) && !(item->ItemFlags & IF_UNDROPPABLE)) + { + todelete.Push(item); + } + } + } + for (auto it : todelete) + { + if (!(it->ObjectFlags & OF_EuthanizeMe)) + { + it->DepleteOrDestroy(); } } } diff --git a/src/g_level.h b/src/g_level.h index c356476a4..cf5d1865d 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -223,6 +223,7 @@ enum ELevelFlags : unsigned int // More flags! LEVEL3_FORCEFAKECONTRAST = 0x00000001, // forces fake contrast even with fog enabled + LEVEL3_RESETINVENTORY = 0x00000002, // kills all INVBAR items on map change. }; diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 89fe27ddf..7a7960115 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1277,6 +1277,7 @@ MapFlagHandlers[] = { "laxmonsteractivation", MITYPE_SETFLAG2, LEVEL2_LAXMONSTERACTIVATION, LEVEL2_LAXACTIVATIONMAPINFO }, { "additive_scrollers", MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL, 0 }, { "keepfullinventory", MITYPE_SETFLAG2, LEVEL2_KEEPFULLINVENTORY, 0 }, + { "resetitems", MITYPE_SETFLAG3, LEVEL2_RESETINVENTORY, 0 }, { "monsterfallingdamage", MITYPE_SETFLAG2, LEVEL2_MONSTERFALLINGDAMAGE, 0 }, { "nomonsterfallingdamage", MITYPE_CLRFLAG2, LEVEL2_MONSTERFALLINGDAMAGE, 0 }, { "clipmidtextures", MITYPE_SETFLAG2, LEVEL2_CLIPMIDTEX, 0 }, From ee6e427e78dabdcfb6a2ed9de1febf352e7f8e0d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 16:54:09 +0100 Subject: [PATCH 12/25] - fixed: USDF did not allow specials > 255. --- src/p_udmf.cpp | 2 +- src/p_usdf.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index fc71160ae..0ba75fc4c 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1393,7 +1393,7 @@ public: if (isTranslated) sec->special = P_TranslateSectorSpecial(sec->special); else if (namespc == NAME_Hexen) { - if (sec->special < 0 || sec->special > 255 || !HexenSectorSpecialOk[sec->special]) + if (sec->special < 0 || sec->special > 140 || !HexenSectorSpecialOk[sec->special]) sec->special = 0; // NULL all unknown specials } continue; diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 5a5f3c826..8c8a0c6e3 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -192,7 +192,7 @@ class USDFParser : public UDMFParserBase case NAME_Special: reply->ActionSpecial = CheckInt(key); - if (reply->ActionSpecial < 0 || reply->ActionSpecial > 255) + if (reply->ActionSpecial < 0) reply->ActionSpecial = 0; break; From f31ddbc57cbbb5ac373a916dc759a16b87dcebde Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 17:05:04 +0100 Subject: [PATCH 13/25] - allow specifying specials in ZSDF by name. - allow specifying a decal ID by name in UDMF. --- specs/usdf_zdoom.txt | 2 ++ src/g_shared/a_decals.cpp | 15 ++++++++++++--- src/namedef.h | 1 + src/p_usdf.cpp | 5 +++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index cd4393351..2025b06ba 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -92,6 +92,8 @@ conversation // Starts a dialog. choice { + specialname = ; // Allows specifying a special by name. + // The amount of an item needed for this option to become available. // You can have as many as needed. All require blocks must be satisfied // to show this option. diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index dfa66795c..3ad19741a 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -751,14 +751,23 @@ IMPLEMENT_CLASS(ADecal, false, false) void ADecal::BeginPlay () { - const FDecalTemplate *tpl; + const FDecalTemplate *tpl = nullptr; Super::BeginPlay (); - int decalid = args[0] + (args[1] << 8); // [KS] High byte for decals. + if (args[0] < 0) + { + FName name = ENamedName(-args[0]); + tpl = DecalLibrary.GetDecalByName(name.GetChars()); + } + else + { + int decalid = args[0] + (args[1] << 8); // [KS] High byte for decals. + tpl = DecalLibrary.GetDecalByNum(decalid); + } // If no decal is specified, don't try to create one. - if (decalid != 0 && (tpl = DecalLibrary.GetDecalByNum (decalid)) != 0) + if (tpl != nullptr) { if (!tpl->PicNum.Exists()) { diff --git a/src/namedef.h b/src/namedef.h index dd4a4f5e3..9cd0a19ec 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -360,6 +360,7 @@ xx(CeilingZ) xx(FloorZ) xx(Health) xx(Pitch) +xx(SpecialName) xx(Special) xx(TID) xx(TIDtoHate) diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 8c8a0c6e3..3d2c2e010 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -196,6 +196,11 @@ class USDFParser : public UDMFParserBase reply->ActionSpecial = 0; break; + case NAME_SpecialName: + if (namespace_bits == Zd) + reply->ActionSpecial = P_FindLineSpecial(CheckString(key)); + break; + case NAME_Arg0: case NAME_Arg1: case NAME_Arg2: From 3f5ef48dacc08bf85741fafbeaee05242d0a1594 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 17:22:02 +0100 Subject: [PATCH 14/25] - allow setting a global dialogue lump through gameinfo. --- src/gi.cpp | 1 + src/gi.h | 1 + src/p_conversation.cpp | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/src/gi.cpp b/src/gi.cpp index fa8afb545..672ca3263 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -374,6 +374,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_PATCH(mStatscreenEnteringFont, "statscreen_enteringpatch") GAMEINFOKEY_BOOL(norandomplayerclass, "norandomplayerclass") GAMEINFOKEY_BOOL(forcekillscripts, "forcekillscripts") // [JM] Force kill scripts on thing death. (MF7_NOKILLSCRIPTS overrides.) + GAMEINFOKEY_STRING(Dialogue, "dialogue") else { diff --git a/src/gi.h b/src/gi.h index 24053b002..2c614e3c7 100644 --- a/src/gi.h +++ b/src/gi.h @@ -176,6 +176,7 @@ struct gameinfo_t FName DefaultEndSequence; FString mMapArrow, mCheatMapArrow; FString mEasyKey, mCheatKey; + FString Dialogue; FGIFont mStatscreenMapNameFont; FGIFont mStatscreenFinishedFont; FGIFont mStatscreenEnteringFont; diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 90271333c..f43313682 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -205,6 +205,11 @@ void P_LoadStrifeConversations (MapData *map, const char *mapname) { if (!LoadScriptFile (scriptname_b, false, 1)) { + if (gameinfo.Dialogue.IsNotEmpty()) + { + if (LoadScriptFile(gameinfo.Dialogue, false, 0)) return; + } + LoadScriptFile ("SCRIPT00", false, 1); } } From c4b546404ace0d20fa5315bba158426abcabaf90 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 17:50:48 +0100 Subject: [PATCH 15/25] - added a 'nocheck' parameter to A_Raise* and Thing_Raise. --- src/actionspecials.h | 2 +- src/p_actionfunctions.cpp | 22 ++++++++++++++++------ src/p_lnspec.cpp | 6 +++--- src/p_local.h | 2 +- src/p_things.cpp | 4 ++-- wadsrc/static/zscript/actor.txt | 6 +++--- wadsrc/static/zscript/constants.txt | 6 ++++++ 7 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index 42861b702..aac1b7161 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -15,7 +15,7 @@ DEFINE_SPECIAL(Door_LockedRaise, 13, 4, 5, 5) DEFINE_SPECIAL(Door_Animated, 14, 4, 4, 4) DEFINE_SPECIAL(Autosave, 15, 0, 0, 0) // [RH] Save the game *now* DEFINE_SPECIAL(Transfer_WallLight, 16, -1, -1, 2) -DEFINE_SPECIAL(Thing_Raise, 17, 1, 1, 1) +DEFINE_SPECIAL(Thing_Raise, 17, 1, 2, 2) DEFINE_SPECIAL(StartConversation, 18, 1, 2, 2) DEFINE_SPECIAL(Thing_Stop, 19, 1, 1, 1) DEFINE_SPECIAL(Floor_LowerByValue, 20, 3, 4, 4) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 16c8c3267..51e71cb3f 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -4602,6 +4602,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeCountFlags) return 0; } + +enum ERaise +{ + RF_TRANSFERFRIENDLINESS = 1, + RF_NOCHECKPOSITION = 2 +}; + //=========================================================================== // // A_RaiseMaster @@ -4610,11 +4617,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeCountFlags) DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) { PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL_DEF(copy); + PARAM_INT_DEF(flags); + bool copy = !!(flags & RF_TRANSFERFRIENDLINESS); if (self->master != NULL) { - P_Thing_Raise(self->master, copy ? self : NULL); + P_Thing_Raise(self->master, copy ? self : NULL, (flags & RF_NOCHECKPOSITION)); } return 0; } @@ -4627,16 +4635,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) { PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL_DEF(copy); + PARAM_INT_DEF(flags); TThinkerIterator it; AActor *mo; + bool copy = !!(flags & RF_TRANSFERFRIENDLINESS); while ((mo = it.Next()) != NULL) { if (mo->master == self) { - P_Thing_Raise(mo, copy ? self : NULL); + P_Thing_Raise(mo, copy ? self : NULL, (flags & RF_NOCHECKPOSITION)); } } return 0; @@ -4650,18 +4659,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) { PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL_DEF(copy); + PARAM_INT_DEF(flags); TThinkerIterator it; AActor *mo; + bool copy = !!(flags & RF_TRANSFERFRIENDLINESS); if (self->master != NULL) { while ((mo = it.Next()) != NULL) { if (mo->master == self->master && mo != self) { - P_Thing_Raise(mo, copy ? self : NULL); + P_Thing_Raise(mo, copy ? self : NULL, (flags & RF_NOCHECKPOSITION)); } } } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 9cbb4aec1..394203c75 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1737,14 +1737,14 @@ FUNC(LS_Thing_SpawnFacing) } FUNC(LS_Thing_Raise) -// Thing_Raise(tid) +// Thing_Raise(tid, nocheck) { AActor * target; bool ok = false; if (arg0==0) { - ok = P_Thing_Raise (it,NULL); + ok = P_Thing_Raise (it,NULL, arg1); } else { @@ -1752,7 +1752,7 @@ FUNC(LS_Thing_Raise) while ( (target = iterator.Next ()) ) { - ok |= P_Thing_Raise(target,NULL); + ok |= P_Thing_Raise(target,NULL, arg1); } } return ok; diff --git a/src/p_local.h b/src/p_local.h index 677de09fc..9ce290be7 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -151,7 +151,7 @@ bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog); int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type); void P_Thing_SetVelocity(AActor *actor, const DVector3 &vec, bool add, bool setbob); void P_RemoveThing(AActor * actor); -bool P_Thing_Raise(AActor *thing, AActor *raiser); +bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck = false); bool P_Thing_CanRaise(AActor *thing); PClassActor *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); diff --git a/src/p_things.cpp b/src/p_things.cpp index f6c06a1e5..d4298f934 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -406,7 +406,7 @@ void P_RemoveThing(AActor * actor) } -bool P_Thing_Raise(AActor *thing, AActor *raiser) +bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck) { FState * RaiseState = thing->GetRaiseState(); if (RaiseState == NULL) @@ -426,7 +426,7 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser) thing->flags |= MF_SOLID; thing->Height = info->Height; // [RH] Use real height thing->radius = info->radius; // [RH] Use real radius - if (!P_CheckPosition (thing, thing->Pos())) + if (!nocheck && !P_CheckPosition (thing, thing->Pos())) { thing->flags = oldflags; thing->radius = oldradius; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 2e9752b97..926b03804 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -790,9 +790,9 @@ class Actor : Thinker native native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0); deprecated native void A_ChangeFlag(string flagname, bool value); native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE); - native void A_RaiseMaster(bool copy = 0); - native void A_RaiseChildren(bool copy = 0); - native void A_RaiseSiblings(bool copy = 0); + native void A_RaiseMaster(int flags = 0); + native void A_RaiseChildren(int flags = 0); + native void A_RaiseSiblings(int flags = 0); deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class missiletype, double missileheight); action native bool, Actor A_ThrowGrenade(class itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true); native void A_Weave(int xspeed, int yspeed, double xdist, double ydist); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 422853ea6..9e9d4dae8 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -996,6 +996,12 @@ enum EFindFloorCeiling FFCF_NODROPOFF = 256, // Caller does not need a dropoff (saves some time when checking portals) }; +enum ERaise +{ + RF_TRANSFERFRIENDLINESS = 1, + RF_NOCHECKPOSITION = 2 +} + enum ETeleport { TELF_DESTFOG = 1, From 5fe04dfd2022e0f235d647ae3d804814191675d7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 18:37:12 +0100 Subject: [PATCH 16/25] - added A_SprayDecal function. --- src/d_net.cpp | 21 ++------------------- src/g_shared/a_decals.cpp | 18 ++++++++++++++++++ src/g_shared/a_sharedglobal.h | 1 + src/p_actionfunctions.cpp | 8 ++++++++ wadsrc/static/zscript/actor.txt | 1 + 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 7163cdd55..fb7cac316 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2376,25 +2376,8 @@ void Net_DoCommand (int type, BYTE **stream, int player) break; case DEM_SPRAY: - { - FTraceResults trace; - - DAngle ang = players[player].mo->Angles.Yaw; - DAngle pitch = players[player].mo->Angles.Pitch; - double c = pitch.Cos(); - DVector3 vec(c * ang.Cos(), c * ang.Sin(), -pitch.Sin()); - - s = ReadString (stream); - - if (Trace (players[player].mo->PosPlusZ(players[player].mo->Height/2), players[player].mo->Sector, - vec, 172., 0, ML_BLOCKEVERYTHING, players[player].mo, trace, TRACE_NoSky)) - { - if (trace.HitType == TRACE_HitWall) - { - DImpactDecal::StaticCreate (s, trace.HitPos, trace.Line->sidedef[trace.Side], NULL); - } - } - } + s = ReadString(stream); + SprayDecal(players[player].mo, s); break; case DEM_PAUSE: diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index 3ad19741a..21f116b07 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -704,6 +704,24 @@ CCMD (spray) Net_WriteString (argv[1]); } +void SprayDecal(AActor *shooter, const char *name) +{ + FTraceResults trace; + + DAngle ang = shooter->Angles.Yaw; + DAngle pitch = shooter->Angles.Pitch; + double c = pitch.Cos(); + DVector3 vec(c * ang.Cos(), c * ang.Sin(), -pitch.Sin()); + + if (Trace(shooter->PosPlusZ(shooter->Height / 2), shooter->Sector, vec, 172., 0, ML_BLOCKEVERYTHING, shooter, trace, TRACE_NoSky)) + { + if (trace.HitType == TRACE_HitWall) + { + DImpactDecal::StaticCreate(name, trace.HitPos, trace.Line->sidedef[trace.Side], NULL); + } + } +} + DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent) { if (tpl == NULL || (tpl = tpl->GetDecal()) == NULL) diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index c9d0d86ce..ea367dd3a 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -11,6 +11,7 @@ struct F3DFloor; class DBaseDecal; class DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent); +void SprayDecal(AActor *shooter, const char *name); class DBaseDecal : public DThinker { diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 51e71cb3f..53fe2b6a0 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -6932,3 +6932,11 @@ DEFINE_ACTION_FUNCTION(AActor, SetCamera) } return 0; } + +DEFINE_ACTION_FUNCTION(AActor, A_SprayDecal) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(name); + SprayDecal(self, name); + return 0; +} diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 926b03804..fdc9ddade 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -868,6 +868,7 @@ class Actor : Thinker native native bool A_SetVisibleRotation(double anglestart = 0, double angleend = 0, double pitchstart = 0, double pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetTranslation(name transname); native bool A_SetSize(double newradius, double newheight = -1, bool testpos = false); + native void A_SprayDecal(String name); native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); From fb3d4bd42a7b46d0652c87a0cde7b0c641d095bd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 18:46:06 +0100 Subject: [PATCH 17/25] - added A_SetMugshotState. --- src/p_actionfunctions.cpp | 10 ++++++++++ wadsrc/static/zscript/actor.txt | 1 + 2 files changed, 11 insertions(+) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 53fe2b6a0..54a577e5b 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -80,6 +80,7 @@ #include "math/cmath.h" #include "g_levellocals.h" #include "r_utility.h" +#include "sbar.h" AActor *SingleActorFromTID(int tid, AActor *defactor); @@ -6940,3 +6941,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_SprayDecal) SprayDecal(self, name); return 0; } + +DEFINE_ACTION_FUNCTION(AActor, A_SetMugshotState) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(name); + if (self->CheckLocalView(consoleplayer)) + StatusBar->SetMugShotState(name); + return 0; +} \ No newline at end of file diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index fdc9ddade..9b52e7271 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -869,6 +869,7 @@ class Actor : Thinker native native void A_SetTranslation(name transname); native bool A_SetSize(double newradius, double newheight = -1, bool testpos = false); native void A_SprayDecal(String name); + native void A_SetMugshotState(String name); native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); From 92b916fd5de907103f906117d915796ad92ef76f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 18:49:40 +0100 Subject: [PATCH 18/25] - fixed: ACS's SetMugshotState function was essentially broken in multiplayer because it contained no checks if the script's activator is connected to the current console player. Ideally this should also be fixed for singleplayer but that would probably break half the mods using this function... --- src/p_acs.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 463868d88..ad66627f5 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -9423,7 +9423,10 @@ scriptwait: } case PCD_SETMUGSHOTSTATE: - StatusBar->SetMugShotState(FBehavior::StaticLookupString(STACK(1))); + if (!multiplayer || (activator != nullptr && activator->CheckLocalView(consoleplayer))) + { + StatusBar->SetMugShotState(FBehavior::StaticLookupString(STACK(1))); + } sp--; break; From 0cc46a2aafa7e5290f13bec4fb62e8161e7729b4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 19:05:20 +0100 Subject: [PATCH 19/25] - added a FORCEINFIGHTING flag. --- src/actor.h | 1 + src/p_interaction.cpp | 3 ++- src/p_map.cpp | 1 + src/scripting/thingdef_data.cpp | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/actor.h b/src/actor.h index c8c7cbc5f..b52cb6571 100644 --- a/src/actor.h +++ b/src/actor.h @@ -389,6 +389,7 @@ enum ActorFlag7 MF7_NOSHIELDREFLECT = 0x08000000, // will not be reflected by shields. MF7_FORCEZERORADIUSDMG = 0x10000000, // passes zero radius damage on to P_DamageMobj, this is necessary in some cases where DoSpecialDamage gets overrideen. MF7_NOINFIGHTSPECIES = 0x20000000, // don't start infights with one's own species. + MF7_FORCEINFIGHTING = 0x40000000, // overrides a map setting of 'no infighting'. }; // --- mobj.renderflags --- diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 33605e4e3..c13024fcf 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1772,7 +1772,8 @@ bool AActor::OkayToSwitchTarget (AActor *other) } int infight; - if (flags5 & MF5_NOINFIGHTING) infight=-1; + if (flags7 & MF7_FORCEINFIGHTING) infight = 1; + else if (flags5 & MF5_NOINFIGHTING) infight = -1; else infight = G_SkillProperty(SKILLP_Infight); if (infight < 0 && other->player == NULL && !IsHostile (other)) diff --git a/src/p_map.cpp b/src/p_map.cpp index 13f566b1f..58aaefc17 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1177,6 +1177,7 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) if (!victim->player && !shooter->player) { int infight = G_SkillProperty(SKILLP_Infight); + if (infight < 0 && (victim->flags7 & MF7_FORCEINFIGHTING)) infight = 0; // This must override the 'no infight' setting to take effect. if (infight < 0) { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index f68667bbb..3a76002fa 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -318,6 +318,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, NOSHIELDREFLECT, AActor, flags7), DEFINE_FLAG(MF7, FORCEZERORADIUSDMG, AActor, flags7), DEFINE_FLAG(MF7, NOINFIGHTSPECIES, AActor, flags7), + DEFINE_FLAG(MF7, FORCEINFIGHTING, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), From b0eb19bbc8b80f3ab6f20a3ff57e9ca739fa5252 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 19:29:27 +0100 Subject: [PATCH 20/25] - added an option to define untranslated fonts through FONTDEFS. Note that due to how the fonts work they cannot be colorized AT ALL! --- src/v_font.cpp | 41 ++++++++++++++++++++++++++++------------- src/v_font.h | 4 +++- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/v_font.cpp b/src/v_font.cpp index a82bd16c1..d668de94c 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -163,7 +163,7 @@ protected: class FSpecialFont : public FFont { public: - FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump); + FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); void LoadTranslations(); @@ -357,7 +357,7 @@ DEFINE_ACTION_FUNCTION(FFont, GetFont) // //========================================================================== -FFont::FFont (const char *name, const char *nametemplate, int first, int count, int start, int fdlump, int spacewidth) +FFont::FFont (const char *name, const char *nametemplate, int first, int count, int start, int fdlump, int spacewidth, bool notranslate) { int i; FTextureID lump; @@ -367,6 +367,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, bool doomtemplate = gameinfo.gametype & GAME_DoomChex ? strncmp (nametemplate, "STCFN", 5) == 0 : false; bool stcfn121 = false; + noTranslate = notranslate; Lump = fdlump; Chars = new CharData[count]; charlumps = new FTexture *[count]; @@ -430,7 +431,8 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, if (charlumps[i] != NULL) { - Chars[i].Pic = new FFontChar1 (charlumps[i]); + if (!noTranslate) Chars[i].Pic = new FFontChar1 (charlumps[i]); + else Chars[i].Pic = charlumps[i]; Chars[i].XMove = Chars[i].Pic->GetScaledWidth(); } else @@ -455,7 +457,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, FixXMoves(); - LoadTranslations(); + if (!noTranslate) LoadTranslations(); delete[] charlumps; } @@ -472,11 +474,15 @@ FFont::~FFont () { int count = LastChar - FirstChar + 1; - for (int i = 0; i < count; ++i) + // A noTranslate font directly references the original textures. + if (!noTranslate) { - if (Chars[i].Pic != NULL && Chars[i].Pic->Name[0] == 0) + for (int i = 0; i < count; ++i) { - delete Chars[i].Pic; + if (Chars[i].Pic != NULL && Chars[i].Pic->Name[0] == 0) + { + delete Chars[i].Pic; + } } } delete[] Chars; @@ -752,7 +758,7 @@ void FFont::BuildTranslations (const double *luminosity, const BYTE *identity, FRemapTable *FFont::GetColorTranslation (EColorRange range) const { - if (ActiveColors == 0) + if (ActiveColors == 0 || noTranslate) return NULL; else if (range >= NumTextColors) range = CR_UNTRANSLATED; @@ -1005,6 +1011,7 @@ FFont::FFont (int lump) PatchRemap = NULL; FontName = NAME_None; Cursor = '_'; + noTranslate = false; } //========================================================================== @@ -1962,7 +1969,7 @@ void FFontChar2::MakeTexture () // //========================================================================== -FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump) : FFont(lump) +FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) : FFont(lump) { int i; FTexture **charlumps; @@ -1971,6 +1978,7 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l memcpy(this->notranslate, notranslate, 256*sizeof(bool)); + noTranslate = donttranslate; FontName = name; Chars = new CharData[count]; charlumps = new FTexture*[count]; @@ -2005,7 +2013,8 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l if (charlumps[i] != NULL) { - Chars[i].Pic = new FFontChar1 (charlumps[i]); + if (!noTranslate) Chars[i].Pic = new FFontChar1 (charlumps[i]); + else Chars[i].Pic = charlumps[i]; Chars[i].XMove = Chars[i].Pic->GetScaledWidth(); } else @@ -2027,7 +2036,7 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l FixXMoves(); - LoadTranslations(); + if (!noTranslate) LoadTranslations(); delete[] charlumps; } @@ -2158,6 +2167,7 @@ void V_InitCustomFonts() FScanner sc; FTexture *lumplist[256]; bool notranslate[256]; + bool donttranslate; FString namebuffer, templatebuf; int i; int llump,lastlump=0; @@ -2175,6 +2185,7 @@ void V_InitCustomFonts() { memset (lumplist, 0, sizeof(lumplist)); memset (notranslate, 0, sizeof(notranslate)); + donttranslate = false; namebuffer = sc.String; format = 0; start = 33; @@ -2226,6 +2237,10 @@ void V_InitCustomFonts() spacewidth = sc.Number; format = 1; } + else if (sc.Compare("DONTTRANSLATE")) + { + donttranslate = true; + } else if (sc.Compare ("NOTRANSLATION")) { if (format == 1) goto wrong; @@ -2256,7 +2271,7 @@ void V_InitCustomFonts() } if (format == 1) { - FFont *fnt = new FFont (namebuffer, templatebuf, first, count, start, llump, spacewidth); + FFont *fnt = new FFont (namebuffer, templatebuf, first, count, start, llump, spacewidth, donttranslate); fnt->SetCursor(cursor); } else if (format == 2) @@ -2279,7 +2294,7 @@ void V_InitCustomFonts() } if (count > 0) { - FFont *fnt = new FSpecialFont (namebuffer, first, count, &lumplist[first], notranslate, llump); + FFont *fnt = new FSpecialFont (namebuffer, first, count, &lumplist[first], notranslate, llump, donttranslate); fnt->SetCursor(cursor); } } diff --git a/src/v_font.h b/src/v_font.h index 21d773d9d..ec85f7622 100644 --- a/src/v_font.h +++ b/src/v_font.h @@ -75,7 +75,7 @@ extern int NumTextColors; class FFont { public: - FFont (const char *fontname, const char *nametemplate, int first, int count, int base, int fdlump, int spacewidth=-1); + FFont (const char *fontname, const char *nametemplate, int first, int count, int base, int fdlump, int spacewidth=-1, bool notranslate = false); virtual ~FFont (); virtual FTexture *GetChar (int code, int *const width) const; @@ -100,6 +100,7 @@ public: int GetCharCode(int code, bool needpic) const; char GetCursor() const { return Cursor; } void SetCursor(char c) { Cursor = c; } + bool NoTranslate() const { return noTranslate; } protected: FFont (int lump); @@ -116,6 +117,7 @@ protected: int FontHeight; int GlobalKerning; char Cursor; + bool noTranslate; struct CharData { FTexture *Pic; From 7267e608cf2cf7936b5057490d1dbc783be6604f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 19:37:25 +0100 Subject: [PATCH 21/25] - added kickback factor skill property. --- src/g_level.h | 2 ++ src/g_skill.cpp | 10 ++++++++++ src/p_interaction.cpp | 1 + 3 files changed, 13 insertions(+) diff --git a/src/g_level.h b/src/g_level.h index cf5d1865d..03fa70dcd 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -497,6 +497,7 @@ enum EFSkillProperty // floating point properties SKILLP_Aggressiveness, SKILLP_MonsterHealth, SKILLP_FriendlyHealth, + SKILLP_KickbackFactor, }; int G_SkillProperty(ESkillProperty prop); @@ -514,6 +515,7 @@ struct FSkillInfo double DamageFactor; double ArmorFactor; double HealthFactor; + double KickbackFactor; bool FastMonsters; bool SlowMonsters; diff --git a/src/g_skill.cpp b/src/g_skill.cpp index d158fa4cd..1bf80bb42 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -66,6 +66,7 @@ void FMapInfoParser::ParseSkill () skill.DamageFactor = 1.; skill.ArmorFactor = 1.; skill.HealthFactor = 1.; + skill.KickbackFactor = 1.; skill.FastMonsters = false; skill.SlowMonsters = false; skill.DisableCheats = false; @@ -118,6 +119,12 @@ void FMapInfoParser::ParseSkill () sc.MustGetFloat (); skill.DamageFactor = sc.Float; } + else if (sc.Compare("kickbackfactor")) + { + ParseAssign(); + sc.MustGetFloat(); + skill.KickbackFactor = sc.Float; + } else if (sc.Compare ("fastmonsters")) { skill.FastMonsters = true; @@ -436,6 +443,9 @@ double G_SkillProperty(EFSkillProperty prop) case SKILLP_FriendlyHealth: return AllSkills[gameskill].FriendlyHealth; + case SKILLP_KickbackFactor: + return AllSkills[gameskill].KickbackFactor; + } } return 0; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index c13024fcf..7699fe376 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1212,6 +1212,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da else kickback = source->player->ReadyWeapon->Kickback; + kickback = int(kickback * G_SkillProperty(SKILLP_KickbackFactor)); if (kickback) { AActor *origin = (source && (flags & DMG_INFLICTOR_IS_PUFF))? source : inflictor; From 4d043f086e494bf249a3122affd4ec1681401798 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 19:41:39 +0100 Subject: [PATCH 22/25] - missed a spot. --- src/g_skill.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_skill.cpp b/src/g_skill.cpp index 1bf80bb42..dd772a745 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -511,6 +511,7 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other) DoubleAmmoFactor = other.DoubleAmmoFactor; DropAmmoFactor = other.DropAmmoFactor; DamageFactor = other.DamageFactor; + KickbackFactor = other.KickbackFactor; FastMonsters = other.FastMonsters; SlowMonsters = other.SlowMonsters; DisableCheats = other.DisableCheats; From 7a1f36bfb00f4f243886874f0a2e0d412f35242a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 20:01:39 +0100 Subject: [PATCH 23/25] - added RF_DONTINTERPOLATE flag. --- src/actor.h | 4 +++- src/scripting/thingdef_data.cpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/actor.h b/src/actor.h index b52cb6571..d767c6cb2 100644 --- a/src/actor.h +++ b/src/actor.h @@ -430,6 +430,7 @@ enum ActorRenderFlag RF_ABSMASKPITCH = 0x00800000, // [MC] The mask rotation does not offset by the actor's pitch. RF_INTERPOLATEANGLES = 0x01000000, // [MC] Allow interpolation of the actor's angle, pitch and roll. RF_MAYBEINVISIBLE = 0x02000000, + RF_DONTINTERPOLATE = 0x04000000, // no render interpolation ever! }; // This translucency value produces the closest match to Heretic's TINTTAB. @@ -1321,7 +1322,8 @@ public: } DVector3 InterpolatedPosition(double ticFrac) const { - return Prev + (ticFrac * (Pos() - Prev)); + if (renderflags & RF_DONTINTERPOLATE) return Pos(); + else return Prev + (ticFrac * (Pos() - Prev)); } DRotator InterpolatedAngles(double ticFrac) const { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 3a76002fa..656b75402 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -339,6 +339,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(RF, XFLIP, AActor, renderflags), DEFINE_FLAG(RF, YFLIP, AActor, renderflags), DEFINE_FLAG(RF, INTERPOLATEANGLES, AActor, renderflags), + DEFINE_FLAG(RF, DONTINTERPOLATE, AActor, renderflags), // Bounce flags DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags), From 0eebaf9f6b65561b9cfdecdebe822bfaa2d32a0c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 20:06:16 +0100 Subject: [PATCH 24/25] - allow nightmare respawn if the current state has the 'canraise' flag. --- src/p_mobj.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index d14c69aad..23e83425f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4437,7 +4437,8 @@ void AActor::Tick () return; // freed itself } } - else + + if (tics == -1 || state->GetCanRaise()) { int respawn_monsters = G_SkillProperty(SKILLP_Respawn); // check for nightmare respawn From 9aff224891bf2948c59b97a5105a988c75fc320e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Feb 2017 20:11:24 +0100 Subject: [PATCH 25/25] - allow a link between the same sector's floor and ceiling. --- src/p_linkedsectors.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/p_linkedsectors.cpp b/src/p_linkedsectors.cpp index 0dd29c10e..7ac614f2e 100644 --- a/src/p_linkedsectors.cpp +++ b/src/p_linkedsectors.cpp @@ -329,11 +329,13 @@ bool P_AddSectorLinks(sector_t *control, int tag, INTBOOL ceiling, int movetype) FSectorTagIterator itr(tag); while ((sec = itr.Next()) >= 0) { - // Don't attach to self! - if (control != &level.sectors[sec]) + // Don't attach to self (but allow attaching to this sector's oposite plane. + if (control == &level.sectors[sec]) { - AddSingleSector(scrollplane, &level.sectors[sec], movetype); + if (ceiling == sector_t::floor && movetype & LINK_FLOOR) continue; + if (ceiling == sector_t::ceiling && movetype & LINK_CEILING) continue; } + AddSingleSector(scrollplane, &level.sectors[sec], movetype); } } else