Merge branch 'new_level_refactor' into localization

This commit is contained in:
Christoph Oelckers 2019-02-09 12:22:15 +01:00
commit 88e227f1f3
59 changed files with 222 additions and 22367 deletions

View file

@ -33,7 +33,7 @@ build_script:
- md build - md build
- cd build - cd build
- cmake -G "%GENERATOR%" -T "%TOOLSET%" -DPK3_QUIET_ZIPDIR=YES .. - cmake -G "%GENERATOR%" -T "%TOOLSET%" -DPK3_QUIET_ZIPDIR=YES ..
- cmake --build . --config "%CONFIGURATION%" -- /verbosity:minimal - cmake --build . --config "%CONFIGURATION%" -- -maxcpucount -verbosity:minimal
after_build: after_build:
- set OUTPUT_DIR=%APPVEYOR_BUILD_FOLDER%\build\%CONFIGURATION%\ - set OUTPUT_DIR=%APPVEYOR_BUILD_FOLDER%\build\%CONFIGURATION%\

View file

@ -108,11 +108,11 @@ matrix:
- os: windows - os: windows
env: env:
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -A Win32" - CMAKE_OPTIONS="-A Win32"
- os: windows - os: windows
env: env:
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -A x64" - CMAKE_OPTIONS="-A x64"
before_install: before_install:
- if [ -n "$GCC_VERSION" ]; then export CC="gcc-${GCC_VERSION}" CXX="g++-${GCC_VERSION}"; fi - if [ -n "$GCC_VERSION" ]; then export CC="gcc-${GCC_VERSION}" CXX="g++-${GCC_VERSION}"; fi
@ -132,8 +132,8 @@ script:
-DFORCE_INTERNAL_GME=YES \ -DFORCE_INTERNAL_GME=YES \
-DPK3_QUIET_ZIPDIR=YES \ -DPK3_QUIET_ZIPDIR=YES \
.. ..
- if [[ $TRAVIS_OS_NAME == 'windows' ]]; then cmake --build . -- -m; fi - if [[ $TRAVIS_OS_NAME == 'windows' ]]; then cmake --build . --config Release -- -maxcpucount -verbosity:minimal; fi
- if [[ $TRAVIS_OS_NAME != 'windows' ]]; then cmake --build . -- -j2; fi - if [[ $TRAVIS_OS_NAME != 'windows' ]]; then cmake --build . -- --jobs=2 --keep-going; fi
notifications: notifications:
email: false email: false

View file

@ -1,47 +0,0 @@
{
"configurations": [
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "Release",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"variables": [
{
"name": "ZDOOM_GENERATE_ASM",
"value": "True",
"type": "BOOL"
},
{
"name": "ZDOOM_GENERATE_MAPFILE",
"value": "True",
"type": "BOOL"
},
{
"name": "ZDOOM_OUTPUT_OLDSTYLE",
"value": "True",
"type": "BOOL"
},
{
"name": "JPEG_INCLUDE_DIR",
"value": "c:\\Programming\\vcpkg\\packages\\libjpeg-turbo_x64-windows-static\\include\\",
"type": "PATH"
},
{
"name": "JPEG_LIBRARY_DEBUG",
"value": "c:\\Programming\\vcpkg\\packages\\libjpeg-turbo_x64-windows-static\\lib\\jpeg.lib",
"type": "FILEPATH"
},
{
"name": "JPEG_LIBRARY_RELEASE",
"value": "c:\\Programming\\vcpkg\\packages\\libjpeg-turbo_x64-windows-static\\lib\\jpeg.lib",
"type": "FILEPATH"
}
]
}
]
}

21073
externs.txt

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -1,43 +0,0 @@
#pragma once
#include "tarray.h"
#include "r_defs.h"
#include "p_trace.h"
// [ZZ] Destructible geometry related
struct FHealthGroup
{
TArray<sector_t*> sectors;
TArray<line_t*> lines;
int health;
int id;
};
// for P_DamageSector
enum
{
SECPART_Floor = 0,
SECPART_Ceiling = 1,
SECPART_3D = 2
};
void P_SetHealthGroupHealth(FHealthGroup* group, int health);
void P_SetHealthGroupHealth(FLevelLocals *Level, int group, int health);
void P_InitHealthGroups(FLevelLocals *Level);
FHealthGroup* P_GetHealthGroup(FLevelLocals *Level, int id);
FHealthGroup* P_GetHealthGroupOrNew(FLevelLocals *Level, int id, int startinghealth);
void P_DamageSector(sector_t* sector, AActor* source, int damage, FName damagetype, int part, DVector3 position, bool isradius, bool dogroups);
void P_DamageLinedef(line_t* line, AActor* source, int damage, FName damagetype, int side, DVector3 position, bool isradius, bool dogroups);
void P_GeometryLineAttack(FTraceResults& trace, AActor* thing, int damage, FName damageType);
void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage, int bombdistance, FName damagetype, int fulldamagedistance);
bool P_ProjectileHitLinedef(AActor* projectile, line_t* line);
bool P_ProjectileHitPlane(AActor* projectile, int part);
bool P_CheckLinedefVulnerable(line_t* line, int side, int part = -1);
bool P_CheckSectorVulnerable(sector_t* sector, int part);
void P_SerializeHealthGroups(FSerializer& arc);

View file

@ -1422,7 +1422,7 @@ public:
} }
int ApplyDamageFactor(FName damagetype, int damage) const; int ApplyDamageFactor(FName damagetype, int damage) const;
int GetModifiedDamage(FName damagetype, int damage, bool passive); int GetModifiedDamage(FName damagetype, int damage, bool passive, AActor *inflictor, AActor *source, int flags = 0);
void DeleteAttachedLights(); void DeleteAttachedLights();
bool isFrozen(); bool isFrozen();

View file

@ -217,7 +217,7 @@ void EventManager::InitHandler(PClass* type)
RegisterHandler(handler); RegisterHandler(handler);
} }
void EventManager::InitStaticHandlers(bool map) void EventManager::InitStaticHandlers(FLevelLocals *l, bool map)
{ {
// don't initialize map handlers if restoring from savegame. // don't initialize map handlers if restoring from savegame.
if (savegamerestore) if (savegamerestore)
@ -225,6 +225,7 @@ void EventManager::InitStaticHandlers(bool map)
// just make sure // just make sure
Shutdown(); Shutdown();
Level = l;
// initialize event handlers from gameinfo // initialize event handlers from gameinfo
for (const FString& typeName : gameinfo.EventHandlers) for (const FString& typeName : gameinfo.EventHandlers)
@ -241,7 +242,7 @@ void EventManager::InitStaticHandlers(bool map)
return; return;
// initialize event handlers from mapinfo // initialize event handlers from mapinfo
for (const FString& typeName : level.info->EventHandlers) for (const FString& typeName : Level->info->EventHandlers)
{ {
PClass* type = GetHandlerClass(typeName); PClass* type = GetHandlerClass(typeName);
if (IsStaticType(type)) if (IsStaticType(type))
@ -257,6 +258,7 @@ void EventManager::Shutdown()
{ {
handler->Destroy(); handler->Destroy();
} }
FirstEventHandler = LastEventHandler = nullptr;
} }
#define DEFINE_EVENT_LOOPER(name, play) void EventManager::name() \ #define DEFINE_EVENT_LOOPER(name, play) void EventManager::name() \

View file

@ -249,7 +249,7 @@ struct EventManager
// check type // check type
bool IsStaticType(PClass* type); bool IsStaticType(PClass* type);
// init static handlers // init static handlers
void InitStaticHandlers(bool map); void InitStaticHandlers(FLevelLocals *l, bool map);
// shutdown handlers // shutdown handlers
void Shutdown(); void Shutdown();

View file

@ -114,7 +114,7 @@ CCMD (countdecals)
while (iterator.Next()) while (iterator.Next())
count++; count++;
Printf("%s: Counted %d impact decals\n", Level->MapName.GetChars(), count); Printf("%s: Counted %d impact decals, level counter is at %d\n", Level->MapName.GetChars(), count, Level->ImpactDecalCount);
} }
} }

View file

@ -573,7 +573,7 @@ static bool unloading;
EXTERN_CVAR(Bool, sv_singleplayerrespawn) EXTERN_CVAR(Bool, sv_singleplayerrespawn)
void FLevelLocals::ChangeLevel(const char *levelname, int position, int flags, int nextSkill) void FLevelLocals::ChangeLevel(const char *levelname, int position, int inflags, int nextSkill)
{ {
if (!isPrimaryLevel()) return; // only the primary level may exit. if (!isPrimaryLevel()) return; // only the primary level may exit.
@ -630,7 +630,7 @@ void FLevelLocals::ChangeLevel(const char *levelname, int position, int flags, i
if (nextSkill != -1) if (nextSkill != -1)
NextSkill = nextSkill; NextSkill = nextSkill;
if (flags & CHANGELEVEL_NOINTERMISSION) if (inflags & CHANGELEVEL_NOINTERMISSION)
{ {
flags |= LEVEL_NOINTERMISSION; flags |= LEVEL_NOINTERMISSION;
} }
@ -647,15 +647,15 @@ void FLevelLocals::ChangeLevel(const char *levelname, int position, int flags, i
{ {
if (nextinfo->flags2 & LEVEL2_RESETINVENTORY) if (nextinfo->flags2 & LEVEL2_RESETINVENTORY)
{ {
flags |= CHANGELEVEL_RESETINVENTORY; inflags |= CHANGELEVEL_RESETINVENTORY;
} }
if (nextinfo->flags2 & LEVEL2_RESETHEALTH) if (nextinfo->flags2 & LEVEL2_RESETHEALTH)
{ {
flags |= CHANGELEVEL_RESETHEALTH; inflags |= CHANGELEVEL_RESETHEALTH;
} }
} }
} }
changeflags = flags; changeflags = inflags;
BotInfo.End(); //Added by MC: BotInfo.End(); //Added by MC:

View file

@ -618,7 +618,7 @@ public:
bool FromSnapshot; // The current map was restored from a snapshot bool FromSnapshot; // The current map was restored from a snapshot
bool HasHeightSecs; // true if some Transfer_Heights effects are present in the map. If this is false, some checks in the renderer can be shortcut. bool HasHeightSecs; // true if some Transfer_Heights effects are present in the map. If this is false, some checks in the renderer can be shortcut.
bool HasDynamicLights; // Another render optimization for maps with no lights at all. bool HasDynamicLights; // Another render optimization for maps with no lights at all.
uint8_t frozenstate; int frozenstate;
double teamdamage; double teamdamage;

View file

@ -76,6 +76,7 @@ void DDecalFader::Tick ()
} }
else if (Level->maptime >= TimeToEndDecay) else if (Level->maptime >= TimeToEndDecay)
{ {
TheDecal->Expired(); // for impact decal bookkeeping.
TheDecal->Destroy (); // remove the decal TheDecal->Destroy (); // remove the decal
Destroy (); // remove myself Destroy (); // remove myself
return; return;

View file

@ -666,6 +666,8 @@ DBaseDecal *DBaseDecal::CloneSelf (const FDecalTemplate *tpl, double ix, double
void DImpactDecal::CheckMax () void DImpactDecal::CheckMax ()
{ {
static int SpawnCounter;
if (++Level->ImpactDecalCount >= cl_maxdecals) if (++Level->ImpactDecalCount >= cl_maxdecals)
{ {
DThinker *thinker = Level->FirstThinker (STAT_AUTODECAL); DThinker *thinker = Level->FirstThinker (STAT_AUTODECAL);
@ -683,6 +685,17 @@ void DImpactDecal::CheckMax ()
// //
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void DImpactDecal::Expired()
{
Level->ImpactDecalCount--;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color) DImpactDecal *DImpactDecal::StaticCreate (FLevelLocals *Level, const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color)
{ {
if (cl_maxdecals > 0) if (cl_maxdecals > 0)

View file

@ -26,6 +26,7 @@ public:
void Serialize(FSerializer &arc); void Serialize(FSerializer &arc);
void OnDestroy() override; void OnDestroy() override;
virtual void Expired() {} // For thinkers that can remove their decal. For impact decal bookkeeping.
FTextureID StickToWall(side_t *wall, double x, double y, F3DFloor * ffloor); FTextureID StickToWall(side_t *wall, double x, double y, F3DFloor * ffloor);
double GetRealZ (const side_t *wall) const; double GetRealZ (const side_t *wall) const;
void SetShade (uint32_t rgb); void SetShade (uint32_t rgb);
@ -71,6 +72,7 @@ public:
static DImpactDecal *StaticCreate(FLevelLocals *Level, const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0); static DImpactDecal *StaticCreate(FLevelLocals *Level, const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0);
void BeginPlay (); void BeginPlay ();
void Expired() override;
protected: protected:
DBaseDecal *CloneSelf(const FDecalTemplate *tpl, double x, double y, double z, side_t *wall, F3DFloor * ffloor) const; DBaseDecal *CloneSelf(const FDecalTemplate *tpl, double x, double y, double z, side_t *wall, F3DFloor * ffloor) const;

View file

@ -62,13 +62,12 @@
Only one selector of each type can be used. Only one selector of each type can be used.
*/ */
AActor *COPY_AAPTR(AActor *origin, int selector) AActor *COPY_AAPTREX(FLevelLocals *Level, AActor *origin, int selector)
{ {
if (selector == AAPTR_DEFAULT) return origin; if (selector == AAPTR_DEFAULT) return origin;
FTranslatedLineTarget t; FTranslatedLineTarget t;
auto Level = origin->Level;
auto AAPTR_RESOLVE_PLAYERNUM = [=](int playernum) -> AActor* auto AAPTR_RESOLVE_PLAYERNUM = [=](int playernum) -> AActor*
{ {
return (Level->PlayerInGame(playernum) ? Level->Players[playernum]->mo : nullptr); return (Level->PlayerInGame(playernum) ? Level->Players[playernum]->mo : nullptr);
@ -119,6 +118,11 @@ AActor *COPY_AAPTR(AActor *origin, int selector)
return origin; return origin;
} }
AActor *COPY_AAPTR(AActor *origin, int selector)
{
if (origin == nullptr) return nullptr;
return COPY_AAPTREX(origin->Level, origin, selector);
}
// [FDARI] Exported logic for guarding against loops in Target (for missiles) and Master (for all) chains. // [FDARI] Exported logic for guarding against loops in Target (for missiles) and Master (for all) chains.
// It is called from multiple locations. // It is called from multiple locations.

View file

@ -64,8 +64,9 @@ enum AAPTR
Only one selector of each type can be used. Only one selector of each type can be used.
*/ */
struct FLevelLocals;
AActor *COPY_AAPTR(AActor *origin, int selector); AActor *COPY_AAPTR(AActor *origin, int selector);
AActor *COPY_AAPTREX(FLevelLocals *Level, AActor *origin, int selector);
enum PTROP enum PTROP
{ {
PTROP_UNSAFETARGET = 1, PTROP_UNSAFETARGET = 1,

View file

@ -692,6 +692,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
double lowestfloor[2] = { double lowestfloor[2] = {
linedef->frontsector->floorplane.ZatPoint(x, y), linedef->frontsector->floorplane.ZatPoint(x, y),
linedef->backsector->floorplane.ZatPoint(x, y) }; linedef->backsector->floorplane.ZatPoint(x, y) };
bool lowestfloorset[2] = { false, false };
FTextureID highestfloorpic; FTextureID highestfloorpic;
int highestfloorterrain = -1; int highestfloorterrain = -1;
FTextureID lowestceilingpic; FTextureID lowestceilingpic;
@ -741,7 +742,11 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
highestfloorplanes[j] = rover->top.plane; highestfloorplanes[j] = rover->top.plane;
} }
} }
if(ff_top > lowestfloor[j] && ff_top <= thing->Z() + thing->MaxStepHeight) lowestfloor[j] = ff_top; if (ff_top > lowestfloor[j] && ff_top <= thing->Z() + thing->MaxStepHeight)
{
lowestfloor[j] = ff_top;
lowestfloorset[j] = true;
}
} }
} }
@ -771,8 +776,14 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
open.topsec = lowestceilingsec; open.topsec = lowestceilingsec;
open.topffloor = lowestceilingffloor; open.topffloor = lowestceilingffloor;
} }
open.lowfloor = MIN(lowestfloor[0], lowestfloor[1]); // Don't overwrite still valid info from portals here.
if ((open.lowfloorthroughportal & 1) && lowestfloorset[0]) open.lowfloorthroughportal &= ~1;
if ((open.lowfloorthroughportal & 2) && lowestfloorset[1]) open.lowfloorthroughportal &= ~2;
double low1 = (open.lowfloorthroughportal & 1) ? open.lowfloor : lowestfloor[0];
double low2 = (open.lowfloorthroughportal & 2) ? open.lowfloor : lowestfloor[1];
open.lowfloor = MIN(low1, low2);
} }
} }
} }

View file

@ -36,6 +36,7 @@ struct FCheckPosition
TMap<AActor*, bool> LastRipped; TMap<AActor*, bool> LastRipped;
bool DoRipping; bool DoRipping;
bool portalstep; bool portalstep;
bool dropoffisportal;
int portalgroup; int portalgroup;
int PushTime; int PushTime;

View file

@ -195,7 +195,7 @@ DHUDMessage::DHUDMessage (FFont *font, const char *text, float x, float y, int h
HandleAspect = true; HandleAspect = true;
Top = y; Top = y;
HoldTics = (int)(holdTime * TICRATE); HoldTics = (int)(holdTime * TICRATE);
Tics = 0; Tics = -1; // -1 to compensate for one additional Tick the message will receive.
TextColor = textColor; TextColor = textColor;
State = 0; State = 0;
SourceText = copystring (text); SourceText = copystring (text);

View file

@ -201,7 +201,7 @@ enum ELevelFlags : unsigned int
LEVEL2_LAXACTIVATIONMAPINFO = 0x00000008, // LEVEL_LAXMONSTERACTIVATION is not a default. LEVEL2_LAXACTIVATIONMAPINFO = 0x00000008, // LEVEL_LAXMONSTERACTIVATION is not a default.
LEVEL2_MISSILESACTIVATEIMPACT=0x00000010, // Missiles are the activators of SPAC_IMPACT events, not their shooters LEVEL2_MISSILESACTIVATEIMPACT=0x00000010, // Missiles are the activators of SPAC_IMPACT events, not their shooters
LEVEL2_FROZEN = 0x00000020, // Game is frozen by a TimeFreezer // = 0x00000020, // unused
LEVEL2_KEEPFULLINVENTORY = 0x00000040, // doesn't reduce the amount of inventory items to 1 LEVEL2_KEEPFULLINVENTORY = 0x00000040, // doesn't reduce the amount of inventory items to 1

View file

@ -395,7 +395,7 @@ void PClassActor::StaticInit()
InitBotStuff(); InitBotStuff();
// reinit GLOBAL static stuff from gameinfo, once classes are loaded. // reinit GLOBAL static stuff from gameinfo, once classes are loaded.
staticEventManager.InitStaticHandlers(false); staticEventManager.InitStaticHandlers(primaryLevel, false);
} }
//========================================================================== //==========================================================================

View file

@ -1034,7 +1034,7 @@ void MapLoader::SpawnLights(sector_t *sector)
// [RH] Hexen-like phased lighting // [RH] Hexen-like phased lighting
case LightSequenceStart: case LightSequenceStart:
Level->CreateThinker<DPhased>(sector); Level->CreateThinker<DPhased>(sector)->Propagate();
break; break;
case dLight_Flicker: case dLight_Flicker:

View file

@ -3247,7 +3247,7 @@ const char *FBehavior::LookupString (uint32_t index, bool forprint) const
token.Substitute(" ", ""); token.Substitute(" ", "");
token.Truncate(5); token.Truncate(5);
FStringf label("TXT_ACS_%s_%d_%.5s", Level->MapName.GetChars(), index, token); FStringf label("TXT_ACS_%s_%d_%.5s", Level->MapName.GetChars(), index, token.GetChars());
auto p = GStrings[label]; auto p = GStrings[label];
if (p) return p; if (p) return p;
} }
@ -5352,7 +5352,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
AActor *ptr = Level->SingleActorFromTID(args[1], activator); AActor *ptr = Level->SingleActorFromTID(args[1], activator);
if (argCount > 2) if (argCount > 2)
{ {
ptr = COPY_AAPTR(ptr, args[2]); ptr = COPY_AAPTREX(Level, ptr, args[2]);
} }
if (ptr == activator) ptr = NULL; if (ptr == activator) ptr = NULL;
ASSIGN_AAPTR(activator, args[0], ptr, (argCount > 3) ? args[3] : 0); ASSIGN_AAPTR(activator, args[0], ptr, (argCount > 3) ? args[3] : 0);
@ -6326,7 +6326,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
actor = Level->SingleActorFromTID(tid1, activator); actor = Level->SingleActorFromTID(tid1, activator);
AActor * actor2 = tid2 == tid1 ? actor : Level->SingleActorFromTID(tid2, activator); AActor * actor2 = tid2 == tid1 ? actor : Level->SingleActorFromTID(tid2, activator);
return COPY_AAPTR(actor, args[0]) == COPY_AAPTR(actor2, args[1]); return COPY_AAPTREX(Level, actor, args[0]) == COPY_AAPTREX(Level, actor2, args[1]);
} }
break; break;
@ -6504,7 +6504,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
int count = argCount >= 4 ? args[3] : 1; int count = argCount >= 4 ? args[3] : 1;
int flags = argCount >= 5 ? args[4] : 0; int flags = argCount >= 5 ? args[4] : 0;
int ptr = argCount >= 6 ? args[5] : AAPTR_DEFAULT; int ptr = argCount >= 6 ? args[5] : AAPTR_DEFAULT;
return P_Thing_CheckProximity(actor, classname, distance, count, flags, ptr); return P_Thing_CheckProximity(Level, actor, classname, distance, count, flags, ptr);
} }
case ACSF_CheckActorState: case ACSF_CheckActorState:
@ -6528,8 +6528,8 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
case ACSF_DamageActor: // [arookas] wrapper around P_DamageMobj case ACSF_DamageActor: // [arookas] wrapper around P_DamageMobj
{ {
// (target, ptr_select1, inflictor, ptr_select2, amount, damagetype) // (target, ptr_select1, inflictor, ptr_select2, amount, damagetype)
AActor* target = COPY_AAPTR(Level->SingleActorFromTID(args[0], activator), args[1]); AActor* target = COPY_AAPTREX(Level, Level->SingleActorFromTID(args[0], activator), args[1]);
AActor* inflictor = COPY_AAPTR(Level->SingleActorFromTID(args[2], activator), args[3]); AActor* inflictor = COPY_AAPTREX(Level, Level->SingleActorFromTID(args[2], activator), args[3]);
FName damagetype(Level->Behaviors.LookupString(args[5])); FName damagetype(Level->Behaviors.LookupString(args[5]));
return P_DamageMobj(target, inflictor, inflictor, args[4], damagetype); return P_DamageMobj(target, inflictor, inflictor, args[4], damagetype);
} }

View file

@ -485,7 +485,7 @@ DEFINE_ACTION_FUNCTION(AActor, CountProximity)
} }
else else
{ {
ret->SetInt(P_Thing_CheckProximity(self, classname, distance, 0, flags, ptr, true)); ret->SetInt(P_Thing_CheckProximity(self->Level, self, classname, distance, 0, flags, ptr, true));
} }
return 1; return 1;
} }
@ -4520,7 +4520,7 @@ DEFINE_ACTION_FUNCTION(AActor, CheckProximity)
PARAM_INT(flags); PARAM_INT(flags);
PARAM_INT(ptr); PARAM_INT(ptr);
ACTION_RETURN_BOOL(!!P_Thing_CheckProximity(self, classname, distance, count, flags, ptr)); ACTION_RETURN_BOOL(!!P_Thing_CheckProximity(self->Level, self, classname, distance, count, flags, ptr));
} }
/*=========================================================================== /*===========================================================================

View file

@ -351,7 +351,7 @@ static FStrifeDialogueNode *ReadRetailNode (FLevelLocals *Level, const char *nam
if (name) if (name)
{ {
FStringf label("$TXT_DLG_%s_d%d_%s", name, int(pos), TokenFromString(speech.Dialogue)); FStringf label("$TXT_DLG_%s_d%d_%s", name, int(pos), TokenFromString(speech.Dialogue).GetChars());
node->Dialogue = label; node->Dialogue = label;
} }
else else
@ -435,7 +435,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FLevelLocals *Level, const char *nam
// Convert the rest of the data to our own internal format. // Convert the rest of the data to our own internal format.
if (name) if (name)
{ {
FStringf label("$TXT_DLG_%s_d%d_%s", name, pos, TokenFromString(speech.Dialogue)); FStringf label("$TXT_DLG_%s_d%d_%s", name, pos, TokenFromString(speech.Dialogue).GetChars());
node->Dialogue = label; node->Dialogue = label;
} }
else else
@ -545,7 +545,7 @@ static void ParseReplies (const char *name, int pos, FStrifeDialogueReply **repl
if (name) if (name)
{ {
FStringf label("$TXT_RPLY%d_%s_d%d_%s", j, name, pos, TokenFromString(rsp->Reply)); FStringf label("$TXT_RPLY%d_%s_d%d_%s", j, name, pos, TokenFromString(rsp->Reply).GetChars());
reply->Reply = label; reply->Reply = label;
} }
else else
@ -569,7 +569,7 @@ static void ParseReplies (const char *name, int pos, FStrifeDialogueReply **repl
{ {
if (name) if (name)
{ {
FStringf label("$TXT_RYES%d_%s_d%d_%s", j, name, pos, TokenFromString(rsp->Yes)); FStringf label("$TXT_RYES%d_%s_d%d_%s", j, name, pos, TokenFromString(rsp->Yes).GetChars());
reply->QuickYes = label; reply->QuickYes = label;
} }
else else
@ -581,7 +581,7 @@ static void ParseReplies (const char *name, int pos, FStrifeDialogueReply **repl
{ {
if (name && strncmp(rsp->No, "NO. ", 4)) // All 'no' nodes starting with 'NO.' won't ever be shown and they all contain broken text. if (name && strncmp(rsp->No, "NO. ", 4)) // All 'no' nodes starting with 'NO.' won't ever be shown and they all contain broken text.
{ {
FStringf label("$TXT_RNO%d_%s_d%d_%s", j, name, pos, TokenFromString(rsp->No)); FStringf label("$TXT_RNO%d_%s_d%d_%s", j, name, pos, TokenFromString(rsp->No).GetChars());
reply->QuickNo = label; reply->QuickNo = label;
} }
else else

View file

@ -1150,13 +1150,13 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
// Handle active damage modifiers (e.g. PowerDamage) // Handle active damage modifiers (e.g. PowerDamage)
if (damage > 0 && !(flags & DMG_NO_ENHANCE)) if (damage > 0 && !(flags & DMG_NO_ENHANCE))
{ {
damage = source->GetModifiedDamage(mod, damage, false); damage = source->GetModifiedDamage(mod, damage, false, inflictor, source, flags);
} }
} }
// Handle passive damage modifiers (e.g. PowerProtection), provided they are not afflicted with protection penetrating powers. // Handle passive damage modifiers (e.g. PowerProtection), provided they are not afflicted with protection penetrating powers.
if (damage > 0 && !(flags & DMG_NO_PROTECT)) if (damage > 0 && !(flags & DMG_NO_PROTECT))
{ {
damage = target->GetModifiedDamage(mod, damage, true); damage = target->GetModifiedDamage(mod, damage, true, inflictor, source, flags);
} }
if (damage > 0 && !(flags & DMG_NO_FACTOR)) if (damage > 0 && !(flags & DMG_NO_FACTOR))
{ {
@ -1747,7 +1747,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPain
// Take half damage in trainer mode // Take half damage in trainer mode
damage = int(damage * G_SkillProperty(SKILLP_DamageFactor) * sv_damagefactorplayer); damage = int(damage * G_SkillProperty(SKILLP_DamageFactor) * sv_damagefactorplayer);
// Handle passive damage modifiers (e.g. PowerProtection) // Handle passive damage modifiers (e.g. PowerProtection)
damage = target->GetModifiedDamage(player->poisontype, damage, true); damage = target->GetModifiedDamage(player->poisontype, damage, true, nullptr, source);
// Modify with damage factors // Modify with damage factors
damage = target->ApplyDamageFactor(player->poisontype, damage); damage = target->ApplyDamageFactor(player->poisontype, damage);

View file

@ -148,7 +148,8 @@ PClassActor *P_GetSpawnableType(int spawnnum);
void InitSpawnablesFromMapinfo(); void InitSpawnablesFromMapinfo();
int P_Thing_CheckInputNum(player_t *p, int inputnum); int P_Thing_CheckInputNum(player_t *p, int inputnum);
int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch); int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch);
int P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr, bool counting = false); struct FLevelLocals;
int P_Thing_CheckProximity(FLevelLocals *Level, AActor *self, PClass *classname, double distance, int count, int flags, int ptr, bool counting = false);
enum enum
{ {

View file

@ -280,6 +280,7 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags)
tmf.ceilingz = NextHighestCeilingAt(sec, tmf.pos.X, tmf.pos.Y, tmf.pos.Z, tmf.pos.Z + tmf.thing->Height, flags, &tmf.ceilingsector, &ffc); tmf.ceilingz = NextHighestCeilingAt(sec, tmf.pos.X, tmf.pos.Y, tmf.pos.Z, tmf.pos.Z + tmf.thing->Height, flags, &tmf.ceilingsector, &ffc);
tmf.floorz = tmf.dropoffz = NextLowestFloorAt(sec, tmf.pos.X, tmf.pos.Y, tmf.pos.Z, flags, tmf.thing->MaxStepHeight, &tmf.floorsector, &fff); tmf.floorz = tmf.dropoffz = NextLowestFloorAt(sec, tmf.pos.X, tmf.pos.Y, tmf.pos.Z, flags, tmf.thing->MaxStepHeight, &tmf.floorsector, &fff);
tmf.dropoffisportal = tmf.floorsector != sec;
if (fff) if (fff)
{ {
@ -1018,7 +1019,12 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
if (open.lowfloor < tm.dropoffz) if (open.lowfloor < tm.dropoffz)
{ {
tm.dropoffz = open.lowfloor; // Do not alter the dropoff if the previous portal layer got it solely from its own data.
if (!(cres.portalflags & FFCF_NOCEILING) || tm.dropoffisportal)
{
tm.dropoffz = open.lowfloor;
tm.dropoffisportal = open.lowfloorthroughportal;
}
} }
} }
} }
@ -1680,6 +1686,7 @@ bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, boo
else else
{ {
tm.floorz = tm.dropoffz = newsec->floorplane.ZatPoint(pos); tm.floorz = tm.dropoffz = newsec->floorplane.ZatPoint(pos);
tm.dropoffisportal = false;
tm.floorpic = newsec->GetTexture(sector_t::floor); tm.floorpic = newsec->GetTexture(sector_t::floor);
tm.ceilingz = newsec->ceilingplane.ZatPoint(pos); tm.ceilingz = newsec->ceilingplane.ZatPoint(pos);
tm.ceilingpic = newsec->GetTexture(sector_t::ceiling); tm.ceilingpic = newsec->GetTexture(sector_t::ceiling);
@ -1704,6 +1711,7 @@ bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, boo
if (ff_top > tm.floorz && fabs(delta1) < fabs(delta2)) if (ff_top > tm.floorz && fabs(delta1) < fabs(delta2))
{ {
tm.floorz = tm.dropoffz = ff_top; tm.floorz = tm.dropoffz = ff_top;
tm.dropoffisportal = false;
tm.floorpic = *rover->top.texture; tm.floorpic = *rover->top.texture;
tm.floorterrain = rover->model->GetTerrain(rover->top.isceiling); tm.floorterrain = rover->model->GetTerrain(rover->top.isceiling);
} }

View file

@ -177,12 +177,17 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, co
bool usefront; bool usefront;
// Store portal state to avoid registering false dropoffs.
open.lowfloorthroughportal = 0;
if (ff == LINEOPEN_MIN) open.lowfloorthroughportal |= 1;
if (bf == LINEOPEN_MIN) open.lowfloorthroughportal |= 2;
// [RH] fudge a bit for actors that are moving across lines // [RH] fudge a bit for actors that are moving across lines
// bordering a slope/non-slope that meet on the floor. Note // bordering a slope/non-slope that meet on the floor. Note
// that imprecisions in the plane equation mean there is a // that imprecisions in the plane equation mean there is a
// good chance that even if a slope and non-slope look like // good chance that even if a slope and non-slope look like
// they line up, they won't be perfectly aligned. // they line up, they won't be perfectly aligned.
if (ff == -FLT_MIN || bf == -FLT_MIN || ref == NULL || fabs (ff-bf) > 1./256) if (ff == LINEOPEN_MIN || bf == LINEOPEN_MIN || ref == NULL || fabs (ff-bf) > 1./256)
{ {
usefront = (ff > bf); usefront = (ff > bf);
} }
@ -196,6 +201,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, co
usefront = !P_PointOnLineSide (*ref, linedef); usefront = !P_PointOnLineSide (*ref, linedef);
} }
open.lowfloorthroughportal = false;
if (usefront) if (usefront)
{ {
open.bottom = ff; open.bottom = ff;

View file

@ -111,6 +111,7 @@ struct FLineOpening
int floorterrain; int floorterrain;
bool touchmidtex; bool touchmidtex;
bool abovemidtex; bool abovemidtex;
uint8_t lowfloorthroughportal;
F3DFloor *topffloor; F3DFloor *topffloor;
F3DFloor *bottomffloor; F3DFloor *bottomffloor;
}; };

View file

@ -4977,7 +4977,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag
mobj = Spawn (this, p->cls, spawn, NO_REPLACE); mobj = Spawn (this, p->cls, spawn, NO_REPLACE);
if (flags & LEVEL_USEPLAYERSTARTZ) if (this->flags & LEVEL_USEPLAYERSTARTZ)
{ {
if (spawn.Z == ONFLOORZ) if (spawn.Z == ONFLOORZ)
mobj->AddZ(mthing->pos.Z); mobj->AddZ(mthing->pos.Z);
@ -7217,15 +7217,15 @@ void AActor::ClearCounters()
} }
} }
int AActor::GetModifiedDamage(FName damagetype, int damage, bool passive) int AActor::GetModifiedDamage(FName damagetype, int damage, bool passive, AActor *inflictor, AActor *source, int flags)
{ {
auto inv = Inventory; auto inv = Inventory;
while (inv != nullptr) while (inv != nullptr)
{ {
IFVIRTUALPTRNAME(inv, NAME_Inventory, ModifyDamage) IFVIRTUALPTRNAME(inv, NAME_Inventory, ModifyDamage)
{ {
VMValue params[5] = { (DObject*)inv, damage, int(damagetype), &damage, passive }; VMValue params[8] = { (DObject*)inv, damage, int(damagetype), &damage, passive, inflictor, source, flags };
VMCall(func, params, 5, nullptr, 0); VMCall(func, params, 8, nullptr, 0);
} }
inv = inv->Inventory; inv = inv->Inventory;
} }

View file

@ -964,7 +964,6 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload)
("spotstate", SpotState) ("spotstate", SpotState)
("fragglethinker", FraggleScriptThinker) ("fragglethinker", FraggleScriptThinker)
("acsthinker", ACSThinker) ("acsthinker", ACSThinker)
("impactdecalcount", ImpactDecalCount)
("scrolls", Scrolls) ("scrolls", Scrolls)
("automap", automap) ("automap", automap)
("interpolator", interpolator) ("interpolator", interpolator)
@ -1015,7 +1014,7 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload)
if (arc.isReading()) if (arc.isReading())
{ {
for (auto &sec : sectors) for (auto &sec : sectors)
{ {
P_Recalculate3DFloors(&sec); P_Recalculate3DFloors(&sec);
} }
for (int i = 0; i < MAXPLAYERS; ++i) for (int i = 0; i < MAXPLAYERS; ++i)
@ -1029,6 +1028,10 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload)
RecreateAllAttachedLights(); RecreateAllAttachedLights();
InitPortalGroups(this); InitPortalGroups(this);
auto it = GetThinkerIterator<DImpactDecal>(NAME_None, STAT_AUTODECAL);
ImpactDecalCount = 0;
while (it.Next()) ImpactDecalCount++;
automap->UpdateShowAllLines(); automap->UpdateShowAllLines();
} }

View file

@ -423,7 +423,7 @@ void P_SetupLevel(FLevelLocals *Level, int position, bool newGame)
// [ZZ] init per-map static handlers. we need to call this before everything is set up because otherwise scripts don't receive PlayerEntered event // [ZZ] init per-map static handlers. we need to call this before everything is set up because otherwise scripts don't receive PlayerEntered event
// (which happens at god-knows-what stage in this function, but definitely not the last part, because otherwise it'd work to put E_InitStaticHandlers before the player spawning) // (which happens at god-knows-what stage in this function, but definitely not the last part, because otherwise it'd work to put E_InitStaticHandlers before the player spawning)
Level->localEventManager->InitStaticHandlers(true); Level->localEventManager->InitStaticHandlers(Level, true);
// generate a checksum for the level, to be included and checked with savegames. // generate a checksum for the level, to be included and checked with savegames.
map->GetChecksum(Level->md5); map->GetChecksum(Level->md5);

View file

@ -567,9 +567,9 @@ int P_Thing_CheckInputNum(player_t *p, int inputnum)
} }
return renum; return renum;
} }
int P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr, bool counting) int P_Thing_CheckProximity(FLevelLocals *Level, AActor *self, PClass *classname, double distance, int count, int flags, int ptr, bool counting)
{ {
AActor *ref = COPY_AAPTR(self, ptr); AActor *ref = COPY_AAPTREX(Level, self, ptr);
// We need these to check out. // We need these to check out.
if (!ref || !classname || distance <= 0) if (!ref || !classname || distance <= 0)

View file

@ -858,29 +858,41 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor
if (DEarthquake::StaticGetQuakeIntensities(viewpoint.TicFrac, viewpoint.camera, jiggers) > 0) if (DEarthquake::StaticGetQuakeIntensities(viewpoint.TicFrac, viewpoint.camera, jiggers) > 0)
{ {
double quakefactor = r_quakeintensity; double quakefactor = r_quakeintensity;
DAngle an; DVector3 pos; pos.Zero();
if (jiggers.RollIntensity != 0 || jiggers.RollWave != 0) if (jiggers.RollIntensity != 0 || jiggers.RollWave != 0)
{ {
viewpoint.Angles.Roll += QuakePower(quakefactor, jiggers.RollIntensity, jiggers.RollWave); viewpoint.Angles.Roll += QuakePower(quakefactor, jiggers.RollIntensity, jiggers.RollWave);
} }
if (jiggers.RelIntensity.X != 0 || jiggers.RelOffset.X != 0) if (jiggers.RelIntensity.X != 0 || jiggers.RelOffset.X != 0)
{ {
an = viewpoint.camera->Angles.Yaw; pos.X += QuakePower(quakefactor, jiggers.RelIntensity.X, jiggers.RelOffset.X);
double power = QuakePower(quakefactor, jiggers.RelIntensity.X, jiggers.RelOffset.X);
viewpoint.Pos += an.ToVector(power);
} }
if (jiggers.RelIntensity.Y != 0 || jiggers.RelOffset.Y != 0) if (jiggers.RelIntensity.Y != 0 || jiggers.RelOffset.Y != 0)
{ {
an = viewpoint.camera->Angles.Yaw + 90; pos.Y += QuakePower(quakefactor, jiggers.RelIntensity.Y, jiggers.RelOffset.Y);
double power = QuakePower(quakefactor, jiggers.RelIntensity.Y, jiggers.RelOffset.Y);
viewpoint.Pos += an.ToVector(power);
} }
// FIXME: Relative Z is not relative
if (jiggers.RelIntensity.Z != 0 || jiggers.RelOffset.Z != 0) if (jiggers.RelIntensity.Z != 0 || jiggers.RelOffset.Z != 0)
{ {
viewpoint.Pos.Z += QuakePower(quakefactor, jiggers.RelIntensity.Z, jiggers.RelOffset.Z); pos.Z += QuakePower(quakefactor, jiggers.RelIntensity.Z, jiggers.RelOffset.Z);
} }
// [MC] Tremendous thanks to Marisa Kirisame for helping me with this.
// Use a rotation matrix to make the view relative.
if (!pos.isZero())
{
DAngle yaw = viewpoint.camera->Angles.Yaw;
DAngle pitch = viewpoint.camera->Angles.Pitch;
DAngle roll = viewpoint.camera->Angles.Roll;
DVector3 relx, rely, relz;
DMatrix3x3 rot =
DMatrix3x3(DVector3(0., 0., 1.), yaw.Cos(), yaw.Sin()) *
DMatrix3x3(DVector3(0., 1., 0.), pitch.Cos(), pitch.Sin()) *
DMatrix3x3(DVector3(1., 0., 0.), roll.Cos(), roll.Sin());
relx = DVector3(1., 0., 0.)*rot;
rely = DVector3(0., 1., 0.)*rot;
relz = DVector3(0., 0., 1.)*rot;
viewpoint.Pos += relx * pos.X + rely * pos.Y + relz * pos.Z;
}
if (jiggers.Intensity.X != 0 || jiggers.Offset.X != 0) if (jiggers.Intensity.X != 0 || jiggers.Offset.X != 0)
{ {
viewpoint.Pos.X += QuakePower(quakefactor, jiggers.Intensity.X, jiggers.Offset.X); viewpoint.Pos.X += QuakePower(quakefactor, jiggers.Intensity.X, jiggers.Offset.X);

View file

@ -95,7 +95,7 @@ namespace swrenderer
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// Changes how rapidly things get dark with distance // Changes how rapidly things get dark with distance
void LightVisibility::SetVisibility(RenderViewport *viewport, double vis) void LightVisibility::SetVisibility(RenderViewport *viewport, double vis, bool nolightfade)
{ {
vis = R_ClampVisibility(vis); vis = R_ClampVisibility(vis);
@ -140,7 +140,7 @@ namespace swrenderer
TiltVisibility = float(vis * viewport->viewwindow.FocalTangent * (16.f * 320.f) / viewwidth); TiltVisibility = float(vis * viewport->viewwindow.FocalTangent * (16.f * 320.f) / viewwidth);
NoLightFade = !!(viewport->Level()->flags3 & LEVEL3_NOLIGHTFADE); NoLightFade = nolightfade;
} }
fixed_t LightVisibility::LightLevelToShadeImpl(RenderViewport *viewport, int lightlevel, bool foggy) fixed_t LightVisibility::LightLevelToShadeImpl(RenderViewport *viewport, int lightlevel, bool foggy)

View file

@ -77,7 +77,7 @@ namespace swrenderer
class LightVisibility class LightVisibility
{ {
public: public:
void SetVisibility(RenderViewport *viewport, double visibility); void SetVisibility(RenderViewport *viewport, double visibility, bool nolightfade);
double GetVisibility() const { return CurrentVisibility; } double GetVisibility() const { return CurrentVisibility; }
// The vis value to pass into the GETPALOOKUP or LIGHTSCALE macros // The vis value to pass into the GETPALOOKUP or LIGHTSCALE macros

View file

@ -118,6 +118,7 @@ namespace swrenderer
double savedvisibility = Thread->Light->GetVisibility(); double savedvisibility = Thread->Light->GetVisibility();
AActor *savedcamera = Thread->Viewport->viewpoint.camera; AActor *savedcamera = Thread->Viewport->viewpoint.camera;
sector_t *savedsector = Thread->Viewport->viewpoint.sector; sector_t *savedsector = Thread->Viewport->viewpoint.sector;
auto Level = Thread->Viewport->Level();
for (VisiblePlane *pl = planes->PopFirstPortalPlane(); pl != nullptr; pl = planes->PopFirstPortalPlane()) for (VisiblePlane *pl = planes->PopFirstPortalPlane(); pl != nullptr; pl = planes->PopFirstPortalPlane())
{ {
@ -137,7 +138,7 @@ namespace swrenderer
// Don't let gun flashes brighten the sky box // Don't let gun flashes brighten the sky box
AActor *sky = port->mSkybox; AActor *sky = port->mSkybox;
Thread->Viewport->viewpoint.extralight = 0; Thread->Viewport->viewpoint.extralight = 0;
Thread->Light->SetVisibility(Thread->Viewport.get(), sky->args[0] * 0.25f); Thread->Light->SetVisibility(Thread->Viewport.get(), sky->args[0] * 0.25f, !!(Level->flags3 & LEVEL3_NOLIGHTFADE));
Thread->Viewport->viewpoint.Pos = sky->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac); Thread->Viewport->viewpoint.Pos = sky->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac);
Thread->Viewport->viewpoint.Angles.Yaw = savedangles.Yaw + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * Thread->Viewport->viewpoint.TicFrac); Thread->Viewport->viewpoint.Angles.Yaw = savedangles.Yaw + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * Thread->Viewport->viewpoint.TicFrac);
@ -150,7 +151,7 @@ namespace swrenderer
case PORTS_PORTAL: case PORTS_PORTAL:
case PORTS_LINKEDPORTAL: case PORTS_LINKEDPORTAL:
Thread->Viewport->viewpoint.extralight = pl->extralight; Thread->Viewport->viewpoint.extralight = pl->extralight;
Thread->Light->SetVisibility(Thread->Viewport.get(), pl->visibility); Thread->Light->SetVisibility(Thread->Viewport.get(), pl->visibility, !!(Level->flags3 & LEVEL3_NOLIGHTFADE));
Thread->Viewport->viewpoint.Pos.X = pl->viewpos.X + port->mDisplacement.X; Thread->Viewport->viewpoint.Pos.X = pl->viewpos.X + port->mDisplacement.X;
Thread->Viewport->viewpoint.Pos.Y = pl->viewpos.Y + port->mDisplacement.Y; Thread->Viewport->viewpoint.Pos.Y = pl->viewpos.Y + port->mDisplacement.Y;
Thread->Viewport->viewpoint.Pos.Z = pl->viewpos.Z; Thread->Viewport->viewpoint.Pos.Z = pl->viewpos.Z;
@ -167,8 +168,6 @@ namespace swrenderer
continue; continue;
} }
auto Level = Thread->Viewport->Level();
SetInSkyBox(port); SetInSkyBox(port);
if (port->mPartner > 0) SetInSkyBox(&Level->sectorPortals[port->mPartner]); if (port->mPartner > 0) SetInSkyBox(&Level->sectorPortals[port->mPartner]);
Thread->Viewport->viewpoint.camera = nullptr; Thread->Viewport->viewpoint.camera = nullptr;
@ -256,7 +255,7 @@ namespace swrenderer
Thread->Viewport->viewpoint.camera = savedcamera; Thread->Viewport->viewpoint.camera = savedcamera;
Thread->Viewport->viewpoint.sector = savedsector; Thread->Viewport->viewpoint.sector = savedsector;
Thread->Viewport->viewpoint.Pos = savedpos; Thread->Viewport->viewpoint.Pos = savedpos;
Thread->Light->SetVisibility(Thread->Viewport.get(), savedvisibility); Thread->Light->SetVisibility(Thread->Viewport.get(), savedvisibility, !!(Level->flags3 & LEVEL3_NOLIGHTFADE));
Thread->Viewport->viewpoint.extralight = savedextralight; Thread->Viewport->viewpoint.extralight = savedextralight;
Thread->Viewport->viewpoint.Angles = savedangles; Thread->Viewport->viewpoint.Angles = savedangles;
Thread->Viewport->viewpoint.SetViewAngle(Thread->Viewport->viewwindow); Thread->Viewport->viewpoint.SetViewAngle(Thread->Viewport->viewwindow);

View file

@ -102,7 +102,7 @@ namespace swrenderer
int height = SCREENHEIGHT; int height = SCREENHEIGHT;
float trueratio; float trueratio;
ActiveRatio(width, height, &trueratio); ActiveRatio(width, height, &trueratio);
viewport->SetViewport(MainThread(), width, height, trueratio); viewport->SetViewport(player->camera->Level, MainThread(), width, height, trueratio);
r_modelscene = r_models && Models.Size() > 0; r_modelscene = r_models && Models.Size() > 0;
if (r_modelscene) if (r_modelscene)
@ -379,7 +379,7 @@ namespace swrenderer
viewwindowx = x; viewwindowx = x;
viewwindowy = y; viewwindowy = y;
viewactive = true; viewactive = true;
viewport->SetViewport(MainThread(), width, height, MainThread()->Viewport->viewwindow.WidescreenRatio); viewport->SetViewport(actor->Level, MainThread(), width, height, MainThread()->Viewport->viewwindow.WidescreenRatio);
if (r_modelscene) if (r_modelscene)
PolyTriangleDrawer::ResizeBuffers(viewport->RenderTarget); PolyTriangleDrawer::ResizeBuffers(viewport->RenderTarget);

View file

@ -95,7 +95,7 @@ namespace swrenderer
return Mat4f::Frustum(-width, width, -height + offset, height + offset, near, far, Handedness::Right, ClipZRange::NegativePositiveW); return Mat4f::Frustum(-width, width, -height + offset, height + offset, near, far, Handedness::Right, ClipZRange::NegativePositiveW);
} }
void RenderViewport::SetViewport(RenderThread *thread, int fullWidth, int fullHeight, float trueratio) void RenderViewport::SetViewport(FLevelLocals *Level, RenderThread *thread, int fullWidth, int fullHeight, float trueratio)
{ {
int virtheight, virtwidth, virtwidth2, virtheight2; int virtheight, virtwidth, virtwidth2, virtheight2;
@ -135,7 +135,7 @@ namespace swrenderer
virtwidth = virtwidth * AspectMultiplier(viewwindow.WidescreenRatio) / 48; virtwidth = virtwidth * AspectMultiplier(viewwindow.WidescreenRatio) / 48;
} }
double ypixelstretch = (Level()->info) ? Level()->info->pixelstretch : 1.2; double ypixelstretch = (Level->info) ? Level->info->pixelstretch : 1.2;
BaseYaspectMul = 320.0 * virtheight2 / (r_Yaspect * virtwidth2); BaseYaspectMul = 320.0 * virtheight2 / (r_Yaspect * virtwidth2);
YaspectMul = 320.0 * virtheight / (r_Yaspect * virtwidth) * ypixelstretch / 1.2; YaspectMul = 320.0 * virtheight / (r_Yaspect * virtwidth) * ypixelstretch / 1.2;
@ -150,7 +150,7 @@ namespace swrenderer
InitTextureMapping(); InitTextureMapping();
// Reset r_*Visibility vars // Reset r_*Visibility vars
thread->Light->SetVisibility(this, r_visibility); thread->Light->SetVisibility(this, r_visibility, !!(Level->flags3 & LEVEL3_NOLIGHTFADE));
SetupBuffer(); SetupBuffer();
} }

View file

@ -20,7 +20,7 @@ namespace swrenderer
RenderViewport(); RenderViewport();
~RenderViewport(); ~RenderViewport();
void SetViewport(RenderThread *thread, int width, int height, float trueratio); void SetViewport(FLevelLocals *Level, RenderThread *thread, int width, int height, float trueratio);
void SetupFreelook(); void SetupFreelook();
void SetupPolyViewport(RenderThread *thread); void SetupPolyViewport(RenderThread *thread);

View file

@ -2106,7 +2106,7 @@ public:
: FxExpression(EFX_Nop, p) : FxExpression(EFX_Nop, p)
{ {
isresolved = true; isresolved = true;
ValueType = TypeError; ValueType = TypeVoid;
} }
ExpEmit Emit(VMFunctionBuilder *build) ExpEmit Emit(VMFunctionBuilder *build)
{ {

View file

@ -2797,9 +2797,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, isFrozen, isFrozen)
void setFrozen(FLevelLocals *self, int on) void setFrozen(FLevelLocals *self, int on)
{ {
self->frozenstate = (self->frozenstate & ~1) | !!on; self->frozenstate = (self->frozenstate & ~1) | !!on;
// For compatibility. The engine itself never checks this.
if (on) self->flags2 |= LEVEL2_FROZEN;
else self->flags2 &= ~LEVEL2_FROZEN;
} }
DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, setFrozen, setFrozen) DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, setFrozen, setFrozen)
@ -2889,6 +2886,9 @@ DEFINE_FIELD(FLevelLocals, outsidefogdensity)
DEFINE_FIELD(FLevelLocals, skyfog) DEFINE_FIELD(FLevelLocals, skyfog)
DEFINE_FIELD(FLevelLocals, pixelstretch) DEFINE_FIELD(FLevelLocals, pixelstretch)
DEFINE_FIELD(FLevelLocals, deathsequence) DEFINE_FIELD(FLevelLocals, deathsequence)
DEFINE_FIELD_BIT(FLevelLocals, frozenstate, frozen, 1) // still needed for backwards compatibility.
DEFINE_FIELD_NAMED(FLevelLocals, i_compatflags, compatflags)
DEFINE_FIELD_NAMED(FLevelLocals, i_compatflags2, compatflags2)
DEFINE_FIELD_BIT(FLevelLocals, flags, noinventorybar, LEVEL_NOINVENTORYBAR) DEFINE_FIELD_BIT(FLevelLocals, flags, noinventorybar, LEVEL_NOINVENTORYBAR)
DEFINE_FIELD_BIT(FLevelLocals, flags, monsterstelefrag, LEVEL_MONSTERSTELEFRAG) DEFINE_FIELD_BIT(FLevelLocals, flags, monsterstelefrag, LEVEL_MONSTERSTELEFRAG)
@ -2901,7 +2901,6 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, checkswitchrange, LEVEL2_CHECKSWITCHRANGE
DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND) DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND)
DEFINE_FIELD_BIT(FLevelLocals, flags2, allowrespawn, LEVEL2_ALLOWRESPAWN) DEFINE_FIELD_BIT(FLevelLocals, flags2, allowrespawn, LEVEL2_ALLOWRESPAWN)
DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS) DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS)
DEFINE_FIELD_BIT(FLevelLocals, flags2, frozen, LEVEL2_FROZEN)
DEFINE_FIELD_BIT(FLevelLocals, flags2, infinite_flight, LEVEL2_INFINITE_FLIGHT) DEFINE_FIELD_BIT(FLevelLocals, flags2, infinite_flight, LEVEL2_INFINITE_FLIGHT)
DEFINE_FIELD_BIT(FLevelLocals, flags2, no_dlg_freeze, LEVEL2_CONV_SINGLE_UNFREEZE) DEFINE_FIELD_BIT(FLevelLocals, flags2, no_dlg_freeze, LEVEL2_CONV_SINGLE_UNFREEZE)
DEFINE_FIELD_BIT(FLevelLocals, flags2, keepfullinventory, LEVEL2_KEEPFULLINVENTORY) DEFINE_FIELD_BIT(FLevelLocals, flags2, keepfullinventory, LEVEL2_KEEPFULLINVENTORY)

View file

@ -799,9 +799,9 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, ClearCounters, ClearCounters)
return 0; return 0;
} }
static int GetModifiedDamage(AActor *self, int type, int damage, bool passive) static int GetModifiedDamage(AActor *self, int type, int damage, bool passive, AActor *inflictor, AActor *source, int flags)
{ {
return self->GetModifiedDamage(ENamedName(type), damage, passive); return self->GetModifiedDamage(ENamedName(type), damage, passive, inflictor, source, flags);
} }
DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetModifiedDamage, GetModifiedDamage) DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetModifiedDamage, GetModifiedDamage)
@ -810,7 +810,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetModifiedDamage, GetModifiedDamage)
PARAM_NAME(type); PARAM_NAME(type);
PARAM_INT(damage); PARAM_INT(damage);
PARAM_BOOL(passive); PARAM_BOOL(passive);
ACTION_RETURN_INT(self->GetModifiedDamage(type, damage, passive)); PARAM_OBJECT(inflictor, AActor);
PARAM_OBJECT(source, AActor);
PARAM_INT(flags);
ACTION_RETURN_INT(self->GetModifiedDamage(type, damage, passive, inflictor, source, flags));
} }
static int ApplyDamageFactor(AActor *self, int type, int damage) static int ApplyDamageFactor(AActor *self, int type, int damage)
@ -1666,34 +1669,6 @@ 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 // PlayerPawn functions

View file

@ -271,7 +271,7 @@ bool DInterBackground::LoadBackground(bool isenterpic)
texture.SetInvalid(); texture.SetInvalid();
level_info_t * li = FindLevelInfo(wbs->current); level_info_t * li = FindLevelInfo(wbs->current);
if (li != nullptr) exitpic = li->EnterPic; if (li != nullptr) exitpic = li->ExitPic;
lumpname = exitpic; lumpname = exitpic;
if (isenterpic) if (isenterpic)

View file

@ -651,7 +651,7 @@ class Actor : Thinker native
native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget); native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget);
native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false); native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false);
native int ApplyDamageFactor(Name damagetype, int damage); native int ApplyDamageFactor(Name damagetype, int damage);
native int GetModifiedDamage(Name damagetype, int damage, bool passive); native int GetModifiedDamage(Name damagetype, int damage, bool passive, Actor inflictor = null, Actor source = null, int flags = 0);
native bool CheckBossDeath(); native bool CheckBossDeath();
void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); } void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); }

View file

@ -630,7 +630,7 @@ extend class Actor
Actor mo; Actor mo;
double spawnz = 0; double spawnz = 0;
if (!compat_notossdrops) if (!(Level.compatflags & COMPATF_NOTOSSDROPS))
{ {
int style = sv_dropstyle; int style = sv_dropstyle;
if (style == 0) if (style == 0)
@ -651,7 +651,7 @@ extend class Actor
{ {
mo.bDropped = true; mo.bDropped = true;
mo.bNoGravity = false; // [RH] Make sure it is affected by gravity mo.bNoGravity = false; // [RH] Make sure it is affected by gravity
if (!compat_notossdrops) if (!(Level.compatflags & COMPATF_NOTOSSDROPS))
{ {
mo.TossItem (); mo.TossItem ();
} }

View file

@ -691,6 +691,8 @@ struct LevelLocals native
native readonly int skyfog; native readonly int skyfog;
native readonly float pixelstretch; native readonly float pixelstretch;
native name deathsequence; native name deathsequence;
native readonly int compatflags;
native readonly int compatflags2;
// level_info_t *info cannot be done yet. // level_info_t *info cannot be done yet.
native String GetUDMFString(int type, int index, Name key); native String GetUDMFString(int type, int index, Name key);

View file

@ -1295,3 +1295,47 @@ enum EChangeLevelFlags
CHANGELEVEL_PRERAISEWEAPON = 64, CHANGELEVEL_PRERAISEWEAPON = 64,
}; };
// [RH] Compatibility flags.
enum ECompatFlags
{
COMPATF_SHORTTEX = 1 << 0, // Use Doom's shortest texture around behavior?
COMPATF_STAIRINDEX = 1 << 1, // Don't fix loop index for stair building?
COMPATF_LIMITPAIN = 1 << 2, // Pain elemental is limited to 20 lost souls?
COMPATF_SILENTPICKUP = 1 << 3, // Pickups are only heard locally?
COMPATF_NO_PASSMOBJ = 1 << 4, // Pretend every actor is infinitely tall?
COMPATF_MAGICSILENCE = 1 << 5, // Limit actors to one sound at a time?
COMPATF_WALLRUN = 1 << 6, // Enable buggier wall clipping so players can wallrun?
COMPATF_NOTOSSDROPS = 1 << 7, // Spawn dropped items directly on the floor?
COMPATF_USEBLOCKING = 1 << 8, // Any special line can block a use line
COMPATF_NODOORLIGHT = 1 << 9, // Don't do the BOOM local door light effect
COMPATF_RAVENSCROLL = 1 << 10, // Raven's scrollers use their original carrying speed
COMPATF_SOUNDTARGET = 1 << 11, // Use sector based sound target code.
COMPATF_DEHHEALTH = 1 << 12, // Limit deh.MaxHealth to the health bonus (as in Doom2.exe)
COMPATF_TRACE = 1 << 13, // Trace ignores lines with the same sector on both sides
COMPATF_DROPOFF = 1 << 14, // Monsters cannot move when hanging over a dropoff
COMPATF_BOOMSCROLL = 1 << 15, // Scrolling sectors are additive like in Boom
COMPATF_INVISIBILITY = 1 << 16, // Monsters can see semi-invisible players
COMPATF_SILENT_INSTANT_FLOORS = 1<<17, // Instantly moving floors are not silent
COMPATF_SECTORSOUNDS = 1 << 18, // Sector sounds use original method for sound origin.
COMPATF_MISSILECLIP = 1 << 19, // Use original Doom heights for clipping against projectiles
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 mods.
COMPATF_MBFMONSTERMOVE = 1 << 24, // Monsters are affected by friction and pushers/pullers.
COMPATF_CORPSEGIBS = 1 << 25, // Crushed monsters are turned into gibs, rather than replaced by gibs.
COMPATF_NOBLOCKFRIENDS = 1 << 26, // Friendly monsters aren't blocked by monster-blocking lines.
COMPATF_SPRITESORT = 1 << 27, // Invert sprite sorting order for sprites of equal distance
COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap anf hit check code.
COMPATF_LIGHT = 1 << 29, // Find neighboring light level like Doom
COMPATF_POLYOBJ = 1 << 30, // Draw polyobjects the old fashioned way
COMPATF_MASKEDMIDTEX = 1 << 31, // Ignore compositing when drawing masked midtextures
COMPATF2_BADANGLES = 1 << 0, // It is impossible to face directly NSEW.
COMPATF2_FLOORMOVE = 1 << 1, // Use the same floor motion behavior as Doom.
COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less
COMPATF2_POINTONLINE = 1 << 3, // Use original but buggy P_PointOnLineSide() and P_PointOnDivlineSideCompat()
COMPATF2_MULTIEXIT = 1 << 4, // Level exit can be triggered multiple times (required by Daedalus's travel tubes, thanks to a faulty script)
COMPATF2_TELEPORT = 1 << 5, // Don't let indirect teleports trigger sector actions
COMPATF2_PUSHWINDOW = 1 << 6, // Disable the window check in CheckForPushSpecial()
};

View file

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

View file

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

View file

@ -1002,7 +1002,7 @@ class Inventory : Actor
// //
//=========================================================================== //===========================================================================
virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {} virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive, Actor inflictor = null, Actor source = null, int flags = 0) {}
virtual bool Use (bool pickup) { return false; } virtual bool Use (bool pickup) { return false; }

View file

@ -1655,7 +1655,7 @@ class PowerDamage : Powerup
// //
//=========================================================================== //===========================================================================
override void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) override void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags)
{ {
if (!passive && damage > 0) if (!passive && damage > 0)
{ {
@ -1749,7 +1749,7 @@ class PowerProtection : Powerup
// //
//=========================================================================== //===========================================================================
override void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) override void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags)
{ {
if (passive && damage > 0) if (passive && damage > 0)
{ {

View file

@ -217,7 +217,7 @@ class StateProvider : Inventory
// Temporarily adjusts the pitch // Temporarily adjusts the pitch
double saved_player_pitch = self.Pitch; double saved_player_pitch = self.Pitch;
self.Pitch += pitch; self.Pitch += pitch;
let misl = SpawnPlayerMissile (missiletype, shootangle, ofs.X, ofs.Y, spawnheight, t, NULL, false, (flags & FPF_NOAUTOAIM) != 0); let misl = SpawnPlayerMissile (missiletype, shootangle, ofs.X, ofs.Y, spawnheight, t, false, (flags & FPF_NOAUTOAIM) != 0);
self.Pitch = saved_player_pitch; self.Pitch = saved_player_pitch;
// automatic handling of seeker missiles // automatic handling of seeker missiles

View file

@ -373,6 +373,7 @@ class LevelCompatibility native play
SetWallTexture(1027, Line.back, Side.top, "SP_HOT1"); SetWallTexture(1027, Line.back, Side.top, "SP_HOT1");
// Replace tag for eastern secret at level start to not // Replace tag for eastern secret at level start to not
// cause any action to the two-Baron trap // cause any action to the two-Baron trap
ClearSectorTags(127);
AddSectorTag(127, 100); AddSectorTag(127, 100);
SetLineSpecial(382, Door_Open, 100, 16); SetLineSpecial(382, Door_Open, 100, 16);
SetLineSpecial(388, Door_Open, 100, 16); SetLineSpecial(388, Door_Open, 100, 16);
@ -997,7 +998,7 @@ class LevelCompatibility native play
SetLineSectorRef(328, Line.front, 74); SetLineSectorRef(328, Line.front, 74);
SetLineSectorRef(329, Line.front, 74); SetLineSectorRef(329, Line.front, 74);
AddSectorTag(74, 4); AddSectorTag(74, 4);
SetLineSpecial(357, Transfer_Heights, 6); SetLineSpecial(357, Transfer_Heights, 4, 6);
break; break;
} }
@ -1220,6 +1221,15 @@ class LevelCompatibility native play
// Fix the soulsphere in a secret area (sector 324) // Fix the soulsphere in a secret area (sector 324)
// so that it doesn't end up in an unreachable position. // so that it doesn't end up in an unreachable position.
SetThingXY(516, -934, 48); SetThingXY(516, -934, 48);
break;
}
case '11EA5B8357DEB70A8F00900117831191': // kdizd_12.pk3 z1m3
{
// Fix incorrectly tagged underwater sector which causes render glitches.
ClearSectorTags(7857);
AddSectorTag(7857, 82);
break;
} }
} }
} }

View file

@ -347,7 +347,7 @@ class Minotaur : Actor
} }
else else
{ {
if (Floorclip > 0 && compat_minotaur) if (Floorclip > 0 && (Level.compatflags & COMPAT_MINOTAUR))
{ {
// only play the sound. // only play the sound.
A_PlaySound ("minotaur/fx2hit", CHAN_WEAPON); A_PlaySound ("minotaur/fx2hit", CHAN_WEAPON);

View file

@ -1930,7 +1930,7 @@ class PlayerPawn : Actor
override int GetMaxHealth(bool withupgrades) const override int GetMaxHealth(bool withupgrades) const
{ {
int ret = MaxHealth > 0? MaxHealth : (compat_dehhealth? 100 : deh.MaxHealth); int ret = MaxHealth > 0? MaxHealth : ((Level.compatflags & COMPATF_DEHHEALTH)? 100 : deh.MaxHealth);
if (withupgrades) ret += stamina + BonusHealth; if (withupgrades) ret += stamina + BonusHealth;
return ret; return ret;
} }