From 9a8e724761064ca81bcf5d7a8dee2edac08c0925 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 27 Feb 2018 09:52:42 +0100 Subject: [PATCH 01/16] - 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 8c3cc16c5..b99f2a51b 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 b78b4e664..673002877 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 02/16] - 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 6d596c717..083df92b4 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 03/16] - 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 f4829ec18..06b09a2ef 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 04/16] - 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 d79ba5296..83c30369d 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 d79ba5296..83c30369d 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 05/16] - 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 92d574d69..ddabdb772 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 06/16] 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 ace456a69..9e6d3811a 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 96393ad4c..24e541a36 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 07/16] - 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 5059834d4..d683e62d6 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 08/16] 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 1510a5787..863e4fb46 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 8e5e1d3a2..371e3f977 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 fa0644755..cb2ceb945 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 09/16] - 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 2a8abdae9..cf8f293c6 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 10/16] - 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 7d5a79de8..16d8ac564 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 11/16] - 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 470cd9776..5db32de04 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 12/16] 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 d4794c639..5b849687c 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 f66e64aa4..fd943cbbd 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 754e3519c..9dd3c7786 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 13/16] - 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 3e497d0f6..8bd188730 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 c36058ca4..03ad9c1cc 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 ab8bef5f0..e4773f1c6 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 14/16] - 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 1bed8cba2..c861a3f8f 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 15/16] - 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 6fb35b067..5ef03d420 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 16/16] 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 ff799b14d..3198afd7f 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 4a8678fa6..e6786a721 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