- added a modified version of MBF's stay-on-lift feature.

The reason this was never added was the hard dependency on the line trigger types. This implements some modified logic that does not try to find all potential lifts in the map.
Also moving the MBF flags to compatflags so that they are easier to control by the user as these must be part of compatibility presets.
This commit is contained in:
Christoph Oelckers 2021-08-24 11:47:15 +02:00
parent 4bd617187b
commit 196a4c0b36
8 changed files with 79 additions and 14 deletions

View file

@ -703,7 +703,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
case 5: // MBF compat mode
v = COMPATF_TRACE | COMPATF_SOUNDTARGET | COMPATF_BOOMSCROLL | COMPATF_MISSILECLIP | COMPATF_MUSHROOM |
COMPATF_MBFMONSTERMOVE | COMPATF_NOBLOCKFRIENDS | COMPATF_MASKEDMIDTEX;
w = COMPATF2_EXPLODE1;
w = COMPATF2_EXPLODE1 | COMPATF2_AVOID_HAZARDS | COMPATF2_STAYONLIFT;
break;
case 6: // Boom with some added settings to reenable some 'broken' behavior
@ -716,7 +716,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
v = COMPATF_CORPSEGIBS | COMPATF_NOBLOCKFRIENDS | COMPATF_MBFMONSTERMOVE | COMPATF_INVISIBILITY |
COMPATF_NOTOSSDROPS | COMPATF_MUSHROOM | COMPATF_NO_PASSMOBJ | COMPATF_BOOMSCROLL | COMPATF_WALLRUN |
COMPATF_TRACE | COMPATF_HITSCAN | COMPATF_MISSILECLIP | COMPATF_MASKEDMIDTEX | COMPATF_SOUNDTARGET;
w = COMPATF2_POINTONLINE | COMPATF2_EXPLODE1 | COMPATF2_EXPLODE2;
w = COMPATF2_POINTONLINE | COMPATF2_EXPLODE1 | COMPATF2_EXPLODE2 | COMPATF2_AVOID_HAZARDS | COMPATF2_STAYONLIFT;
break;
}
compatflags = v;
@ -766,6 +766,8 @@ CVAR (Flag, compat_checkswitchrange, compatflags2, COMPATF2_CHECKSWITCHRANGE);
CVAR (Flag, compat_explode1, compatflags2, COMPATF2_EXPLODE1);
CVAR (Flag, compat_explode2, compatflags2, COMPATF2_EXPLODE2);
CVAR (Flag, compat_railing, compatflags2, COMPATF2_RAILING);
CVAR (Flag, compat_avoidhazard, compatflags2, COMPATF2_AVOID_HAZARDS);
CVAR (Flag, compat_stayonlift, compatflags2, COMPATF2_STAYONLIFT);
CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)

View file

@ -222,6 +222,9 @@ enum : unsigned int
COMPATF2_EXPLODE2 = 1 << 9, // Use original explosion code throughout.
COMPATF2_RAILING = 1 << 10, // Bugged Strife railings.
COMPATF2_SCRIPTWAIT = 1 << 11, // Use old scriptwait implementation where it doesn't wait on a non-running script.
COMPATF2_AVOID_HAZARDS = 1 << 12, // another MBF thing.
COMPATF2_STAYONLIFT = 1 << 13, // yet another MBF thing.
};
// Emulate old bugs for select maps. These are not exposed by a cvar

View file

@ -1663,7 +1663,6 @@ MapFlagHandlers[] =
{ "enableskyboxao", MITYPE_SETFLAG3, LEVEL3_SKYBOXAO, 0 },
{ "disableskyboxao", MITYPE_CLRFLAG3, LEVEL3_SKYBOXAO, 0 },
{ "avoidmelee", MITYPE_SETFLAG3, LEVEL3_AVOIDMELEE, 0 },
{ "avoidhazards", MITYPE_SETFLAG3, LEVEL3_AVOID_HAZARDS, 0 },
{ "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes
{ "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX, 0 },
{ "compat_stairs", MITYPE_COMPATFLAG, COMPATF_STAIRINDEX, 0 },
@ -1705,6 +1704,8 @@ MapFlagHandlers[] =
{ "compat_explode2", MITYPE_COMPATFLAG, 0, COMPATF2_EXPLODE2 },
{ "compat_railing", MITYPE_COMPATFLAG, 0, COMPATF2_RAILING },
{ "compat_scriptwait", MITYPE_COMPATFLAG, 0, COMPATF2_SCRIPTWAIT },
{ "compat_avoidhazards", MITYPE_COMPATFLAG, 0, COMPATF2_AVOID_HAZARDS },
{ "compat_stayonlift", MITYPE_COMPATFLAG, 0, COMPATF2_STAYONLIFT },
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end2_track", MITYPE_EATNEXT, 0, 0 },

View file

@ -260,7 +260,6 @@ enum ELevelFlags : unsigned int
LEVEL3_NOSHADOWMAP = 0x00010000, // disables shadowmaps for a given level.
LEVEL3_AVOIDMELEE = 0x00020000, // global flag needed for proper MBF support.
LEVEL3_NOJUMPDOWN = 0x00040000, // only for MBF21. Inverse of MBF's dog_jumping flag.
LEVEL3_AVOID_HAZARDS = 0x00080000, // another MBF thing.
};

View file

@ -485,6 +485,7 @@ enum
SECMF_HIDDEN = 256, // Do not draw on textured automap
SECMF_OVERLAPPING = 512, // floor and ceiling overlap and require special renderer action.
SECMF_NOSKYWALLS = 1024, // Do not draw "sky walls"
SECMF_LIFT = 2048, // For MBF monster AI
};
enum

View file

@ -787,6 +787,27 @@ void MapLoader::SpawnSpecials ()
SpawnLinePortal(&line);
break;
// partial support for MBF's stay-on-lift feature.
// Unlike MBF we cannot scan all lines for a proper special each time because it'd take too long.
// So instead, set the info here, but only for repeatable lifts to keep things simple.
// This also cannot consider lifts triggered by scripts etc.
case Generic_Lift:
if (line.args[3] != 1) continue;
case Plat_DownWaitUpStay:
case Plat_DownWaitUpStayLip:
case Plat_UpWaitDownStay:
case Plat_UpNearestWaitDownStay:
if (line.flags & ML_REPEAT_SPECIAL)
{
auto it = Level->GetSectorTagIterator(line.args[0], &line);
int secno;
while ((secno = it.Next()) != -1)
{
Level->sectors[secno].MoreFlags |= SECMF_LIFT;
}
}
break;
// [RH] ZDoom Static_Init settings
case Static_Init:
switch (line.args[1])

View file

@ -422,6 +422,7 @@ enum ActorFlag8
MF8_MAP07BOSS1 = 0x00400000, // MBF21 boss death.
MF8_MAP07BOSS2 = 0x00800000, // MBF21 boss death.
MF8_AVOIDHAZARDS = 0x01000000, // MBF AI enhancement.
MF8_STAYONLIFT = 0x02000000, // MBF AI enhancement.
};
// --- mobj.renderflags ---

View file

@ -69,6 +69,7 @@ static FRandom pr_slook ("SlooK");
static FRandom pr_dropoff ("Dropoff");
static FRandom pr_defect ("Defect");
static FRandom pr_avoidcrush("AvoidCrush");
static FRandom pr_stayonlift("StayOnLift");
static FRandom pr_skiptarget("SkipTarget");
static FRandom pr_enemystrafe("EnemyStrafe");
@ -409,6 +410,33 @@ int P_HitFriend(AActor * self)
return false;
}
/*
* P_IsOnLift
*
* killough 9/9/98:
*
* Returns true if the object is on a lift. Used for AI,
* since it may indicate the need for crowded conditions,
* or that a monster should stay on the lift for a while
* while it goes up or down.
*/
static bool P_IsOnLift(const AActor* actor)
{
sector_t* sec = actor->Sector;
// Short-circuit: it's on a lift which is active.
DSectorEffect* e = sec->floordata;
if (e && e->IsKindOf(RUNTIME_CLASS(DPlat)))
return true;
// Check to see if it's in a sector which can be activated as a lift.
// This is a bit more restrictive than MBF as it only considers repeatable lifts moving from A->B->A and stop.
// Other types of movement are not easy to detect with the more complex map setup
// and also do not really make sense in this context unless they are actually active
return !!(sec->MoreFlags & SECMF_LIFT);
}
/*
* P_IsUnderDamage
*
@ -437,6 +465,20 @@ static int P_IsUnderDamage(AActor* actor)
return dir;
}
//
// P_CheckTags
// Checks if 2 sectors share the same primary activation tag
//
bool P_CheckTags(sector_t* sec1, sector_t* sec2)
{
auto Level = sec1->Level;
if (!Level->SectorHasTags(sec1) || !Level->SectorHasTags(sec2)) return sec1 == sec2;
if (Level->GetFirstSectorTag(sec1) == Level->GetFirstSectorTag(sec2)) return true;
// todo: check secondary tags as well.
return false;
}
//
// P_Move
// Move in the current direction,
@ -686,15 +728,12 @@ int P_SmartMove(AActor* actor)
{
AActor* target = actor->target;
int on_lift = false, dropoff = false, under_damage;
bool monster_avoid_hazards = (actor->Level->flags3 & LEVEL3_AVOID_HAZARDS) || (actor->flags8 & MF8_AVOIDHAZARDS);
bool monster_avoid_hazards = (actor->Level->i_compatflags2 & COMPATF2_AVOID_HAZARDS) || (actor->flags8 & MF8_AVOIDHAZARDS);
#if 0
/* killough 9/12/98: Stay on a lift if target is on one */
on_lift = !comp[comp_staylift]
&& target && target->health > 0
&& target->subsector->sector->tag == actor->subsector->sector->tag &&
P_IsOnLift(actor);
#endif
on_lift = ((actor->flags8 & MF8_STAYONLIFT) || (actor->Level->i_compatflags2 & COMPATF2_STAYONLIFT))
&& target && target->health > 0 && P_IsOnLift(actor)
&& P_CheckTags(target->Sector, actor->Sector);
under_damage = monster_avoid_hazards && P_IsUnderDamage(actor) != 0;//e6y
@ -703,11 +742,9 @@ int P_SmartMove(AActor* actor)
// killough 9/9/98: avoid crushing ceilings or other damaging areas
if (
#if 0
(on_lift && P_Random(pr_stayonlift) < 230 && // Stay on lift
(on_lift && pr_stayonlift() < 230 && // Stay on lift
!P_IsOnLift(actor))
||
#endif
(monster_avoid_hazards && !under_damage && //e6y // Get away from damage
(under_damage = P_IsUnderDamage(actor)) &&
(under_damage < 0 || pr_avoidcrush() < 200))