From ea8c94d637bddfc2cda655165bd466c6c7f3e8fe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 14 Sep 2009 20:47:53 +0000 Subject: [PATCH] - 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) --- docs/rh-log.txt | 3 + src/actionspecials.h | 2 +- src/actor.h | 8 +- src/compatibility.cpp | 6 + src/d_main.cpp | 19 +- src/doomdef.h | 8 +- src/g_mapinfo.cpp | 5 + src/m_options.cpp | 12 +- src/namedef.h | 1 + src/p_enemy.cpp | 65 ++++-- src/p_interaction.cpp | 2 +- src/p_lnspec.cpp | 10 - src/p_lnspec.h | 1 - src/p_local.h | 2 + src/p_map.cpp | 106 +++++++-- src/p_mobj.cpp | 245 +++++++++++++-------- src/p_spec.cpp | 12 +- src/p_user.cpp | 4 +- src/thingdef/thingdef.h | 2 + src/thingdef/thingdef_data.cpp | 4 + src/thingdef/thingdef_expression.cpp | 2 + wadsrc/static/actors/actor.txt | 3 + wadsrc/static/actors/shared/sharedmisc.txt | 3 +- wadsrc/static/dehsupp.txt | 2 +- 24 files changed, 367 insertions(+), 160 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 2c88821d2..8656a9a3b 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -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.) diff --git a/src/actionspecials.h b/src/actionspecials.h index ec8aef9cf..aefdcc951 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -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) diff --git a/src/actor.h b/src/actor.h index 5c94eec6f..17eb0401b 100644 --- a/src/actor.h +++ b/src/actor.h @@ -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 --- diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 8d9726d48..6ff899f8f 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -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 } }; diff --git a/src/d_main.cpp b/src/d_main.cpp index 6581db7e8..6582767b5 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -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); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index c6402addd..53e740ac3 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -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: diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 34b627736..3749aa627 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -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 }, diff --git a/src/m_options.cpp b/src/m_options.cpp index 1f127ff26..366908187 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -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} }, }; diff --git a/src/namedef.h b/src/namedef.h index ea4aaa4c2..8510cd95b 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -178,6 +178,7 @@ xx(No) xx(Greetings) xx(Idle) xx(GenericFreezeDeath) +xx(GenericCrush) // Compatible death names for the decorate parser. xx(XDeath) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 1d8ebc114..cf2aca521 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -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,20 +412,23 @@ bool P_Move (AActor *actor) speed = actor->Speed; -#if 0 // [RH] I'm not so sure this is such a good idea - // killough 10/98: make monsters get affected by ice and sludge too: - movefactor = P_GetMoveFactor (actor, &friction); + // [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); - if (friction < ORIG_FRICTION) - { // sludge - speed = ((ORIG_FRICTION_FACTOR - (ORIG_FRICTION_FACTOR-movefactor)/2) - * speed) / ORIG_FRICTION_FACTOR; - if (speed == 0) - { // always give the monster a little bit of speed - speed = ksgn(actor->Speed); + if (friction < ORIG_FRICTION) + { // sludge + speed = ((ORIG_FRICTION_FACTOR - (ORIG_FRICTION_FACTOR-movefactor)/2) + * speed) / ORIG_FRICTION_FACTOR; + if (speed == 0) + { // always give the monster a little bit of speed + 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 - /* - // Make raised corpses look ghostly - if (corpsehit->alpha > TRANSLUC50) - corpsehit->alpha /= 2; - */ + 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; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index d48b6e8d6..03d489b8d 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -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; } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 7e535756f..b34ed4878 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -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)"; -} \ No newline at end of file diff --git a/src/p_lnspec.h b/src/p_lnspec.h index 05f305520..495947243 100644 --- a/src/p_lnspec.h +++ b/src/p_lnspec.h @@ -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__ diff --git a/src/p_local.h b/src/p_local.h index 3ed7c8725..dd9826e1f 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -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); diff --git a/src/p_map.cpp b/src/p_map.cpp index 144091d0c..a937db4d3 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -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 - (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 + else if ((ld->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING)) || // explicitly blocking everything + (!(NotBlocked) && (ld->flags & ML_BLOCKMONSTERS)) || // block monsters only + (tm.thing->player != NULL && (ld->flags & ML_BLOCK_PLAYERS)) || // block players + ((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) { - P_ExplodeMissile(mo, NULL, NULL); + 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 diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 9161a5a09..0520c46d0 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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<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.", diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 4dfd9e4c7..e1d486869 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -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; diff --git a/src/p_user.cpp b/src/p_user.cpp index 0f7d480a1..d1f89c166 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -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: // @@ -2535,7 +2535,7 @@ void player_t::Serialize (FArchive &arc) << ConversationPC << ConversationNPCAngle << ConversationFaceTalker; - + for (i = 0; i < MAXPLAYERS; i++) arc << frags[i]; for (i = 0; i < NUMPSPRITES; i++) diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index b60f0f422..df4bc78ab 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -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 diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 8ef4ca640..c65cb5d21 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -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), diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index bcb630826..eee2b3608 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -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) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index c41c062f9..fbb13b54f 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -269,6 +269,9 @@ ACTOR Actor native //: Thinker "----" A 5 A_GenericFreezeDeath "----" A 1 A_FreezeDeathChunks Wait + GenericCrush: + POL5 A -1 + Stop } } diff --git a/wadsrc/static/actors/shared/sharedmisc.txt b/wadsrc/static/actors/shared/sharedmisc.txt index a51ab52ae..fd53c34df 100644 --- a/wadsrc/static/actors/shared/sharedmisc.txt +++ b/wadsrc/static/actors/shared/sharedmisc.txt @@ -87,8 +87,7 @@ ACTOR RealGibs States { Spawn: - POL5 A -1 - Stop + goto GenericCrush } } diff --git a/wadsrc/static/dehsupp.txt b/wadsrc/static/dehsupp.txt index a1503ed0a..c46dfb6b5 100644 --- a/wadsrc/static/dehsupp.txt +++ b/wadsrc/static/dehsupp.txt @@ -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