Merge branch 'master' into timidity++

# Conflicts:
#	src/sound/musicformats/music_midistream.cpp
This commit is contained in:
Christoph Oelckers 2018-03-02 00:08:12 +01:00
commit 4c0f68bcd4
41 changed files with 430 additions and 132 deletions

View file

@ -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);

View file

@ -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;
}
}
}
}

View file

@ -2840,14 +2840,14 @@ static bool LoadDehSupp ()
sc.MustGetString();
PClassActor *actortype = static_cast<PClassActor *>(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());
}

View file

@ -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)

View file

@ -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<DHUDMessageBase*> 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<DHUDMessage*> 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<DHUDMessage*> Messages[NUM_HUDMSGLAYERS];
TObjPtr<DHUDMessageBase*> Messages[NUM_HUDMSGLAYERS];
int BaseRelTop;
int BaseSBarHorizontalResolution;

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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]);

View file

@ -164,7 +164,7 @@ bool FRenderState::ApplyShader()
activeShader->muFogEnabled.Set(fogset);
activeShader->muPalLightLevels.Set(static_cast<int>(gl_bandedswlight) | (static_cast<int>(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);

View file

@ -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);

View file

@ -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->z2<fh->z) || 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);
}
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -377,6 +377,8 @@ xx(MomZ)
xx(Threshold)
xx(DefThreshold)
xx(Abs)
xx(TeleportSpecial)
xx(Teleport)
xx(ACS_NamedExecuteWithResult)
xx(CallACS)
xx(Sqrt)

View file

@ -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)

View file

@ -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<int> *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);

View file

@ -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<int>[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] =
{

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -447,6 +447,7 @@ enum
MDL_USEACTORROLL = 64,
MDL_BADROTATION = 128,
MDL_DONTCULLBACKFACES = 256,
MDL_USEROTATIONCENTER = 512,
};
struct FSpriteModelFrame

View file

@ -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)
{

View file

@ -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<PArray*>(Array->ValueType->toPointer()->PointedType);
auto ptr = Array->ValueType->toPointer();
if (ptr != nullptr)
{
arraytype = static_cast<PArray*>(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)

View file

@ -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<AActor>();
ResetBaggage (&bag, RUNTIME_CLASS(AActor));
static_cast<PClassActor*>(bag.Info)->ActorInfo()->SkipSuperSet = true; // ZScript processes the states later so this property must be flagged for later handling.
}
//==========================================================================

View file

@ -1968,7 +1968,10 @@ void PDynArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *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))
{

View file

@ -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<PClassActor*>(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)

View file

@ -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

View file

@ -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;

View file

@ -35,6 +35,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <wctype.h>
#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);

View file

@ -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
}

View file

@ -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)
{

View file

@ -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);

View file

@ -244,6 +244,11 @@ class Korax : Actor
void A_KoraxMissile()
{
if (!target)
{
return;
}
static const class<Actor> choices[] =
{
"WraithFX1", "Demon1FX1", "Demon2FX1", "FireDemonMissile", "CentaurFX", "SerpentFX"
@ -282,6 +287,11 @@ class Korax : Actor
void KoraxFire (Class<Actor> type, int arm)
{
if (!target)
{
return;
}
static const int extension[] =
{
KORAX_ARM_EXTENSION_SHORT,

View file

@ -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;
}

View file

@ -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;

View file

@ -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();

View file

@ -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
{

View file

@ -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
{