- moved the combined compatibility flags into FLevelLocals.

This commit is contained in:
Christoph Oelckers 2019-01-29 19:28:22 +01:00
parent d716a17b96
commit 6451b7d592
35 changed files with 162 additions and 97 deletions

View File

@ -530,9 +530,6 @@ CVAR (Flag, sv_respawnsuper, dmflags2, DF2_RESPAWN_SUPER);
//
//==========================================================================
int i_compatflags, i_compatflags2; // internal compatflags composed from the compatflags CVAR and MAPINFO settings
int ii_compatflags, ii_compatflags2, ib_compatflags;
EXTERN_CVAR(Int, compatmode)
static int GetCompatibility(FLevelLocals *Level, int mask)
@ -549,17 +546,24 @@ static int GetCompatibility2(FLevelLocals *Level, int mask)
CUSTOM_CVAR (Int, compatflags, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
{
int old = i_compatflags;
i_compatflags = GetCompatibility(&level, self) | ii_compatflags;
if ((old ^ i_compatflags) & COMPATF_POLYOBJ)
for (auto Level : AllLevels())
{
level.ClearAllSubsectorLinks();
int old = Level->i_compatflags;
Level->i_compatflags = GetCompatibility(Level, self) | Level->ii_compatflags;
if ((old ^ Level->i_compatflags) & COMPATF_POLYOBJ)
{
Level->ClearAllSubsectorLinks();
}
}
}
CUSTOM_CVAR (Int, compatflags2, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
{
i_compatflags2 = GetCompatibility2(&level, self) | ii_compatflags2;
for (auto Level : AllLevels())
{
Level->i_compatflags2 = GetCompatibility2(Level, self) | Level->ii_compatflags2;
Level->SetCompatLineOnSide(true);
}
}
CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)

View File

@ -151,7 +151,9 @@ enum ELineFlags : unsigned
ML_MAPPED = 0x00000100, // set if already drawn in automap
ML_REPEAT_SPECIAL = 0x00000200, // special is repeatable
// 0x400, 0x800 and 0x1000 are ML_SPAC_MASK, they can be used for internal things but not for real map flags.
ML_ADDTRANS = 0x00000400, // additive translucency (can only be set internally)
ML_COMPATSIDE = 0x00000800, // for compatible PointOnLineSide checks. Using the global compatibility check would be a bit expensive for this check.
// Extended flags
ML_MONSTERSCANACTIVATE = 0x00002000, // [RH] Monsters (as well as players) can activate the line

View File

@ -248,7 +248,6 @@ EXTERN_CVAR (Int, dmflags2); // [BC]
EXTERN_CVAR (Int, compatflags);
EXTERN_CVAR (Int, compatflags2);
extern int i_compatflags, i_compatflags2, ii_compatflags, ii_compatflags2, ib_compatflags;
// Filters from AddAutoloadFiles(). Used to filter files from archives.
extern FString LumpFilterIWAD;

View File

@ -214,7 +214,7 @@ EMoveResult sector_t::MoveFloor(double speed, double dest, int crush, int direct
//destheight = (dest < ceilingheight) ? dest : ceilingheight;
if (!ceilingplane.isSlope() && !floorplane.isSlope() &&
!PortalIsLinked(sector_t::ceiling) &&
(!(i_compatflags2 & COMPATF2_FLOORMOVE) && -dest > ceilingplane.fD()))
(!(Level->i_compatflags2 & COMPATF2_FLOORMOVE) && -dest > ceilingplane.fD()))
{
dest = -ceilingplane.fD();
}
@ -304,7 +304,7 @@ EMoveResult sector_t::MoveCeiling(double speed, double dest, int crush, int dire
//destheight = (dest > floorheight) ? dest : floorheight;
if (!ceilingplane.isSlope() && !floorplane.isSlope() &&
!PortalIsLinked(sector_t::floor) &&
(!(i_compatflags2 & COMPATF2_FLOORMOVE) && dest < -floorplane.fD()))
(!(Level->i_compatflags2 & COMPATF2_FLOORMOVE) && dest < -floorplane.fD()))
{
dest = -floorplane.fD();
}

View File

@ -578,7 +578,7 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
Printf (TEXTCOLOR_RED "Unloading scripts cannot exit the level again.\n");
return;
}
if (gameaction == ga_completed && !(i_compatflags2 & COMPATF2_MULTIEXIT)) // do not exit multiple times.
if (gameaction == ga_completed && !(level.i_compatflags2 & COMPATF2_MULTIEXIT)) // do not exit multiple times.
{
return;
}
@ -1070,7 +1070,7 @@ void G_DoLoadLevel (const FString &nextmapname, int position, bool autosave, boo
level.starttime = gametic;
level.UnSnapshotLevel (!savegamerestore); // [RH] Restore the state of the level.
int pnumerr = G_FinishTravel ();
int pnumerr = level.FinishTravel ();
if (!level.FromSnapshot)
{
@ -2075,6 +2075,21 @@ int FLevelLocals::GetInfighting()
return G_SkillProperty(SKILLP_Infight);
}
//============================================================================
//
// transfers the compatiblity flag for old PointOnLineSide to each line.
// This gets checked in a frequently called worker function and the closer
// this info is to the data this function works on, the better.
//
//============================================================================
void FLevelLocals::SetCompatLineOnSide(bool state)
{
int on = (state && (i_compatflags2 & COMPATF2_POINTONLINE));
if (on) for (auto l : lines) l.flags |= ML_COMPATSIDE;
else for (auto l : lines) l.flags &= ML_COMPATSIDE;
}
//==========================================================================
// IsPointInMap
//

View File

@ -120,6 +120,7 @@ struct FLevelLocals
void SetConversation(int convid, PClassActor *Class, int dlgindex);
int FindNode (const FStrifeDialogueNode *node);
int GetInfighting();
void SetCompatLineOnSide(bool state);
void Init();
private:
@ -442,6 +443,12 @@ public:
FDialogueIDMap DialogueRoots;
FDialogueMap ClassRoots;
int ii_compatflags = 0;
int ii_compatflags2 = 0;
int ib_compatflags = 0;
int i_compatflags = 0;
int i_compatflags2 = 0;
uint8_t md5[16]; // for savegame validation. If the MD5 does not match the savegame won't be loaded.
int time; // time in the hub
int maptime; // time in the map

View File

@ -588,7 +588,7 @@ inline int HWDrawList::CompareSprites(SortNode * a,SortNode * b)
int res = s1->depth - s2->depth;
if (res != 0) return -res;
else return (i_compatflags & COMPATF_SPRITESORT)? s2->index-s1->index : s1->index-s2->index;
else return reverseSort? s2->index-s1->index : s1->index-s2->index;
}
//==========================================================================
@ -702,6 +702,7 @@ SortNode * HWDrawList::DoSort(HWDrawInfo *di, SortNode * head)
//==========================================================================
void HWDrawList::Sort(HWDrawInfo *di)
{
reverseSort = !!(di->Level->i_compatflags & COMPATF_SPRITESORT);
SortZ = di->Viewpoint.Pos.Z;
MakeSortList();
sorted = DoSort(di, SortNodes[SortNodeStart]);

View File

@ -67,6 +67,7 @@ struct HWDrawList
int SortNodeStart;
float SortZ;
SortNode * sorted;
bool reverseSort;
public:
HWDrawList()

View File

@ -2068,7 +2068,7 @@ void GLWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_
FTexture *tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::mid), true);
if (tex != NULL)
{
if (i_compatflags & COMPATF_MASKEDMIDTEX)
if (di->Level->i_compatflags & COMPATF_MASKEDMIDTEX)
{
tex = tex->GetRawTexture();
}

View File

@ -279,17 +279,17 @@ FName MapLoader::CheckCompatibility(MapData *map)
if (BCompatMap.CountUsed() == 0) ParseCompatibility();
ii_compatflags = 0;
ii_compatflags2 = 0;
ib_compatflags = 0;
Level->ii_compatflags = 0;
Level->ii_compatflags2 = 0;
Level->ib_compatflags = 0;
// When playing Doom IWAD levels force COMPAT_SHORTTEX and COMPATF_LIGHT.
// I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt.
// TNT's MAP31 also needs COMPATF_STAIRINDEX but that only gets activated for TNT.WAD.
if (Wads.GetLumpFile(map->lumpnum) == Wads.GetIwadNum() && (gameinfo.flags & GI_COMPATSHORTTEX) && Level->maptype == MAPTYPE_DOOM)
{
ii_compatflags = COMPATF_SHORTTEX|COMPATF_LIGHT;
if (gameinfo.flags & GI_COMPATSTAIRS) ii_compatflags |= COMPATF_STAIRINDEX;
Level->ii_compatflags = COMPATF_SHORTTEX|COMPATF_LIGHT;
if (gameinfo.flags & GI_COMPATSTAIRS) Level->ii_compatflags |= COMPATF_STAIRINDEX;
}
map->GetChecksum(md5.Bytes);
@ -319,9 +319,9 @@ FName MapLoader::CheckCompatibility(MapData *map)
if (flags != NULL)
{
ii_compatflags |= flags->CompatFlags[SLOT_COMPAT];
ii_compatflags2 |= flags->CompatFlags[SLOT_COMPAT2];
ib_compatflags |= flags->CompatFlags[SLOT_BCOMPAT];
Level->ii_compatflags |= flags->CompatFlags[SLOT_COMPAT];
Level->ii_compatflags2 |= flags->CompatFlags[SLOT_COMPAT2];
Level->ib_compatflags |= flags->CompatFlags[SLOT_BCOMPAT];
}
// Reset i_compatflags
@ -330,7 +330,7 @@ FName MapLoader::CheckCompatibility(MapData *map)
// Set floatbob compatibility for all maps with an original Hexen MAPINFO.
if (Level->flags2 & LEVEL2_HEXENHACK)
{
ib_compatflags |= BCOMPATF_FLOATBOB;
Level->ib_compatflags |= BCOMPATF_FLOATBOB;
}
return FName(hash, true); // if this returns NAME_None it means there is no scripted compatibility handler.
}
@ -574,6 +574,9 @@ CCMD (mapchecksum)
CCMD (hiddencompatflags)
{
Printf("%08x %08x %08x\n", ii_compatflags, ii_compatflags2, ib_compatflags);
for(auto Level : AllLevels())
{
Printf("%s: %08x %08x %08x\n", Level->MapName.GetChars(), Level->ii_compatflags, Level->ii_compatflags2, Level->ib_compatflags);
}
}

View File

@ -1516,7 +1516,7 @@ void MapLoader::SetLineID (int i, line_t *ld)
break;
case Plane_Align:
if (!(ib_compatflags & BCOMPATF_NOSLOPEID)) setid = ld->args[2];
if (!(Level->ib_compatflags & BCOMPATF_NOSLOPEID)) setid = ld->args[2];
break;
case Static_Init:
@ -3016,7 +3016,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
Level->maptype = MAPTYPE_UDMF;
}
FName checksum = CheckCompatibility(map);
if (ib_compatflags & BCOMPATF_REBUILDNODES)
if (Level->ib_compatflags & BCOMPATF_REBUILDNODES)
{
ForceNodeBuild = true;
}

View File

@ -179,7 +179,7 @@ void MapLoader::SetSlope (secplane_t *plane, bool setCeil, int xyangi, int zangi
DVector3 norm;
if (ib_compatflags & BCOMPATF_SETSLOPEOVERFLOW)
if (Level->ib_compatflags & BCOMPATF_SETSLOPEOVERFLOW)
{
// We have to consider an integer multiplication overflow here.
norm[0] = FixedToFloat(FloatToFixed(zang.Cos()) * FloatToFixed(xyang.Cos())) / 65536.;

View File

@ -352,7 +352,7 @@ void DDoor::Construct(sector_t *sec, EVlDoor type, double speed, int delay, int
m_TopCountdown = topcountdown;
m_LightTag = lightTag;
if (i_compatflags & COMPATF_NODOORLIGHT)
if (Level->i_compatflags & COMPATF_NODOORLIGHT)
{
m_LightTag = 0;
}

View File

@ -464,7 +464,7 @@ int P_Move (AActor *actor)
// [RH] I'm not so sure this is such a good idea
// [GZ] That's why it's compat-optioned.
if (compatflags & COMPATF_MBFMONSTERMOVE && !(actor->flags8 & MF8_NOFRICTION))
if (actor->Level->i_compatflags & COMPATF_MBFMONSTERMOVE && !(actor->flags8 & MF8_NOFRICTION))
{
// killough 10/98: make monsters get affected by ice and sludge too:
movefactor = P_GetMoveFactor (actor, &friction);
@ -864,7 +864,7 @@ void P_NewChaseDir(AActor * actor)
if (actor->floorz - actor->dropoffz > actor->MaxDropOffHeight &&
actor->Z() <= actor->floorz && !(actor->flags & MF_DROPOFF) &&
!(actor->flags2 & MF2_ONMOBJ) &&
!(actor->flags & MF_FLOAT) && !(i_compatflags & COMPATF_DROPOFF))
!(actor->flags & MF_FLOAT) && !(actor->Level->i_compatflags & COMPATF_DROPOFF))
{
FBoundingBox box(actor->X(), actor->Y(), actor->radius);
FBlockLinesIterator it(actor->Level, box);
@ -1715,7 +1715,7 @@ int P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
// the player then, eh?
if(!(actor->flags6 & MF6_SEEINVISIBLE))
{
if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) ||
if ((player->mo->flags & MF_SHADOW && !(actor->Level->i_compatflags & COMPATF_INVISIBILITY)) ||
player->mo->flags3 & MF3_GHOST)
{
if (player->mo->Distance2D (actor) > 128 && player->mo->Vel.XY().LengthSquared() < 5*5)
@ -1776,7 +1776,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
}
else
{
targ = (i_compatflags & COMPATF_SOUNDTARGET || self->flags & MF_NOSECTOR)?
targ = (self->Level->i_compatflags & COMPATF_SOUNDTARGET || self->flags & MF_NOSECTOR)?
self->Sector->SoundTarget : self->LastHeard;
// [RH] If the soundtarget is dead, don't chase it
@ -1909,7 +1909,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LookEx)
{
if (!(flags & LOF_NOSOUNDCHECK))
{
targ = (i_compatflags & COMPATF_SOUNDTARGET || self->flags & MF_NOSECTOR)?
targ = (self->Level->i_compatflags & COMPATF_SOUNDTARGET || self->flags & MF_NOSECTOR)?
self->Sector->SoundTarget : self->LastHeard;
if (targ != NULL)
{
@ -2721,7 +2721,7 @@ bool P_CheckForResurrection(AActor *self, bool usevilestates)
{
corpsehit->Translation = info->Translation; // Clean up bloodcolor translation from crushed corpses
}
if (ib_compatflags & BCOMPATF_VILEGHOSTS)
if (self->Level->ib_compatflags & BCOMPATF_VILEGHOSTS)
{
corpsehit->Height *= 4;
// [GZ] This was a commented-out feature, so let's make use of it,
@ -3116,7 +3116,7 @@ void A_BossDeath(AActor *self)
LEVEL_SORCERER2SPECIAL)) == 0)
return;
if ((i_compatflags & COMPATF_ANYBOSSDEATH) || ( // [GZ] Added for UAC_DEAD
if ((Level->i_compatflags & COMPATF_ANYBOSSDEATH) || ( // [GZ] Added for UAC_DEAD
((Level->flags & LEVEL_MAP07SPECIAL) && (type == NAME_Fatso || type == NAME_Arachnotron)) ||
((Level->flags & LEVEL_BRUISERSPECIAL) && (type == NAME_BaronOfHell)) ||
((Level->flags & LEVEL_CYBORGSPECIAL) && (type == NAME_Cyberdemon)) ||

View File

@ -461,7 +461,7 @@ bool FLevelLocals::CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *
// [Graf Zahl]
// Don't make sounds for instant movement hacks but make an exception for
// switches that activate their own back side.
if (!(i_compatflags & COMPATF_SILENT_INSTANT_FLOORS))
if (!(sec->Level->i_compatflags & COMPATF_SILENT_INSTANT_FLOORS))
{
if (!line || !(line->activation & (SPAC_Use | SPAC_Push)) || line->backsector != sec)
silent = true;

View File

@ -3065,7 +3065,7 @@ FUNC(LS_SetPlayerProperty)
{
int i;
if ((ib_compatflags & BCOMPATF_LINKFROZENPROPS) && (mask & (CF_FROZEN | CF_TOTALLYFROZEN)))
if ((Level->ib_compatflags & BCOMPATF_LINKFROZENPROPS) && (mask & (CF_FROZEN | CF_TOTALLYFROZEN)))
{ // Clearing one of these properties clears both of them (if the compat flag is set.)
mask = CF_FROZEN | CF_TOTALLYFROZEN;
}

View File

@ -459,7 +459,7 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi
// [RH] Z-Check
// But not if not MF2_PASSMOBJ or MF3_DONTOVERLAP are set!
// Otherwise those things would get stuck inside each other.
if ((thing->flags2 & MF2_PASSMOBJ || th->flags4 & MF4_ACTLIKEBRIDGE) && !(i_compatflags & COMPATF_NO_PASSMOBJ))
if ((thing->flags2 & MF2_PASSMOBJ || th->flags4 & MF4_ACTLIKEBRIDGE) && !(thing->Level->i_compatflags & COMPATF_NO_PASSMOBJ))
{
if (!(th->flags3 & thing->flags3 & MF3_DONTOVERLAP))
{
@ -516,7 +516,7 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi
// If this teleport was caused by a move, P_TryMove() will handle the
// sector transition messages better than we can here.
// This needs to be compatibility optioned because some older maps exploited this missing feature.
if (!(thing->flags6 & MF6_INTRYMOVE) && !(i_compatflags2 & COMPATF2_TELEPORT))
if (!(thing->flags6 & MF6_INTRYMOVE) && !(thing->Level->i_compatflags2 & COMPATF2_TELEPORT))
{
thing->CheckSectorTransition(oldsec);
}
@ -850,7 +850,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
// 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)));
|| ((tm.thing->Level->i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY)));
uint32_t ProjectileBlocking = ML_BLOCKEVERYTHING | ML_BLOCKPROJECTILE;
if ( tm.thing->flags8 & MF8_BLOCKASPLAYER ) ProjectileBlocking |= ML_BLOCK_PLAYERS | ML_BLOCKING;
@ -1263,7 +1263,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch
// walking on other actors and unblocking is too messy through restricted portal types so disable it.
if (!(cres.portalflags & FFCF_RESTRICTEDPORTAL))
{
if (!(i_compatflags & COMPATF_NO_PASSMOBJ) && !(tm.thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY | MF_NOGRAVITY)) &&
if (!(thing->Level->i_compatflags & COMPATF_NO_PASSMOBJ) && !(tm.thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY | MF_NOGRAVITY)) &&
(thing->flags & MF_SOLID) && (thing->flags4 & MF4_ACTLIKEBRIDGE))
{
// [RH] Let monsters walk on actors as well as floors
@ -1311,7 +1311,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch
// [RH] If the other thing is a bridge, then treat the moving thing as if it had MF2_PASSMOBJ, so
// you can use a scrolling floor to move scenery items underneath a bridge.
if ((tm.thing->flags2 & MF2_PASSMOBJ || thing->flags4 & MF4_ACTLIKEBRIDGE) && !(i_compatflags & COMPATF_NO_PASSMOBJ))
if ((tm.thing->flags2 & MF2_PASSMOBJ || thing->flags4 & MF4_ACTLIKEBRIDGE) && !(tm.thing->Level->i_compatflags & COMPATF_NO_PASSMOBJ))
{ // check if a mobj passed over/under another object
if (!(tm.thing->flags & MF_MISSILE) ||
!(tm.thing->flags2 & MF2_RIP) ||
@ -1441,7 +1441,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch
{
clipheight = thing->projectilepassheight;
}
else if (thing->projectilepassheight < 0 && (i_compatflags & COMPATF_MISSILECLIP))
else if (thing->projectilepassheight < 0 && (thing->Level->i_compatflags & COMPATF_MISSILECLIP))
{
clipheight = -thing->projectilepassheight;
}
@ -1763,7 +1763,7 @@ bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, boo
AActor *BlockingMobj = thing->BlockingMobj;
// If this blocks through a restricted line portal, it will always completely block.
if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ) || (tcres.portalflags & FFCF_RESTRICTEDPORTAL))
if (BlockingMobj == NULL || (thing->Level->i_compatflags & COMPATF_NO_PASSMOBJ) || (tcres.portalflags & FFCF_RESTRICTEDPORTAL))
{ // Thing slammed into something; don't let it move now.
thing->Height = realHeight;
return false;
@ -2068,7 +2068,7 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, DVector2 *
{
if (line->special && !(mobj->flags6 & MF6_NOTRIGGER))
{
if (posforwindowcheck && !(i_compatflags2 & COMPATF2_PUSHWINDOW) && line->backsector != NULL)
if (posforwindowcheck && !(mobj->Level->i_compatflags2 & COMPATF2_PUSHWINDOW) && line->backsector != NULL)
{ // Make sure this line actually blocks us and is not a window
// or similar construct we are standing inside of.
DVector3 pos = mobj->PosRelative(line);
@ -2175,7 +2175,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos,
goto pushline;
}
}
if (!(tm.thing->flags2 & MF2_PASSMOBJ) || (i_compatflags & COMPATF_NO_PASSMOBJ))
if (!(tm.thing->flags2 & MF2_PASSMOBJ) || (tm.thing->Level->i_compatflags & COMPATF_NO_PASSMOBJ))
{
thing->SetZ(oldz);
thing->flags6 &= ~MF6_INTRYMOVE;
@ -2274,7 +2274,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos,
// compatibility check: Doom originally did not allow monsters to cross dropoffs at all.
// If the compatibility flag is on, only allow this when the velocity comes from a scroller
if ((i_compatflags & COMPATF_CROSSDROPOFF) && !(thing->flags4 & MF4_SCROLLMOVE))
if ((thing->Level->i_compatflags & COMPATF_CROSSDROPOFF) && !(thing->flags4 & MF4_SCROLLMOVE))
{
dropoff = false;
}
@ -2963,7 +2963,7 @@ void FSlide::SlideTraverse(const DVector2 &start, const DVector2 &end)
goto isblocking;
}
if (li->flags & ML_BLOCKMONSTERS && !((slidemo->flags3 & MF3_NOBLOCKMONST)
|| ((i_compatflags & COMPATF_NOBLOCKFRIENDS) && (slidemo->flags & MF_FRIENDLY))))
|| ((slidemo->Level->i_compatflags & COMPATF_NOBLOCKFRIENDS) && (slidemo->flags & MF_FRIENDLY))))
{
goto isblocking;
}
@ -4588,7 +4588,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
// Hit a thing, so it could be either a puff or blood
DVector3 bleedpos = trace.HitPos;
// position a bit closer for puffs/blood if using compatibility mode.
if (i_compatflags & COMPATF_HITSCAN)
if (trace.Actor->Level->i_compatflags & COMPATF_HITSCAN)
{
DVector2 ofs = t1->Level->GetPortalOffsetPosition(bleedpos.X, bleedpos.Y, -10 * trace.HitVector.X, -10 * trace.HitVector.Y);
bleedpos.X = ofs.X;
@ -4781,7 +4781,7 @@ int P_LineTrace(AActor *t1, DAngle angle, double distance,
if ( flags & TRF_BLOCKSELF )
{
bool Projectile = ( (t1->flags&MF_MISSILE) || (t1->BounceFlags&BOUNCE_MBF) );
bool NotBlocked = ( (t1->flags3&MF3_NOBLOCKMONST) || ( (i_compatflags&COMPATF_NOBLOCKFRIENDS) && (t1->flags&MF_FRIENDLY) ) );
bool NotBlocked = ( (t1->flags3&MF3_NOBLOCKMONST) || ( (t1->Level->i_compatflags&COMPATF_NOBLOCKFRIENDS) && (t1->flags&MF_FRIENDLY) ) );
if ( Projectile ) lflags |= ML_BLOCKPROJECTILE;
if ( !Projectile || (t1->flags8&MF8_BLOCKASPLAYER) ) lflags |= ML_BLOCKING;
if ( !NotBlocked ) lflags |= ML_BLOCKMONSTERS;
@ -5099,7 +5099,7 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata)
newhit.HitActor = res.Actor;
newhit.HitPos = res.HitPos;
newhit.HitAngle = res.SrcAngleFromTarget;
if (i_compatflags & COMPATF_HITSCAN)
if (res.Actor->Level->i_compatflags & COMPATF_HITSCAN)
{
DVector2 ofs = res.Actor->Level->GetPortalOffsetPosition(newhit.HitPos.X, newhit.HitPos.Y, -10 * res.HitVector.X, -10 * res.HitVector.Y);
newhit.HitPos.X = ofs.X;
@ -5427,7 +5427,7 @@ bool P_UseTraverse(AActor *usething, const DVector2 &start, const DVector2 &end,
P_LineOpening(open, NULL, in->d.line, it.InterceptPoint(in));
}
if (open.range <= 0 ||
(in->d.line->special != 0 && (i_compatflags & COMPATF_USEBLOCKING)))
(in->d.line->special != 0 && (usething->Level->i_compatflags & COMPATF_USEBLOCKING)))
{
// [RH] Give sector a chance to intercept the use
@ -5487,7 +5487,7 @@ bool P_UseTraverse(AActor *usething, const DVector2 &start, const DVector2 &end,
//[RH] And now I've changed it again. If the line is of type
// SPAC_USE, then it eats the use. Everything else passes
// it through, including SPAC_USETHROUGH.
if (i_compatflags & COMPATF_USEBLOCKING)
if (usething->Level->i_compatflags & COMPATF_USEBLOCKING)
{
if (in->d.line->activation & SPAC_UseThrough) continue;
else return true;

View File

@ -1543,7 +1543,7 @@ void FPathTraverse::init(double x1, double y1, double x2, double y2, int flags,
// Count is present to prevent a round off error
// from skipping the break statement.
bool compatible = (flags & PT_COMPATIBLE) && (i_compatflags & COMPATF_HITSCAN);
bool compatible = (flags & PT_COMPATIBLE) && (Level->i_compatflags & COMPATF_HITSCAN);
// we want to use one list of checked actors for the entire operation
FBlockThingsIterator btit(Level);

View File

@ -4,6 +4,7 @@
#include <float.h>
#include "r_defs.h"
#include "doomstat.h"
#include "doomdata.h"
#include "m_bbox.h"
extern int validcount;
@ -50,7 +51,7 @@ inline int P_PointOnLineSidePrecise(const DVector2 &pt, const line_t *line)
inline int P_PointOnLineSide (double x, double y, const line_t *line)
{
extern int P_VanillaPointOnLineSide(double x, double y, const line_t* line);
return i_compatflags2 & COMPATF2_POINTONLINE
return (line->flags & ML_COMPATSIDE)
? P_VanillaPointOnLineSide(x, y, line) : P_PointOnLineSidePrecise(x, y, line);
}

View File

@ -1161,7 +1161,7 @@ bool AActor::Grind(bool items)
// 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,
&& (Level->i_compatflags & COMPATF_CORPSEGIBS) // 2. the compat setting is on,
&& player == NULL) // 3. and the thing isn't a player.
{
isgeneric = true;
@ -1816,7 +1816,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll)
// [anon] When friction is turned off, turn off the crouching and water
// speed caps as well, since it is a sort of friction, and the modders
// most likely want to deal with that themselves.
if ((mo->player != NULL && (i_compatflags & COMPATF_WALLRUN)) || ((mo->waterlevel >= 1 ||
if ((mo->player != NULL && (mo->Level->i_compatflags & COMPATF_WALLRUN)) || ((mo->waterlevel >= 1 ||
(mo->player != NULL && mo->player->crouchfactor < 0.75)) && !(mo->flags8 & MF8_NOFRICTION)))
{
// preserve the direction instead of clamping x and y independently.
@ -1938,7 +1938,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll)
DAngle oldangle = mo->Angles.Yaw;
do
{
if (i_compatflags & COMPATF_WALLRUN) pushtime++;
if (mo->Level->i_compatflags & COMPATF_WALLRUN) pushtime++;
tm.PushTime = pushtime;
ptry = start + move * step / steps;
@ -1989,7 +1989,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll)
// actor's velocity, do not attempt to slide.
if (mo->Vel.XY() == startvel)
{
if (player && (i_compatflags & COMPATF_WALLRUN))
if (player && (mo->Level->i_compatflags & COMPATF_WALLRUN))
{
// [RH] Here is the key to wall running: The move is clipped using its full speed.
// If the move is done a second time (because it was too fast for one move), it
@ -2007,7 +2007,7 @@ double P_XYMovement (AActor *mo, DVector2 scroll)
}
else
{
if (!player || !(i_compatflags & COMPATF_WALLRUN))
if (!player || !(mo->Level->i_compatflags & COMPATF_WALLRUN))
{
move = mo->Vel;
onestep = move / steps;
@ -2451,7 +2451,7 @@ void P_ZMovement (AActor *mo, double oldfloorz)
// Hexen yanked all items to the floor, except those being spawned at map start in the air.
// Those were kept at their original height.
// Do this only if the item was actually spawned by the map above ground to avoid problems.
if (mo->specialf1 > 0 && (mo->flags2 & MF2_FLOATBOB) && (ib_compatflags & BCOMPATF_FLOATBOB))
if (mo->specialf1 > 0 && (mo->flags2 & MF2_FLOATBOB) && (mo->Level->ib_compatflags & BCOMPATF_FLOATBOB))
{
mo->SetZ(mo->floorz + mo->specialf1);
}
@ -3713,7 +3713,7 @@ void AActor::Tick ()
scrolltype <= Scroll_SouthWest_Fast)
{ // Hexen scroll special
scrolltype -= Scroll_North_Slow;
if (i_compatflags&COMPATF_RAVENSCROLL)
if (Level->i_compatflags&COMPATF_RAVENSCROLL)
{
scrollv.X -= HexenCompatSpeeds[HexenScrollies[scrolltype][0]+4] * (1. / (32 * CARRYFACTOR));
scrollv.Y += HexenCompatSpeeds[HexenScrollies[scrolltype][1]+4] * (1. / (32 * CARRYFACTOR));
@ -3732,7 +3732,7 @@ void AActor::Tick ()
scrolltype -= Carry_East5;
uint8_t dir = HereticScrollDirs[scrolltype / 5];
double carryspeed = HereticSpeedMuls[scrolltype % 5] * (1. / (32 * CARRYFACTOR));
if (scrolltype < 5 && !(i_compatflags&COMPATF_RAVENSCROLL))
if (scrolltype < 5 && !(Level->i_compatflags&COMPATF_RAVENSCROLL))
{
// Use speeds that actually match the scrolling textures!
carryspeed = (1 << ((scrolltype % 5) + 15)) / 65536.;
@ -3742,7 +3742,7 @@ void AActor::Tick ()
}
else if (scrolltype == dScroll_EastLavaDamage)
{ // Special Heretic scroll special
if (i_compatflags&COMPATF_RAVENSCROLL)
if (Level->i_compatflags&COMPATF_RAVENSCROLL)
{
scrollv.X += 28. / (32*CARRYFACTOR);
}
@ -3795,7 +3795,7 @@ void AActor::Tick ()
// Some levels designed with Boom in mind actually want things to accelerate
// at neighboring scrolling sector boundaries. But it is only important for
// non-player objects.
if (player != NULL || !(i_compatflags & COMPATF_BOOMSCROLL))
if (player != NULL || !(Level->i_compatflags & COMPATF_BOOMSCROLL))
{
if (countx > 1)
{
@ -3888,7 +3888,7 @@ void AActor::Tick ()
}
if (Vel.Z != 0 || BlockingMobj || Z() != floorz)
{ // Handle Z velocity and gravity
if (((flags2 & MF2_PASSMOBJ) || (flags & MF_SPECIAL)) && !(i_compatflags & COMPATF_NO_PASSMOBJ))
if (((flags2 & MF2_PASSMOBJ) || (flags & MF_SPECIAL)) && !(Level->i_compatflags & COMPATF_NO_PASSMOBJ))
{
if (!(onmo = P_CheckOnmobj (this)))
{
@ -5414,7 +5414,7 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position)
if (sz == ONFLOORZ)
{
mobj->AddZ(mthing->pos.Z);
if ((mobj->flags2 & MF2_FLOATBOB) && (ib_compatflags & BCOMPATF_FLOATBOB))
if ((mobj->flags2 & MF2_FLOATBOB) && (mobj->Level->ib_compatflags & BCOMPATF_FLOATBOB))
{
mobj->specialf1 = mthing->pos.Z;
}
@ -5437,7 +5437,7 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position)
}
// For Hexen floatbob 'compatibility' we do not really want to alter the floorz.
if (mobj->specialf1 == 0 || !(mobj->flags2 & MF2_FLOATBOB) || !(ib_compatflags & BCOMPATF_FLOATBOB))
if (mobj->specialf1 == 0 || !(mobj->flags2 & MF2_FLOATBOB) || !(mobj->Level->ib_compatflags & BCOMPATF_FLOATBOB))
{
P_FindFloorCeiling(mobj, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT);
}

View File

@ -199,7 +199,7 @@ void DPusher::Tick ()
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)
if (Level->i_compatflags & COMPATF_MBFMONSTERMOVE)
{
pusharound = ((pusharound || (thing->IsSentient()) || (thing->flags & MF_SHOOTABLE)) // Add categories here
&& (!(thing->player && (thing->flags & (MF_NOGRAVITY))))); // Exclude flying players here

View File

@ -984,7 +984,9 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload)
Behaviors.SerializeModuleStates(arc);
// The order here is important: First world state, then portal state, then thinkers, and last polyobjects.
SetCompatLineOnSide(false); // This flag should not be saved. It solely depends on current compatibility state.
arc("linedefs", lines, loadlines);
SetCompatLineOnSide(true);
arc("sidedefs", sides, loadsides);
arc("sectors", sectors, loadsectors);
arc("zones", Zones);

View File

@ -473,9 +473,9 @@ double FindHighestCeilingSurrounding (const sector_t *sector, vertex_t **v)
// jff 02/03/98 Add routine to find shortest lower texture
//
static inline void CheckShortestTex (FTextureID texnum, double &minsize)
static inline void CheckShortestTex (FLevelLocals *Level, FTextureID texnum, double &minsize)
{
if (texnum.isValid() || (texnum.isNull() && (i_compatflags & COMPATF_SHORTTEX)))
if (texnum.isValid() || (texnum.isNull() && (Level->i_compatflags & COMPATF_SHORTTEX)))
{
FTexture *tex = TexMan.GetTexture(texnum);
if (tex != NULL)
@ -497,8 +497,8 @@ double FindShortestTextureAround (sector_t *sec)
{
if (check->flags & ML_TWOSIDED)
{
CheckShortestTex (check->sidedef[0]->GetTexture(side_t::bottom), minsize);
CheckShortestTex (check->sidedef[1]->GetTexture(side_t::bottom), minsize);
CheckShortestTex (sec->Level, check->sidedef[0]->GetTexture(side_t::bottom), minsize);
CheckShortestTex (sec->Level, check->sidedef[1]->GetTexture(side_t::bottom), minsize);
}
}
return minsize < FLT_MAX ? minsize : TexMan.ByIndex(0)->GetDisplayHeight();
@ -522,8 +522,8 @@ double FindShortestUpperAround (sector_t *sec)
{
if (check->flags & ML_TWOSIDED)
{
CheckShortestTex (check->sidedef[0]->GetTexture(side_t::top), minsize);
CheckShortestTex (check->sidedef[1]->GetTexture(side_t::top), minsize);
CheckShortestTex (sec->Level, check->sidedef[0]->GetTexture(side_t::top), minsize);
CheckShortestTex (sec->Level, check->sidedef[1]->GetTexture(side_t::top), minsize);
}
}
return minsize < FLT_MAX ? minsize : TexMan.ByIndex(0)->GetDisplayHeight();

View File

@ -546,6 +546,7 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame)
Level->automap = AM_Create(Level);
Level->automap->LevelInit();
Level->SetCompatLineOnSide(true);
// [RH] Start lightning, if MAPINFO tells us to
if (Level->flags & LEVEL_STARTLIGHTNING)

View File

@ -222,7 +222,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in)
//
// ignore self referencing sectors if COMPAT_TRACE is on
if ((i_compatflags & COMPATF_TRACE) && li->frontsector == li->backsector)
if ((Level->i_compatflags & COMPATF_TRACE) && li->frontsector == li->backsector)
return true;
double trX = Trace.x + Trace.dx * in->frac;

View File

@ -421,7 +421,7 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit, bool spec
// For backwards compatibility: Ignore lines with the same sector on both sides.
// This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15) need it.
if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector && !special3dpass)
if (Level->i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector && !special3dpass)
{
// We must check special activation here because the code below is never reached.
if (TraceFlags & TRACE_PCross)

View File

@ -1674,7 +1674,7 @@ void FPolyObj::CreateSubsectorLinks()
seg->v2 = side->V2();
seg->wall = side;
}
if (!(i_compatflags & COMPATF_POLYOBJ))
if (!(Level->i_compatflags & COMPATF_POLYOBJ))
{
SplitPoly(node, Level->HeadNode(), dummybbox);
}

View File

@ -848,7 +848,7 @@ static bool ValidatePosVel(const FSoundChan *const chan, const FVector3 &pos, co
static void CalcSectorSoundOrg(const DVector3 &listenpos, const sector_t *sec, int channum, FVector3 &pos)
{
if (!(i_compatflags & COMPATF_SECTORSOUNDS))
if (!(sec->Level->i_compatflags & COMPATF_SECTORSOUNDS))
{
// Are we inside the sector? If yes, the closest point is the one we're on.
if (currentUILevel->PointInSector(listenpos.X, listenpos.Y) == sec)
@ -1663,7 +1663,7 @@ void S_StopSound (int channel)
{
FSoundChan *next = chan->NextChan;
if (chan->SourceType == SOURCE_None &&
(chan->EntChannel == channel || (i_compatflags & COMPATF_MAGICSILENCE)))
(chan->EntChannel == channel || (compatflags & COMPATF_MAGICSILENCE)))
{
S_StopChannel(chan);
}
@ -1687,7 +1687,7 @@ void S_StopSound (AActor *actor, int channel)
FSoundChan *next = chan->NextChan;
if (chan->SourceType == SOURCE_Actor &&
chan->Actor == actor &&
(chan->EntChannel == channel || (i_compatflags & COMPATF_MAGICSILENCE)))
(chan->EntChannel == channel || (compatflags & COMPATF_MAGICSILENCE)))
{
S_StopChannel(chan);
}
@ -1711,7 +1711,7 @@ void S_StopSound (const sector_t *sec, int channel)
FSoundChan *next = chan->NextChan;
if (chan->SourceType == SOURCE_Sector &&
chan->Sector == sec &&
(chan->EntChannel == channel || (i_compatflags & COMPATF_MAGICSILENCE)))
(chan->EntChannel == channel || (compatflags & COMPATF_MAGICSILENCE)))
{
S_StopChannel(chan);
}
@ -1735,7 +1735,7 @@ void S_StopSound (const FPolyObj *poly, int channel)
FSoundChan *next = chan->NextChan;
if (chan->SourceType == SOURCE_Polyobj &&
chan->Poly == poly &&
(chan->EntChannel == channel || (i_compatflags & COMPATF_MAGICSILENCE)))
(chan->EntChannel == channel || (compatflags & COMPATF_MAGICSILENCE)))
{
S_StopChannel(chan);
}
@ -1827,7 +1827,7 @@ void S_ChangeSoundVolume(AActor *actor, int channel, double dvolume)
{
if (chan->SourceType == SOURCE_Actor &&
chan->Actor == actor &&
(chan->EntChannel == channel || (i_compatflags & COMPATF_MAGICSILENCE)))
(chan->EntChannel == channel || (compatflags & COMPATF_MAGICSILENCE)))
{
GSnd->ChannelVolume(chan, volume);
chan->Volume = volume;
@ -1933,7 +1933,7 @@ static bool S_IsChannelUsed(AActor *actor, int channel, int *seen)
bool S_IsActorPlayingSomething (AActor *actor, int channel, int sound_id)
{
if (i_compatflags & COMPATF_MAGICSILENCE)
if (compatflags & COMPATF_MAGICSILENCE)
{
channel = 0;
}

View File

@ -6858,9 +6858,7 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build)
int *pVal;
auto cv = static_cast<FFlagCVar *>(CVar);
auto vcv = &cv->ValueVar;
if (vcv == &compatflags) pVal = &i_compatflags;
else if (vcv == &compatflags2) pVal = &i_compatflags2;
else pVal = &vcv->Value;
pVal = &vcv->Value;
build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(pVal));
build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul);
build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum);

View File

@ -1666,6 +1666,34 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, isFrozen, isFrozen)
}
//=====================================================================================
//
// compat flags. These two are the only ones that get checked in script code
// so anything more complex isn't really needed.
//
//=====================================================================================
static int compat_limitpain_(AActor *self)
{
return self->Level->i_compatflags & COMPATF_LIMITPAIN;
}
static int compat_mushroom_(AActor *self)
{
return self->Level->i_compatflags & COMPATF_MUSHROOM;
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, compat_limitpain, compat_limitpain_)
{
PARAM_SELF_PROLOGUE(AActor);
ACTION_RETURN_INT(compat_limitpain_(self));
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, compat_mushroom, compat_mushroom_)
{
PARAM_SELF_PROLOGUE(AActor);
ACTION_RETURN_INT(compat_mushroom_(self));
}
//===========================================================================
//
// PlayerPawn functions

View File

@ -591,7 +591,7 @@ namespace swrenderer
if (mFrontSector->e && mFrontSector->e->XFloor.lightlist.Size()) return true;
if (mBackSector->e && mBackSector->e->XFloor.lightlist.Size()) return true;
if (sidedef->GetTexture(side_t::mid).isValid() && ((ib_compatflags & BCOMPATF_CLIPMIDTEX) || (linedef->flags & (ML_CLIP_MIDTEX | ML_WRAP_MIDTEX)) || sidedef->Flags & (WALLF_CLIP_MIDTEX | WALLF_WRAP_MIDTEX))) return true;
if (sidedef->GetTexture(side_t::mid).isValid() && ((mFrontSector->Level->ib_compatflags & BCOMPATF_CLIPMIDTEX) || (linedef->flags & (ML_CLIP_MIDTEX | ML_WRAP_MIDTEX)) || sidedef->Flags & (WALLF_CLIP_MIDTEX | WALLF_WRAP_MIDTEX))) return true;
return false;
}
@ -653,7 +653,7 @@ namespace swrenderer
if (sidedef->GetTexture(side_t::mid).isValid())
{
if (ib_compatflags & BCOMPATF_CLIPMIDTEX) return true;
if (mFrontSector->Level->ib_compatflags & BCOMPATF_CLIPMIDTEX) return true;
if (linedef->flags & (ML_CLIP_MIDTEX | ML_WRAP_MIDTEX)) return true;
if (sidedef->Flags & (WALLF_CLIP_MIDTEX | WALLF_WRAP_MIDTEX)) return true;
}

View File

@ -150,7 +150,7 @@ namespace swrenderer
return false;
FTexture *ttex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::mid), true);
if (i_compatflags & COMPATF_MASKEDMIDTEX)
if (curline->GetLevel()->i_compatflags & COMPATF_MASKEDMIDTEX)
{
ttex = ttex->GetRawTexture();
}
@ -294,7 +294,7 @@ namespace swrenderer
// this drawseg.
if ((curline->linedef->flags & ML_CLIP_MIDTEX) ||
(curline->sidedef->Flags & WALLF_CLIP_MIDTEX) ||
(ib_compatflags & BCOMPATF_CLIPMIDTEX))
(curline->GetLevel()->ib_compatflags & BCOMPATF_CLIPMIDTEX))
{
ClipMidtex(x1, x2);
}
@ -356,7 +356,7 @@ namespace swrenderer
// this drawseg.
if ((curline->linedef->flags & ML_CLIP_MIDTEX) ||
(curline->sidedef->Flags & WALLF_CLIP_MIDTEX) ||
(ib_compatflags & BCOMPATF_CLIPMIDTEX))
(curline->GetLevel()->ib_compatflags & BCOMPATF_CLIPMIDTEX))
{
ClipMidtex(x1, x2);
}

View File

@ -69,7 +69,7 @@ namespace swrenderer
if (count == 0)
return;
if (!(i_compatflags & COMPATF_SPRITESORT))
if (!(thread->Viewport->Level()->i_compatflags & COMPATF_SPRITESORT))
{
for (unsigned int i = 0; i < count; i++)
SortedSprites[i] = Sprites[first + i];

View File

@ -105,6 +105,7 @@ extend class Actor
{
const FATSPREAD = 90./8;
private native bool compat_mushroom();
void A_FatRaise()
{
@ -195,7 +196,7 @@ extend class Actor
aimtarget.Height = Height;
bool shootmode = ((flags & MSF_Classic) || // Flag explicitly set, or no flags and compat options
(flags == 0 && CurState.bDehacked && compat_mushroom));
(flags == 0 && CurState.bDehacked && compat_mushroom()));
for (i = -numspawns; i <= numspawns; i += 8)
{

View File

@ -62,6 +62,8 @@ class PainElemental : Actor
extend class Actor
{
private native bool compat_limitpain();
//
// A_PainShootSkull
// Spawn a lost soul and launch it at the target
@ -86,7 +88,7 @@ extend class Actor
}
// [RH] make this optional
if (limit < 0 && compat_limitpain)
if (limit < 0 && compat_limitpain())
limit = 21;
if (limit > 0)