From 12eb760ff4905196a54d8b1196760f4e176be797 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 22 Feb 2018 16:52:45 +0200 Subject: [PATCH 01/29] Do not abort if Korax target destroyed before attack begins https://forum.zdoom.org/viewtopic.php?t=59551 --- wadsrc/static/zscript/hexen/korax.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/wadsrc/static/zscript/hexen/korax.txt b/wadsrc/static/zscript/hexen/korax.txt index 8f313bc19e..b94664bea9 100644 --- a/wadsrc/static/zscript/hexen/korax.txt +++ b/wadsrc/static/zscript/hexen/korax.txt @@ -244,6 +244,11 @@ class Korax : Actor void A_KoraxMissile() { + if (!target) + { + return; + } + static const class choices[] = { "WraithFX1", "Demon1FX1", "Demon2FX1", "FireDemonMissile", "CentaurFX", "SerpentFX" @@ -282,6 +287,11 @@ class Korax : Actor void KoraxFire (Class type, int arm) { + if (!target) + { + return; + } + static const int extension[] = { KORAX_ARM_EXTENSION_SHORT, From 1679065a5d975f314b96fcde6d2b50274a974cef Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 24 Feb 2018 16:23:55 +0200 Subject: [PATCH 02/29] Exposed Actor.ACS_ScriptCall() function This method can be used with arbitrary actor object like thing.ACS_ScriptCall("script") CallACS() and ACS_NamedExecuteWithResult() intrinsics work only within self actor context --- wadsrc/static/zscript/actor.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index dbea3fd47c..7c9140788d 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -1177,7 +1177,7 @@ class Actor : Thinker native { return ACS_LockedExecuteDoor(-int(script), mapnum, arg1, arg2, lock); } - int ACS_NamedExecuteWithResult(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0) + int ACS_ScriptCall(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0) { return ACS_ExecuteWithResult(-int(script), arg1, arg2, arg3, arg4); } From 76ff1adb282839f3abe9e425ef33826cf6537e08 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 24 Feb 2018 17:44:39 +0200 Subject: [PATCH 03/29] Disabled reverb editor's test environment by default https://forum.zdoom.org/viewtopic.php?t=59583 --- src/s_environment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/s_environment.cpp b/src/s_environment.cpp index ac268bc5fc..0618d72e35 100644 --- a/src/s_environment.cpp +++ b/src/s_environment.cpp @@ -677,7 +677,7 @@ void S_UnloadReverbDef () Environments = &Off; } -CUSTOM_CVAR(Bool, eaxedit_test, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +CUSTOM_CVAR(Bool, eaxedit_test, false, CVAR_NOINITCALL) { if (self) { From 3436b80232c0f97eaa355b3db1f1305998476835 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 24 Feb 2018 17:50:13 +0200 Subject: [PATCH 04/29] Added SHARE_DIR search path back https://github.com/coelckers/gzdoom/pull/377#issuecomment-368235506 --- src/gameconfigfile.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index 5053fd033d..d0a5c22e36 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -149,6 +149,7 @@ FGameConfigFile::FGameConfigFile () SetValueForKey ("Path", "$PROGDIR", true); #else SetValueForKey ("Path", "$HOME/" GAME_DIR, true); + SetValueForKey ("Path", SHARE_DIR, true); SetValueForKey ("Path", "/usr/local/share/doom", true); SetValueForKey ("Path", "/usr/local/share/games/doom", true); SetValueForKey ("Path", "/usr/share/doom", true); From fb1f8a604580727d86dfa6dde3139d8879833a11 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 24 Feb 2018 22:03:23 +0200 Subject: [PATCH 05/29] Restored ACS_NamedExecuteWithResult for DECORATE https://forum.zdoom.org/viewtopic.php?t=59250 --- wadsrc/static/zscript/actor.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 7c9140788d..fa06447552 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -1177,7 +1177,7 @@ class Actor : Thinker native { return ACS_LockedExecuteDoor(-int(script), mapnum, arg1, arg2, lock); } - int ACS_ScriptCall(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0) + int ACS_NamedExecuteWithResult(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0) { return ACS_ExecuteWithResult(-int(script), arg1, arg2, arg3, arg4); } @@ -1185,6 +1185,10 @@ class Actor : Thinker native { return ACS_ExecuteAlways(-int(script), mapnum, arg1, arg2, arg3); } + int ACS_ScriptCall(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0) + { + return ACS_ExecuteWithResult(-int(script), arg1, arg2, arg3, arg4); + } States(Actor, Overlay, Weapon, Item) { From 07f168a58bb82c81280eb65fa497742ab6b2ff3a Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Sat, 24 Feb 2018 16:04:20 -0500 Subject: [PATCH 06/29] - additional check for tween-tic particle rendering, prevents jitter with timefreeze powerup --- src/gl/scene/gl_sprite.cpp | 2 +- src/polyrenderer/scene/poly_particle.cpp | 2 +- src/swrenderer/things/r_particle.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index cfaa34f6ff..74e5b8ed98 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -1211,7 +1211,7 @@ void GLSprite::ProcessParticle (particle_t *particle, sector_t *sector)//, int s } double timefrac = r_viewpoint.TicFrac; - if (paused || bglobal.freeze) + if (paused || bglobal.freeze || (level.flags2 & LEVEL2_FROZEN)) timefrac = 0.; float xvf = (particle->Vel.X) * timefrac; float yvf = (particle->Vel.Y) * timefrac; diff --git a/src/polyrenderer/scene/poly_particle.cpp b/src/polyrenderer/scene/poly_particle.cpp index 0ab3beb229..942ef13464 100644 --- a/src/polyrenderer/scene/poly_particle.cpp +++ b/src/polyrenderer/scene/poly_particle.cpp @@ -35,7 +35,7 @@ EXTERN_CVAR(Int, gl_particles_style) void RenderPolyParticle::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, particle_t *particle, subsector_t *sub, uint32_t stencilValue) { double timefrac = r_viewpoint.TicFrac; - if (paused || bglobal.freeze) + if (paused || bglobal.freeze || (level.flags2 & LEVEL2_FROZEN)) timefrac = 0.; DVector3 pos = particle->Pos + (particle->Vel * timefrac); double psize = particle->size / 8.0; diff --git a/src/swrenderer/things/r_particle.cpp b/src/swrenderer/things/r_particle.cpp index 7c2d88f481..ee791b56b3 100644 --- a/src/swrenderer/things/r_particle.cpp +++ b/src/swrenderer/things/r_particle.cpp @@ -79,7 +79,7 @@ namespace swrenderer sector_t* heightsec = NULL; double timefrac = r_viewpoint.TicFrac; - if (paused || bglobal.freeze) + if (paused || bglobal.freeze || (level.flags2 & LEVEL2_FROZEN)) timefrac = 0.; double ippx = particle->Pos.X + particle->Vel.X * timefrac; From 9a8e724761064ca81bcf5d7a8dee2edac08c0925 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 27 Feb 2018 09:52:42 +0100 Subject: [PATCH 07/29] - added a compatibility setting for Perdition's Gate MAP31 which was having render issues with an unsupported vanilla effect. --- src/compatibility.cpp | 29 +++++++++++++++++++++++++++++ wadsrc/static/compatibility.txt | 14 ++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 8c3cc16c5c..b99f2a51b0 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -92,6 +92,7 @@ enum CP_SETTHINGSKILLS, CP_SETSECTORTEXTURE, CP_SETSECTORLIGHT, + CP_SETLINESECTORREF, }; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -283,6 +284,18 @@ void ParseCompatibility() CompatParams.Push(sc.Number); } } + else if (sc.Compare("setlinesectorref")) + { + if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); + CompatParams.Push(CP_SETLINESECTORREF); + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + sc.MustGetString(); + CompatParams.Push(sc.MustMatchString(LineSides)); + sc.MustGetNumber(); + CompatParams.Push(sc.Number); + flags.CompatFlags[SLOT_BCOMPAT] |= BCOMPATF_REBUILDNODES; + } else if (sc.Compare("clearlinespecial")) { if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size(); @@ -719,6 +732,22 @@ void SetCompatibilityParams() i += 3; break; } + case CP_SETLINESECTORREF: + { + if ((unsigned)CompatParams[i + 1] < level.lines.Size()) + { + line_t *line = &level.lines[CompatParams[i + 1]]; + assert(line != nullptr); + side_t *side = line->sidedef[CompatParams[i + 2]]; + if (side != nullptr && (unsigned)CompatParams[i + 3] < level.sectors.Size()) + { + side->sector = &level.sectors[CompatParams[i + 3]]; + } + } + i += 4; + break; + } + } } } diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index b78b4e6648..6730028771 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -868,3 +868,17 @@ CA3773ED313E8899311F3DD0CA195A68 // e3m6 { shorttex } + +FCCA97FC851F6473EAA069F74247B317 // pg-raw.wad map31 +{ + setlinesectorref 331 front 74 + setlinesectorref 326 front 74 + setlinesectorref 497 front 74 + setlinesectorref 474 front 74 + setlinesectorref 471 front 74 + setlinesectorref 327 front 74 + setlinesectorref 328 front 74 + setlinesectorref 329 front 74 + setsectortag 74 4 + setlinespecial 357 Transfer_Heights 4 2 0 0 0 +} From 883a6ffe3a80aa5d19d0bf8a96e4d13e23bca6ac Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 27 Feb 2018 10:40:43 +0100 Subject: [PATCH 08/29] - added an inventory check to A_KeenDie so that it still works if a patch repurposes a pickup item that may end up in the player's inventory. --- wadsrc/static/zscript/doom/keen.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/zscript/doom/keen.txt b/wadsrc/static/zscript/doom/keen.txt index 6d596c717a..083df92b48 100644 --- a/wadsrc/static/zscript/doom/keen.txt +++ b/wadsrc/static/zscript/doom/keen.txt @@ -70,8 +70,13 @@ extend class Actor { if (mo.health > 0 && mo != self) { - // other Keen not dead - return; + // Added check for Dehacked and repurposed inventory items. + let inv = Inventory(mo); + if (inv == null || inv.Owner == null) + { + // other Keen not dead + return; + } } } Door_Open(doortag, 16); From fd27b228575c914cebaab3b42ab7112f465bee0b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 27 Feb 2018 11:10:47 +0100 Subject: [PATCH 09/29] - use iswspace to classify whitespace in V_BreakLines. isspace does not work because it is limited to 8-bit character sets. --- src/v_text.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/v_text.cpp b/src/v_text.cpp index f4829ec183..06b09a2ef8 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "v_text.h" @@ -387,7 +388,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bo continue; } - if (isspace(c)) + if (iswspace(c)) { if (!lastWasSpace) { @@ -420,12 +421,12 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bo start = space; space = NULL; - while (*start && isspace (*start) && *start != '\n') + while (*start && iswspace (*start) && *start != '\n') start++; if (*start == '\n') start++; else - while (*start && isspace (*start)) + while (*start && iswspace (*start)) start++; string = start; } @@ -443,7 +444,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bo while (s < string) { // If there is any non-white space in the remainder of the string, add it. - if (!isspace (*s++)) + if (!iswspace (*s++)) { auto i = Lines.Reserve(1); breakit (&Lines[i], font, start, string, linecolor); From f3deaf54c63665509ec6b45e849f07fc1eaf6377 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 27 Feb 2018 11:16:28 +0100 Subject: [PATCH 10/29] - added light definition for megasphere. --- wadsrc_lights/static/filter/doom.doom1/gldefs.txt | 15 +++++++++++++++ wadsrc_lights/static/filter/doom.doom2/gldefs.txt | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/wadsrc_lights/static/filter/doom.doom1/gldefs.txt b/wadsrc_lights/static/filter/doom.doom1/gldefs.txt index d79ba52963..83c30369dd 100644 --- a/wadsrc_lights/static/filter/doom.doom1/gldefs.txt +++ b/wadsrc_lights/static/filter/doom.doom1/gldefs.txt @@ -559,6 +559,21 @@ object SoulSphere frame SOUL { light SOULSPHERE } } +pulselight MEGASPHERE +{ + color 0.5 0.5 0.4 + size 60 + secondarySize 63 + interval 2.0 + offset 0 16 0 + attenuate 1 +} + +object MegaSphere +{ + frame MEGA { light MEGASPHERE } +} + // Invulnerability Sphere pulselight INVULN { diff --git a/wadsrc_lights/static/filter/doom.doom2/gldefs.txt b/wadsrc_lights/static/filter/doom.doom2/gldefs.txt index d79ba52963..83c30369dd 100644 --- a/wadsrc_lights/static/filter/doom.doom2/gldefs.txt +++ b/wadsrc_lights/static/filter/doom.doom2/gldefs.txt @@ -559,6 +559,21 @@ object SoulSphere frame SOUL { light SOULSPHERE } } +pulselight MEGASPHERE +{ + color 0.5 0.5 0.4 + size 60 + secondarySize 63 + interval 2.0 + offset 0 16 0 + attenuate 1 +} + +object MegaSphere +{ + frame MEGA { light MEGASPHERE } +} + // Invulnerability Sphere pulselight INVULN { From d873ae75ab9430e42a93b05da457eee406192a9e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 27 Feb 2018 11:34:44 +0100 Subject: [PATCH 11/29] - silence all error messages in the state map parser for DEHSUPP when re-reading the data. The state map will just be skipped and the parser only needs to run to get over the data. However, due to changes from a previous patch the data cannot be validated so aside from not using the data it may also not abort on errors. --- src/d_dehacked.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 92d574d699..ddabdb7721 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2840,14 +2840,14 @@ static bool LoadDehSupp () sc.MustGetString(); PClassActor *actortype = static_cast(type); s.State = actortype->FindState(sc.String); - if (s.State == NULL) + if (s.State == NULL && addit) { sc.ScriptError("Invalid state '%s' in '%s'", sc.String, type->TypeName.GetChars()); } sc.MustGetStringName(","); sc.MustGetNumber(); - if (s.State == NULL || sc.Number < 1 || !actortype->OwnsState(s.State + sc.Number - 1)) + if (addit && (s.State == NULL || sc.Number < 1 || !actortype->OwnsState(s.State + sc.Number - 1))) { sc.ScriptError("Invalid state range in '%s'", type->TypeName.GetChars()); } From aaaf9aa108d1d74e247d59bdad78f8a2be29a6be Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 27 Feb 2018 12:44:00 +0100 Subject: [PATCH 12/29] Added 'TeleportSpecial' as an alias for 'Teleport' in ZScript to deconflict from the Actor.Teleport function. --- src/namedef.h | 2 ++ src/scripting/backend/codegen.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/namedef.h b/src/namedef.h index ace456a691..9e6d3811a6 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -377,6 +377,8 @@ xx(MomZ) xx(Threshold) xx(DefThreshold) xx(Abs) +xx(TeleportSpecial) +xx(Teleport) xx(ACS_NamedExecuteWithResult) xx(CallACS) xx(Sqrt) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 96393ad4c1..24e541a36d 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -7758,6 +7758,8 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } else { + // This alias is needed because Actor has a Teleport function. + if (MethodName == NAME_TeleportSpecial) MethodName = NAME_Teleport; special = P_FindLineSpecial(MethodName.GetChars(), &min, &max); } if (special != 0 && min >= 0) From af14609de77e82d5c7c2213949d921b39fb058cc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 27 Feb 2018 15:42:22 +0100 Subject: [PATCH 13/29] - don't skip empty arrays which are themselves array elements in the ZScript serializer. --- src/scripting/types.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/scripting/types.cpp b/src/scripting/types.cpp index 5059834d48..d683e62d6f 100644 --- a/src/scripting/types.cpp +++ b/src/scripting/types.cpp @@ -1968,7 +1968,10 @@ void PDynArray::SetPointerArray(void *base, unsigned offset, TArray *spe void PDynArray::WriteValue(FSerializer &ar, const char *key, const void *addr) const { FArray *aray = (FArray*)addr; - if (aray->Count > 0) + // We may skip an empty array only if it gets stored under a named key. + // If no name is given, i.e. it's part of an outer array's element list, even empty arrays must be stored, + // because otherwise the array would lose its entry. + if (aray->Count > 0 || key == nullptr) { if (ar.BeginArray(key)) { From 7ac8b496f1ae92ad55c42352444f4a101a00dcdb Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sat, 24 Feb 2018 14:36:17 -0600 Subject: [PATCH 14/29] Added Distance(2/3)DSquared functions. --- src/actor.h | 6 ++++++ src/p_mobj.cpp | 14 ++++++++++++++ wadsrc/static/zscript/actor.txt | 2 ++ 3 files changed, 22 insertions(+) diff --git a/src/actor.h b/src/actor.h index 1510a5787c..863e4fb46a 100644 --- a/src/actor.h +++ b/src/actor.h @@ -886,6 +886,12 @@ public: // a full 3D version of the above + double Distance3DSquared(AActor *other, bool absolute = false) + { + DVector3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return (Pos() - otherpos).LengthSquared(); + } + double Distance3D(AActor *other, bool absolute = false) { DVector3 otherpos = absolute ? other->Pos() : other->PosRelative(this); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8e5e1d3a26..371e3f9773 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -8127,6 +8127,20 @@ DEFINE_ACTION_FUNCTION(AActor, absangle) // should this be global? ACTION_RETURN_FLOAT(absangle(DAngle(a1), DAngle(a2)).Degrees); } +DEFINE_ACTION_FUNCTION(AActor, Distance2DSquared) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); + ACTION_RETURN_FLOAT(self->Distance2DSquared(other)); +} + +DEFINE_ACTION_FUNCTION(AActor, Distance3DSquared) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); + ACTION_RETURN_FLOAT(self->Distance3DSquared(other)); +} + DEFINE_ACTION_FUNCTION(AActor, Distance2D) { PARAM_SELF_PROLOGUE(AActor); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index fa06447552..cb2ceb9458 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -580,6 +580,8 @@ class Actor : Thinker native native void SetDamage(int dmg); native clearscope double Distance2D(Actor other) const; native clearscope double Distance3D(Actor other) const; + native clearscope double Distance2DSquared(Actor other) const; + native clearscope double Distance3DSquared(Actor other) const; native void SetOrigin(vector3 newpos, bool moving); native void SetXYZ(vector3 newpos); native Actor GetPointer(int aaptr); From 4ccbc4ea9e8822bf915a09c6aa01aca07eaca89d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Feb 2018 09:46:28 +0100 Subject: [PATCH 15/29] - Send a GM reset SYSEX event when music playback is started. --- src/sound/musicformats/music_midistream.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sound/musicformats/music_midistream.cpp b/src/sound/musicformats/music_midistream.cpp index 2a8abdae99..cf8f293c6d 100644 --- a/src/sound/musicformats/music_midistream.cpp +++ b/src/sound/musicformats/music_midistream.cpp @@ -745,6 +745,14 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, uint32_t max_time) if (InitialPlayback) { InitialPlayback = false; + // Send the GS System Reset SysEx message. + events[0] = 0; // dwDeltaTime + events[1] = 0; // dwStreamID + events[2] = (MEVENT_LONGMSG << 24) | 6; // dwEvent + events[3] = MAKE_ID(0xf0, 0x7e, 0x7f, 0x09); // dwParms[0] + events[4] = MAKE_ID(0x01, 0xf7, 0x00, 0x00); // dwParms[1] + events += 5; + // Send the full master volume SysEx message. events[0] = 0; // dwDeltaTime events[1] = 0; // dwStreamID @@ -752,6 +760,7 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, uint32_t max_time) events[3] = MAKE_ID(0xf0,0x7f,0x7f,0x04); // dwParms[0] events[4] = MAKE_ID(0x01,0x7f,0x7f,0xf7); // dwParms[1] events += 5; + DoInitialSetup(); } From 910a3062c79be5e63bba64491270e993a46d6083 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Feb 2018 10:12:10 +0100 Subject: [PATCH 16/29] - fixed some problems with the stepping up through a portal logic: * this has to be disabled for missiles which should explode instead of stepping up. * interpolation adjustment was not correct * it could crash because the target portal group could be retrieved from a non-portal sector. --- src/p_map.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 7d5a79de88..16d8ac564b 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -898,7 +898,9 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec } // check if the actor can step through the ceiling portal. In this case one-sided lines in the current area should not block - if (!cres.line->frontsector->PortalBlocksMovement(sector_t::ceiling)) + // Use the same rules for stepping through a portal as for non-portal case. + bool ismissile = (tm.thing->flags & MF_MISSILE) && !(tm.thing->flags6 & MF6_STEPMISSILE) && !(tm.thing->flags3 & MF3_FLOORHUGGER); + if (!ismissile && !cres.line->frontsector->PortalBlocksMovement(sector_t::ceiling)) { double portz = cres.line->frontsector->GetPortalPlaneZ(sector_t::ceiling); if (tm.thing->Z() < portz && tm.thing->Z() + tm.thing->MaxStepHeight >= portz && tm.floorz < portz) @@ -1008,7 +1010,9 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec FLineOpening open; P_LineOpening(open, tm.thing, ld, ref, &cres.Position, cres.portalflags); - if (!tm.thing->Sector->PortalBlocksMovement(sector_t::ceiling)) + // Use the same rules for stepping through a portal as for non-portal case. + bool ismissile = (tm.thing->flags & MF_MISSILE) && !(tm.thing->flags6 & MF6_STEPMISSILE) && !(tm.thing->flags3 & MF3_FLOORHUGGER); + if (!ismissile && !tm.thing->Sector->PortalBlocksMovement(sector_t::ceiling)) { sector_t *oppsec = cres.line->frontsector == tm.thing->Sector ? cres.line->backsector : cres.line->frontsector; if (oppsec->PortalBlocksMovement(sector_t::ceiling)) @@ -2707,8 +2711,8 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, FLinkContext ctx; DVector3 oldpos = thing->Pos(); thing->UnlinkFromWorld(&ctx); - thing->SetXYZ(thing->PosRelative(thing->Sector->GetOppositePortalGroup(sector_t::ceiling))); - thing->Prev = thing->Pos() - oldpos; + thing->SetXYZ(thing->PosRelative(tm.portalgroup)); + thing->Prev += thing->Pos() - oldpos; thing->Sector = P_PointInSector(thing->Pos()); thing->PrevPortalGroup = thing->Sector->PortalGroup; thing->LinkToWorld(&ctx); From e70250425a876f26b3467350f1ac15b45cd7d0d0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Feb 2018 13:15:04 +0100 Subject: [PATCH 17/29] - fixed: For two-sided midtextures the light lists were always taken from the sector referenced by the rendered sidedef, not the sector in which the line gets renderered. For polyobjects these two are not identical. --- src/gl/scene/gl_walls.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gl/scene/gl_walls.cpp b/src/gl/scene/gl_walls.cpp index 470cd97768..5db32de049 100644 --- a/src/gl/scene/gl_walls.cpp +++ b/src/gl/scene/gl_walls.cpp @@ -1060,8 +1060,8 @@ void GLWall::DoMidTexture(seg_t * seg, bool drawfogboundary, // Draw the stuff // // - if (realfront->e->XFloor.lightlist.Size()==0 || mDrawer->FixedColormap) split.PutWall(translucent); - else split.SplitWall(realfront, translucent); + if (front->e->XFloor.lightlist.Size()==0 || mDrawer->FixedColormap) split.PutWall(translucent); + else split.SplitWall(front, translucent); t=1; } @@ -1074,8 +1074,8 @@ void GLWall::DoMidTexture(seg_t * seg, bool drawfogboundary, // Draw the stuff without splitting // // - if (realfront->e->XFloor.lightlist.Size()==0 || mDrawer->FixedColormap) PutWall(translucent); - else SplitWall(realfront, translucent); + if (front->e->XFloor.lightlist.Size()==0 || mDrawer->FixedColormap) PutWall(translucent); + else SplitWall(front, translucent); } alpha=1.0f; } @@ -1437,7 +1437,7 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector) sector_t * segback; #ifdef _DEBUG - if (seg->linedef->Index() == 1) + if (seg->linedef->Index() == 10) { int a = 0; } From 56df88c7929d6b241b1148a37030ea5a60470457 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 28 Feb 2018 14:27:22 +0200 Subject: [PATCH 18/29] Use 64-bit fixed point for node builder's vertex map https://forum.zdoom.org/viewtopic.php?t=59368 --- src/nodebuild.cpp | 4 ++-- src/nodebuild.h | 6 ++++-- src/nodebuild_utility.cpp | 12 ++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index d4794c639f..5b849687c6 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -814,8 +814,8 @@ void FNodeBuilder::SplitSegs (uint32_t set, node_t &node, uint32_t splitseg, uin frac = InterceptVector (node, *seg); newvert.x = Vertices[seg->v1].x; newvert.y = Vertices[seg->v1].y; - newvert.x += fixed_t(frac * double(Vertices[seg->v2].x - newvert.x)); - newvert.y += fixed_t(frac * double(Vertices[seg->v2].y - newvert.y)); + newvert.x += fixed_t(frac * (double(Vertices[seg->v2].x) - newvert.x)); + newvert.y += fixed_t(frac * (double(Vertices[seg->v2].y) - newvert.y)); vertnum = VertexMap->SelectVertexClose (newvert); if (vertnum != (unsigned int)seg->v1 && vertnum != (unsigned int)seg->v2) diff --git a/src/nodebuild.h b/src/nodebuild.h index f66e64aa4d..fd943cbbd0 100644 --- a/src/nodebuild.h +++ b/src/nodebuild.h @@ -91,6 +91,8 @@ struct FSimpleVert fixed_t x, y; }; +typedef int64_t fixed64_t; + class FNodeBuilder { struct FPrivSeg @@ -167,14 +169,14 @@ class FNodeBuilder FNodeBuilder &MyBuilder; TArray *VertexGrid; - fixed_t MinX, MinY, MaxX, MaxY; + fixed64_t MinX, MinY, MaxX, MaxY; int BlocksWide, BlocksTall; enum { BLOCK_SHIFT = 8 + FRACBITS }; enum { BLOCK_SIZE = 1 << BLOCK_SHIFT }; int InsertVertex (FPrivVert &vert); - inline int GetBlock (fixed_t x, fixed_t y) + inline int GetBlock (fixed64_t x, fixed64_t y) { assert (x >= MinX); assert (y >= MinY); diff --git a/src/nodebuild_utility.cpp b/src/nodebuild_utility.cpp index 754e3519c8..9dd3c7786f 100644 --- a/src/nodebuild_utility.cpp +++ b/src/nodebuild_utility.cpp @@ -641,8 +641,8 @@ FNodeBuilder::FVertexMap::FVertexMap (FNodeBuilder &builder, MinY = miny; BlocksWide = int(((double(maxx) - minx + 1) + (BLOCK_SIZE - 1)) / BLOCK_SIZE); BlocksTall = int(((double(maxy) - miny + 1) + (BLOCK_SIZE - 1)) / BLOCK_SIZE); - MaxX = MinX + BlocksWide * BLOCK_SIZE - 1; - MaxY = MinY + BlocksTall * BLOCK_SIZE - 1; + MaxX = MinX + fixed64_t(BlocksWide) * BLOCK_SIZE - 1; + MaxY = MinY + fixed64_t(BlocksTall) * BLOCK_SIZE - 1; VertexGrid = new TArray[BlocksWide * BlocksTall]; } @@ -703,10 +703,10 @@ int FNodeBuilder::FVertexMap::InsertVertex (FNodeBuilder::FPrivVert &vert) // If a vertex is near a block boundary, then it will be inserted on // both sides of the boundary so that SelectVertexClose can find // it by checking in only one block. - fixed_t minx = MAX (MinX, vert.x - VERTEX_EPSILON); - fixed_t maxx = MIN (MaxX, vert.x + VERTEX_EPSILON); - fixed_t miny = MAX (MinY, vert.y - VERTEX_EPSILON); - fixed_t maxy = MIN (MaxY, vert.y + VERTEX_EPSILON); + fixed64_t minx = MAX (MinX, fixed64_t(vert.x) - VERTEX_EPSILON); + fixed64_t maxx = MIN (MaxX, fixed64_t(vert.x) + VERTEX_EPSILON); + fixed64_t miny = MAX (MinY, fixed64_t(vert.y) - VERTEX_EPSILON); + fixed64_t maxy = MIN (MaxY, fixed64_t(vert.y) + VERTEX_EPSILON); int blk[4] = { From 425f1408f7f542037b6821601a2d41171bccff12 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Feb 2018 18:09:32 +0100 Subject: [PATCH 19/29] - fixed skip_super application fro ZScript. The order of processing is different here so when the property gets parsed there are no states to delete. To fix this the property just flags the class and lets the ZScript state compiler deal with this as needed. --- src/info.h | 3 ++- src/scripting/thingdef_properties.cpp | 3 ++- src/scripting/zscript/zcc_compile.cpp | 13 ++++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/info.h b/src/info.h index 3e497d0f63..8bd1887300 100644 --- a/src/info.h +++ b/src/info.h @@ -244,6 +244,7 @@ struct FActorInfo PClassActor *Replacee = nullptr; FState *OwnedStates = nullptr; int NumOwnedStates = 0; + bool SkipSuperSet = false; uint8_t GameFilter = GAME_Any; uint16_t SpawnID = 0; uint16_t ConversationID = 0; @@ -287,7 +288,7 @@ struct FActorInfo }; // This is now merely a wrapper that adds actor-specific functionality to PClass. -// No objects of this type will be created ever - its only use is to static_casr +// No objects of this type will be created ever - its only use is to static_cast // PClass to it. class PClassActor : public PClass { diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index c36058ca46..03ad9c1ccb 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -540,7 +540,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor) if (info->Size != actorclass->Size) { bag.ScriptPosition.Message(MSG_OPTERROR, - "'skip_super' is only allowed in subclasses of AActor with no additional fields and will be ignored in type %s.", info->TypeName.GetChars()); + "'skip_super' is only allowed in subclasses of Actor with no additional fields and will be ignored in type %s.", info->TypeName.GetChars()); return; } if (bag.StateSet) @@ -552,6 +552,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor) *defaults = *GetDefault(); ResetBaggage (&bag, RUNTIME_CLASS(AActor)); + static_cast(bag.Info)->ActorInfo()->SkipSuperSet = true; // ZScript processes the states later so this property must be flagged for later handling. } //========================================================================== diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index ab8bef5f0c..e4773f1c68 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2872,7 +2872,18 @@ void ZCCCompiler::CompileStates() FString statename; // The state builder wants the label as one complete string, not separated into tokens. FStateDefinitions statedef; - statedef.MakeStateDefines(ValidateActor(c->ClassType()->ParentClass)); + + if (static_cast(c->ClassType())->ActorInfo()->SkipSuperSet) + { + // SKIP_SUPER'ed actors only get the base states from AActor. + statedef.MakeStateDefines(RUNTIME_CLASS(AActor)); + } + else + { + statedef.MakeStateDefines(ValidateActor(c->ClassType()->ParentClass)); + } + + int numframes = 0; for (auto s : c->States) From 3a3cd87ce021958fbe426f5fd01612950060aef1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Feb 2018 18:26:25 +0100 Subject: [PATCH 20/29] - perform the stepping adjustment for FastProjectiles in 3D. Not checking the z-Axis means that they might pass through 3D floors without noticing at steep angles and very high speeds. --- wadsrc/static/zscript/shared/fastprojectile.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/shared/fastprojectile.txt b/wadsrc/static/zscript/shared/fastprojectile.txt index 1bed8cba22..c861a3f8fa 100644 --- a/wadsrc/static/zscript/shared/fastprojectile.txt +++ b/wadsrc/static/zscript/shared/fastprojectile.txt @@ -66,7 +66,7 @@ class FastProjectile : Actor int count = 8; if (radius > 0) { - while ( abs(Vel.X) > radius * count || abs(Vel.Y) > radius * count) + while ( abs(Vel.X) >= radius * count || abs(Vel.Y) >= radius * count || abs(Vel.Z) >= height * count) { // we need to take smaller steps. count += count; From 6e8dbb590dffaf7654ee4db65daff73f007ece22 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Feb 2018 20:15:44 +0100 Subject: [PATCH 21/29] - fixed: PowerMorph.EndEffect should not tinker around with morph duration. There was a clear attempt here to let the item keep control of the remaining morph time, but since the item would have gotten destroyed right afterward it just shot itself in the foot badly by doing so. Just leaving the remaining work to the main unmorphing check in the PlayerThink code by doing nothing will avoid the bad situation where a player gets stuck in its morphed form. --- wadsrc/static/zscript/inventory/powerups.txt | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 6fb35b067e..5ef03d4209 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -1931,22 +1931,6 @@ class PowerMorph : Powerup int savedMorphTics = MorphedPlayer.morphTics; MorphedPlayer.UndoPlayerMorph (MorphedPlayer, 0, !!(MorphedPlayer.MorphStyle & MRF_UNDOALWAYS)); - - // Abort if unmorph failed; in that case, - // set the usual retry timer and return. - if (MorphedPlayer != null && MorphedPlayer.morphTics) - { - // Transfer retry timeout - // to the powerup's timer. - EffectTics = MorphedPlayer.morphTics; - // Reload negative morph tics; - // use actual value; it may - // be in use for animation. - MorphedPlayer.morphTics = savedMorphTics; - // Try again some time later - return; - } - // Unmorph suceeded MorphedPlayer = null; } From bba3027d3792d70fa7135d3a97495a4f510dd80e Mon Sep 17 00:00:00 2001 From: InsanityBringer Date: Wed, 28 Feb 2018 13:35:01 -0600 Subject: [PATCH 22/29] Add option to use Rotation-Center for an actor's normal pitch/angle/roll rotation. --- src/r_data/models/models.cpp | 15 +++++++++++++++ src/r_data/models/models.h | 1 + 2 files changed, 16 insertions(+) diff --git a/src/r_data/models/models.cpp b/src/r_data/models/models.cpp index ff799b14dd..3198afd7f6 100644 --- a/src/r_data/models/models.cpp +++ b/src/r_data/models/models.cpp @@ -125,9 +125,17 @@ void FModelRenderer::RenderModel(float x, float y, float z, FSpriteModelFrame *s // Applying model transformations: // 1) Applying actor angle, pitch and roll to the model + if (smf->flags & MDL_USEROTATIONCENTER) + { + objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterZ, smf->rotationCenterY); + } objectToWorldMatrix.rotate(-angle, 0, 1, 0); objectToWorldMatrix.rotate(pitch, 0, 0, 1); objectToWorldMatrix.rotate(-roll, 1, 0, 0); + if (smf->flags & MDL_USEROTATIONCENTER) + { + objectToWorldMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterZ, -smf->rotationCenterY); + } // 2) Applying Doomsday like rotation of the weapon pickup models // The rotation angle is based on the elapsed time. @@ -789,6 +797,13 @@ void gl_InitModels() { smf.flags |= MDL_DONTCULLBACKFACES; } + else if (sc.Compare("userotationcenter")) + { + smf.flags |= MDL_USEROTATIONCENTER; + smf.rotationCenterX = 0.; + smf.rotationCenterY = 0.; + smf.rotationCenterZ = 0.; + } else { sc.ScriptMessage("Unrecognized string \"%s\"", sc.String); diff --git a/src/r_data/models/models.h b/src/r_data/models/models.h index 4a8678fa6f..e6786a7210 100644 --- a/src/r_data/models/models.h +++ b/src/r_data/models/models.h @@ -447,6 +447,7 @@ enum MDL_USEACTORROLL = 64, MDL_BADROTATION = 128, MDL_DONTCULLBACKFACES = 256, + MDL_USEROTATIONCENTER = 512, }; struct FSpriteModelFrame From 711471e9dd9df2af58f097b4248b3200a86d8c28 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 1 Mar 2018 11:08:38 +0200 Subject: [PATCH 23/29] Fixed potential crash during state validation https://forum.zdoom.org/viewtopic.php?t=57116 The problem was caused by missing state label in conjunction with incomplete class actor A : ArmorBonus { Inventory.ForbiddenTo "Missing" } actor B : Pistol { states { TNT1 A 0 Loop } } --- src/info.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.h b/src/info.h index 8bd1887300..69912534fa 100644 --- a/src/info.h +++ b/src/info.h @@ -344,7 +344,7 @@ public: bool OwnsState(const FState *state) { auto i = ActorInfo(); - return state >= i->OwnedStates && state < i->OwnedStates + i->NumOwnedStates; + return i != nullptr && state >= i->OwnedStates && state < i->OwnedStates + i->NumOwnedStates; } PClassActor *GetReplacement(bool lookskill=true); From dd893b6a0c650ec4809e4379b6289e6776e37f1f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Mar 2018 10:32:19 +0100 Subject: [PATCH 24/29] - split off the interface part of DHUDMessage into an abstract base class. The purpose is to allow creating custom message types in ZScript. --- src/g_shared/hudmessages.cpp | 20 ++++++++++------ src/g_statusbar/sbar.h | 41 +++++++++++++++++++++++---------- src/g_statusbar/shared_sbar.cpp | 38 +++++++++++++++--------------- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 722fb353df..073a02c68f 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -43,12 +43,14 @@ EXTERN_CVAR(Int, con_scaletext) -IMPLEMENT_CLASS(DHUDMessage, false, true) - -IMPLEMENT_POINTERS_START(DHUDMessage) - IMPLEMENT_POINTER(Next) +IMPLEMENT_CLASS(DHUDMessageBase, true, true) +IMPLEMENT_POINTERS_START(DHUDMessageBase) +IMPLEMENT_POINTER(Next) IMPLEMENT_POINTERS_END + +IMPLEMENT_CLASS(DHUDMessage, false, false) + IMPLEMENT_CLASS(DHUDMessageFadeOut, false, false) IMPLEMENT_CLASS(DHUDMessageFadeInOut, false, false) IMPLEMENT_CLASS(DHUDMessageTypeOnFadeOut, false, false) @@ -57,6 +59,13 @@ IMPLEMENT_CLASS(DHUDMessageTypeOnFadeOut, false, false) * Basic HUD message. Appears and disappears without any special effects * *************************************************************************/ +void DHUDMessageBase::Serialize(FSerializer &arc) +{ + Super::Serialize(arc); + arc("next", Next) + ("sbarid", SBarID); +} + //============================================================================ // // DHUDMessage Constructor @@ -130,7 +139,6 @@ DHUDMessage::DHUDMessage (FFont *font, const char *text, float x, float y, int h WrapWidth = 0; HandleAspect = true; Top = y; - Next = NULL; Lines = NULL; HoldTics = (int)(holdTime * TICRATE); Tics = 0; @@ -184,10 +192,8 @@ void DHUDMessage::Serialize(FSerializer &arc) ("tics", Tics) ("state", State) .Enum("textcolor", TextColor) - ("sbarid", SBarID) ("sourcetext", SourceText) ("font", Font) - ("next", Next) ("hudwidth", HUDWidth) ("hudheight", HUDHeight) ("nowrap", NoWrap) diff --git a/src/g_statusbar/sbar.h b/src/g_statusbar/sbar.h index 42b164e2bd..13e051c6db 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -59,10 +59,30 @@ bool ST_IsLatencyVisible(); // HUD Message base object -------------------------------------------------- -class DHUDMessage : public DObject +// This is a mo-op base class to allow derived ZScript message types that can be managed by the status bar. +class DHUDMessageBase : public DObject { - DECLARE_CLASS (DHUDMessage, DObject) + DECLARE_CLASS(DHUDMessageBase, DObject) HAS_OBJECT_POINTERS + +public: + virtual void Serialize(FSerializer &arc); + virtual bool Tick() { return true; } // Returns true to indicate time for removal + virtual void ScreenSizeChanged() {} + virtual void Draw(int bottom, int visibility) {} + +private: + TObjPtr Next = nullptr; + uint32_t SBarID = 0; + friend class DBaseStatusBar; + +}; + +// HUD Message -------------------------------------------------- + +class DHUDMessage : public DHUDMessageBase +{ + DECLARE_CLASS (DHUDMessage, DHUDMessageBase) public: DHUDMessage (FFont *font, const char *text, float x, float y, int hudwidth, int hudheight, EColorRange textColor, float holdTime); @@ -70,12 +90,12 @@ public: virtual void Serialize(FSerializer &arc); - void Draw (int bottom, int visibility); + virtual void Draw (int bottom, int visibility) override; virtual void ResetText (const char *text); virtual void DrawSetup (); virtual void DoDraw (int linenum, int x, int y, bool clean, int hudheight); - virtual bool Tick (); // Returns true to indicate time for removal - virtual void ScreenSizeChanged (); + virtual bool Tick () override; + virtual void ScreenSizeChanged () override; void SetVisibility(int vis) { @@ -130,11 +150,8 @@ protected: DHUDMessage () : SourceText(NULL) {} private: - TObjPtr Next; - uint32_t SBarID; char *SourceText; - friend class DBaseStatusBar; }; // HUD message visibility flags @@ -360,9 +377,9 @@ public: void SetSize(int reltop = 32, int hres = 320, int vres = 200, int hhres = -1, int hvres = -1); void OnDestroy() override; - void AttachMessage (DHUDMessage *msg, uint32_t id=0, int layer=HUDMSGLayer_Default); - DHUDMessage *DetachMessage (DHUDMessage *msg); - DHUDMessage *DetachMessage (uint32_t id); + void AttachMessage (DHUDMessageBase *msg, uint32_t id=0, int layer=HUDMSGLayer_Default); + DHUDMessageBase *DetachMessage (DHUDMessageBase *msg); + DHUDMessageBase *DetachMessage (uint32_t id); void DetachAllMessages (); void ShowPlayerName (); double GetDisplacement() { return Displacement; } @@ -455,7 +472,7 @@ private: void DrawWaiting () const; void SetDrawSize(int reltop, int hres, int vres); - TObjPtr Messages[NUM_HUDMSGLAYERS]; + TObjPtr Messages[NUM_HUDMSGLAYERS]; int BaseRelTop; int BaseSBarHorizontalResolution; diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 22ab540359..b097002fe5 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -410,10 +410,10 @@ void DBaseStatusBar::OnDestroy () { for (size_t i = 0; i < countof(Messages); ++i) { - DHUDMessage *msg = Messages[i]; + DHUDMessageBase *msg = Messages[i]; while (msg) { - DHUDMessage *next = msg->Next; + DHUDMessageBase *next = msg->Next; msg->Destroy(); msg = next; } @@ -594,12 +594,12 @@ void DBaseStatusBar::Tick () { for (size_t i = 0; i < countof(Messages); ++i) { - DHUDMessage *msg = Messages[i]; - DHUDMessage **prev = &Messages[i]; + DHUDMessageBase *msg = Messages[i]; + DHUDMessageBase **prev = &Messages[i]; while (msg) { - DHUDMessage *next = msg->Next; + DHUDMessageBase *next = msg->Next; if (msg->Tick ()) { @@ -662,10 +662,10 @@ void DBaseStatusBar::CallTick() // //--------------------------------------------------------------------------- -void DBaseStatusBar::AttachMessage (DHUDMessage *msg, uint32_t id, int layer) +void DBaseStatusBar::AttachMessage (DHUDMessageBase *msg, uint32_t id, int layer) { - DHUDMessage *old = NULL; - DHUDMessage **prev; + DHUDMessageBase *old = NULL; + DHUDMessageBase **prev; DObject *container = this; old = (id == 0 || id == 0xFFFFFFFF) ? NULL : DetachMessage (id); @@ -703,12 +703,12 @@ void DBaseStatusBar::AttachMessage (DHUDMessage *msg, uint32_t id, int layer) // //--------------------------------------------------------------------------- -DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) +DHUDMessageBase *DBaseStatusBar::DetachMessage (DHUDMessageBase *msg) { for (size_t i = 0; i < countof(Messages); ++i) { - DHUDMessage *probe = Messages[i]; - DHUDMessage **prev = &Messages[i]; + DHUDMessageBase *probe = Messages[i]; + DHUDMessageBase **prev = &Messages[i]; while (probe && probe != msg) { @@ -725,12 +725,12 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) return NULL; } -DHUDMessage *DBaseStatusBar::DetachMessage (uint32_t id) +DHUDMessageBase *DBaseStatusBar::DetachMessage (uint32_t id) { for (size_t i = 0; i < countof(Messages); ++i) { - DHUDMessage *probe = Messages[i]; - DHUDMessage **prev = &Messages[i]; + DHUDMessageBase *probe = Messages[i]; + DHUDMessageBase **prev = &Messages[i]; while (probe && probe->SBarID != id) { @@ -757,12 +757,12 @@ void DBaseStatusBar::DetachAllMessages () { for (size_t i = 0; i < countof(Messages); ++i) { - DHUDMessage *probe = Messages[i]; + DHUDMessageBase *probe = Messages[i]; Messages[i] = NULL; while (probe != NULL) { - DHUDMessage *next = probe->Next; + DHUDMessageBase *next = probe->Next; probe->Destroy(); probe = next; } @@ -940,7 +940,7 @@ void DBaseStatusBar::FlashCrosshair () void DBaseStatusBar::DrawMessages (int layer, int bottom) { - DHUDMessage *msg = Messages[layer]; + DHUDMessageBase *msg = Messages[layer]; int visibility = 0; if (viewactive) @@ -953,7 +953,7 @@ void DBaseStatusBar::DrawMessages (int layer, int bottom) } while (msg) { - DHUDMessage *next = msg->Next; + DHUDMessageBase *next = msg->Next; msg->Draw (bottom, visibility); msg = next; } @@ -1307,7 +1307,7 @@ void DBaseStatusBar::ScreenSizeChanged () for (size_t i = 0; i < countof(Messages); ++i) { - DHUDMessage *message = Messages[i]; + DHUDMessageBase *message = Messages[i]; while (message != NULL) { message->ScreenSizeChanged (); From bb16e34bf4f589f74acbd51fe31e96c07d37b838 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Mar 2018 11:45:19 +0100 Subject: [PATCH 25/29] - exposed the HUD message interface to ZScript. Note that this is just the bare abstract interface. It is up to content makers to define usable HUD message classes and optionally contribute them to the engine. --- src/g_shared/hudmessages.cpp | 56 +++++++++++++++++++ src/g_statusbar/sbar.h | 4 ++ src/g_statusbar/shared_sbar.cpp | 39 ++++++++++++- wadsrc/static/zscript/statusbar/statusbar.txt | 10 ++++ 4 files changed, 106 insertions(+), 3 deletions(-) diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 073a02c68f..32465f7b10 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -40,6 +40,7 @@ #include "cmdlib.h" #include "doomstat.h" #include "serializer.h" +#include "vm.h" EXTERN_CVAR(Int, con_scaletext) @@ -66,6 +67,61 @@ void DHUDMessageBase::Serialize(FSerializer &arc) ("sbarid", SBarID); } +DEFINE_ACTION_FUNCTION(DHUDMessageBase, Tick) +{ + PARAM_SELF_PROLOGUE(DHUDMessageBase); + ACTION_RETURN_BOOL(self->Tick()); +} + +DEFINE_ACTION_FUNCTION(DHUDMessageBase, ScreenSizeChanged) +{ + PARAM_SELF_PROLOGUE(DHUDMessageBase); + self->ScreenSizeChanged(); + return 0; +} + +DEFINE_ACTION_FUNCTION(DHUDMessageBase, Draw) +{ + PARAM_SELF_PROLOGUE(DHUDMessageBase); + PARAM_INT(bottom); + PARAM_INT(visibility); + self->Draw(bottom, visibility); + return 0; +} + +bool DHUDMessageBase::CallTick() +{ + IFVIRTUAL(DHUDMessageBase, Tick) + { + VMValue params[] = { (DObject*)this }; + int retval; + VMReturn ret; ret.IntAt(&retval); + VMCall(func, params, countof(params), &ret, 1); + return !!retval; + } + return Tick(); +} + +void DHUDMessageBase::CallScreenSizeChanged() +{ + IFVIRTUAL(DHUDMessageBase, ScreenSizeChanged) + { + VMValue params[] = { (DObject*)this }; + VMCall(func, params, countof(params), nullptr, 0); + } + else ScreenSizeChanged(); +} + +void DHUDMessageBase::CallDraw(int bottom, int visibility) +{ + IFVIRTUAL(DHUDMessageBase, Draw) + { + VMValue params[] = { (DObject*)this, bottom, visibility }; + VMCall(func, params, countof(params), nullptr, 0); + } + else Draw(bottom, visibility); +} + //============================================================================ // // DHUDMessage Constructor diff --git a/src/g_statusbar/sbar.h b/src/g_statusbar/sbar.h index 13e051c6db..ba3d379b86 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -71,6 +71,10 @@ public: virtual void ScreenSizeChanged() {} virtual void Draw(int bottom, int visibility) {} + bool CallTick(); // Returns true to indicate time for removal + void CallScreenSizeChanged(); + void CallDraw(int bottom, int visibility); + private: TObjPtr Next = nullptr; uint32_t SBarID = 0; diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index b097002fe5..d9fa88cc2e 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -601,7 +601,7 @@ void DBaseStatusBar::Tick () { DHUDMessageBase *next = msg->Next; - if (msg->Tick ()) + if (msg->CallTick ()) { *prev = next; msg->Destroy(); @@ -697,6 +697,16 @@ void DBaseStatusBar::AttachMessage (DHUDMessageBase *msg, uint32_t id, int layer GC::WriteBarrier(container, msg); } +DEFINE_ACTION_FUNCTION(DBaseStatusBar, AttachMessage) +{ + PARAM_SELF_PROLOGUE(DBaseStatusBar); + PARAM_OBJECT(msg, DHUDMessageBase); + PARAM_UINT(id); + PARAM_INT(layer); + self->AttachMessage(msg, id, layer); + return 0; +} + //--------------------------------------------------------------------------- // // PROC DetachMessage @@ -725,6 +735,14 @@ DHUDMessageBase *DBaseStatusBar::DetachMessage (DHUDMessageBase *msg) return NULL; } +DEFINE_ACTION_FUNCTION(DBaseStatusBar, DetachMessage) +{ + PARAM_SELF_PROLOGUE(DBaseStatusBar); + PARAM_OBJECT(msg, DHUDMessageBase); + ACTION_RETURN_OBJECT(self->DetachMessage(msg)); +} + + DHUDMessageBase *DBaseStatusBar::DetachMessage (uint32_t id) { for (size_t i = 0; i < countof(Messages); ++i) @@ -747,6 +765,13 @@ DHUDMessageBase *DBaseStatusBar::DetachMessage (uint32_t id) return NULL; } +DEFINE_ACTION_FUNCTION(DBaseStatusBar, DetachMessageID) +{ + PARAM_SELF_PROLOGUE(DBaseStatusBar); + PARAM_INT(id); + ACTION_RETURN_OBJECT(self->DetachMessage(id)); +} + //--------------------------------------------------------------------------- // // PROC DetachAllMessages @@ -769,6 +794,14 @@ void DBaseStatusBar::DetachAllMessages () } } +DEFINE_ACTION_FUNCTION(DBaseStatusBar, DetachAllMessages) +{ + PARAM_SELF_PROLOGUE(DBaseStatusBar); + self->DetachAllMessages(); + return 0; +} + + //--------------------------------------------------------------------------- // // PROC ShowPlayerName @@ -954,7 +987,7 @@ void DBaseStatusBar::DrawMessages (int layer, int bottom) while (msg) { DHUDMessageBase *next = msg->Next; - msg->Draw (bottom, visibility); + msg->CallDraw (bottom, visibility); msg = next; } } @@ -1310,7 +1343,7 @@ void DBaseStatusBar::ScreenSizeChanged () DHUDMessageBase *message = Messages[i]; while (message != NULL) { - message->ScreenSizeChanged (); + message->CallScreenSizeChanged (); message = message->Next; } } diff --git a/wadsrc/static/zscript/statusbar/statusbar.txt b/wadsrc/static/zscript/statusbar/statusbar.txt index 56e831f97b..29f9d01b07 100644 --- a/wadsrc/static/zscript/statusbar/statusbar.txt +++ b/wadsrc/static/zscript/statusbar/statusbar.txt @@ -101,6 +101,12 @@ class InventoryBarState ui } +class HUDMessageBase native ui +{ + virtual native bool Tick(); + virtual native void ScreenSizeChanged(); + virtual native void Draw(int bottom, int visibility); +} class BaseStatusBar native ui { @@ -291,6 +297,10 @@ class BaseStatusBar native ui private HUDFont mSmallFont; + native void AttachMessage(HUDMessageBase msg); + native HUDMessageBase DetachMessage(HUDMessageBase msg); + native HUDMessageBase DetachMessageID(uint msgid); + native void DetachAllMessages(); native void SetSize(int height, int vwidth, int vheight, int hwidth = -1, int hheight = -1); native Vector2 GetHUDScale(); From b39cb4f095c0071da7734b06ea4c50ec312888ce Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Mar 2018 13:01:26 +0100 Subject: [PATCH 26/29] - fixed translucemt sorting for particles. At least on any semi-modern hardware. On old legacy hardware which lacks some important features this will still glitch. --- src/gl/scene/gl_drawinfo.cpp | 41 +++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index 84da70596d..2e2d5d1aad 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -358,47 +358,51 @@ void GLDrawList::SortWallIntoPlane(SortNode * head,SortNode * sort) // // //========================================================================== -void GLDrawList::SortSpriteIntoPlane(SortNode * head,SortNode * sort) +void GLDrawList::SortSpriteIntoPlane(SortNode * head, SortNode * sort) { - GLFlat * fh=&flats[drawitems[head->itemindex].index]; - GLSprite * ss=&sprites[drawitems[sort->itemindex].index]; + GLFlat * fh = &flats[drawitems[head->itemindex].index]; + GLSprite * ss = &sprites[drawitems[sort->itemindex].index]; bool ceiling = fh->z > r_viewpoint.Pos.Z; - if ((ss->z1>fh->z && ss->z2z) || ss->modelframe) + auto hiz = ss->z1 > ss->z2 ? ss->z1 : ss->z2; + auto loz = ss->z1 < ss->z2 ? ss->z1 : ss->z2; + + if ((hiz > fh->z && loz < fh->z) || ss->modelframe) { // We have to split this sprite - GLSprite s=*ss; + GLSprite s = *ss; AddSprite(&s); // add a copy to avoid reallocation issues. - - // Splitting is done in the shader with clip planes, if available + + // Splitting is done in the shader with clip planes, if available. + // The fallback here only really works for non-y-billboarded sprites. if (gl.flags & RFL_NO_CLIP_PLANES) { GLSprite * ss1; - ss1=&sprites[sprites.Size()-1]; - ss=&sprites[drawitems[sort->itemindex].index]; // may have been reallocated! - float newtexv=ss->vt + ((ss->vb-ss->vt)/(ss->z2-ss->z1))*(fh->z-ss->z1); + ss1 = &sprites[sprites.Size() - 1]; + ss = &sprites[drawitems[sort->itemindex].index]; // may have been reallocated! + float newtexv = ss->vt + ((ss->vb - ss->vt) / (ss->z2 - ss->z1))*(fh->z - ss->z1); if (!ceiling) { - ss->z1=ss1->z2=fh->z; - ss->vt=ss1->vb=newtexv; + ss->z1 = ss1->z2 = fh->z; + ss->vt = ss1->vb = newtexv; } else { - ss1->z1=ss->z2=fh->z; - ss1->vt=ss->vb=newtexv; + ss1->z1 = ss->z2 = fh->z; + ss1->vt = ss->vb = newtexv; } } - SortNode * sort2=SortNodes.GetNew(); - memset(sort2,0,sizeof(SortNode)); - sort2->itemindex=drawitems.Size()-1; + SortNode * sort2 = SortNodes.GetNew(); + memset(sort2, 0, sizeof(SortNode)); + sort2->itemindex = drawitems.Size() - 1; head->AddToLeft(sort); head->AddToRight(sort2); } - else if ((ss->z2z && !ceiling) || (ss->z1>fh->z && ceiling)) // completely on the left side + else if ((hiz < fh->z && !ceiling) || (loz > fh->z && ceiling)) // completely on the left side { head->AddToLeft(sort); } @@ -406,7 +410,6 @@ void GLDrawList::SortSpriteIntoPlane(SortNode * head,SortNode * sort) { head->AddToRight(sort); } - } From 685e5c1e954e2a6febe60f5416e602ad48f7b575 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Mar 2018 13:52:23 +0100 Subject: [PATCH 27/29] - fixed: Camera textures must always be drawn with texture mode opaque, because the contents of their alpha channels are undefined. --- src/gl/compatibility/gl_20.cpp | 5 +++-- src/gl/renderer/gl_2ddrawer.cpp | 1 - src/gl/renderer/gl_renderstate.cpp | 2 +- src/gl/renderer/gl_renderstate.h | 9 +++++++++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/gl/compatibility/gl_20.cpp b/src/gl/compatibility/gl_20.cpp index 3321f95613..e5f097228e 100644 --- a/src/gl/compatibility/gl_20.cpp +++ b/src/gl/compatibility/gl_20.cpp @@ -209,9 +209,10 @@ static bool currentModelMatrixState; void FRenderState::ApplyFixedFunction() { - if (mTextureMode != ffTextureMode) + int thistm = mTextureMode == TM_MODULATE && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode; + if (thistm != ffTextureMode) { - ffTextureMode = mTextureMode; + ffTextureMode = thistm; if (ffTextureMode == TM_CLAMPY) ffTextureMode = TM_MODULATE; // this cannot be replicated. Too bad if it creates visual artifacts gl_SetTextureMode(ffTextureMode); } diff --git a/src/gl/renderer/gl_2ddrawer.cpp b/src/gl/renderer/gl_2ddrawer.cpp index 130b6931a6..cda4ea3742 100644 --- a/src/gl/renderer/gl_2ddrawer.cpp +++ b/src/gl/renderer/gl_2ddrawer.cpp @@ -405,7 +405,6 @@ void F2DDrawer::Draw() gl_SetRenderStyle(dt->mRenderStyle, !dt->mMasked, false); gl_RenderState.SetMaterial(dt->mTexture, CLAMP_XY_NOMIP, dt->mTranslation, -1, dt->mAlphaTexture); - if (dt->mTexture->tex->bHasCanvas) gl_RenderState.SetTextureMode(TM_OPAQUE); glEnable(GL_SCISSOR_TEST); glScissor(dt->mScissor[0], dt->mScissor[1], dt->mScissor[2], dt->mScissor[3]); diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 119444af6e..81672b63cf 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -164,7 +164,7 @@ bool FRenderState::ApplyShader() activeShader->muFogEnabled.Set(fogset); activeShader->muPalLightLevels.Set(static_cast(gl_bandedswlight) | (static_cast(gl_fogmode) << 8)); activeShader->muGlobVis.Set(GLRenderer->mGlobVis / 32.0f); - activeShader->muTextureMode.Set(mTextureMode); + activeShader->muTextureMode.Set(mTextureMode == TM_MODULATE && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode); activeShader->muCameraPos.Set(mCameraPos.vec); activeShader->muLightParms.Set(mLightParms); activeShader->muFogColor.Set(mFogColor); diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 92de96e9a6..6de2b1455d 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -112,6 +112,7 @@ class FRenderState int mEffectState; int mColormapState; + int mTempTM = TM_MODULATE; float stAlphaThreshold; int stSrcBlend, stDstBlend; @@ -150,6 +151,14 @@ public: { if (mat->tex->UseBasePalette() || gl.legacyMode) translation = TRANSLATION(TRANSLATION_Standard, 8); } + if (mat->tex->bHasCanvas) + { + mTempTM = TM_OPAQUE; + } + else + { + mTempTM = TM_MODULATE; + } mEffectState = overrideshader >= 0? overrideshader : mat->mShaderIndex; mShaderTimer = mat->tex->gl_info.shaderspeed; mat->Bind(clampmode, translation); From bcc897235641576e9b1c6527a160aa314e703f8e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Mar 2018 15:00:18 +0100 Subject: [PATCH 28/29] - fixed: A preincrement of a local variable generated wrong code if passed as a function parameter. Due to the special nature of this expression the code generator got stuck in 'address' mode and passed the address of the variable instead of its value. --- src/scripting/backend/codegen.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 24e541a36d..273d4e4987 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -2304,6 +2304,7 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) } pointer.Free(build); + value.Target = false; // This is for 'unrequesting' the address of a register variable. If not done here, passing a preincrement expression to a function will generate bad code. return value; } @@ -7406,7 +7407,16 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) if (arrayispointer) { - arraytype = static_cast(Array->ValueType->toPointer()->PointedType); + auto ptr = Array->ValueType->toPointer(); + if (ptr != nullptr) + { + arraytype = static_cast(ptr->PointedType); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Internal error when generating code for array access"); + return ExpEmit(); + } } else { From bc25ad41365726b98a62522a2c321ee5730f285d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Mar 2018 17:10:21 +0100 Subject: [PATCH 29/29] - fixed a small logic error introduced by fixing the translucent particle sorting. Due to an unintended swap of two values a few equal comparisons led to incorrect sorting. --- src/gl/scene/gl_drawinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index 2e2d5d1aad..c2d79b3ca1 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -402,7 +402,7 @@ void GLDrawList::SortSpriteIntoPlane(SortNode * head, SortNode * sort) head->AddToLeft(sort); head->AddToRight(sort2); } - else if ((hiz < fh->z && !ceiling) || (loz > fh->z && ceiling)) // completely on the left side + else if ((ss->z2z && !ceiling) || (ss->z1>fh->z && ceiling)) // completely on the left side { head->AddToLeft(sort); }