diff --git a/src/actor.h b/src/actor.h index 18d4cf155d..2de96d84c8 100644 --- a/src/actor.h +++ b/src/actor.h @@ -818,22 +818,28 @@ public: return ( abs(X() - other->X()) < blockdist && abs(Y() - other->Y()) < blockdist); } - // '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) - { - 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) + fixed_t AproxDistance(fixed_t otherx, fixed_t 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) { - 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) @@ -844,18 +850,21 @@ public: // more precise, but slower version, being used in a few places fixed_t Distance2D(AActor *other, bool absolute = false) { - return xs_RoundToInt(TVector2(X() - other->X(), Y() - other->Y()).Length()); + fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return xs_RoundToInt(TVector2(X() - otherpos.x, Y() - otherpos.y).Length()); } // a full 3D version of the above fixed_t Distance3D(AActor *other, bool absolute = false) { - return xs_RoundToInt(TVector3(X() - other->X(), Y() - other->Y(), Z() - other->Z()).Length()); + fixedvec3 otherpos = absolute ? other->Pos() : other->PosRelative(this); + return xs_RoundToInt(TVector3(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 @@ -863,53 +872,71 @@ public: 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 ret = { other->X() - X(), other->Y() - Y() }; + fixedvec3 otherpos = other->PosRelative(this); + fixedvec2 ret = { otherpos.x - X(), otherpos.y - Y() }; return ret; } 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; } - 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 }; - return ret; + if (absolute) + { + 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]), - Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) }; - return ret; + if (absolute) + { + 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 }; - return ret; + if (absolute) + { + 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 }; - 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(); @@ -1190,7 +1217,7 @@ public: return __pos; } - fixedvec3 PosRelative(AActor *other) const; + fixedvec3 PosRelative(const AActor *other) const; fixedvec3 PosRelative(sector_t *sec) const; fixedvec3 PosRelative(line_t *line) const; diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index b0e57b618e..c68fce87b4 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -513,7 +513,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, z -= source->floorclip; th = Spawn (type, x, y, z, ALLOW_REPLACE); th->target = source; // Originator - an = source->AngleXYTo(x, y, dest); + an = th->AngleTo(dest); if (dest->flags & MF_SHADOW) { // Invisible target an += pr_kmissile.Random2()<<21; @@ -522,7 +522,7 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, an >>= ANGLETOFINESHIFT; th->velx = FixedMul (th->Speed, finecosine[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) { dist = 1; diff --git a/src/namedef.h b/src/namedef.h index 83f4aca9b0..fc0ebad243 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -284,8 +284,18 @@ xx(FRandom) xx(Random2) xx(RandomPick) xx(FRandomPick) +xx(Exp) +xx(Log10) +xx(Ceil) +xx(ACos) +xx(ASin) +xx(ATan) xx(Cos) xx(Sin) +xx(Tan) +xx(CosH) +xx(SinH) +xx(TanH) xx(Alpha) xx(Angle) xx(Args) @@ -322,6 +332,7 @@ xx(Radius) xx(ReactionTime) xx(MeleeRange) xx(Speed) +xx(Clamp) // Various actor names which are used internally xx(MapSpot) diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index eee5167ce8..67c2303e79 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -856,7 +856,7 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) void FMultiBlockLinesIterator::startIteratorForGroup(int group) { - offset = Displacements(basegroup, group); + offset = Displacements.getOffset(basegroup, group); offset.x += checkpoint.x; offset.y += checkpoint.y; bbox.setBox(offset.x, offset.y, checkpoint.z); @@ -1088,7 +1088,7 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite if (thing != NULL) { item->thing = thing; - item->position = checkpoint + Displacements(basegroup, thing->Sector->PortalGroup); + item->position = checkpoint + Displacements.getOffset(basegroup, thing->Sector->PortalGroup); item->portalflags = portalflags; return true; } @@ -1127,7 +1127,7 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite void FMultiBlockThingsIterator::startIteratorForGroup(int group) { - fixedvec2 offset = Displacements(basegroup, group); + fixedvec2 offset = Displacements.getOffset(basegroup, group); offset.x += checkpoint.x; offset.y += checkpoint.y; bbox.setBox(offset.x, offset.y, checkpoint.z); diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 756495ac81..8c21ff5fff 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -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. while (!check->PortalBlocksMovement(ceiling) && planeheight < check->SkyBoxes[ceiling]->threshold) { - FDisplacement &disp = check->CeilingDisplacement(); - x += disp.pos.x; - y += disp.pos.y; + fixedvec2 pos = check->CeilingDisplacement(); + x += pos.x; + y += pos.y; planeheight = check->SkyBoxes[ceiling]->threshold; 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. while (!check->PortalBlocksMovement(floor) && planeheight > check->SkyBoxes[floor]->threshold) { - FDisplacement &disp = check->FloorDisplacement(); - x += disp.pos.x; - y += disp.pos.y; + fixedvec2 pos = check->FloorDisplacement(); + x += pos.x; + y += pos.y; planeheight = check->SkyBoxes[floor]->threshold; 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 { - FDisplacement &disp = sec->CeilingDisplacement(); - x += disp.pos.x; - y += disp.pos.y; + fixedvec2 pos = sec->CeilingDisplacement(); + x += pos.x; + y += pos.y; planeheight = sec->SkyBoxes[ceiling]->threshold; 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 { - FDisplacement &disp = sec->FloorDisplacement(); - x += disp.pos.x; - y += disp.pos.y; + fixedvec2 pos = sec->FloorDisplacement(); + x += pos.x; + y += pos.y; planeheight = sec->SkyBoxes[floor]->threshold; sec = P_PointInSector(x, y); } diff --git a/src/p_things.cpp b/src/p_things.cpp index 357fdcef6c..82fe0d5a24 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -786,7 +786,7 @@ int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, if (flags & WARPF_WARPINTERPOLATION) { // 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->PrevY += caller->Y() - displacedold.y; 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) { // Map both positions of the reference actor to the current portal group - fixedvec3 displacedold = old + Displacements(reference->PrevPortalGroup, caller->Sector->PortalGroup); - fixedvec3 displacedref = old + Displacements(reference->Sector->PortalGroup, caller->Sector->PortalGroup); + fixedvec3 displacedold = old + Displacements.getOffset(reference->PrevPortalGroup, caller->Sector->PortalGroup); + fixedvec3 displacedref = old + Displacements.getOffset(reference->Sector->PortalGroup, caller->Sector->PortalGroup); caller->PrevX = caller->X() + displacedold.x - displacedref.x; caller->PrevY = caller->Y() + displacedold.y - displacedref.y; caller->PrevZ = caller->Z() + displacedold.z - displacedref.z; diff --git a/src/portal.cpp b/src/portal.cpp index 8446b3151a..2a920f74c0 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -121,6 +121,11 @@ static void BuildBlockmap() { PortalBlockmap.containsLines = true; 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) { - fixedvec3 dest = { actor->X() + dx, actor->Y() + dy }; + fixedvec2 dest = { actor->X() + dx, actor->Y() + dy }; if (PortalBlockmap.containsLines) { 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; bool repeat; do { - it.init(actx, acty, dx, dy, PT_ADDLINES); + it.init(actx, acty, dx, dy, PT_ADDLINES|PT_DELTA); intercept_t *in; 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) { sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector; - FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup); - fixed_t dx = position.x + disp.pos.x; - fixed_t dy = position.y + disp.pos.y; + fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup); + fixed_t dx = position.x + pos.x; + fixed_t dy = position.y + pos.y; processMask.setBit(othersec->PortalGroup); out.Add(othersec->PortalGroup|FPortalGroupArray::UPPER); 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) { sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector; - FDisplacement &disp = Displacements(startgroup, othersec->PortalGroup); - fixed_t dx = position.x + disp.pos.x; - fixed_t dy = position.y + disp.pos.y; + fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup); + fixed_t dx = position.x + pos.x; + fixed_t dy = position.y + pos.y; processMask.setBit(othersec->PortalGroup|FPortalGroupArray::LOWER); out.Add(othersec->PortalGroup); wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat diff --git a/src/portal.h b/src/portal.h index 942a44c4ac..ef8cec98af 100644 --- a/src/portal.h +++ b/src/portal.h @@ -30,10 +30,6 @@ struct FDisplacement bool isSet; BYTE indirect; // just for illustration. - operator fixedvec2() - { - return pos; - } }; struct FDisplacementTable @@ -55,9 +51,18 @@ struct FDisplacementTable FDisplacement &operator()(int x, int y) { - if (x == y) return data[0]; // shortcut for the most common case 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; @@ -72,7 +77,13 @@ extern FDisplacementTable Displacements; 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 portallines; + + FPortalBlock() + { + neighborContainsLines = false; + } }; 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_NormalizeVXVY(fixed_t& vx, fixed_t& vy); 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 \ No newline at end of file diff --git a/src/r_defs.h b/src/r_defs.h index cac0215aaf..34ba653e61 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -838,14 +838,14 @@ struct sector_t } // 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; @@ -1375,24 +1375,24 @@ inline sector_t *P_PointInSector(fixed_t x, fixed_t y) 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 { - return __pos + Displacements(Sector->PortalGroup, sec->PortalGroup); + return __pos + Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup); } 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) { - return pos + Displacements(refsec->PortalGroup, line->frontsector->PortalGroup); + return pos + Displacements.getOffset(refsec->PortalGroup, line->frontsector->PortalGroup); } inline void AActor::ClearInterpolation() diff --git a/src/r_utility.cpp b/src/r_utility.cpp index a97ebc65ec..628310fcec 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -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 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); viewy = iview->oviewy + FixedMul (frac, iview->nviewy - iview->oviewy - disp.y); viewz = iview->oviewz + FixedMul (frac, iview->nviewz - iview->oviewz); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index e03d674c78..ec876da15e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -323,6 +323,40 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetDistance) 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__ @@ -5147,7 +5181,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) if (spawnblood) { 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); } } } diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 7ef93563c1..8cfd737b95 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -57,6 +57,7 @@ static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls); static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls); static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cls); +static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls); // // ParseExpression @@ -381,6 +382,8 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) case NAME_Min: case NAME_Max: return ParseMinMax(sc, identifier, cls); + case NAME_Clamp: + return ParseClamp(sc, cls); case NAME_Abs: return ParseAbs(sc, cls); default: @@ -521,3 +524,23 @@ static FxExpression *ParseMinMax(FScanner &sc, FName identifier, PClassActor *cl } 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 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); +} diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 294399d791..62640e7e13 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -830,19 +830,19 @@ public: //========================================================================== // -// FxGlobalFunctionCall +// FxFlopFunctionCall // //========================================================================== -class FxGlobalFunctionCall : public FxExpression +class FxFlopFunctionCall : public FxExpression { - FName Name; + int Index; FArgumentList *ArgList; public: - FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos); - ~FxGlobalFunctionCall(); + FxFlopFunctionCall(int index, FArgumentList *args, const FScriptPosition &pos); + ~FxFlopFunctionCall(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 833f3a3d5b..2ac41f7a8b 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -54,6 +54,36 @@ #include "vmbuilder.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) : RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) { @@ -3146,20 +3176,21 @@ FxFunctionCall::~FxFunctionCall() FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) { - // There's currently only 3 global functions. - // If this changes later, it won't be here! - if (MethodName == NAME_Sin || MethodName == NAME_Cos || MethodName == NAME_Sqrt) + for (int i = 0; i < countof(FxFlops); ++i) { - 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; - 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; @@ -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) { - Name = fname; + assert(index >= 0 && index < countof(FxFlops) && "FLOP index out of range"); + Index = index; ArgList = args; } @@ -3496,18 +3528,18 @@ FxGlobalFunctionCall::FxGlobalFunctionCall(FName fname, FArgumentList *args, con // //========================================================================== -FxGlobalFunctionCall::~FxGlobalFunctionCall() +FxFlopFunctionCall::~FxFlopFunctionCall() { SAFE_DELETE(ArgList); } -FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) +FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); 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; return NULL; } @@ -3528,15 +3560,7 @@ FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) if ((*ArgList)[0]->isConstant()) { double v = static_cast((*ArgList)[0])->GetValue().GetFloat(); - if (Name == NAME_Sqrt) - { - v = sqrt(v); - } - else - { - v *= M_PI / 180.0; // convert from degrees to radians - v = (Name == NAME_Sin) ? sin(v) : cos(v); - } + v = FxFlops[Index].Evaluate(v); FxExpression *x = new FxConstant(v, ScriptPosition); delete this; 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); assert(!v.Konst && v.RegType == REGT_FLOAT); - build->Emit(OP_FLOP, v.RegNum, v.RegNum, - (Name == NAME_Sqrt) ? FLOP_SQRT : - (Name == NAME_Sin) ? FLOP_SIN_DEG : - FLOP_COS_DEG); + build->Emit(OP_FLOP, v.RegNum, v.RegNum, FxFlops[Index].Flop); return v; } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 642269f283..34fbd5cef7 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -42,6 +42,8 @@ ACTOR Actor native //: Thinker native bool IsPointerEqual(int ptr_select1, int ptr_select2); native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); native float GetDistance(bool checkz, int ptr = AAPTR_DEFAULT); + native int GetSpawnHealth(); + native int GetGibHealth(); // Action functions // Meh, MBF redundant functions. Only for DeHackEd support.