- MBF21: more work on flags.

* added handlers for the missing upper flags in the first flag word.
* refactored some code related to MF_BOUNCES to adapt to other flags' changes to avoid constant property updates for too many flags.
* treat anything with RF_ZDOOMTRANS as non-translucent for the purpose of the flag checks.
This commit is contained in:
Christoph Oelckers 2021-07-02 19:48:58 +02:00
parent e82fd43313
commit 9082ef7d49
6 changed files with 157 additions and 35 deletions

View file

@ -1154,8 +1154,7 @@ static int PatchThing (int thingy)
while ((result = GetLine ()) == 1)
{
char *endptr;
uint64_t val64 = strtoull (Line2, &endptr, 10);
uint32_t val = (uint32_t)val64;
uint32_t val = (uint32_t)strtoull (Line2, &endptr, 10);
size_t linelen = strlen (Line1);
if (linelen == 10 && stricmp (Line1, "Hit points") == 0)
@ -1174,6 +1173,7 @@ static int PatchThing (int thingy)
{
info->Alpha = DEHToDouble(val);
info->RenderStyle = STYLE_Translucent;
info->renderflags &= ~RF_ZDOOMTRANS;
hadTranslucency = true;
hadStyle = true;
}
@ -1474,10 +1474,10 @@ static int PatchThing (int thingy)
// This is different from BOUNCE_Heretic behavior as in Heretic the missiles
// die when they bounce, while in MBF they will continue to bounce until they
// collide with a wall or a solid actor.
if (value[0] & MF_MISSILE) info->BounceFlags = BOUNCE_Classic;
if (value[0] & MF_MISSILE) info->BounceFlags = BOUNCE_Classic | BOUNCE_DEH;
// MBF bouncing actors that do not have the missile flag will also rebound on
// walls, and this does correspond roughly to the ZDoom bounce style.
else info->BounceFlags = BOUNCE_Grenade;
else info->BounceFlags = BOUNCE_Grenade | BOUNCE_DEH;
// MBF grenades are dehacked rockets that gain the BOUNCES flag but
// lose the MISSILE flag, so they can be identified here easily.
@ -1487,27 +1487,13 @@ static int PatchThing (int thingy)
info->effects |= FX_GRENADE; // by grenade trail
}
// MBF bounce factors depend on flag combos:
const double MBF_BOUNCE_NOGRAVITY = 1; // With NOGRAVITY: full momentum
const double MBF_BOUNCE_FLOATDROPOFF = 0.85; // With FLOAT and DROPOFF: 85%
const double MBF_BOUNCE_FLOAT = 0.7; // With FLOAT alone: 70%
const double MBF_BOUNCE_DEFAULT = 0.45; // Without the above flags: 45%
const double MBF_BOUNCE_WALL = 0.5; // Bouncing off walls: 50%
// bounce factors are dynamic, we only set some defaults here.
info->bouncefactor = 0.45;
info->wallbouncefactor = 0.85;
info->bouncefactor = ((value[0] & MF_NOGRAVITY) ? MBF_BOUNCE_NOGRAVITY
: (value[0] & MF_FLOAT) ? (value[0] & MF_DROPOFF) ? MBF_BOUNCE_FLOATDROPOFF
: MBF_BOUNCE_FLOAT : MBF_BOUNCE_DEFAULT);
info->wallbouncefactor = ((value[0] & MF_NOGRAVITY) ? MBF_BOUNCE_NOGRAVITY : MBF_BOUNCE_WALL);
// MBF sentient actors with BOUNCE and FLOAT are able to "jump" by floating up.
if (info->IsSentient())
{
if (value[0] & MF_FLOAT) info->flags6 |= MF6_CANJUMP;
}
// Non sentient actors can be damaged but they shouldn't bleed.
else
if (!info->IsSentient())
{
// Non sentient actors can be damaged but they shouldn't bleed.
value[0] |= MF_NOBLOOD;
}
}
@ -1581,6 +1567,7 @@ static int PatchThing (int thingy)
else if (value[2] & 4)
info->Alpha = 0.75;
info->RenderStyle = STYLE_Translucent;
info->renderflags &= ~RF_ZDOOMTRANS;
}
if (value[2] & 8)
info->renderflags |= RF_INVISIBLE;
@ -3652,6 +3639,7 @@ struct FlagHandler
#define F2(flag) { [](AActor* a) { a->flags2 |= flag; }, [](AActor* a) { a->flags2 &= ~flag; }, [](AActor* a)->bool { return a->flags2 & flag; } }
#define F3(flag) { [](AActor* a) { a->flags3 |= flag; }, [](AActor* a) { a->flags3 &= ~flag; }, [](AActor* a)->bool { return a->flags3 & flag; } }
#define F4(flag) { [](AActor* a) { a->flags4 |= flag; }, [](AActor* a) { a->flags4 &= ~flag; }, [](AActor* a)->bool { return a->flags4 & flag; } }
#define F6(flag) { [](AActor* a) { a->flags6 |= flag; }, [](AActor* a) { a->flags6 &= ~flag; }, [](AActor* a)->bool { return a->flags6 & flag; } }
#define F8(flag) { [](AActor* a) { a->flags8 |= flag; }, [](AActor* a) { a->flags8 &= ~flag; }, [](AActor* a)->bool { return a->flags8 & flag; } }
#define DEPF(flag) { [](AActor* a) { HandleDeprecatedFlags(a, nullptr, true, flag); }, [](AActor* a) { HandleDeprecatedFlags(a, nullptr, false, flag); }, [](AActor* a)->bool { return CheckDeprecatedFlags(a, nullptr, flag); } }
@ -3741,6 +3729,99 @@ void ClearFullVol(AActor* a)
a->flags3 &= ~MF3_FULLVOLDEATH;
}
void SetTranslucent(AActor* a)
{
a->RenderStyle = STYLE_Translucent;
a->Alpha = 0.5;
a->renderflags &= ~RF_ZDOOMTRANS;
}
void ClearTranslucent(AActor* a)
{
a->RenderStyle = STYLE_Normal;
a->Alpha = 1;
a->renderflags &= ~RF_ZDOOMTRANS;
}
bool CheckTranslucent(AActor* a)
{
// This is solely for MBF21. It will treat all objects with ZDOOMTRANS as non-translucent to ensure consistent results.
// This also means that all translucency changes via Dehacked need to clear this flag.
return !(a->renderflags & RF_ZDOOMTRANS) && a->Alpha < 1 - FLT_EPSILON;
}
constexpr int t0 = 0;
constexpr int t1 = TRANSLATION(TRANSLATION_Standard, 0);
constexpr int t2 = TRANSLATION(TRANSLATION_Standard, 1);
constexpr int t3 = TRANSLATION(TRANSLATION_Standard, 2);
void SetTranslation1(AActor* a)
{
if (a->Translation == t2 || a->Translation == t3) a->Translation = t3;
else a->Translation = t1;
}
void ClearTranslation1(AActor* a)
{
if (a->Translation == t3 || a->Translation == t2) a->Translation = t2;
else a->Translation = t0;
}
bool CheckTranslation1(AActor* a)
{
return a->Translation == t1 || a->Translation == t3;
}
void SetTranslation2(AActor* a)
{
if (a->Translation == t1 || a->Translation == t3) a->Translation = t3;
else a->Translation = t2;
}
void ClearTranslation2(AActor* a)
{
if (a->Translation == t3 || a->Translation == t1) a->Translation = t1;
else a->Translation = t0;
}
bool CheckTranslation2(AActor* a)
{
return a->Translation == t2 || a->Translation == t3;
}
// Bounces is very complex...
void SetBounces(AActor* info)
{
info->flags6 |= MF6_VULNERABLE;
info->flags3 |= MF3_NOBLOCKMONST;
info->flags4 |= (MF4_FORCERADIUSDMG | MF4_DONTHARMCLASS);
info->effects &= ~FX_ROCKET; // disable rocket trail if set.
if (info->flags & MF_MISSILE) info->BounceFlags = BOUNCE_Classic | BOUNCE_DEH;
else info->BounceFlags = BOUNCE_Grenade | BOUNCE_DEH;
}
void ClearBounces(AActor* info)
{
info->flags6 &= ~MF6_VULNERABLE;
info->flags3 &= ~MF3_NOBLOCKMONST;
info->flags4 &= ~(MF4_FORCERADIUSDMG | MF4_DONTHARMCLASS);
info->BounceFlags = 0;
}
// The missile flag affects the bouncing mode.
void SetMissile(AActor* info)
{
info->flags |= MF_MISSILE;
if (info->BounceFlags & BOUNCE_DEH) info->BounceFlags = BOUNCE_Classic | BOUNCE_DEH;
}
void ClearMissile(AActor* info)
{
info->flags &= ~MF_MISSILE;
if (info->BounceFlags & BOUNCE_DEH) info->BounceFlags = BOUNCE_Grenade | BOUNCE_DEH;
}
static FlagHandler flag1handlers[32] = {
F(MF_SPECIAL),
@ -3759,7 +3840,7 @@ static FlagHandler flag1handlers[32] = {
F(MF_SLIDE),
F(MF_FLOAT),
F(MF_TELEPORT),
F(MF_MISSILE),
{ SetMissile, ClearMissile, [](AActor* a)->bool { return a->flags & MF_MISSILE; } },
F(MF_DROPPED),
F(MF_SHADOW),
F(MF_NOBLOOD),
@ -3769,7 +3850,12 @@ static FlagHandler flag1handlers[32] = {
{ SetCountitem, ClearCountitem, [](AActor* a)->bool { return a->flags & MF_COUNTITEM; } },
F(MF_SKULLFLY),
F(MF_NOTDMATCH),
// translation, unused and translucent are no longer checkable in any way. Pity.
{ SetTranslation1, ClearTranslation1, CheckTranslation1 },
{ SetTranslation2, ClearTranslation2, CheckTranslation2 },
F6(MF6_TOUCHY),
{ SetBounces, ClearBounces, [](AActor* a)->bool { return a->BounceFlags & BOUNCE_DEH; } },
F(MF_FRIENDLY),
{ SetTranslucent, ClearTranslucent, CheckTranslucent }
};
static FlagHandler flag2handlers[32] = {

View file

@ -508,6 +508,7 @@ enum ActorBounceFlag
BOUNCE_NotOnShootables = 1<<15, // do not bounce off shootable actors if we are a projectile. Explode instead.
BOUNCE_BounceOnUnrips = 1<<16, // projectile bounces on actors with DONTRIP
BOUNCE_NotOnSky = 1<<17, // Don't bounce on sky floors / ceilings / walls
BOUNCE_DEH = 1<<18, // Flag was set through Dehacked.
BOUNCE_TypeMask = BOUNCE_Walls | BOUNCE_Floors | BOUNCE_Ceilings | BOUNCE_Actors | BOUNCE_AutoOff | BOUNCE_HereticType | BOUNCE_MBF,

View file

@ -207,4 +207,39 @@ inline bool P_IsBlockedByLine(AActor* actor, line_t* line)
if ((actor->flags & MF_FLOAT) && (line->flags & ML_BLOCK_FLOATERS)) return true;
return false;
}
// For Dehacked modified actors we need to dynamically check the bounce factors because MBF didn't bother to implement this properly and with other flags changing this must adjust.
inline double GetMBFBounceFactor(AActor* actor)
{
if (actor->BounceFlags & BOUNCE_DEH) // only when modified through Dehacked.
{
constexpr double MBF_BOUNCE_NOGRAVITY = 1; // With NOGRAVITY: full momentum
constexpr double MBF_BOUNCE_FLOATDROPOFF = 0.85; // With FLOAT and DROPOFF: 85%
constexpr double MBF_BOUNCE_FLOAT = 0.7; // With FLOAT alone: 70%
constexpr double MBF_BOUNCE_DEFAULT = 0.45; // Without the above flags: 45%
if (actor->flags & MF_NOGRAVITY) return MBF_BOUNCE_NOGRAVITY;
if (actor->flags & MF_FLOAT) return (actor->flags & MF_DROPOFF) ? MBF_BOUNCE_FLOATDROPOFF : MBF_BOUNCE_FLOAT;
return MBF_BOUNCE_DEFAULT;
}
return actor->bouncefactor;
}
inline double GetWallBounceFactor(AActor* actor)
{
if (actor->BounceFlags & BOUNCE_DEH) // only when modified through Dehacked.
{
constexpr double MBF_BOUNCE_NOGRAVITY = 1; // With NOGRAVITY: full momentum
constexpr double MBF_BOUNCE_WALL = 0.5; // Bouncing off walls: 50%
return ((actor->flags & MF_NOGRAVITY) ? MBF_BOUNCE_NOGRAVITY : MBF_BOUNCE_WALL);
}
return actor->wallbouncefactor;
}
// Yet another hack for MBF...
inline bool CanJump(AActor* actor)
{
return (actor->flags6 & MF6_CANJUMP) || (
(actor->BounceFlags & BOUNCE_MBF) && actor->IsSentient() && (actor->flags & MF_FLOAT));
}

View file

@ -445,7 +445,7 @@ int P_Move (AActor *actor)
// want to yank them to the ground here as Doom did, since that makes
// it difficult to thrust them vertically in a reasonable manner.
// [GZ] Let jumping actors jump.
if (!((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP))
if (!((actor->flags & MF_NOGRAVITY) || CanJump(actor))
&& actor->Z() > actor->floorz && !(actor->flags2 & MF2_ONMOBJ))
{
return false;
@ -558,7 +558,7 @@ int P_Move (AActor *actor)
// to the floor if it is within MaxStepHeight, presuming that it is
// actually walking down a step.
if (try_ok &&
!((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP))
!((actor->flags & MF_NOGRAVITY) || CanJump(actor))
&& actor->Z() > actor->floorz && !(actor->flags2 & MF2_ONMOBJ))
{
if (actor->Z() <= actor->floorz + actor->MaxStepHeight)
@ -585,7 +585,7 @@ int P_Move (AActor *actor)
if (!try_ok)
{
if (((actor->flags6 & MF6_CANJUMP)||(actor->flags & MF_FLOAT)) && tm.floatok)
if ((CanJump(actor) || (actor->flags & MF_FLOAT)) && tm.floatok)
{ // must adjust height
double savedz = actor->Z();
@ -596,7 +596,7 @@ int P_Move (AActor *actor)
// [RH] Check to make sure there's nothing in the way of the float
if (P_TestMobjZ (actor))
if (P_TestMobjZ(actor))
{
actor->flags |= MF_INFLOAT;
return true;

View file

@ -3486,7 +3486,7 @@ bool FSlide::BounceWall(AActor *mo)
deltaangle = (lineangle * 2) - moveangle;
mo->Angles.Yaw = deltaangle;
movelen = mo->Vel.XY().Length() * mo->wallbouncefactor;
movelen = mo->Vel.XY().Length() * GetWallBounceFactor(mo);
FBoundingBox box(mo->X(), mo->Y(), mo->radius);
if (BoxOnLineSide(box, line) == -1)
@ -3573,7 +3573,7 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop)
if (!ontop)
{
DAngle angle = BlockingMobj->AngleTo(mo) + ((pr_bounce() % 16) - 8);
double speed = mo->VelXYToSpeed() * mo->wallbouncefactor; // [GZ] was 0.75, using wallbouncefactor seems more consistent
double speed = mo->VelXYToSpeed() * GetWallBounceFactor(mo); // [GZ] was 0.75, using wallbouncefactor seems more consistent
if (fabs(speed) < EQUAL_EPSILON) speed = 0;
mo->Angles.Yaw = angle;
mo->VelFromAngle(speed);
@ -3595,7 +3595,7 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop)
}
else
{
mo->Vel.Z *= mo->bouncefactor;
mo->Vel.Z *= GetMBFBounceFactor(mo);
}
}
else // Don't run through this for MBF-style bounces

View file

@ -1608,7 +1608,7 @@ bool AActor::FloorBounceMissile (secplane_t &plane)
flags &= ~MF_INBOUNCE;
return false;
}
else Vel.Z *= bouncefactor;
else Vel.Z *= GetMBFBounceFactor(this);
}
else // Don't run through this for MBF-style bounces
{
@ -2551,7 +2551,7 @@ void P_ZMovement (AActor *mo, double oldfloorz)
if (mo->BounceFlags & BOUNCE_Floors)
{
mo->FloorBounceMissile (mo->floorsector->floorplane);
/* if (!(mo->flags6 & MF6_CANJUMP)) */ return;
/* if (!CanJump(mo)) */ return;
}
else if (mo->flags3 & MF3_NOEXPLODEFLOOR)
{
@ -2660,7 +2660,7 @@ void P_ZMovement (AActor *mo, double oldfloorz)
if (mo->BounceFlags & BOUNCE_Ceilings)
{ // ceiling bounce
mo->FloorBounceMissile (mo->ceilingsector->ceilingplane);
/*if (!(mo->flags6 & MF6_CANJUMP))*/ return;
/* if (!CanJump(mo)) */ return;
}
if (mo->flags & MF_SKULLFLY)
{ // the skull slammed into something