This commit is contained in:
Rachael Alexanderson 2018-03-01 03:37:38 -05:00
commit 353e621970
26 changed files with 184 additions and 48 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

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

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

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

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

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

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

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

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

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

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

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