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/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/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()); } diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 722fb353df..32465f7b10 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -40,15 +40,18 @@ #include "cmdlib.h" #include "doomstat.h" #include "serializer.h" +#include "vm.h" 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 +60,68 @@ 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); +} + +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 @@ -130,7 +195,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 +248,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..ba3d379b86 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -59,10 +59,34 @@ 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) {} + + 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; + 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 +94,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 +154,8 @@ protected: DHUDMessage () : SourceText(NULL) {} private: - TObjPtr Next; - uint32_t SBarID; char *SourceText; - friend class DBaseStatusBar; }; // HUD message visibility flags @@ -360,9 +381,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 +476,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..d9fa88cc2e 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,14 +594,14 @@ 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 ()) + if (msg->CallTick ()) { *prev = next; msg->Destroy(); @@ -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); @@ -697,18 +697,28 @@ void DBaseStatusBar::AttachMessage (DHUDMessage *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 // //--------------------------------------------------------------------------- -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 +735,20 @@ DHUDMessage *DBaseStatusBar::DetachMessage (DHUDMessage *msg) return NULL; } -DHUDMessage *DBaseStatusBar::DetachMessage (uint32_t id) +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) { - DHUDMessage *probe = Messages[i]; - DHUDMessage **prev = &Messages[i]; + DHUDMessageBase *probe = Messages[i]; + DHUDMessageBase **prev = &Messages[i]; while (probe && probe->SBarID != id) { @@ -747,6 +765,13 @@ DHUDMessage *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 @@ -757,18 +782,26 @@ 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; } } } +DEFINE_ACTION_FUNCTION(DBaseStatusBar, DetachAllMessages) +{ + PARAM_SELF_PROLOGUE(DBaseStatusBar); + self->DetachAllMessages(); + return 0; +} + + //--------------------------------------------------------------------------- // // PROC ShowPlayerName @@ -940,7 +973,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,8 +986,8 @@ void DBaseStatusBar::DrawMessages (int layer, int bottom) } while (msg) { - DHUDMessage *next = msg->Next; - msg->Draw (bottom, visibility); + DHUDMessageBase *next = msg->Next; + msg->CallDraw (bottom, visibility); msg = next; } } @@ -1307,10 +1340,10 @@ 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 (); + message->CallScreenSizeChanged (); message = message->Next; } } diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index 957a2d00cf..80e08b3e70 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); 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); diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index 84da70596d..c2d79b3ca1 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -358,42 +358,46 @@ 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); @@ -406,7 +410,6 @@ void GLDrawList::SortSpriteIntoPlane(SortNode * head,SortNode * sort) { head->AddToRight(sort); } - } 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/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; } diff --git a/src/info.h b/src/info.h index 3e497d0f63..69912534fa 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 { @@ -343,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); 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/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] = { 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); 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/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/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 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) { diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 96393ad4c1..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 { @@ -7758,6 +7768,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 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/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)) { 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) diff --git a/src/sound/musicformats/music_midistream.cpp b/src/sound/musicformats/music_midistream.cpp index db610e23ff..5889b0e1da 100644 --- a/src/sound/musicformats/music_midistream.cpp +++ b/src/sound/musicformats/music_midistream.cpp @@ -190,32 +190,32 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) { try { - switch (devtype) - { + switch (devtype) + { case MDEV_GUS: return new TimidityMIDIDevice(Args); - case MDEV_MMAPI: + case MDEV_MMAPI: #ifdef _WIN32 - return CreateWinMIDIDevice(mididevice); + return CreateWinMIDIDevice(mididevice); #endif - // Intentional fall-through for non-Windows systems. + // Intentional fall-through for non-Windows systems. - case MDEV_FLUIDSYNTH: - return new FluidSynthMIDIDevice(Args); + case MDEV_FLUIDSYNTH: + return new FluidSynthMIDIDevice(Args); - case MDEV_OPL: - return new OPLMIDIDevice(Args); + case MDEV_OPL: + return new OPLMIDIDevice(Args); - case MDEV_TIMIDITY: - return CreateTimidityPPMIDIDevice(Args); + case MDEV_TIMIDITY: + return CreateTimidityPPMIDIDevice(Args); - case MDEV_WILDMIDI: - return new WildMIDIDevice(Args); + case MDEV_WILDMIDI: + return new WildMIDIDevice(Args); - default: + default: break; - } + } } catch (CRecoverableError &err) { @@ -721,6 +721,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 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; 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); 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 +} diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index dbea3fd47c..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); @@ -1185,6 +1187,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) { 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); 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, 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; } 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; 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(); 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 {