Merge branch 'zmaster'

This commit is contained in:
Christoph Oelckers 2016-02-26 11:54:08 +01:00
commit bb4bd76257
15 changed files with 261 additions and 118 deletions

View file

@ -818,22 +818,28 @@ public:
return ( abs(X() - other->X()) < blockdist && abs(Y() - other->Y()) < blockdist); return ( abs(X() - other->X()) < blockdist && abs(Y() - other->Y()) < blockdist);
} }
// 'absolute' is reserved for a linked portal implementation which needs fixed_t AproxDistance(fixed_t otherx, fixed_t othery)
// to distinguish between portal-aware and portal-unaware distance calculation.
fixed_t AproxDistance(AActor *other, bool absolute = false)
{
return P_AproxDistance(X() - other->X(), Y() - other->Y());
}
// same with 'ref' here.
fixed_t AproxDistance(fixed_t otherx, fixed_t othery, AActor *ref = NULL)
{ {
return P_AproxDistance(X() - otherx, Y() - othery); return P_AproxDistance(X() - otherx, Y() - othery);
} }
fixed_t AngleTo(fixed_t otherx, fixed_t othery)
{
return R_PointToAngle2(X(), Y(), otherx, othery);
}
// 'absolute' is reserved for a linked portal implementation which needs
// to distinguish between portal-aware and portal-unaware distance calculation.
fixed_t AproxDistance(AActor *other, bool absolute = false)
{
fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return P_AproxDistance(X() - otherpos.x, Y() - otherpos.y);
}
fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false) fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false)
{ {
return P_AproxDistance(X() - other->X() + xadd, Y() - other->Y() + yadd); fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return P_AproxDistance(X() - otherpos.x + xadd, Y() - otherpos.y + yadd);
} }
fixed_t AproxDistance3D(AActor *other, bool absolute = false) fixed_t AproxDistance3D(AActor *other, bool absolute = false)
@ -844,18 +850,21 @@ public:
// more precise, but slower version, being used in a few places // more precise, but slower version, being used in a few places
fixed_t Distance2D(AActor *other, bool absolute = false) fixed_t Distance2D(AActor *other, bool absolute = false)
{ {
return xs_RoundToInt(TVector2<double>(X() - other->X(), Y() - other->Y()).Length()); fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return xs_RoundToInt(TVector2<double>(X() - otherpos.x, Y() - otherpos.y).Length());
} }
// a full 3D version of the above // a full 3D version of the above
fixed_t Distance3D(AActor *other, bool absolute = false) fixed_t Distance3D(AActor *other, bool absolute = false)
{ {
return xs_RoundToInt(TVector3<double>(X() - other->X(), Y() - other->Y(), Z() - other->Z()).Length()); fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return xs_RoundToInt(TVector3<double>(X() - otherpos.x, Y() - otherpos.y, Z() - otherpos.z).Length());
} }
angle_t AngleTo(AActor *other, bool absolute = false) const angle_t AngleTo(AActor *other, bool absolute = false)
{ {
return R_PointToAngle2(X(), Y(), other->X(), other->Y()); fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
return R_PointToAngle2(X(), Y(), otherpos.x, otherpos.y);
} }
angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const
@ -863,53 +872,71 @@ public:
return R_PointToAngle2(X(), Y(), other->X() + oxofs, other->Y() + oyofs); return R_PointToAngle2(X(), Y(), other->X() + oxofs, other->Y() + oyofs);
} }
fixed_t AngleTo(fixed_t otherx, fixed_t othery, AActor *ref = NULL)
{
return R_PointToAngle2(X(), Y(), otherx, othery);
}
fixed_t AngleXYTo(fixed_t myx, fixed_t myy, AActor *other, bool absolute = false)
{
return R_PointToAngle2(myx, myy, other->X(), other->Y());
}
fixedvec2 Vec2To(AActor *other) const fixedvec2 Vec2To(AActor *other) const
{ {
fixedvec2 ret = { other->X() - X(), other->Y() - Y() }; fixedvec3 otherpos = other->PosRelative(this);
fixedvec2 ret = { otherpos.x - X(), otherpos.y - Y() };
return ret; return ret;
} }
fixedvec3 Vec3To(AActor *other) const fixedvec3 Vec3To(AActor *other) const
{ {
fixedvec3 ret = { other->X() - X(), other->Y() - Y(), other->Z() - Z() }; fixedvec3 otherpos = other->PosRelative(this);
fixedvec3 ret = { otherpos.x - X(), otherpos.y - Y(), otherpos.z - Z() };
return ret; return ret;
} }
fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy, bool absolute = false) const fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy, bool absolute = false)
{ {
fixedvec2 ret = { X() + dx, Y() + dy }; if (absolute)
return ret; {
fixedvec2 ret = { X() + dx, Y() + dy };
return ret;
}
else return P_GetOffsetPosition(this, dx, dy);
} }
fixedvec2 Vec2Angle(fixed_t length, angle_t angle, bool absolute = false) const fixedvec2 Vec2Angle(fixed_t length, angle_t angle, bool absolute = false)
{ {
fixedvec2 ret = { X() + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), if (absolute)
Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) }; {
return ret; fixedvec2 ret = { X() + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]),
Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) };
return ret;
}
else return P_GetOffsetPosition(this, FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]));
} }
fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false) const fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false)
{ {
fixedvec3 ret = { X() + dx, Y() + dy, Z() + dz }; if (absolute)
return ret; {
fixedvec3 ret = { X() + dx, Y() + dy, Z() + dz };
return ret;
}
else
{
fixedvec2 op = P_GetOffsetPosition(this, dx, dy);
fixedvec3 pos = { op.x, op.y, Z() + dz };
return pos;
}
} }
fixedvec3 Vec3Angle(fixed_t length, angle_t angle, fixed_t dz, bool absolute = false) const fixedvec3 Vec3Angle(fixed_t length, angle_t angle, fixed_t dz, bool absolute = false)
{ {
fixedvec3 ret = { X() + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), if (absolute)
{
fixedvec3 ret = { X() + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]),
Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]), Z() + dz }; Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]), Z() + dz };
return ret; return ret;
}
else
{
fixedvec2 op = P_GetOffsetPosition(this, FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]));
fixedvec3 pos = { op.x, op.y, Z() + dz };
return pos;
}
} }
void ClearInterpolation(); void ClearInterpolation();
@ -1190,7 +1217,7 @@ public:
return __pos; return __pos;
} }
fixedvec3 PosRelative(AActor *other) const; fixedvec3 PosRelative(const AActor *other) const;
fixedvec3 PosRelative(sector_t *sec) const; fixedvec3 PosRelative(sector_t *sec) const;
fixedvec3 PosRelative(line_t *line) const; fixedvec3 PosRelative(line_t *line) const;

View file

@ -513,7 +513,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z,
z -= source->floorclip; z -= source->floorclip;
th = Spawn (type, x, y, z, ALLOW_REPLACE); th = Spawn (type, x, y, z, ALLOW_REPLACE);
th->target = source; // Originator th->target = source; // Originator
an = source->AngleXYTo(x, y, dest); an = th->AngleTo(dest);
if (dest->flags & MF_SHADOW) if (dest->flags & MF_SHADOW)
{ // Invisible target { // Invisible target
an += pr_kmissile.Random2()<<21; an += pr_kmissile.Random2()<<21;
@ -522,7 +522,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z,
an >>= ANGLETOFINESHIFT; an >>= ANGLETOFINESHIFT;
th->velx = FixedMul (th->Speed, finecosine[an]); th->velx = FixedMul (th->Speed, finecosine[an]);
th->vely = FixedMul (th->Speed, finesine[an]); th->vely = FixedMul (th->Speed, finesine[an]);
dist = dest->AproxDistance (x, y, source) / th->Speed; dist = dest->AproxDistance (th) / th->Speed;
if (dist < 1) if (dist < 1)
{ {
dist = 1; dist = 1;

View file

@ -284,8 +284,18 @@ xx(FRandom)
xx(Random2) xx(Random2)
xx(RandomPick) xx(RandomPick)
xx(FRandomPick) xx(FRandomPick)
xx(Exp)
xx(Log10)
xx(Ceil)
xx(ACos)
xx(ASin)
xx(ATan)
xx(Cos) xx(Cos)
xx(Sin) xx(Sin)
xx(Tan)
xx(CosH)
xx(SinH)
xx(TanH)
xx(Alpha) xx(Alpha)
xx(Angle) xx(Angle)
xx(Args) xx(Args)
@ -322,6 +332,7 @@ xx(Radius)
xx(ReactionTime) xx(ReactionTime)
xx(MeleeRange) xx(MeleeRange)
xx(Speed) xx(Speed)
xx(Clamp)
// Various actor names which are used internally // Various actor names which are used internally
xx(MapSpot) xx(MapSpot)

View file

@ -856,7 +856,7 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item)
void FMultiBlockLinesIterator::startIteratorForGroup(int group) void FMultiBlockLinesIterator::startIteratorForGroup(int group)
{ {
offset = Displacements(basegroup, group); offset = Displacements.getOffset(basegroup, group);
offset.x += checkpoint.x; offset.x += checkpoint.x;
offset.y += checkpoint.y; offset.y += checkpoint.y;
bbox.setBox(offset.x, offset.y, checkpoint.z); bbox.setBox(offset.x, offset.y, checkpoint.z);
@ -1088,7 +1088,7 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite
if (thing != NULL) if (thing != NULL)
{ {
item->thing = thing; item->thing = thing;
item->position = checkpoint + Displacements(basegroup, thing->Sector->PortalGroup); item->position = checkpoint + Displacements.getOffset(basegroup, thing->Sector->PortalGroup);
item->portalflags = portalflags; item->portalflags = portalflags;
return true; return true;
} }
@ -1127,7 +1127,7 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite
void FMultiBlockThingsIterator::startIteratorForGroup(int group) void FMultiBlockThingsIterator::startIteratorForGroup(int group)
{ {
fixedvec2 offset = Displacements(basegroup, group); fixedvec2 offset = Displacements.getOffset(basegroup, group);
offset.x += checkpoint.x; offset.x += checkpoint.x;
offset.y += checkpoint.y; offset.y += checkpoint.y;
bbox.setBox(offset.x, offset.y, checkpoint.z); bbox.setBox(offset.x, offset.y, checkpoint.z);

View file

@ -897,9 +897,9 @@ fixed_t sector_t::HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec)
// Continue until we find a blocking portal or a portal below where we actually are. // Continue until we find a blocking portal or a portal below where we actually are.
while (!check->PortalBlocksMovement(ceiling) && planeheight < check->SkyBoxes[ceiling]->threshold) while (!check->PortalBlocksMovement(ceiling) && planeheight < check->SkyBoxes[ceiling]->threshold)
{ {
FDisplacement &disp = check->CeilingDisplacement(); fixedvec2 pos = check->CeilingDisplacement();
x += disp.pos.x; x += pos.x;
y += disp.pos.y; y += pos.y;
planeheight = check->SkyBoxes[ceiling]->threshold; planeheight = check->SkyBoxes[ceiling]->threshold;
check = P_PointInSector(x, y); check = P_PointInSector(x, y);
} }
@ -921,9 +921,9 @@ fixed_t sector_t::LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec)
// Continue until we find a blocking portal or a portal above where we actually are. // Continue until we find a blocking portal or a portal above where we actually are.
while (!check->PortalBlocksMovement(floor) && planeheight > check->SkyBoxes[floor]->threshold) while (!check->PortalBlocksMovement(floor) && planeheight > check->SkyBoxes[floor]->threshold)
{ {
FDisplacement &disp = check->FloorDisplacement(); fixedvec2 pos = check->FloorDisplacement();
x += disp.pos.x; x += pos.x;
y += disp.pos.y; y += pos.y;
planeheight = check->SkyBoxes[floor]->threshold; planeheight = check->SkyBoxes[floor]->threshold;
check = P_PointInSector(x, y); check = P_PointInSector(x, y);
} }
@ -960,9 +960,9 @@ fixed_t sector_t::NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flag
} }
else else
{ {
FDisplacement &disp = sec->CeilingDisplacement(); fixedvec2 pos = sec->CeilingDisplacement();
x += disp.pos.x; x += pos.x;
y += disp.pos.y; y += pos.y;
planeheight = sec->SkyBoxes[ceiling]->threshold; planeheight = sec->SkyBoxes[ceiling]->threshold;
sec = P_PointInSector(x, y); sec = P_PointInSector(x, y);
} }
@ -1003,9 +1003,9 @@ fixed_t sector_t::NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags,
} }
else else
{ {
FDisplacement &disp = sec->FloorDisplacement(); fixedvec2 pos = sec->FloorDisplacement();
x += disp.pos.x; x += pos.x;
y += disp.pos.y; y += pos.y;
planeheight = sec->SkyBoxes[floor]->threshold; planeheight = sec->SkyBoxes[floor]->threshold;
sec = P_PointInSector(x, y); sec = P_PointInSector(x, y);
} }

View file

@ -786,7 +786,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs,
if (flags & WARPF_WARPINTERPOLATION) if (flags & WARPF_WARPINTERPOLATION)
{ {
// This just translates the movement but doesn't change the vector // This just translates the movement but doesn't change the vector
fixedvec3 displacedold = old + Displacements(oldpgroup, caller->Sector->PortalGroup); fixedvec3 displacedold = old + Displacements.getOffset(oldpgroup, caller->Sector->PortalGroup);
caller->PrevX += caller->X() - displacedold.x; caller->PrevX += caller->X() - displacedold.x;
caller->PrevY += caller->Y() - displacedold.y; caller->PrevY += caller->Y() - displacedold.y;
caller->PrevZ += caller->Z() - displacedold.z; caller->PrevZ += caller->Z() - displacedold.z;
@ -795,8 +795,8 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs,
else if (flags & WARPF_COPYINTERPOLATION) else if (flags & WARPF_COPYINTERPOLATION)
{ {
// Map both positions of the reference actor to the current portal group // Map both positions of the reference actor to the current portal group
fixedvec3 displacedold = old + Displacements(reference->PrevPortalGroup, caller->Sector->PortalGroup); fixedvec3 displacedold = old + Displacements.getOffset(reference->PrevPortalGroup, caller->Sector->PortalGroup);
fixedvec3 displacedref = old + Displacements(reference->Sector->PortalGroup, caller->Sector->PortalGroup); fixedvec3 displacedref = old + Displacements.getOffset(reference->Sector->PortalGroup, caller->Sector->PortalGroup);
caller->PrevX = caller->X() + displacedold.x - displacedref.x; caller->PrevX = caller->X() + displacedold.x - displacedref.x;
caller->PrevY = caller->Y() + displacedold.y - displacedref.y; caller->PrevY = caller->Y() + displacedold.y - displacedref.y;
caller->PrevZ = caller->Z() + displacedold.z - displacedref.z; caller->PrevZ = caller->Z() + displacedold.z - displacedref.z;

View file

@ -121,6 +121,11 @@ static void BuildBlockmap()
{ {
PortalBlockmap.containsLines = true; PortalBlockmap.containsLines = true;
block.portallines.Push(ld); block.portallines.Push(ld);
block.neighborContainsLines = true;
if (x > 0) PortalBlockmap(x - 1, y).neighborContainsLines = true;
if (y > 0) PortalBlockmap(x, y - 1).neighborContainsLines = true;
if (x < PortalBlockmap.dx - 1) PortalBlockmap(x + 1, y).neighborContainsLines = true;
if (y < PortalBlockmap.dy - 1) PortalBlockmap(x, y + 1).neighborContainsLines = true;
} }
} }
} }
@ -691,15 +696,23 @@ void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy)
fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy) fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy)
{ {
fixedvec3 dest = { actor->X() + dx, actor->Y() + dy }; fixedvec2 dest = { actor->X() + dx, actor->Y() + dy };
if (PortalBlockmap.containsLines) if (PortalBlockmap.containsLines)
{ {
fixed_t actx = actor->X(), acty = actor->Y(); fixed_t actx = actor->X(), acty = actor->Y();
// Try some easily discoverable early-out first. If we know that the trace cannot possibly find a portal, this saves us from calling the traverser completely for vast parts of the map.
if (dx < 128 * FRACUNIT && dy < 128 * FRACUNIT)
{
fixed_t blockx = GetSafeBlockX(actx - bmaporgx);
fixed_t blocky = GetSafeBlockX(acty - bmaporgy);
if (blockx < 0 || blocky < 0 || blockx >= bmapwidth || blocky >= bmapheight || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest;
}
FLinePortalTraverse it; FLinePortalTraverse it;
bool repeat; bool repeat;
do do
{ {
it.init(actx, acty, dx, dy, PT_ADDLINES); it.init(actx, acty, dx, dy, PT_ADDLINES|PT_DELTA);
intercept_t *in; intercept_t *in;
repeat = false; repeat = false;
@ -1159,9 +1172,9 @@ bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t
while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold) while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold)
{ {
sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector; sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector;
FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup); fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup);
fixed_t dx = position.x + disp.pos.x; fixed_t dx = position.x + pos.x;
fixed_t dy = position.y + disp.pos.y; fixed_t dy = position.y + pos.y;
processMask.setBit(othersec->PortalGroup); processMask.setBit(othersec->PortalGroup);
out.Add(othersec->PortalGroup|FPortalGroupArray::UPPER); out.Add(othersec->PortalGroup|FPortalGroupArray::UPPER);
wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat
@ -1171,9 +1184,9 @@ bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t
while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold) while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold)
{ {
sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector; sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector;
FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup); fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup);
fixed_t dx = position.x + disp.pos.x; fixed_t dx = position.x + pos.x;
fixed_t dy = position.y + disp.pos.y; fixed_t dy = position.y + pos.y;
processMask.setBit(othersec->PortalGroup|FPortalGroupArray::LOWER); processMask.setBit(othersec->PortalGroup|FPortalGroupArray::LOWER);
out.Add(othersec->PortalGroup); out.Add(othersec->PortalGroup);
wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat

View file

@ -30,10 +30,6 @@ struct FDisplacement
bool isSet; bool isSet;
BYTE indirect; // just for illustration. BYTE indirect; // just for illustration.
operator fixedvec2()
{
return pos;
}
}; };
struct FDisplacementTable struct FDisplacementTable
@ -55,9 +51,18 @@ struct FDisplacementTable
FDisplacement &operator()(int x, int y) FDisplacement &operator()(int x, int y)
{ {
if (x == y) return data[0]; // shortcut for the most common case
return data[x + size*y]; return data[x + size*y];
} }
fixedvec2 getOffset(int x, int y) const
{
if (x == y)
{
fixedvec2 nulvec = { 0,0 };
return nulvec; // shortcut for the most common case
}
return data[x + size*y].pos;
}
}; };
extern FDisplacementTable Displacements; extern FDisplacementTable Displacements;
@ -72,7 +77,13 @@ extern FDisplacementTable Displacements;
struct FPortalBlock struct FPortalBlock
{ {
bool neighborContainsLines; // this is for skipping the traverser and exiting early if we can quickly decide that there's no portals nearby.
TArray<line_t*> portallines; TArray<line_t*> portallines;
FPortalBlock()
{
neighborContainsLines = false;
}
}; };
struct FPortalBlockmap struct FPortalBlockmap
@ -187,5 +198,6 @@ void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z); void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z);
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy); void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy);
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y); fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy);
#endif #endif

View file

@ -838,14 +838,14 @@ struct sector_t
} }
// These may only be called if the portal has been validated // These may only be called if the portal has been validated
FDisplacement &FloorDisplacement() fixedvec2 FloorDisplacement()
{ {
return Displacements(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup); return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup);
} }
FDisplacement &CeilingDisplacement() fixedvec2 CeilingDisplacement()
{ {
return Displacements(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup); return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup);
} }
int GetTerrain(int pos) const; int GetTerrain(int pos) const;
@ -1375,24 +1375,24 @@ inline sector_t *P_PointInSector(fixed_t x, fixed_t y)
return P_PointInSubsector(x, y)->sector; return P_PointInSubsector(x, y)->sector;
} }
inline fixedvec3 AActor::PosRelative(AActor *other) const inline fixedvec3 AActor::PosRelative(const AActor *other) const
{ {
return __pos + Displacements(Sector->PortalGroup, other->Sector->PortalGroup); return __pos + Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup);
} }
inline fixedvec3 AActor::PosRelative(sector_t *sec) const inline fixedvec3 AActor::PosRelative(sector_t *sec) const
{ {
return __pos + Displacements(Sector->PortalGroup, sec->PortalGroup); return __pos + Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup);
} }
inline fixedvec3 AActor::PosRelative(line_t *line) const inline fixedvec3 AActor::PosRelative(line_t *line) const
{ {
return __pos + Displacements(Sector->PortalGroup, line->frontsector->PortalGroup); return __pos + Displacements.getOffset(Sector->PortalGroup, line->frontsector->PortalGroup);
} }
inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL) inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL)
{ {
return pos + Displacements(refsec->PortalGroup, line->frontsector->PortalGroup); return pos + Displacements.getOffset(refsec->PortalGroup, line->frontsector->PortalGroup);
} }
inline void AActor::ClearInterpolation() inline void AActor::ClearInterpolation()

View file

@ -583,7 +583,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi
} }
int oldgroup = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector->PortalGroup; int oldgroup = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector->PortalGroup;
int newgroup = R_PointInSubsector(iview->nviewx, iview->nviewy)->sector->PortalGroup; int newgroup = R_PointInSubsector(iview->nviewx, iview->nviewy)->sector->PortalGroup;
fixedvec2 disp = Displacements(oldgroup, newgroup); fixedvec2 disp = Displacements.getOffset(oldgroup, newgroup);
viewx = iview->oviewx + FixedMul (frac, iview->nviewx - iview->oviewx - disp.x); viewx = iview->oviewx + FixedMul (frac, iview->nviewx - iview->oviewx - disp.x);
viewy = iview->oviewy + FixedMul (frac, iview->nviewy - iview->oviewy - disp.y); viewy = iview->oviewy + FixedMul (frac, iview->nviewy - iview->oviewy - disp.y);
viewz = iview->oviewz + FixedMul (frac, iview->nviewz - iview->oviewz); viewz = iview->oviewz + FixedMul (frac, iview->nviewz - iview->oviewz);

View file

@ -323,6 +323,40 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetDistance)
return 0; return 0;
} }
//==========================================================================
//
// GetSpawnHealth
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpawnHealth)
{
if (numret > 0)
{
PARAM_PROLOGUE;
PARAM_OBJECT(self, AActor);
ret->SetInt(self->SpawnHealth());
return 1;
}
return 0;
}
//==========================================================================
//
// GetGibHealth
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetGibHealth)
{
if (numret > 0)
{
PARAM_PROLOGUE;
PARAM_OBJECT(self, AActor);
ret->SetInt(self->GetGibHealth());
return 1;
}
return 0;
}
//=========================================================================== //===========================================================================
// //
// __decorate_internal_state__ // __decorate_internal_state__
@ -5147,7 +5181,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack)
if (spawnblood) if (spawnblood)
{ {
P_SpawnBlood(bloodpos, angle, newdam > 0 ? newdam : damage, self->target); P_SpawnBlood(bloodpos, angle, newdam > 0 ? newdam : damage, self->target);
P_TraceBleed(newdam > 0 ? newdam : damage, self->target, self->AngleTo(dx, dy, self->target), 0); P_TraceBleed(newdam > 0 ? newdam : damage, self->target, self);
} }
} }
} }

View file

@ -57,6 +57,7 @@ static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor
static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls); static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls);
static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls); static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls);
static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cls); static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cls);
static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls);
// //
// ParseExpression // ParseExpression
@ -381,6 +382,8 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
case NAME_Min: case NAME_Min:
case NAME_Max: case NAME_Max:
return ParseMinMax(sc, identifier, cls); return ParseMinMax(sc, identifier, cls);
case NAME_Clamp:
return ParseClamp(sc, cls);
case NAME_Abs: case NAME_Abs:
return ParseAbs(sc, cls); return ParseAbs(sc, cls);
default: default:
@ -521,3 +524,23 @@ static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cl
} }
return new FxMinMax(list, identifier, sc); return new FxMinMax(list, identifier, sc);
} }
static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls)
{
FxExpression *src = ParseExpressionM(sc, cls);
sc.MustGetToken(',');
FxExpression *min = ParseExpressionM(sc, cls);
sc.MustGetToken(',');
FxExpression *max = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
// Build clamp(a,x,y) as min(max(a,x),y)
TArray<FxExpression *> list(2);
list.Reserve(2);
list[0] = src;
list[1] = min;
FxExpression *maxexpr = new FxMinMax(list, NAME_Max, sc);
list[0] = maxexpr;
list[1] = max;
return new FxMinMax(list, NAME_Min, sc);
}

View file

@ -830,19 +830,19 @@ public:
//========================================================================== //==========================================================================
// //
// FxGlobalFunctionCall // FxFlopFunctionCall
// //
//========================================================================== //==========================================================================
class FxGlobalFunctionCall : public FxExpression class FxFlopFunctionCall : public FxExpression
{ {
FName Name; int Index;
FArgumentList *ArgList; FArgumentList *ArgList;
public: public:
FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos); FxFlopFunctionCall(int index, FArgumentList *args, const FScriptPosition &pos);
~FxGlobalFunctionCall(); ~FxFlopFunctionCall();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };

View file

@ -54,6 +54,36 @@
#include "vmbuilder.h" #include "vmbuilder.h"
#include "v_text.h" #include "v_text.h"
struct FLOP
{
ENamedName Name;
int Flop;
double (*Evaluate)(double);
};
// Decorate operates on degrees, so the evaluate functions need to convert
// degrees to radians for those that work with angles.
static const FLOP FxFlops[] =
{
{ NAME_Exp, FLOP_EXP, [](double v) { return exp(v); } },
{ NAME_Log, FLOP_LOG, [](double v) { return log(v); } },
{ NAME_Log10, FLOP_LOG10, [](double v) { return log10(v); } },
{ NAME_Sqrt, FLOP_SQRT, [](double v) { return sqrt(v); } },
{ NAME_Ceil, FLOP_CEIL, [](double v) { return ceil(v); } },
{ NAME_Floor, FLOP_FLOOR, [](double v) { return floor(v); } },
{ NAME_ACos, FLOP_ACOS_DEG, [](double v) { return acos(v) * (180.0 / M_PI); } },
{ NAME_ASin, FLOP_ASIN_DEG, [](double v) { return asin(v) * (180.0 / M_PI); } },
{ NAME_ATan, FLOP_ATAN_DEG, [](double v) { return atan(v) * (180.0 / M_PI); } },
{ NAME_Cos, FLOP_COS_DEG, [](double v) { return cos(v * (M_PI / 180.0)); } },
{ NAME_Sin, FLOP_SIN_DEG, [](double v) { return sin(v * (M_PI / 180.0)); } },
{ NAME_Tan, FLOP_TAN_DEG, [](double v) { return tan(v * (M_PI / 180.0)); } },
{ NAME_CosH, FLOP_COSH, [](double v) { return cosh(v); } },
{ NAME_SinH, FLOP_SINH, [](double v) { return sinh(v); } },
{ NAME_TanH, FLOP_TANH, [](double v) { return tanh(v); } },
};
ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) ExpEmit::ExpEmit(VMFunctionBuilder *build, int type)
: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) : RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false)
{ {
@ -3146,20 +3176,21 @@ FxFunctionCall::~FxFunctionCall()
FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
{ {
// There's currently only 3 global functions. for (int i = 0; i < countof(FxFlops); ++i)
// If this changes later, it won't be here!
if (MethodName == NAME_Sin || MethodName == NAME_Cos || MethodName == NAME_Sqrt)
{ {
if (Self != NULL) if (MethodName == FxFlops[i].Name)
{ {
ScriptPosition.Message(MSG_ERROR, "Global functions cannot have a self pointer"); if (Self != NULL)
{
ScriptPosition.Message(MSG_ERROR, "Global functions cannot have a self pointer");
delete this;
return NULL;
}
FxExpression *x = new FxFlopFunctionCall(i, ArgList, ScriptPosition);
ArgList = NULL;
delete this; delete this;
return NULL; return x->Resolve(ctx);
} }
FxExpression *x = new FxGlobalFunctionCall(MethodName, ArgList, ScriptPosition);
ArgList = NULL;
delete this;
return x->Resolve(ctx);
} }
int min, max, special; int min, max, special;
@ -3483,10 +3514,11 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
// //
//========================================================================== //==========================================================================
FxGlobalFunctionCall::FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos) FxFlopFunctionCall::FxFlopFunctionCall(int index, FArgumentList *args, const FScriptPosition &pos)
: FxExpression(pos) : FxExpression(pos)
{ {
Name = fname; assert(index >= 0 && index < countof(FxFlops) && "FLOP index out of range");
Index = index;
ArgList = args; ArgList = args;
} }
@ -3496,18 +3528,18 @@ FxGlobalFunctionCall::FxGlobalFunctionCall(FName fname, FArgumentList *args, con
// //
//========================================================================== //==========================================================================
FxGlobalFunctionCall::~FxGlobalFunctionCall() FxFlopFunctionCall::~FxFlopFunctionCall()
{ {
SAFE_DELETE(ArgList); SAFE_DELETE(ArgList);
} }
FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx)
{ {
CHECKRESOLVED(); CHECKRESOLVED();
if (ArgList == NULL || ArgList->Size() != 1) if (ArgList == NULL || ArgList->Size() != 1)
{ {
ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", Name.GetChars()); ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", FName(FxFlops[Index].Name).GetChars());
delete this; delete this;
return NULL; return NULL;
} }
@ -3528,15 +3560,7 @@ FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx)
if ((*ArgList)[0]->isConstant()) if ((*ArgList)[0]->isConstant())
{ {
double v = static_cast<FxConstant *>((*ArgList)[0])->GetValue().GetFloat(); double v = static_cast<FxConstant *>((*ArgList)[0])->GetValue().GetFloat();
if (Name == NAME_Sqrt) v = FxFlops[Index].Evaluate(v);
{
v = sqrt(v);
}
else
{
v *= M_PI / 180.0; // convert from degrees to radians
v = (Name == NAME_Sin) ? sin(v) : cos(v);
}
FxExpression *x = new FxConstant(v, ScriptPosition); FxExpression *x = new FxConstant(v, ScriptPosition);
delete this; delete this;
return x; return x;
@ -3554,15 +3578,12 @@ FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx)
// //
//========================================================================== //==========================================================================
ExpEmit FxGlobalFunctionCall::Emit(VMFunctionBuilder *build) ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build)
{ {
ExpEmit v = (*ArgList)[0]->Emit(build); ExpEmit v = (*ArgList)[0]->Emit(build);
assert(!v.Konst && v.RegType == REGT_FLOAT); assert(!v.Konst && v.RegType == REGT_FLOAT);
build->Emit(OP_FLOP, v.RegNum, v.RegNum, build->Emit(OP_FLOP, v.RegNum, v.RegNum, FxFlops[Index].Flop);
(Name == NAME_Sqrt) ? FLOP_SQRT :
(Name == NAME_Sin) ? FLOP_SIN_DEG :
FLOP_COS_DEG);
return v; return v;
} }

View file

@ -42,6 +42,8 @@ ACTOR Actor native //: Thinker
native bool IsPointerEqual(int ptr_select1, int ptr_select2); native bool IsPointerEqual(int ptr_select1, int ptr_select2);
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT); native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
native float GetDistance(bool checkz, int ptr = AAPTR_DEFAULT); native float GetDistance(bool checkz, int ptr = AAPTR_DEFAULT);
native int GetSpawnHealth();
native int GetGibHealth();
// Action functions // Action functions
// Meh, MBF redundant functions. Only for DeHackEd support. // Meh, MBF redundant functions. Only for DeHackEd support.