From 196a4c0b3691c4481539772e23c818399d6cc597 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 24 Aug 2021 11:47:15 +0200 Subject: [PATCH] - 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. --- src/d_main.cpp | 6 ++-- src/doomdef.h | 3 ++ src/gamedata/g_mapinfo.cpp | 3 +- src/gamedata/g_mapinfo.h | 1 - src/gamedata/r_defs.h | 1 + src/maploader/specials.cpp | 21 ++++++++++++++ src/playsim/actor.h | 1 + src/playsim/p_enemy.cpp | 57 +++++++++++++++++++++++++++++++------- 8 files changed, 79 insertions(+), 14 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 842b1e9f4..556664662 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -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) diff --git a/src/doomdef.h b/src/doomdef.h index 1adf81d7d..05e7ebb95 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -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 diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index 3b8c5ca3b..3b823c59e 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -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 }, diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index ecb6ba0e6..9f7472854 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -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. }; diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index fa4a30227..d7fb686cf 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -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 diff --git a/src/maploader/specials.cpp b/src/maploader/specials.cpp index 2024954f7..280eba279 100644 --- a/src/maploader/specials.cpp +++ b/src/maploader/specials.cpp @@ -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]) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 61b65b593..e604cbfeb 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -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 --- diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 1432fa67d..b877bcd12 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -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))