- Fixed: Argument count for UsePuzzleItem was wrong.

- Added more things from Gez's experimental build:
  * MBF grenade and bouncing code.
  * Arch Vile ghosts emulation (only for compatibility.txt.)
  * Several MBF related compatibility options.



SVN r1821 (trunk)
This commit is contained in:
Christoph Oelckers 2009-09-14 20:47:53 +00:00
commit ea8c94d637
24 changed files with 367 additions and 160 deletions

View file

@ -1013,24 +1013,42 @@ void AActor::Touch (AActor *toucher)
bool AActor::Grind(bool items)
{
// crunch bodies to giblets
if ((this->flags & MF_CORPSE) &&
!(this->flags3 & MF3_DONTGIB) &&
(this->health <= 0))
if ((flags & MF_CORPSE) && !(flags3 & MF3_DONTGIB) && (health <= 0))
{
FState * state = this->FindState(NAME_Crush);
if (state != NULL && !(this->flags & MF_ICECORPSE))
FState * state = FindState(NAME_Crush);
bool isgeneric = false;
// ZDoom behavior differs from standard as crushed corpses cannot be raised.
// The reason for the change was originally because of a problem with players,
// see rh_log entry for February 21, 1999. Don't know if it is still relevant.
if (state == NULL // Only use the default crushed state if:
&& !(flags & MF_NOBLOOD) // 1. the monster bleeeds,
&& (i_compatflags & COMPATF_CORPSEGIBS) // 2. the compat setting is on,
&& player != NULL) // 3. and the thing isn't a player.
{
isgeneric = true;
state = FindState(NAME_GenericCrush);
if (state != NULL && (sprites[state->sprite].numframes <= 0))
state = NULL; // If one of these tests fails, do not use that state.
}
if (state != NULL && !(flags & MF_ICECORPSE))
{
if (this->flags4 & MF4_BOSSDEATH)
{
CALL_ACTION(A_BossDeath, this);
}
this->flags &= ~MF_SOLID;
this->flags3 |= MF3_DONTGIB;
this->height = this->radius = 0;
this->SetState (state);
flags &= ~MF_SOLID;
flags3 |= MF3_DONTGIB;
height = radius = 0;
SetState (state);
if (isgeneric) // Not a custom crush state, so colorize it appropriately.
{
S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE);
PalEntry bloodcolor = PalEntry(GetClass()->Meta.GetMetaInt(AMETA_BloodColor));
if (bloodcolor!=0) Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
}
return false;
}
if (!(this->flags & MF_NOBLOOD))
if (!(flags & MF_NOBLOOD))
{
if (this->flags4 & MF4_BOSSDEATH)
{
@ -1053,17 +1071,17 @@ bool AActor::Grind(bool items)
if (i == NULL)
{
// if there's no gib sprite don't crunch it.
this->flags &= ~MF_SOLID;
this->flags3 |= MF3_DONTGIB;
this->height = this->radius = 0;
flags &= ~MF_SOLID;
flags3 |= MF3_DONTGIB;
height = radius = 0;
return false;
}
AActor *gib = Spawn (i, this->x, this->y, this->z, ALLOW_REPLACE);
AActor *gib = Spawn (i, x, y, z, ALLOW_REPLACE);
if (gib != NULL)
{
gib->RenderStyle = this->RenderStyle;
gib->alpha = this->alpha;
gib->RenderStyle = RenderStyle;
gib->alpha = alpha;
gib->height = 0;
gib->radius = 0;
}
@ -1072,37 +1090,45 @@ bool AActor::Grind(bool items)
PalEntry bloodcolor = (PalEntry)this->GetClass()->Meta.GetMetaInt(AMETA_BloodColor);
if (bloodcolor!=0) gib->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
}
if (this->flags & MF_ICECORPSE)
if (flags & MF_ICECORPSE)
{
this->tics = 1;
this->velx = this->vely = this->velz = 0;
tics = 1;
velx = vely = velz = 0;
}
else if (this->player)
else if (player)
{
this->flags |= MF_NOCLIP;
this->flags3 |= MF3_DONTGIB;
this->renderflags |= RF_INVISIBLE;
flags |= MF_NOCLIP;
flags3 |= MF3_DONTGIB;
renderflags |= RF_INVISIBLE;
}
else
{
this->Destroy ();
Destroy ();
}
return false; // keep checking
}
// crunch dropped items
if (this->flags & MF_DROPPED)
if (flags & MF_DROPPED)
{
if (items) this->Destroy (); // Only destroy dropped items if wanted
if (items) Destroy (); // Only destroy dropped items if wanted
return false; // keep checking
}
if (!(this->flags & MF_SOLID) || (this->flags & MF_NOCLIP))
// killough 11/98: kill touchy things immediately
if (flags6 & MF6_TOUCHY && (flags6 & MF6_ARMED || IsSentient()))
{
flags6 &= ~MF6_ARMED; // Disarm
P_DamageMobj (this, NULL, NULL, health, NAME_Crush, DMG_FORCED); // kill object
return true; // keep checking
}
if (!(flags & MF_SOLID) || (flags & MF_NOCLIP))
{
return false;
}
if (!(this->flags & MF_SHOOTABLE))
if (!(flags & MF_SHOOTABLE))
{
return false; // assume it is bloody gibs or something
}
@ -1324,7 +1350,10 @@ bool AActor::FloorBounceMissile (secplane_t &plane)
// Landed in some sort of liquid
if (BounceFlags & BOUNCE_ExplodeOnWater)
{
P_ExplodeMissile(this, NULL, NULL);
if (flags & MF_MISSILE)
P_ExplodeMissile(this, NULL, NULL);
else
Die(NULL, NULL);
return true;
}
if (!(BounceFlags & BOUNCE_CanBounceWater))
@ -1348,37 +1377,49 @@ bool AActor::FloorBounceMissile (secplane_t &plane)
// The amount of bounces is limited
if (bouncecount>0 && --bouncecount==0)
{
P_ExplodeMissile(this, NULL, NULL);
if (flags & MF_MISSILE)
P_ExplodeMissile(this, NULL, NULL);
else
Die(NULL, NULL);
return true;
}
fixed_t dot = TMulScale16 (velx, plane.a, vely, plane.b, velz, plane.c);
if (BounceFlags & BOUNCE_HereticType)
if (BounceFlags & (BOUNCE_HereticType | BOUNCE_MBF))
{
velx -= MulScale15 (plane.a, dot);
vely -= MulScale15 (plane.b, dot);
velz -= MulScale15 (plane.c, dot);
angle = R_PointToAngle2 (0, 0, velx, vely);
flags |= MF_INBOUNCE;
SetState (FindState(NAME_Death));
flags &= ~MF_INBOUNCE;
return false;
if (!(BounceFlags & BOUNCE_MBF)) // Heretic projectiles die, MBF projectiles don't.
{
flags |= MF_INBOUNCE;
SetState (FindState(NAME_Death));
flags &= ~MF_INBOUNCE;
return false;
}
else velz = FixedMul(velz, bouncefactor);
}
else // Don't run through this for MBF-style bounces
{
// The reflected velocity keeps only about 70% of its original speed
velx = FixedMul (velx - MulScale15 (plane.a, dot), bouncefactor);
vely = FixedMul (vely - MulScale15 (plane.b, dot), bouncefactor);
velz = FixedMul (velz - MulScale15 (plane.c, dot), bouncefactor);
angle = R_PointToAngle2 (0, 0, velx, vely);
}
// The reflected velocity keeps only about 70% of its original speed
velx = FixedMul (velx - MulScale15 (plane.a, dot), bouncefactor);
vely = FixedMul (vely - MulScale15 (plane.b, dot), bouncefactor);
velz = FixedMul (velz - MulScale15 (plane.c, dot), bouncefactor);
angle = R_PointToAngle2 (0, 0, velx, vely);
PlayBounceSound(true);
if (BounceFlags & BOUNCE_AutoOff)
if (BounceFlags & BOUNCE_MBF) // Bring it to rest below a certain speed
{
if (abs(velz) < (fixed_t)(Mass * GetGravity() / 64))
velz = 0;
}
else if (BounceFlags & BOUNCE_AutoOff)
{
if (!(flags & MF_NOGRAVITY) && (velz < 3*FRACUNIT))
{
BounceFlags &= ~BOUNCE_TypeMask;
}
}
return false;
}
@ -1723,13 +1764,20 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
if (!P_TryMove (mo, ptryx, ptryy, true, walkplane, tm))
{
// blocked move
AActor *BlockingMobj = mo->BlockingMobj;
line_t *BlockingLine = mo->BlockingLine;
if ((mo->flags2 & (MF2_SLIDE|MF2_BLASTED) || bForceSlide) && !(mo->flags&MF_MISSILE))
if (!(mo->flags & MF_MISSILE) && (mo->BounceFlags & BOUNCE_MBF)
&& (BlockingMobj != NULL ? P_BounceActor(mo, BlockingMobj) : P_BounceWall(mo)))
{
// try to slide along it
if (mo->BlockingMobj == NULL)
// Do nothing, relevant actions already done in the condition.
// This allows to avoid setting velocities to 0 in the final else of this series.
}
else if ((mo->flags2 & (MF2_SLIDE|MF2_BLASTED) || bForceSlide) && !(mo->flags&MF_MISSILE))
{ // try to slide along it
if (BlockingMobj == NULL)
{ // slide against wall
if (mo->BlockingLine != NULL &&
if (BlockingLine != NULL &&
mo->player && mo->waterlevel && mo->waterlevel < 3 &&
(mo->player->cmd.ucmd.forwardmove | mo->player->cmd.ucmd.sidemove) &&
mo->BlockingLine->sidedef[1] != NULL)
@ -1800,36 +1848,17 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
}
else if (mo->flags & MF_MISSILE)
{
AActor *BlockingMobj = mo->BlockingMobj;
steps = 0;
if (BlockingMobj)
{
if (mo->BounceFlags & BOUNCE_Actors)
{
if ((mo->BounceFlags & BOUNCE_AllActors) ||
(BlockingMobj->flags2 & MF2_REFLECTIVE) ||
((!BlockingMobj->player) &&
(!(BlockingMobj->flags3 & MF3_ISMONSTER))))
{
fixed_t speed;
angle = R_PointToAngle2 (BlockingMobj->x,
BlockingMobj->y, mo->x, mo->y)
+ANGLE_1*((pr_bounce()%16)-8);
speed = P_AproxDistance (mo->velx, mo->vely);
speed = FixedMul (speed, (fixed_t)(0.75*FRACUNIT));
mo->angle = angle;
angle >>= ANGLETOFINESHIFT;
mo->velx = FixedMul (speed, finecosine[angle]);
mo->vely = FixedMul (speed, finesine[angle]);
mo->PlayBounceSound(true);
return oldfloorz;
}
else
{ // Struck a player/creature
// Bounce test and code moved to P_BounceActor
if (!P_BounceActor(mo, BlockingMobj))
{ // Struck a player/creature
P_ExplodeMissile (mo, NULL, BlockingMobj);
return oldfloorz;
}
return oldfloorz;
}
}
else
@ -1841,12 +1870,9 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
return oldfloorz;
}
}
if (BlockingMobj &&
(BlockingMobj->flags2 & MF2_REFLECTIVE))
if (BlockingMobj && (BlockingMobj->flags2 & MF2_REFLECTIVE))
{
angle = R_PointToAngle2(BlockingMobj->x,
BlockingMobj->y,
mo->x, mo->y);
angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y);
// Change angle for deflection/reflection
if (mo->AdjustReflectionAngle (BlockingMobj, angle))
@ -1947,10 +1973,12 @@ explode:
return oldfloorz;
}
if (mo->flags & MF_CORPSE)
// killough 8/11/98: add bouncers
// killough 9/15/98: add objects falling off ledges
// killough 11/98: only include bouncers hanging off ledges
if ((mo->flags & MF_CORPSE) || (mo->BounceFlags & BOUNCE_MBF && mo->z > mo->dropoffz) || (mo->flags6 & MF6_FALLING))
{ // Don't stop sliding if halfway off a step with some velocity
if (mo->velx > FRACUNIT/4 || mo->velx < -FRACUNIT/4
|| mo->vely > FRACUNIT/4 || mo->vely < -FRACUNIT/4)
if (mo->velx > FRACUNIT/4 || mo->velx < -FRACUNIT/4 || mo->vely > FRACUNIT/4 || mo->vely < -FRACUNIT/4)
{
if (mo->floorz > mo->Sector->floorplane.ZatPoint (mo->x, mo->y))
{
@ -2170,7 +2198,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
if (mo->BounceFlags & BOUNCE_Floors)
{
mo->FloorBounceMissile (mo->floorsector->floorplane);
return;
/* if (!(mo->flags6 & MF6_CANJUMP)) */ return;
}
else if (mo->flags3 & MF3_NOEXPLODEFLOOR)
{
@ -2196,6 +2224,10 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
return;
}
}
else if (mo->BounceFlags & BOUNCE_MBF && mo->velz) // check for MBF-like bounce on non-missiles
{
mo->FloorBounceMissile(mo->floorsector->floorplane);
}
if (mo->flags3 & MF3_ISMONSTER) // Blasted mobj falling
{
if (mo->velz < -(23*FRACUNIT))
@ -2263,7 +2295,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz)
if (mo->BounceFlags & BOUNCE_Ceilings)
{ // ceiling bounce
mo->FloorBounceMissile (mo->ceilingsector->ceilingplane);
return;
/*if (!(mo->flags6 & MF6_CANJUMP))*/ return;
}
if (mo->flags & MF_SKULLFLY)
{ // the skull slammed into something
@ -3157,11 +3189,18 @@ void AActor::Tick ()
{ // actor was destroyed
return;
}
if ((velx | vely) == 0 && (flags2 & MF2_BLASTED))
{ // Reset to not blasted when velocitiess are gone
flags2 &= ~MF2_BLASTED;
}
if ((velx | vely) == 0) // Actors at rest
{
if (flags2 & MF2_BLASTED)
{ // Reset to not blasted when velocities are gone
flags2 &= ~MF2_BLASTED;
}
if ((flags6 & MF6_TOUCHY) && !IsSentient())
{ // Arm a mine which has come to rest
flags6 |= MF6_ARMED;
}
}
if (flags2 & MF2_FLOATBOB)
{ // Floating item bobbing motion
z += FloatBobDiffs[(FloatBobPhase + level.maptime) & 63];
@ -4685,6 +4724,15 @@ bool P_HitFloor (AActor *thing)
{
const msecnode_t *m;
// killough 11/98: touchy objects explode on impact
// Allow very short drops to be safe, so that a touchy can be summoned without exploding.
if (thing->flags6 & MF6_TOUCHY && ((thing->flags6 & MF6_ARMED) || thing->IsSentient()) && ((thing->velz) < (-5 * FRACUNIT)))
{
thing->flags6 &= ~MF6_ARMED; // Disarm
P_DamageMobj (thing, NULL, NULL, thing->health, NAME_Crush, DMG_FORCED); // kill object
return true;
}
if (thing->flags2 & MF2_FLOATBOB || thing->flags3 & MF3_DONTSPLASH)
return false;
@ -4770,9 +4818,26 @@ bool P_CheckMissileSpawn (AActor* th)
th->y += th->vely >> shift;
th->z += th->velz >> shift;
// killough 3/15/98: no dropoff (really = don't care for missiles)
// killough 8/12/98: for non-missile objects (e.g. grenades)
//
// [GZ] MBF excludes non-missile objects from the P_TryMove test
// and subsequent potential P_ExplodeMissile call. That is because
// in MBF, a projectile is not an actor with the MF_MISSILE flag
// but an actor with either or both the MF_MISSILE and MF_BOUNCES
// flags, and a grenade is identified by not having MF_MISSILE.
// Killough wanted grenades not to explode directly when spawned,
// therefore they can be fired safely even when humping a wall as
// they will then just drop on the floor at their shooter's feet.
//
// However, ZDoom does allow non-missiles to be shot as well, so
// Killough's check for non-missiles is inadequate here. So let's
// replace it by a check for non-missile and MBF bounce type.
// This should allow MBF behavior where relevant without altering
// established ZDoom behavior for crazy stuff like a cacodemon cannon.
bool MBFGrenade = (!(th->flags & MF_MISSILE) || (th->BounceFlags & BOUNCE_MBF));
if (!P_TryMove (th, th->x, th->y, false, false, tm))
// killough 3/15/98: no dropoff (really = don't care for missiles)
if (!(P_TryMove (th, th->x, th->y, false, false, tm)))
{
// [RH] Don't explode ripping missiles that spawn inside something
if (th->BlockingMobj == NULL || !(th->flags2 & MF2_RIP) || (th->BlockingMobj->flags5 & MF5_DONTRIP))
@ -4788,6 +4853,10 @@ bool P_CheckMissileSpawn (AActor* th)
{
th->Destroy ();
}
else if (MBFGrenade && th->BlockingLine != NULL )
{
P_BounceWall(th);
}
else
{
P_ExplodeMissile (th, NULL, th->BlockingMobj);
@ -5461,7 +5530,7 @@ void PrintMiscActorInfo(AActor * query)
if (query->renderflags & 1<<flagi) Printf(" %s", flagnamesr[flagi]);
*/
Printf("\nIts thing special and arguments are %s(%i, %i, %i, %i, %i), and its specials are %i and %i.",
GetSpecialName(query->special), query->args[0], query->args[1],
LineSpecialsInfo[query->special]->name, query->args[0], query->args[1],
query->args[2], query->args[3], query->args[4],
query->special1, query->special2);
Printf("\nIts coordinates are x: %f, y: %f, z:%f, floor:%f, ceiling:%f.",