- added true level compatibility map processing and deleted all related map hack code.

This commit is contained in:
Christoph Oelckers 2022-10-31 10:45:47 +01:00
parent a6af6b88df
commit 0e113dab79
23 changed files with 133 additions and 149 deletions

View file

@ -163,107 +163,6 @@ static int32_t LoadMapHack(const char *filename, SpawnSpriteDef& sprites)
} }
} }
} }
else if (sc.Compare("picnum"))
{
if (sc.CheckNumber())
{
if (currentwall != -1 && validateWall())
{
wall[currentwall].picnum = sc.Number;
}
else if (currentsprite != -1 && validateSprite())
{
sprites.sprites[currentsprite].picnum = sc.Number;
}
}
}
else if (sc.Compare("overpicnum"))
{
if (sc.CheckNumber() && validateWall())
{
wall[currentwall].overpicnum = sc.Number;
}
}
else if (sc.Compare("overpicnum"))
{
if (sc.CheckNumber() && validateWall())
{
wall[currentwall].overpicnum = sc.Number;
}
}
else if (sc.Compare("split"))
{
int start = -1, end = -1;
if (sc.CheckNumber()) start = sc.Number;
if (sc.CheckNumber()) end = sc.Number;
if (end >= 0 && validateSector())
{
hw_SetSplitSector(currentsector, start, end);
}
}
else if (sc.Compare("dontclip"))
{
sector[currentsector].exflags |= SECTOREX_DONTCLIP;
}
else if (sc.Compare("clearflags"))
{
if (currentsector != -1 && validateSector())
{
sc.GetString();
if (sc.Compare("floor") && sc.CheckNumber())
{
sector[currentsector].floorstat &= ESectorFlags::FromInt(~sc.Number);
}
else if (sc.Compare("ceiling") && sc.CheckNumber())
{
sector[currentsector].ceilingstat &= ESectorFlags::FromInt(~sc.Number);
}
else sc.ScriptError("Bad token %s", sc.String);
}
else if (sc.CheckNumber())
{
if (currentwall != -1 && validateWall())
{
wall[currentwall].cstat &= EWallFlags::FromInt(~sc.Number);
}
else if (currentsprite != -1 && validateSprite())
{
sprites.sprites[currentsprite].cstat &= ESpriteFlags::FromInt(~sc.Number);
}
}
}
else if (sc.Compare("setflags"))
{
if (sc.CheckNumber())
{
if (currentwall != -1 && validateWall())
{
wall[currentwall].cstat |= EWallFlags::FromInt(sc.Number);
}
else if (currentsprite != -1 && validateSprite())
{
sprites.sprites[currentsprite].cstat |= ESpriteFlags::FromInt(sc.Number);
}
}
}
else if (sc.Compare("lotag"))
{
if (sc.CheckNumber())
{
if (currentwall != -1 && validateWall())
{
wall[currentwall].lotag = sc.Number;
}
else if (currentsprite != -1 && validateSprite())
{
sprites.sprites[currentsprite].lotag = sc.Number;
}
}
}
else if (sc.Compare("sw_serp_continue")) // This is a hack for SW's Last Warrior mod to continue from L4 to L5.
{
if (currentLevel) currentLevel->gameflags |= LEVEL_SW_DEATHEXIT_SERPENT_NEXT;
}
else if (sc.Compare("angleoff") || sc.Compare("angoff")) else if (sc.Compare("angleoff") || sc.Compare("angoff"))
{ {
@ -383,8 +282,6 @@ static int32_t LoadMapHack(const char *filename, SpawnSpriteDef& sprites)
void loadMapHack(const char* filename, const uint8_t* md4, SpawnSpriteDef& sprites) void loadMapHack(const char* filename, const uint8_t* md4, SpawnSpriteDef& sprites)
{ {
hw_ClearSplitSector();
FString internal = "engine/compatibility/"; FString internal = "engine/compatibility/";
for (int j = 0; j < 16; ++j) for (int j = 0; j < 16; ++j)
{ {

View file

@ -543,6 +543,7 @@ void loadMap(const char* filename, int flags, DVector3* pos, int16_t* ang, secto
auto buffer = fr.Read(); auto buffer = fr.Read();
uint8_t md4[16]; uint8_t md4[16];
md4once(buffer.Data(), buffer.Size(), md4); md4once(buffer.Data(), buffer.Size(), md4);
PostProcessLevel(md4, filename, sprites);
loadMapHack(filename, md4, sprites); loadMapHack(filename, md4, sprites);
setWallSectors(); setWallSectors();
hw_CreateSections(); hw_CreateSections();

View file

@ -698,6 +698,7 @@ TArray<walltype> loadMapWalls(const char* filename);
void loadMapBackup(const char* filename); void loadMapBackup(const char* filename);
void loadMapHack(const char* filename, const uint8_t*, SpawnSpriteDef& sprites); void loadMapHack(const char* filename, const uint8_t*, SpawnSpriteDef& sprites);
void validateStartSector(const char* filename, const DVector3& pos, sectortype** cursectnum, unsigned numsectors, bool noabort = false); void validateStartSector(const char* filename, const DVector3& pos, sectortype** cursectnum, unsigned numsectors, bool noabort = false);
void PostProcessLevel(const uint8_t* checksum, const FString& mapname, SpawnSpriteDef& sprites);
// should only be used to read angles from map-loaded data (for proper documentation) // should only be used to read angles from map-loaded data (for proper documentation)
constexpr DAngle mapangle(int mapang) constexpr DAngle mapangle(int mapang)

View file

@ -37,6 +37,9 @@
#include "vm.h" #include "vm.h"
#include "printf.h" #include "printf.h"
#include "types.h" #include "types.h"
#include "maptypes.h"
#include "hw_sections.h"
#include "mapinfo.h"
//========================================================================== //==========================================================================
// //
@ -48,13 +51,21 @@ class DLevelPostProcessor : public DObject
{ {
DECLARE_ABSTRACT_CLASS(DLevelPostProcessor, DObject) DECLARE_ABSTRACT_CLASS(DLevelPostProcessor, DObject)
public: public:
SpawnSpriteDef* sprites;
}; };
IMPLEMENT_CLASS(DLevelPostProcessor, true, false); IMPLEMENT_CLASS(DLevelPostProcessor, true, false);
void PostProcessLevel(FName checksum, const FString& mapname) void PostProcessLevel(const uint8_t* md4, const FString& mapname, SpawnSpriteDef& sprites)
{ {
hw_ClearSplitSector();
auto lc = Create<DLevelPostProcessor>(); auto lc = Create<DLevelPostProcessor>();
lc->sprites = &sprites;
char md4string[33];
for (int i = 0; i < 16; i++) mysnprintf(md4string + 2 * i, 3, "%02x", md4[i]);
FName checksum(md4string, true);
if (checksum == NAME_None) return; // we do not have anything so save the work.
for(auto cls : PClass::AllClasses) for(auto cls : PClass::AllClasses)
{ {
@ -83,21 +94,47 @@ void PostProcessLevel(FName checksum, const FString& mapname)
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetSpriteLotag) DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SetSpriteLotag)
{ {
PARAM_SELF_PROLOGUE(DLevelPostProcessor); PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_INT(sprite); PARAM_UINT(sprite);
PARAM_INT(lotag); PARAM_INT(lotag);
if (sprite < self->sprites->sprites.Size())
self->sprites->sprites[sprite].lotag = lotag;
// todo
return 0; return 0;
} }
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, ChangeSpriteFlags) DEFINE_ACTION_FUNCTION(DLevelPostProcessor, ChangeSpriteFlags)
{ {
PARAM_SELF_PROLOGUE(DLevelPostProcessor); PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_INT(sprite); PARAM_UINT(sprite);
PARAM_INT(clearmask); PARAM_INT(clearmask);
PARAM_INT(setflag); PARAM_INT(setmask);
if (sprite < self->sprites->sprites.Size())
self->sprites->sprites[sprite].cstat = (self->sprites->sprites[sprite].cstat & ~ESpriteFlags::FromInt(clearmask)) | ESpriteFlags::FromInt(setmask);
// todo
return 0; return 0;
} }
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, SplitSector)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
PARAM_UINT(sectornum);
PARAM_INT(firstwall);
PARAM_INT(secondwall);
if (sectornum < sector.Size())
{
if (firstwall >= sector[sectornum].wallptr && firstwall < sector[sectornum].wallptr + sector[sectornum].wallnum &&
secondwall >= sector[sectornum].wallptr && secondwall < sector[sectornum].wallptr + sector[sectornum].wallnum)
hw_SetSplitSector(sectornum, firstwall, secondwall);
}
return 0;
}
DEFINE_ACTION_FUNCTION(DLevelPostProcessor, sw_serp_continue)
{
PARAM_SELF_PROLOGUE(DLevelPostProcessor);
currentLevel->gameflags |= LEVEL_SW_DEATHEXIT_SERPENT_NEXT;
return 0;
}

View file

@ -293,7 +293,7 @@ void InitThingdef()
//secplanestruct->Size = sizeof(secplane_t); //secplanestruct->Size = sizeof(secplane_t);
//secplanestruct->Align = alignof(secplane_t); //secplanestruct->Align = alignof(secplane_t);
auto sectorstruct = NewStruct("Sector", nullptr, true); auto sectorstruct = NewStruct("sectortype", nullptr, true);
sectorstruct->Size = sizeof(sectortype); sectorstruct->Size = sizeof(sectortype);
sectorstruct->Align = alignof(sectortype); sectorstruct->Align = alignof(sectortype);
NewPointer(sectorstruct, false)->InstallHandlers( NewPointer(sectorstruct, false)->InstallHandlers(
@ -308,7 +308,7 @@ void InitThingdef()
} }
); );
auto linestruct = NewStruct("Wall", nullptr, true); auto linestruct = NewStruct("walltype", nullptr, true);
linestruct->Size = sizeof(walltype); linestruct->Size = sizeof(walltype);
linestruct->Align = alignof(walltype); linestruct->Align = alignof(walltype);
NewPointer(linestruct, false)->InstallHandlers( NewPointer(linestruct, false)->InstallHandlers(

View file

@ -35,6 +35,7 @@
#include "maptypes.h" #include "maptypes.h"
#include "vm.h" #include "vm.h"
#include "gamefuncs.h"
//============================================================================= //=============================================================================
// //
@ -496,6 +497,21 @@ DEFINE_ACTION_FUNCTION_NATIVE(_walltype, move, wall_move)
return 0; return 0;
} }
void wall_dragpoint(walltype* wal, double x, double y)
{
if (!wal) ThrowAbortException(X_READ_NIL, nullptr);
dragpoint(wal, DVector2(x, y));
}
DEFINE_ACTION_FUNCTION_NATIVE(_walltype, dragpoint, wall_dragpoint)
{
PARAM_SELF_STRUCT_PROLOGUE(walltype);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
wall_dragpoint(self, x, y);
return 0;
}
int wall_twosided(walltype* wal) int wall_twosided(walltype* wal)
{ {
if (!wal) ThrowAbortException(X_READ_NIL, nullptr); if (!wal) ThrowAbortException(X_READ_NIL, nullptr);

View file

@ -593,6 +593,7 @@ void dbLoadMap(const char* pPath, DVector3& pos, short* pAngle, sectortype** cur
auto buffer = fr.Read(); auto buffer = fr.Read();
uint8_t md4[16]; uint8_t md4[16];
md4once(buffer.Data(), buffer.Size(), md4); md4once(buffer.Data(), buffer.Size(), md4);
PostProcessLevel(md4, mapname, sprites);
loadMapHack(mapname, md4, sprites); loadMapHack(mapname, md4, sprites);
if (CalcCRC32(buffer.Data(), buffer.Size() - 4) != nCRC) if (CalcCRC32(buffer.Data(), buffer.Size() - 4) != nCRC)

View file

@ -421,11 +421,6 @@ void prelevel_r(int g, TArray<DDukeActor*>& actors)
prelevel_common(g); prelevel_common(g);
p = &ps[screenpeek]; p = &ps[screenpeek];
if (currentLevel->levelNumber == 1001 && wall.Size() > 4687 && wall[4592].pos.X == 1612 && wall[4592].pos.Y == -2714) // fix sector overlap in E1L1 Taylor Town
{
dragpoint(&wall[4592], { 1615., -2715. });
}
if (currentLevel->gameflags & LEVEL_RR_CLEARMOONSHINE) if (currentLevel->gameflags & LEVEL_RR_CLEARMOONSHINE)
ps[myconnectindex].steroids_amount = 0; ps[myconnectindex].steroids_amount = 0;

View file

@ -1,2 +0,0 @@
// RR E1L1.map sector bleeds into another area.
sector 47 split 367 375

View file

@ -1,2 +0,0 @@
// Wanton Destruction $auto.map - workaround for sector object overlapping with an outer wall.
sector 152 dontclip

View file

@ -1,4 +0,0 @@
// bad sky setting in WT's $volcano.map (original version)
sector 118 clearflags ceiling 1
sector 57 clearflags ceiling 1
sector 281 clearflags ceiling 1

View file

@ -1,2 +0,0 @@
// missing texture in RR E1L2.
wall 3312 setflags 2

View file

@ -1,3 +0,0 @@
// SW $plax1.map sector bleeds into another area.
sector 64 split 281 283

View file

@ -1,3 +0,0 @@
// SW $bath.ap sector bleeds into another area.
sector 198 split 1105 1125

View file

@ -1,4 +0,0 @@
// bad sky setting in WT's $volcano.map (fixed version)
sector 118 clearflags ceiling 1
sector 57 clearflags ceiling 1
sector 281 clearflags ceiling 1

View file

@ -1,2 +0,0 @@
// SW's Last Warrior level 4. Do not make the serpent's death end the game. The menu has no second episode so this needs to continue.
sw_serp_continue

View file

@ -1,3 +0,0 @@
// SW $outpost.map
// silence a misplaced and *very* annoying ambient sound.
sprite 442 lotag -1

View file

@ -1,2 +0,0 @@
// CP07 sector bleeds into another area.
sector 33 split 192 196

View file

@ -1,3 +0,0 @@
// flip inverted keyholes in TD's $shore.map
sprite 298 clearflags 8
sprite 307 clearflags 8

View file

@ -1,2 +0,0 @@
// flip the inverted card reader in TD's level 10.
sprite 179 clearflags 12

View file

@ -7,6 +7,64 @@ class LevelCompatibility : LevelPostProcessor
{ {
case 'none': case 'none':
return; return;
case 'c3bfb6a6e7cded2e5fe16cea86632d79': // CP07
SplitSector(33, 192, 196); // sector bleeds into another area.
break;
case '24c7b1434070dbe01fa83c6a48926ed9': // RR E1L1.map
SplitSector(47, 367, 375); // sector bleeds into another area.
wall[4592].dragpoint((1615., -2715.)); // fix overlapping sectors
break;
case 'd7bf49213531cd2607e0459b950ac454': // RR E2L7.map
// need to add a sprite with picnum 11 (RRJAILDOOR) lotag = 48, hitag = 32, sector = 534
// see premap_r.cpp, line 477.
break;
case '491a04a732cd5aa253703216ff2feff4': // RR E1L2.map
wall[3312].cstat |= CSTAT_WALL_BOTTOM_SWAP; // missing lower texture .
break;
case '4f2233ed8fb32f6a3deebc7803dbed69': // SW $plax.map
SplitSector(64, 281, 283); // sector bleeds into another area.
break;
case '5e49c7f6c496e337d59d0c072ed1879b': // SW $bath.map
SplitSector(198, 1105, 1125); // sector bleeds into another area.
break;
case 'b4ee363e9d15adc5c9becd01520acd23': // SW $outpost.map
SetSpriteLotag(442, -1); // silence a misplaced and *very* annoying ambient sound.
break;
case '25d4164814f10cd71d26d52d494c4fb8': // WT $auto.map
sector[152].exflags |= SECTOREX_DONTCLIP; // workaround for sector object overlapping with an outer wall.
break;
case '2bac4971499306ee6c86462e6a03dae8': // WT $volcano.map (original version)
case '67207fb90130ad561479301c0970c7ba': // WT $volcano.map (fixed version)
sector[118].ceilingstat &= ~CSTAT_SECTOR_SKY;
sector[57].ceilingstat &= ~CSTAT_SECTOR_SKY;
sector[281].ceilingstat &= ~CSTAT_SECTOR_SKY;
break;
case '745182e393945e0d308e8e0a5ee80c3c': // SW Last Warrior level 4.
sw_serp_continue(); // Do not make the serpent's death end the game. The menu has no second episode so this needs to continue.
break;
case 'c6f9e49e397c0b424e8030abc23ac003': // TD $shore.map
ChangeSpriteFlags(298, CSTAT_SPRITE_YFLIP, 0); // flip inverted keyhole
ChangeSpriteFlags(307, CSTAT_SPRITE_YFLIP, 0); // flip inverted keyhole
break;
case 'ef6331237eb36c84a4f7b9f5c3cd225d': // TD level 10
ChangeSpriteFlags(179, CSTAT_SPRITE_XFLIP | CSTAT_SPRITE_YFLIP, 0); // flip the inverted card reader
break;
} }
} }
} }

View file

@ -7,4 +7,6 @@ class LevelPostProcessor native play
protected native void SetSpriteLotag(int sprite, int tag); protected native void SetSpriteLotag(int sprite, int tag);
protected native void ChangeSpriteFlags(int sprite, int set, int clear); protected native void ChangeSpriteFlags(int sprite, int set, int clear);
protected native void sw_serp_continue();
protected native void SplitSector(int sect, int wal1, int wal2);
} }

View file

@ -99,6 +99,13 @@ enum ETSprFlags
TSPR_SLOPESPRITE = 8, // render as sloped sprite TSPR_SLOPESPRITE = 8, // render as sloped sprite
} }
enum ESectorExBits
{
SECTOREX_CLOUDSCROLL = 1,
SECTOREX_DRAGGED = 2,
SECTOREX_DONTCLIP = 4,
};
//============================================================================= //=============================================================================
@ -262,6 +269,7 @@ struct walltype native
native double Length(); native double Length();
native void move(Vector2 vec); native void move(Vector2 vec);
native void dragpoint(Vector2 vec);
} }
//============================================================================= //=============================================================================