mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-03-10 03:02:21 +00:00
This commit is contained in:
parent
233ad7a306
commit
d7bbb03121
6 changed files with 193 additions and 207 deletions
|
@ -1583,6 +1583,7 @@ int FLevelLocals::FinishTravel ()
|
|||
pawn->ceilingpic = pawndup->ceilingpic;
|
||||
pawn->Floorclip = pawndup->Floorclip;
|
||||
pawn->waterlevel = pawndup->waterlevel;
|
||||
pawn->waterdepth = pawndup->waterdepth;
|
||||
}
|
||||
else if (failnum == 0) // In the failure case this may run into some undefined data.
|
||||
{
|
||||
|
|
|
@ -497,6 +497,7 @@ xx(Special)
|
|||
xx(TID)
|
||||
xx(TIDtoHate)
|
||||
xx(WaterLevel)
|
||||
xx(WaterDepth)
|
||||
xx(MomX)
|
||||
xx(MomY)
|
||||
xx(MomZ)
|
||||
|
|
|
@ -771,6 +771,10 @@ public:
|
|||
virtual void Touch(AActor *toucher);
|
||||
void CallTouch(AActor *toucher);
|
||||
|
||||
// Apply gravity and/or make actor sink in water.
|
||||
virtual void FallAndSink(double grav, double oldfloorz);
|
||||
void CallFallAndSink(double grav, double oldfloorz);
|
||||
|
||||
// Centaurs and ettins squeal when electrocuted, poisoned, or "holy"-ed
|
||||
// Made a metadata property so no longer virtual
|
||||
void Howl ();
|
||||
|
@ -1131,6 +1135,7 @@ public:
|
|||
AActor *inext, **iprev;// Links to other mobjs in same bucket
|
||||
TObjPtr<AActor*> goal; // Monster's goal if not chasing anything
|
||||
int waterlevel; // 0=none, 1=feet, 2=waist, 3=eyes
|
||||
double waterdepth; // Stores how deep into water you are, in map units
|
||||
uint8_t boomwaterlevel; // splash information for non-swimmable water sectors
|
||||
uint8_t MinMissileChance;// [RH] If a random # is > than this, then missile attack.
|
||||
int8_t LastLookPlayerNumber;// Player number last looked for (if TIDtoHate == 0)
|
||||
|
@ -1269,6 +1274,7 @@ public:
|
|||
bool IsMapActor();
|
||||
int GetTics(FState * newstate);
|
||||
bool SetState (FState *newstate, bool nofunction=false);
|
||||
int UpdateWaterDepth(bool splash);
|
||||
virtual void SplashCheck();
|
||||
virtual bool UpdateWaterLevel (bool splash=true);
|
||||
bool isFast();
|
||||
|
|
|
@ -2396,84 +2396,7 @@ void P_ZMovement (AActor *mo, double oldfloorz)
|
|||
|
||||
mo->AddZ(mo->Vel.Z);
|
||||
|
||||
//
|
||||
// apply gravity
|
||||
//
|
||||
if (mo->Z() > mo->floorz && !(mo->flags & MF_NOGRAVITY))
|
||||
{
|
||||
double startvelz = mo->Vel.Z;
|
||||
|
||||
if (mo->waterlevel == 0 || (mo->player &&
|
||||
!(mo->player->cmd.ucmd.forwardmove | mo->player->cmd.ucmd.sidemove)))
|
||||
{
|
||||
// [RH] Double gravity only if running off a ledge. Coming down from
|
||||
// an upward thrust (e.g. a jump) should not double it.
|
||||
if (mo->Vel.Z == 0 && oldfloorz > mo->floorz && mo->Z() == oldfloorz)
|
||||
{
|
||||
mo->Vel.Z -= grav + grav;
|
||||
}
|
||||
else
|
||||
{
|
||||
mo->Vel.Z -= grav;
|
||||
}
|
||||
}
|
||||
if (mo->player == NULL)
|
||||
{
|
||||
if (mo->waterlevel >= 1)
|
||||
{
|
||||
double sinkspeed;
|
||||
|
||||
if ((mo->flags & MF_SPECIAL) && !(mo->flags3 & MF3_ISMONSTER))
|
||||
{ // Pickup items don't sink if placed and drop slowly if dropped
|
||||
sinkspeed = (mo->flags & MF_DROPPED) ? -WATER_SINK_SPEED / 8 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sinkspeed = -WATER_SINK_SPEED;
|
||||
|
||||
// If it's not a player, scale sinkspeed by its mass, with
|
||||
// 100 being equivalent to a player.
|
||||
if (mo->player == NULL)
|
||||
{
|
||||
sinkspeed = sinkspeed * clamp(mo->Mass, 1, 4000) / 100;
|
||||
}
|
||||
}
|
||||
if (mo->Vel.Z < sinkspeed)
|
||||
{ // Dropping too fast, so slow down toward sinkspeed.
|
||||
mo->Vel.Z -= max(sinkspeed*2, -8.);
|
||||
if (mo->Vel.Z > sinkspeed)
|
||||
{
|
||||
mo->Vel.Z = sinkspeed;
|
||||
}
|
||||
}
|
||||
else if (mo->Vel.Z > sinkspeed)
|
||||
{ // Dropping too slow/going up, so trend toward sinkspeed.
|
||||
mo->Vel.Z = startvelz + max(sinkspeed/3, -8.);
|
||||
if (mo->Vel.Z < sinkspeed)
|
||||
{
|
||||
mo->Vel.Z = sinkspeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mo->waterlevel > 1)
|
||||
{
|
||||
double sinkspeed = -WATER_SINK_SPEED;
|
||||
|
||||
if (mo->Vel.Z < sinkspeed)
|
||||
{
|
||||
mo->Vel.Z = (startvelz < sinkspeed) ? startvelz : sinkspeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
mo->Vel.Z = startvelz + ((mo->Vel.Z - startvelz) *
|
||||
(mo->waterlevel == 1 ? WATER_SINK_SMALL_FACTOR : WATER_SINK_FACTOR));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mo->CallFallAndSink(grav, oldfloorz);
|
||||
|
||||
// Hexen compatibility handling for floatbobbing. Ugh...
|
||||
// Hexen yanked all items to the floor, except those being spawned at map start in the air.
|
||||
|
@ -2807,7 +2730,112 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj)
|
|||
// mo->player->centering = true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// AActor :: FallAndSink
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void AActor::FallAndSink(double grav, double oldfloorz)
|
||||
{
|
||||
if (Z() > floorz && !(flags & MF_NOGRAVITY))
|
||||
{
|
||||
double startvelz = Vel.Z;
|
||||
|
||||
if (waterlevel == 0 || (player &&
|
||||
!(player->cmd.ucmd.forwardmove | player->cmd.ucmd.sidemove)))
|
||||
{
|
||||
// [RH] Double gravity only if running off a ledge. Coming down from
|
||||
// an upward thrust (e.g. a jump) should not double it.
|
||||
if (Vel.Z == 0 && oldfloorz > floorz && Z() == oldfloorz)
|
||||
{
|
||||
Vel.Z -= grav + grav;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vel.Z -= grav;
|
||||
}
|
||||
}
|
||||
if (player == NULL)
|
||||
{
|
||||
if (waterlevel >= 1)
|
||||
{
|
||||
double sinkspeed;
|
||||
|
||||
if ((flags & MF_SPECIAL) && !(flags3 & MF3_ISMONSTER))
|
||||
{ // Pickup items don't sink if placed and drop slowly if dropped
|
||||
sinkspeed = (flags & MF_DROPPED) ? -WATER_SINK_SPEED / 8 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sinkspeed = -WATER_SINK_SPEED;
|
||||
|
||||
// If it's not a player, scale sinkspeed by its mass, with
|
||||
// 100 being equivalent to a player.
|
||||
if (player == NULL)
|
||||
{
|
||||
sinkspeed = sinkspeed * clamp(Mass, 1, 4000) / 100;
|
||||
}
|
||||
}
|
||||
if (Vel.Z < sinkspeed)
|
||||
{ // Dropping too fast, so slow down toward sinkspeed.
|
||||
Vel.Z -= max(sinkspeed * 2, -8.);
|
||||
if (Vel.Z > sinkspeed)
|
||||
{
|
||||
Vel.Z = sinkspeed;
|
||||
}
|
||||
}
|
||||
else if (Vel.Z > sinkspeed)
|
||||
{ // Dropping too slow/going up, so trend toward sinkspeed.
|
||||
Vel.Z = startvelz + max(sinkspeed / 3, -8.);
|
||||
if (Vel.Z < sinkspeed)
|
||||
{
|
||||
Vel.Z = sinkspeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (waterlevel > 1)
|
||||
{
|
||||
double sinkspeed = -WATER_SINK_SPEED;
|
||||
|
||||
if (Vel.Z < sinkspeed)
|
||||
{
|
||||
Vel.Z = (startvelz < sinkspeed) ? startvelz : sinkspeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vel.Z = startvelz + ((Vel.Z - startvelz) *
|
||||
(waterlevel == 1 ? WATER_SINK_SMALL_FACTOR : WATER_SINK_FACTOR));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, FallAndSink)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_FLOAT(grav);
|
||||
PARAM_FLOAT(oldfloorz);
|
||||
self->FallAndSink(grav, oldfloorz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AActor::CallFallAndSink(double grav, double oldfloorz)
|
||||
{
|
||||
IFVIRTUAL(AActor, FallAndSink)
|
||||
{
|
||||
VMValue params[3] = { (DObject*)this, grav, oldfloorz };
|
||||
VMCall(func, params, 3, nullptr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
FallAndSink(grav, oldfloorz);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// P_NightmareRespawn
|
||||
|
@ -4232,27 +4260,32 @@ void AActor::CheckSectorTransition(sector_t *oldsec)
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// AActor::SplashCheck
|
||||
// AActor::UpdateWaterDepth
|
||||
//
|
||||
// Returns true if actor should splash
|
||||
// Updates the actor's current waterlevel and waterdepth.
|
||||
// Consolidates common code in UpdateWaterLevel and SplashCheck.
|
||||
//
|
||||
// Returns the floor height used for the depth check, or -FLT_MAX
|
||||
// if the actor wasn't in a sector.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void AActor::SplashCheck()
|
||||
int AActor::UpdateWaterDepth(bool splash)
|
||||
{
|
||||
double fh = -FLT_MAX;
|
||||
bool reset = false;
|
||||
|
||||
waterlevel = 0;
|
||||
waterdepth = 0;
|
||||
|
||||
if (Sector == NULL)
|
||||
{
|
||||
return;
|
||||
return fh;
|
||||
}
|
||||
|
||||
if (Sector->MoreFlags & SECMF_UNDERWATER) // intentionally not SECMF_UNDERWATERMASK
|
||||
{
|
||||
waterlevel = 3;
|
||||
waterdepth = Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4260,28 +4293,16 @@ void AActor::SplashCheck()
|
|||
if (hsec != NULL)
|
||||
{
|
||||
fh = hsec->floorplane.ZatPoint(this);
|
||||
//if (hsec->MoreFlags & SECMF_UNDERWATERMASK) // also check Boom-style non-swimmable sectors
|
||||
|
||||
// splash checks also check Boom-style non-swimmable sectors
|
||||
// as well as non-solid, visible 3D floors (below)
|
||||
if (splash || hsec->MoreFlags & SECMF_UNDERWATERMASK)
|
||||
{
|
||||
if (Z() < fh)
|
||||
waterdepth = fh - Z();
|
||||
|
||||
if (waterdepth <= 0 && !(hsec->MoreFlags & SECMF_FAKEFLOORONLY) && (Top() > hsec->ceilingplane.ZatPoint(this)))
|
||||
{
|
||||
waterlevel = 1;
|
||||
if (Center() < fh)
|
||||
{
|
||||
waterlevel = 2;
|
||||
if ((player && Z() + player->viewheight <= fh) ||
|
||||
(Top() <= fh))
|
||||
{
|
||||
waterlevel = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(hsec->MoreFlags & SECMF_FAKEFLOORONLY) && (Top() > hsec->ceilingplane.ZatPoint(this)))
|
||||
{
|
||||
waterlevel = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
waterlevel = 0;
|
||||
waterdepth = Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4294,32 +4315,56 @@ void AActor::SplashCheck()
|
|||
if (rover->flags & FF_SOLID) continue;
|
||||
|
||||
bool reset = !(rover->flags & FF_SWIMMABLE);
|
||||
if (reset && rover->alpha == 0) continue;
|
||||
if (splash) { reset &= rover->alpha == 0; }
|
||||
if (reset) continue;
|
||||
|
||||
double ff_bottom = rover->bottom.plane->ZatPoint(this);
|
||||
double ff_top = rover->top.plane->ZatPoint(this);
|
||||
|
||||
if (ff_top <= Z() || ff_bottom > (Center())) continue;
|
||||
if (ff_top <= Z() || ff_bottom > Center()) continue;
|
||||
|
||||
fh = ff_top;
|
||||
if (Z() < fh)
|
||||
{
|
||||
waterlevel = 1;
|
||||
if (Center() < fh)
|
||||
{
|
||||
waterlevel = 2;
|
||||
if ((player && Z() + player->viewheight <= fh) ||
|
||||
(Top() <= fh))
|
||||
{
|
||||
waterlevel = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
waterdepth = ff_top - Z();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (waterdepth < 0) { waterdepth = 0; }
|
||||
|
||||
if (waterdepth > (Height / 2))
|
||||
{
|
||||
// When noclipping around and going from low to high sector, your view height
|
||||
// can go negative, which is why this is nested inside here
|
||||
if ((player && (waterdepth >= player->viewheight)) || (waterdepth >= Height))
|
||||
{
|
||||
waterlevel = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
waterlevel = 2;
|
||||
}
|
||||
}
|
||||
else if (waterdepth > 0)
|
||||
{
|
||||
waterlevel = 1;
|
||||
}
|
||||
|
||||
return fh;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// AActor::SplashCheck
|
||||
//
|
||||
// Returns true if actor should splash
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void AActor::SplashCheck()
|
||||
{
|
||||
double fh = UpdateWaterDepth(true);
|
||||
|
||||
// some additional checks to make deep sectors like Boom's splash without setting
|
||||
// the water flags.
|
||||
if (boomwaterlevel == 0 && waterlevel != 0)
|
||||
|
@ -4340,106 +4385,36 @@ void AActor::SplashCheck()
|
|||
|
||||
bool AActor::UpdateWaterLevel(bool dosplash)
|
||||
{
|
||||
int oldlevel = waterlevel;
|
||||
|
||||
if (dosplash) SplashCheck();
|
||||
|
||||
double fh = -FLT_MAX;
|
||||
bool reset = false;
|
||||
int oldlevel = waterlevel;
|
||||
UpdateWaterDepth(false);
|
||||
|
||||
waterlevel = 0;
|
||||
// Play surfacing and diving sounds, as appropriate.
|
||||
//
|
||||
// (used to be that this code was wrapped around a "Sector != nullptr" check,
|
||||
// but actors should always be within a sector, and besides, this is just
|
||||
// sound stuff)
|
||||
|
||||
if (Sector != nullptr)
|
||||
if (player != nullptr)
|
||||
{
|
||||
if (Sector->MoreFlags & SECMF_UNDERWATER) // intentionally not SECMF_UNDERWATERMASK
|
||||
if (oldlevel < 3 && waterlevel == 3)
|
||||
{
|
||||
waterlevel = 3;
|
||||
// Our head just went under.
|
||||
S_Sound(this, CHAN_VOICE, 0, "*dive", 1, ATTN_NORM);
|
||||
}
|
||||
else
|
||||
else if (oldlevel == 3 && waterlevel < 3)
|
||||
{
|
||||
const sector_t *hsec = Sector->GetHeightSec();
|
||||
if (hsec != NULL)
|
||||
// Our head just came up.
|
||||
if (player->air_finished > Level->maptime)
|
||||
{
|
||||
fh = hsec->floorplane.ZatPoint(this);
|
||||
if (hsec->MoreFlags & SECMF_UNDERWATERMASK) // also check Boom-style non-swimmable sectors
|
||||
{
|
||||
if (Z() < fh)
|
||||
{
|
||||
waterlevel = 1;
|
||||
if (Center() < fh)
|
||||
{
|
||||
waterlevel = 2;
|
||||
if ((player && Z() + player->viewheight <= fh) ||
|
||||
(Top() <= fh))
|
||||
{
|
||||
waterlevel = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(hsec->MoreFlags & SECMF_FAKEFLOORONLY) && (Top() > hsec->ceilingplane.ZatPoint(this)))
|
||||
{
|
||||
waterlevel = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
waterlevel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check 3D floors as well!
|
||||
for (auto rover : Sector->e->XFloor.ffloors)
|
||||
{
|
||||
if (!(rover->flags & FF_EXISTS)) continue;
|
||||
if (rover->flags & FF_SOLID) continue;
|
||||
if (!(rover->flags & FF_SWIMMABLE)) continue;
|
||||
|
||||
double ff_bottom = rover->bottom.plane->ZatPoint(this);
|
||||
double ff_top = rover->top.plane->ZatPoint(this);
|
||||
|
||||
if (ff_top <= Z() || ff_bottom > (Center())) continue;
|
||||
|
||||
fh = ff_top;
|
||||
if (Z() < fh)
|
||||
{
|
||||
waterlevel = 1;
|
||||
if (Center() < fh)
|
||||
{
|
||||
waterlevel = 2;
|
||||
if ((player && Z() + player->viewheight <= fh) ||
|
||||
(Top() <= fh))
|
||||
{
|
||||
waterlevel = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Play surfacing and diving sounds, as appropriate.
|
||||
if (player != nullptr)
|
||||
{
|
||||
if (oldlevel < 3 && waterlevel == 3)
|
||||
{
|
||||
// Our head just went under.
|
||||
S_Sound(this, CHAN_VOICE, 0, "*dive", 1, ATTN_NORM);
|
||||
}
|
||||
else if (oldlevel == 3 && waterlevel < 3)
|
||||
{
|
||||
// Our head just came up.
|
||||
if (player->air_finished > Level->maptime)
|
||||
{
|
||||
// We hadn't run out of air yet.
|
||||
S_Sound(this, CHAN_VOICE, 0, "*surface", 1, ATTN_NORM);
|
||||
}
|
||||
// If we were running out of air, then ResetAirSupply() will play *gasp.
|
||||
// We hadn't run out of air yet.
|
||||
S_Sound(this, CHAN_VOICE, 0, "*surface", 1, ATTN_NORM);
|
||||
}
|
||||
// If we were running out of air, then ResetAirSupply() will play *gasp.
|
||||
}
|
||||
}
|
||||
|
||||
return false; // we did the splash ourselves
|
||||
}
|
||||
|
||||
|
|
|
@ -1929,6 +1929,7 @@ DEFINE_FIELD(AActor, special)
|
|||
DEFINE_FIELD(AActor, tid)
|
||||
DEFINE_FIELD(AActor, TIDtoHate)
|
||||
DEFINE_FIELD(AActor, waterlevel)
|
||||
DEFINE_FIELD(AActor, waterdepth)
|
||||
DEFINE_FIELD(AActor, Score)
|
||||
DEFINE_FIELD(AActor, accuracy)
|
||||
DEFINE_FIELD(AActor, stamina)
|
||||
|
|
|
@ -166,6 +166,7 @@ class Actor : Thinker native
|
|||
native readonly int TID;
|
||||
native readonly int TIDtoHate;
|
||||
native readonly int WaterLevel;
|
||||
native readonly double WaterDepth;
|
||||
native int Score;
|
||||
native int Accuracy;
|
||||
native int Stamina;
|
||||
|
@ -483,6 +484,7 @@ class Actor : Thinker native
|
|||
virtual native void Die(Actor source, Actor inflictor, int dmgflags = 0, Name MeansOfDeath = 'none');
|
||||
virtual native bool Slam(Actor victim);
|
||||
virtual native void Touch(Actor toucher);
|
||||
virtual native void FallAndSink(double grav, double oldfloorz);
|
||||
private native void Substitute(Actor replacement);
|
||||
native ui void DisplayNameTag();
|
||||
|
||||
|
|
Loading…
Reference in a new issue