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/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/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()); } 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; } 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/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/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] = { diff --git a/src/p_map.cpp b/src/p_map.cpp index 138a62595..50397d852 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); 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/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 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) 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/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)) { 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) 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(); } 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); 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 +} diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 2beb46b73..a7f76f348 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -581,6 +581,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); 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); 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; } 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; 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 {