- 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
parent 238d4c3fac
commit ea8c94d637
24 changed files with 367 additions and 160 deletions

View file

@ -1,5 +1,8 @@
September 14, 2009 (Changes by Graf Zahl)
- Fixed: Argument count for UsePuzzleItem was wrong.
- Added a few things from Gez's experimental build:
* MBF grenade and bouncing code.
* several compatibility options.
* info CCMD to print extended actor information (not fully implemented yet)
* summonmbf CCMD.
* Beta BFG code pointer (but not the related missiles yet.)

View file

@ -118,7 +118,7 @@ Thing_SetSprite, 126, -1, -1)
#endif
DEFINE_SPECIAL(Thing_SetSpecial, 127, 5, 5, 5)
DEFINE_SPECIAL(ThrustThingZ, 128, 4, 4, 4)
DEFINE_SPECIAL(UsePuzzleItem, 129, 1, 1, 1)
DEFINE_SPECIAL(UsePuzzleItem, 129, 2, 5, 5)
DEFINE_SPECIAL(Thing_Activate, 130, 1, 1, 1)
DEFINE_SPECIAL(Thing_Deactivate, 131, 1, 1, 1)
DEFINE_SPECIAL(Thing_Remove, 132, 1, 1, 1)

View file

@ -309,7 +309,13 @@ enum
MF6_DONTHARMSPECIES = 0x00000040, // Don't hurt one's own species with explosions (hitscans, too?)
MF6_STEPMISSILE = 0x00000080, // Missile can "walk" up steps
MF6_NOTELEFRAG = 0x00000100, // [HW] Actor can't be telefragged
MF6_TOUCHY = 0x00000200, // From MBF: killough 11/98: dies when solids touch it
MF6_CANJUMP = 0x00000400, // From MBF: a dedicated flag instead of the BOUNCES+FLOAT+sentient combo
MF6_JUMPDOWN = 0x00000800, // From MBF: generalization of dog behavior wrt. dropoffs.
MF6_VULNERABLE = 0x00001000, // Actor can be damaged (even if not shootable).
MF6_ARMED = 0x00002000, // From MBF: Object is armed (for MF6_TOUCHY objects)
MF6_FALLING = 0x00004000, // From MBF: Object is falling (for pseudotorque simulation)
MF6_LINEDONE = 0x00008000, // From MBF: Object has already run a line effect
// --- mobj.renderflags ---

View file

@ -78,6 +78,7 @@ static FCompatOption Options[] =
{ "setslopeoverflow", 0, BCOMPATF_SETSLOPEOVERFLOW },
{ "resetplayerspeed", 0, BCOMPATF_RESETPLAYERSPEED },
{ "spechitoverflow", 0, BCOMPATF_SPECHITOVERFLOW },
{ "vileghosts", 0, BCOMPATF_VILEGHOSTS },
// list copied from g_mapinfo.cpp
{ "shorttex", COMPATF_SHORTTEX, 0 },
@ -101,6 +102,11 @@ static FCompatOption Options[] =
{ "wallrun", COMPATF_WALLRUN, 0 }, // [GZ] Added for CC MAP29
{ "anybossdeath", COMPATF_ANYBOSSDEATH, 0}, // [GZ] Added for UAC_DEAD
{ "mushroom", COMPATF_MUSHROOM, 0},
{ "mbfdehacked", COMPATF_MBFDEHACKED, 0},
{ "mbftorque", COMPATF_MBFTORQUE, 0},
{ "mbfmonstermove", COMPATF_MBFMONSTERMOVE, 0 },
{ "corpsegibs", COMPATF_CORPSEGIBS, 0 },
{ "noblockfriends", COMPATF_NOBLOCKFRIENDS, 0 },
{ NULL, 0, 0 }
};

View file

@ -499,16 +499,22 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
case 2: // same as 1 but stricter (NO_PASSMOBJ and INVISIBILITY are also set)
v = COMPATF_SHORTTEX|COMPATF_STAIRINDEX|COMPATF_USEBLOCKING|COMPATF_NODOORLIGHT|
COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_NO_PASSMOBJ|COMPATF_LIMITPAIN|
COMPATF_DEHHEALTH|COMPATF_INVISIBILITY|COMPATF_CROSSDROPOFF;
COMPATF_DEHHEALTH|COMPATF_INVISIBILITY|COMPATF_CROSSDROPOFF|COMPATF_CORPSEGIBS;
break;
case 3:
v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MUSHROOM;
case 3: // Boom compat mode
v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL;
break;
case 4:
case 4: // Old ZDoom compat mode
v = COMPATF_SOUNDTARGET;
break;
case 5: // MBF compat mode
v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MUSHROOM|
COMPATF_MBFDEHACKED|COMPATF_MBFTORQUE|COMPATF_MBFMONSTERMOVE|COMPATF_NOBLOCKFRIENDS;
break;
}
compatflags = v;
}
@ -537,6 +543,11 @@ CVAR (Flag, compat_crossdropoff,compatflags, COMPATF_CROSSDROPOFF);
CVAR (Flag, compat_anybossdeath,compatflags, COMPATF_ANYBOSSDEATH);
CVAR (Flag, compat_minotaur, compatflags, COMPATF_MINOTAUR);
CVAR (Flag, compat_mushroom, compatflags, COMPATF_MUSHROOM);
CVAR (Flag, compat_mbfdehacked, compatflags, COMPATF_MBFDEHACKED);
CVAR (Flag, compat_mbftorque, compatflags, COMPATF_MBFTORQUE);
CVAR (Flag, compat_mbfmonstermove,compatflags, COMPATF_MBFMONSTERMOVE);
CVAR (Flag, compat_corpsegibs, compatflags, COMPATF_CORPSEGIBS);
CVAR (Flag, compat_noblockfriends,compatflags,COMPATF_NOBLOCKFRIENDS);
//==========================================================================
//

View file

@ -320,7 +320,12 @@ enum
COMPATF_CROSSDROPOFF = 1 << 20, // monsters can't be pushed over dropoffs
COMPATF_ANYBOSSDEATH = 1 << 21, // [GZ] Any monster which calls BOSSDEATH counts for level specials
COMPATF_MINOTAUR = 1 << 22, // Minotaur's floor flame is exploded immediately when feet are clipped
COMPATF_MUSHROOM = 1 << 23, // Force original velocity calculations for A_Mushroom in Dehacked oods.
COMPATF_MUSHROOM = 1 << 23, // Force original velocity calculations for A_Mushroom in Dehacked mods.
COMPATF_MBFDEHACKED = 1 << 24, // Allow a state's miscs to be out of offset ranges, for use as params.
COMPATF_MBFTORQUE = 1 << 25, // Uses MBF-style pseudo torque simulation.
COMPATF_MBFMONSTERMOVE = 1 << 26, // Monsters are affected by friction and pushers/pullers.
COMPATF_CORPSEGIBS = 1 << 27, // Crushed monsters are turned into gibs, rather than replaced by gibs.
COMPATF_NOBLOCKFRIENDS = 1 << 28, // Friendly monsters aren't blocked by monster-blocking lines.
};
// Emulate old bugs for select maps. These are not exposed by a cvar
@ -330,6 +335,7 @@ enum
BCOMPATF_SETSLOPEOVERFLOW = 1 << 0, // SetSlope things can overflow
BCOMPATF_RESETPLAYERSPEED = 1 << 1, // Set player speed to 1.0 when changing maps
BCOMPATF_SPECHITOVERFLOW = 1 << 2, // Emulate spechit overflow (e.g. Strain MAP07)
BCOMPATF_VILEGHOSTS = 1 << 3, // Monsters' radius and height aren't restored properly when resurrected.
};
// phares 3/20/98:

View file

@ -1356,6 +1356,11 @@ MapFlagHandlers[] =
{ "compat_anybossdeath", MITYPE_COMPATFLAG, COMPATF_ANYBOSSDEATH},
{ "compat_minotaur", MITYPE_COMPATFLAG, COMPATF_MINOTAUR},
{ "compat_mushroom", MITYPE_COMPATFLAG, COMPATF_MUSHROOM},
{ "compat_mbfdehacked", MITYPE_COMPATFLAG, COMPATF_MBFDEHACKED},
{ "compat_mbftorque", MITYPE_COMPATFLAG, COMPATF_MBFTORQUE},
{ "compat_mbfmonstermove", MITYPE_COMPATFLAG, COMPATF_MBFMONSTERMOVE},
{ "compat_corpsegibs", MITYPE_COMPATFLAG, COMPATF_CORPSEGIBS},
{ "compat_noblockfriends", MITYPE_COMPATFLAG, COMPATF_NOBLOCKFRIENDS},
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end2_track", MITYPE_EATNEXT, 0, 0 },

View file

@ -148,12 +148,13 @@ value_t OffOn[2] = {
{ 1.0, "Off" }
};
value_t CompatModes[5] = {
value_t CompatModes[6] = {
{ 0.0, "Default" },
{ 1.0, "Doom" },
{ 2.0, "Doom (strict)" },
{ 3.0, "Boom" },
{ 4.0, "ZDoom 2.0.63" }
{ 4.0, "ZDoom 2.0.63" },
{ 5.0, "MBF" },
};
menu_t *CurrentMenu;
@ -1079,7 +1080,7 @@ static menu_t DMFlagsMenu =
*=======================================*/
static menuitem_t CompatibilityItems[] = {
{ discrete, "Compatibility mode", {&compatmode}, {5.0}, {1.0}, {0.0}, {CompatModes} },
{ discrete, "Compatibility mode", {&compatmode}, {6.0}, {1.0}, {0.0}, {CompatModes} },
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ bitflag, "Find shortest textures like Doom", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SHORTTEX} },
{ bitflag, "Use buggier stair building", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_STAIRINDEX} },
@ -1105,6 +1106,11 @@ static menuitem_t CompatibilityItems[] = {
{ bitflag, "Allow any bossdeath for level special", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_ANYBOSSDEATH} },
{ bitflag, "No Minotaur floor flames in water", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_MINOTAUR} },
{ bitflag, "Original A_Mushroom speed in DEH mods", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_MUSHROOM} },
{ bitflag, "Allow MBF DeHackEd parameters", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_MBFDEHACKED} },
{ bitflag, "Allow MBF pseudo-torque effects", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_MBFTORQUE} },
{ bitflag, "Monster movement is affected by effects", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_MBFMONSTERMOVE} },
{ bitflag, "Crushed monsters can be resurrected", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_CORPSEGIBS} },
{ bitflag, "Friendly monsters aren't blocked", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_NOBLOCKFRIENDS} },
{ discrete, "Interpolate monster movement", {&nomonsterinterpolation}, {2.0}, {0.0}, {0.0}, {NoYes} },
};

View file

@ -178,6 +178,7 @@ xx(No)
xx(Greetings)
xx(Idle)
xx(GenericFreezeDeath)
xx(GenericCrush)
// Compatible death names for the decorate parser.
xx(XDeath)

View file

@ -371,6 +371,7 @@ bool P_HitFriend(AActor * self)
// Move in the current direction,
// returns false if the move is blocked.
//
bool P_Move (AActor *actor)
{
@ -392,8 +393,9 @@ bool P_Move (AActor *actor)
// [RH] Instead of yanking non-floating monsters to the ground,
// let gravity drop them down, unless they're moving down a step.
if (!(actor->flags & MF_NOGRAVITY) && actor->z > actor->floorz
&& !(actor->flags2 & MF2_ONMOBJ))
// [GZ] Let jumping actors jump.
if (!((actor->flags & MF_NOGRAVITY) || (actor->flags6 & MF6_CANJUMP))
&& actor->z > actor->floorz && !(actor->flags2 & MF2_ONMOBJ))
{
if (actor->z > actor->floorz + actor->MaxStepHeight)
{
@ -410,7 +412,10 @@ bool P_Move (AActor *actor)
speed = actor->Speed;
#if 0 // [RH] I'm not so sure this is such a good idea
// [RH] I'm not so sure this is such a good idea
// [GZ] That's why it's compat-optioned.
if (compatflags & COMPATF_MBFMONSTERMOVE)
{
// killough 10/98: make monsters get affected by ice and sludge too:
movefactor = P_GetMoveFactor (actor, &friction);
@ -423,7 +428,7 @@ bool P_Move (AActor *actor)
speed = ksgn(actor->Speed);
}
}
#endif
}
tryx = (origx = actor->x) + (deltax = FixedMul (speed, xspeed[actor->movedir]));
tryy = (origy = actor->y) + (deltay = FixedMul (speed, yspeed[actor->movedir]));
@ -485,7 +490,7 @@ bool P_Move (AActor *actor)
if (!try_ok)
{
if ((actor->flags & MF_FLOAT) && tm.floatok)
if (((actor->flags6 & MF6_CANJUMP)||(actor->flags & MF_FLOAT)) && tm.floatok)
{ // must adjust height
fixed_t savedz = actor->z;
@ -2220,13 +2225,31 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
S_Sound (corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE);
info = corpsehit->GetDefault ();
corpsehit->height = info->height; // [RH] Use real mobj height
corpsehit->radius = info->radius; // [RH] Use real radius
/*
if (ib_compatflags & BCOMPATF_VILEGHOSTS)
{
corpsehit->height <<= 2;
// [GZ] This was a commented-out feature, so let's make use of it,
// but only for ghost monsters so that they are visibly different.
if (corpsehit->height == 0)
{
// Make raised corpses look ghostly
if (corpsehit->alpha > TRANSLUC50)
{
corpsehit->alpha /= 2;
*/
}
// This will only work if the render style is changed as well.
if (corpsehit->RenderStyle == LegacyRenderStyles[STYLE_Normal])
{
corpsehit->RenderStyle = STYLE_Translucent;
}
}
corpsehit->Translation = info->Translation; // Clean up bloodcolor translation from crushed corpses
}
else
{
corpsehit->height = info->height; // [RH] Use real mobj height
corpsehit->radius = info->radius; // [RH] Use real radius
}
corpsehit->flags = info->flags;
corpsehit->flags2 = info->flags2;
corpsehit->flags3 = info->flags3;

View file

@ -883,7 +883,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
FState * woundstate = NULL;
PainChanceList * pc = NULL;
if (target == NULL || !(target->flags & MF_SHOOTABLE))
if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE)))
{ // Shouldn't happen
return;
}

View file

@ -3250,13 +3250,3 @@ int P_FindLineSpecial (const char *string, int *min_args, int *max_args)
}
return 0;
}
const char *GetSpecialName(int num)
{
for(int i = 0; i < countof(LineSpecialNames); i++)
{
if (LineSpecialNames[i].number == num)
return LineSpecialNames[i].name;
}
return "(unknown)";
}

View file

@ -196,6 +196,5 @@ typedef int (*lnSpecFunc)(struct line_t *line,
extern lnSpecFunc LineSpecials[256];
int P_FindLineSpecial (const char *string, int *min_args=NULL, int *max_args=NULL);
const char *GetSpecialName(int num);
#endif //__P_LNSPEC_H__

View file

@ -380,10 +380,12 @@ void P_FakeZMovement (AActor *mo);
bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, bool dropoff, const secplane_t * onfloor, FCheckPosition &tm);
bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, bool dropoff, const secplane_t * onfloor = NULL);
bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y);
void P_ApplyTorque(AActor *mo);
bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag); // [RH] Added z and telefrag parameters
void P_PlayerStartStomp (AActor *actor); // [RH] Stomp on things for a newly spawned player
void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps);
bool P_BounceWall (AActor *mo);
bool P_BounceActor (AActor *mo, AActor * BlockingMobj);
bool P_CheckSight (const AActor* t1, const AActor* t2, int flags=0);
void P_ResetSightCounters (bool full);
void P_UseLines (player_t* player);

View file

@ -590,17 +590,25 @@ bool PIT_CheckLine (line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
return false;
}
if (!(tm.thing->flags & MF_MISSILE) || (ld->flags & (ML_BLOCKEVERYTHING|ML_BLOCKPROJECTILE)))
{
// MBF bouncers are treated as missiles here.
bool Projectile = (tm.thing->flags & MF_MISSILE || tm.thing->BounceFlags & BOUNCE_MBF);
// MBF considers that friendly monsters are not blocked by monster-blocking lines.
// This is added here as a compatibility option. Note that monsters that are dehacked
// into being friendly with the MBF flag automatically gain MF3_NOBLOCKMONST, so this
// just optionally generalizes the behavior to other friendly monsters.
bool NotBlocked = ((tm.thing->flags3 & MF3_NOBLOCKMONST)
|| ((i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY)));
if (!(Projectile) || (ld->flags & (ML_BLOCKEVERYTHING|ML_BLOCKPROJECTILE))) {
if (ld->flags & ML_RAILING)
{
rail = true;
}
else if ((ld->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING)) || // explicitly blocking everything
(!(tm.thing->flags3 & MF3_NOBLOCKMONST) && (ld->flags & ML_BLOCKMONSTERS)) || // block monsters only
(!(NotBlocked) && (ld->flags & ML_BLOCKMONSTERS)) || // block monsters only
(tm.thing->player != NULL && (ld->flags & ML_BLOCK_PLAYERS)) || // block players
((tm.thing->flags & MF_MISSILE) && (ld->flags & ML_BLOCKPROJECTILE)) || // block projectiles
((ld->flags & ML_BLOCK_FLOATERS) && (tm.thing->flags & MF_FLOAT))) // block floaters
((Projectile) && (ld->flags & ML_BLOCKPROJECTILE)) || // block projectiles
((tm.thing->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS))) // block floaters
{
if (tm.thing->flags2 & MF2_BLASTED)
{
@ -754,6 +762,13 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm)
bool solid;
int damage;
if (!((thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)) || thing->flags6 & MF6_TOUCHY))
return true; // can't hit thing
fixed_t blockdist = thing->radius + tm.thing->radius;
if ( abs(thing->x - tm.x) >= blockdist || abs(thing->y - tm.y) >= blockdist)
return true;
// don't clip against self
if (thing == tm.thing)
return true;
@ -764,13 +779,6 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm)
if ((tm.thing->flags6 & MF6_THRUSPECIES) && (tm.thing->GetSpecies() == thing->GetSpecies()))
return true;
if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)) )
return true; // can't hit thing
fixed_t blockdist = thing->radius + tm.thing->radius;
if ( abs(thing->x - tm.x) >= blockdist || abs(thing->y - tm.y) >= blockdist)
return true;
tm.thing->BlockingMobj = thing;
topz = thing->z + thing->height;
if (!(i_compatflags & COMPATF_NO_PASSMOBJ) && !(tm.thing->flags & (MF_FLOAT|MF_MISSILE|MF_SKULLFLY|MF_NOGRAVITY)) &&
@ -806,6 +814,26 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm)
return true;
}
}
// touchy object is alive, toucher is solid
if (thing->flags6 & MF6_TOUCHY && tm.thing->flags & MF_SOLID && thing->health > 0 &&
// Thing is an armed mine or a sentient thing
(thing->flags6 & MF6_ARMED || thing->IsSentient()) &&
// either different classes or players
(thing->player || thing->GetClass() != tm.thing->GetClass()) &&
// or different species if DONTHARMSPECIES
(!(thing->flags6 & MF6_DONTHARMSPECIES) || thing->GetSpecies() != tm.thing->GetSpecies()) &&
// touches vertically
thing->z + thing->height >= tm.thing->z && tm.thing->z + tm.thing->height >= thing->z &&
// prevents lost souls from exploding when fired by pain elementals
(thing->master != tm.thing && tm.thing->master != thing))
// Difference with MBF: MBF hardcodes the LS/PE check and lets actors of the same species
// but different classes trigger the touchiness, but that seems less straightforwards.
{
thing->flags6 &= ~MF6_ARMED; // Disarm
P_DamageMobj (thing, NULL, NULL, thing->health, NAME_None, DMG_FORCED); // kill object
return true;
}
// Check for skulls slamming into things
if (tm.thing->flags & MF_SKULLFLY)
{
@ -839,8 +867,8 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm)
LineSpecials[thing->special] (NULL, tm.thing, false, thing->args[0],
thing->args[1], thing->args[2], thing->args[3], thing->args[4]);
}
// Check for missile
if (tm.thing->flags & MF_MISSILE)
// Check for missile or non-solid MBF bouncer
if (tm.thing->flags & MF_MISSILE || ((tm.thing->BounceFlags & BOUNCE_MBF) && !(tm.thing->flags & MF_SOLID)))
{
// Check for a non-shootable mobj
if (thing->flags2 & MF2_NONSHOOTABLE)
@ -891,7 +919,8 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm)
// [RH] What is the point of this check, again? In Hexen, it is unconditional,
// but here we only do it if the missile's damage is 0.
if ((tm.thing->BounceFlags & BOUNCE_Actors) && tm.thing->Damage == 0)
// MBF bouncer might have a non-0 damage value, but they must not deal damage on impact either.
if ((tm.thing->BounceFlags & BOUNCE_Actors) && (tm.thing->Damage == 0 || !(tm.thing->flags & MF_MISSILE)))
{
return (tm.thing->target == thing || !(thing->flags & MF_SOLID));
}
@ -1707,6 +1736,12 @@ bool P_TryMove (AActor *thing, fixed_t x, fixed_t y,
oldAboveFakeCeiling = eyez > oldsec->heightsec->ceilingplane.ZatPoint (thing->x, thing->y);
}
// Borrowed from MBF:
if (thing->BounceFlags & BOUNCE_MBF && // killough 8/13/98
!(thing->flags & (MF_MISSILE|MF_NOGRAVITY)) &&
!thing->IsSentient() && tm.floorz - thing->z > 16*FRACUNIT)
return false; // too big a step up for MBF bouncers under gravity
// the move is ok, so link the thing into its new position
thing->UnlinkFromWorld ();
@ -1973,8 +2008,6 @@ struct FSlide
bool BounceWall (AActor *mo);
};
//
// P_HitSlideLine
// Adjusts the xmove / ymove
@ -2153,7 +2186,8 @@ void FSlide::SlideTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_
{
goto isblocking;
}
if (li->flags & ML_BLOCKMONSTERS && !(slidemo->flags3 & MF3_NOBLOCKMONST))
if (li->flags & ML_BLOCKMONSTERS && !((slidemo->flags3 & MF3_NOBLOCKMONST)
|| ((i_compatflags & COMPATF_NOBLOCKFRIENDS) && (slidemo->flags & MF_FRIENDLY))))
{
goto isblocking;
}
@ -2596,7 +2630,10 @@ bool FSlide::BounceWall (AActor *mo)
// The amount of bounces is limited
if (mo->bouncecount>0 && --mo->bouncecount==0)
{
if (mo->flags & MF_MISSILE)
P_ExplodeMissile(mo, NULL, NULL);
else
mo->Die(NULL, NULL);
return true;
}
@ -2637,7 +2674,28 @@ bool P_BounceWall (AActor *mo)
return slide.BounceWall(mo);
}
extern FRandom pr_bounce ("Bounce");
bool P_BounceActor (AActor *mo, AActor * BlockingMobj)
{
if (mo && BlockingMobj && ((mo->BounceFlags & BOUNCE_AllActors)
|| ((mo->flags & MF_MISSILE) && (BlockingMobj->flags2 & MF2_REFLECTIVE)
|| ((!BlockingMobj->player) && (!(BlockingMobj->flags3 & MF3_ISMONSTER))))
))
{
fixed_t speed;
angle_t 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, mo->wallbouncefactor); // [GZ] was 0.75, using wallbouncefactor seems more consistent
mo->angle = angle;
angle >>= ANGLETOFINESHIFT;
mo->velx = FixedMul (speed, finecosine[angle]);
mo->vely = FixedMul (speed, finesine[angle]);
mo->PlayBounceSound(true);
return true;
}
else return false;
}
//============================================================================
//
@ -3976,7 +4034,9 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b
while ((thing = it.Next()))
{
if (!(thing->flags & MF_SHOOTABLE) )
// Vulnerable actors can be damaged by radius attacks even if not shootable
// Used to emulate MBF's vulnerability of non-missile bouncers to explosions.
if (!((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE)))
continue;
// Boss spider and cyborg and Heretic's ep >= 2 bosses

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)
{
if (flags & MF_MISSILE)
P_ExplodeMissile(this, NULL, NULL);
else
Die(NULL, NULL);
return true;
}
if (!(BounceFlags & BOUNCE_CanBounceWater))
@ -1348,38 +1377,50 @@ bool AActor::FloorBounceMissile (secplane_t &plane)
// The amount of bounces is limited
if (bouncecount>0 && --bouncecount==0)
{
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);
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);
}
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
// 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
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.",

View file

@ -1737,7 +1737,17 @@ void DPusher::Tick ()
while ((thing = it.Next()))
{
if ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP))
// Normal ZDoom is based only on the WINDTHRUST flag, with the noclip cheat as an exemption.
bool pusharound = ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP));
// MBF allows any sentient or shootable thing to be affected, but players with a fly cheat aren't.
if (compatflags & COMPATF_MBFMONSTERMOVE)
{
pusharound = ((pusharound || (thing->IsSentient()) || (thing->flags & MF_SHOOTABLE)) // Add categories here
&& (!(thing->player && (thing->flags & (MF_NOGRAVITY))))); // Exclude flying players here
}
if ((pusharound) )
{
int sx = m_X;
int sy = m_Y;

View file

@ -1653,7 +1653,7 @@ void P_MovePlayer (player_t *player)
mo->angle += cmd->ucmd.yaw << 16;
}
onground = (mo->z <= mo->floorz) || (mo->flags2 & MF2_ONMOBJ);
onground = (mo->z <= mo->floorz) || (mo->flags2 & MF2_ONMOBJ) || (mo->BounceFlags & BOUNCE_MBF);
// killough 10/98:
//

View file

@ -48,6 +48,8 @@ enum EStateDefineFlags
SDF_WAIT = 3,
SDF_LABEL = 4,
SDF_INDEX = 5,
SDF_MASK = 7,
SDF_DEHACKED = 8, // Identify a state as having been modified by a dehacked lump
};
struct FStateDefine

View file

@ -214,6 +214,10 @@ static FFlagDef ActorFlags[]=
DEFINE_FLAG(MF6, DONTHARMSPECIES, AActor, flags6),
DEFINE_FLAG(MF6, STEPMISSILE, AActor, flags6),
DEFINE_FLAG(MF6, NOTELEFRAG, AActor, flags6),
DEFINE_FLAG(MF6, TOUCHY, AActor, flags6),
DEFINE_FLAG(MF6, CANJUMP, AActor, flags6),
DEFINE_FLAG(MF6, JUMPDOWN, AActor, flags6),
DEFINE_FLAG(MF6, VULNERABLE, AActor, flags6),
// Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),

View file

@ -62,6 +62,8 @@ DEFINE_MEMBER_VARIABLE(floorz, AActor)
DEFINE_MEMBER_VARIABLE(health, AActor)
DEFINE_MEMBER_VARIABLE(pitch, AActor)
DEFINE_MEMBER_VARIABLE(special, AActor)
DEFINE_MEMBER_VARIABLE(special1, AActor)
DEFINE_MEMBER_VARIABLE(special2, AActor)
DEFINE_MEMBER_VARIABLE(tid, AActor)
DEFINE_MEMBER_VARIABLE(TIDtoHate, AActor)
DEFINE_MEMBER_VARIABLE(waterlevel, AActor)

View file

@ -269,6 +269,9 @@ ACTOR Actor native //: Thinker
"----" A 5 A_GenericFreezeDeath
"----" A 1 A_FreezeDeathChunks
Wait
GenericCrush:
POL5 A -1
Stop
}
}

View file

@ -87,8 +87,7 @@ ACTOR RealGibs
States
{
Spawn:
POL5 A -1
Stop
goto GenericCrush
}
}

View file

@ -360,7 +360,7 @@ StateMap
BloodyTwitch, Spawn, 4, // S_BLOODYTWITCH - S_BLOODYTWITCH4
DoomUnusedStates, Label2, 2, // S_DEADTORSO - S_DEADBOTTOM
HeadsOnAStick, Spawn, 1, // S_HEADSONSTICK
RealGibs, Spawn, 1, // S_GIBS
Actor, GenericCrush, 1, // S_GIBS
HeadOnAStick, Spawn, 1, // S_HEADONASTICK
HeadCandles, Spawn, 2, // S_HEADCANDLES - S_HEADCANDLES2
DeadStick, Spawn, 1, // S_DEADSTICK