- engine-side portal setup for Blood and RRRA.

This commit is contained in:
Christoph Oelckers 2021-03-21 14:48:35 +01:00
parent b91441f849
commit a36377111c
6 changed files with 212 additions and 16 deletions

View file

@ -36,15 +36,13 @@ enum
{
PORTAL_SECTOR_FLOOR = 1,
PORTAL_SECTOR_CEILING = 2,
PORTAL_SECTOR_FLOOR_REFLECT = 4,
PORTAL_SECTOR_CEILING_REFLECT = 8,
PORTAL_SECTOR_FLOOR_REFLECT = 3,
PORTAL_SECTOR_CEILING_REFLECT = 4,
PORTAL_WALL_VIEW = 5,
PORTAL_WALL_MIRROR = 6,
PORTAL_SECTOR_GEOMETRY = 7,
};
enum
{
PORTAL_WALL_VIEW = 1,
PORTAL_WALL_MIRROR = 2,
};
//40 bytes
struct sectortype
@ -68,6 +66,7 @@ struct sectortype
uint8_t dirty;
float ceilingxpan_, ceilingypan_, floorxpan_, floorypan_;
uint8_t portalflags;
uint8_t portalnum;
int ceilingxpan() const { return int(ceilingxpan_); }
int ceilingypan() const { return int(ceilingypan_); }
@ -120,6 +119,7 @@ struct walltype
float xpan_, ypan_;
angle_t clipangle;
uint8_t portalflags;
uint8_t portalnum;
int xpan() const { return int(xpan_); }
int ypan() const { return int(ypan_); }

View file

@ -54,6 +54,7 @@ EXTERN_CVAR(Bool, cl_capfps)
PalEntry GlobalMapFog;
float GlobalFogDensity;
TArray<PortalDesc> allPortals;
#if 0

View file

@ -3,3 +3,69 @@
void render_drawrooms(spritetype* playersprite, const vec3_t& position, int sectnum, fixed_t q16angle, fixed_t q16horizon, float rollang);
struct PortalDesc
{
int type;
int dx, dy, dz;
TArray<int> targets;
};
extern TArray<PortalDesc> allPortals;
inline void portalClear()
{
allPortals.Clear();
}
inline int portalAdd(int type, int target, int dx = 0, int dy = 0, int dz = 0)
{
auto& pt = allPortals[allPortals.Reserve(1)];
pt.type = type;
pt.targets.Push(target);
pt.dx = dx;
pt.dy = dy;
pt.dz = dz;
return allPortals.Size() - 1;
}
// merges portals in adjoining sectors. AFAIK the only one of this kind is in Blood's E4M9, which with the original code is very glitchy.
inline void mergePortals()
{
Printf("Have %d portals\n", allPortals.Size());
bool didsomething = true;
while (didsomething)
{
didsomething = false;
for (unsigned i = 0; i < allPortals.Size(); i++)
{
auto& pt1 = allPortals[i];
if (pt1.type == PORTAL_SECTOR_CEILING || pt1.type == PORTAL_SECTOR_FLOOR)
{
for (unsigned j = i + 1; j < allPortals.Size(); j++)
{
auto& pt2 = allPortals[j];
if (pt1.type != pt2.type || pt1.dx != pt2.dx || pt1.dy != pt2.dy || pt1.dz != pt2.dz) continue;
for (unsigned s = 0; s < pt1.targets.Size(); s++)
{
for (unsigned t = 0; t < pt2.targets.Size(); t++)
{
if (findwallbetweensectors(pt1.targets[s], pt2.targets[t]) >= 0)
{
pt1.targets.Append(pt2.targets);
pt2.targets.Reset();
pt2.type = -1;
for (int n = 0; n < numsectors; n++)
{
Printf("Merged %d and %d\n", i, j);
if (sector[n].portalnum == j) sector[n].portalnum = i;
didsomething = true;
break;
}
}
}
}
}
}
}
}
}

View file

@ -555,6 +555,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, sectortype &c, sectort
("hitag", c.hitag, def->hitag)
("extra", c.extra, def->extra)
("portalflags", c.portalflags, def->portalflags)
("portalnum", c.portalnum, def->portalnum)
.EndObject();
}
return arc;
@ -582,6 +583,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, walltype &c, walltype
("hitag", c.hitag, def->hitag)
("extra", c.extra, def->extra)
("portalflags", c.portalflags, def->portalflags)
("portalnum", c.portalnum, def->portalnum)
.EndObject();
}
return arc;

View file

@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "savegamehelp.h"
#include "blood.h"
#include "render.h"
BEGIN_BLD_NS
@ -42,6 +43,7 @@ void InitMirrors(void)
mirrorcnt = 0;
tileDelete(504);
portalClear();
for (int i = 0; i < 16; i++)
{
@ -57,7 +59,7 @@ void InitMirrors(void)
if (wall[i].extra > 0 && GetWallType(i) == kWallStack)
{
wall[i].overpicnum = nTile;
wall[i].portalflags = PORTAL_WALL_VIEW;
mirror[mirrorcnt].wallnum = i;
mirror[mirrorcnt].type = 0;
wall[i].cstat |= 32;
@ -78,8 +80,15 @@ void InitMirrors(void)
}
}
if (j < 0)
I_Error("wall[%d] has no matching wall link! (data=%d)\n", i, tmp);
mirrorcnt++;
{
Printf(PRINT_HIGH, "wall[%d] has no matching wall link! (data=%d)\n", i, tmp);
}
else
{
mirrorcnt++;
wall[i].portalflags = PORTAL_WALL_VIEW;
wall[i].portalnum = portalAdd(PORTAL_WALL_VIEW, j);
}
}
continue;
}
@ -117,6 +126,7 @@ void InitMirrors(void)
mirror[mirrorcnt].link = j;
sector[i].floorpicnum = 4080+mirrorcnt;
sector[i].portalflags = PORTAL_SECTOR_FLOOR;
sector[i].portalnum = portalAdd(PORTAL_SECTOR_FLOOR, j, mirror[mirrorcnt].dx, mirror[mirrorcnt].dy, mirror[mirrorcnt].dz);
mirrorcnt++;
mirror[mirrorcnt].type = 1;
mirror[mirrorcnt].dx = sprite[nLink].x-sprite[nLink2].x;
@ -126,10 +136,12 @@ void InitMirrors(void)
mirror[mirrorcnt].link = i;
sector[j].ceilingpicnum = 4080+mirrorcnt;
sector[j].portalflags = PORTAL_SECTOR_CEILING;
sector[i].portalnum = portalAdd(PORTAL_SECTOR_CEILING, j, mirror[mirrorcnt].dx, mirror[mirrorcnt].dy, mirror[mirrorcnt].dz);
mirrorcnt++;
}
}
mirrorsector = numsectors;
mergePortals();
#if 1 // The new backend won't need this shit anymore.
for (int i = 0; i < 4; i++)
{

View file

@ -36,6 +36,7 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
#include "automap.h"
#include "dukeactor.h"
#include "interpolate.h"
#include "render.h"
BEGIN_DUKE_NS
@ -838,6 +839,124 @@ void newgame(MapRecord* map, int sk, func completion)
else completion1(false);
}
//---------------------------------------------------------------------------
//
// the setup here is very, very sloppy, because mappings are not 1:1.
// Each portal can have multiple sectors, and even extends to unmarked
// neighboring sectors if they got the portal tile as floor or ceiling
//
//---------------------------------------------------------------------------
static void SpawnPortals()
{
for (int i = 0; i < numwalls; i++)
{
if (wall[i].overpicnum == TILE_MIRROR) wall[i].portalflags |= PORTAL_WALL_MIRROR;
}
portalClear();
int tag;
if (!isRR()) tag = 40;
else if (isRRRA()) tag = 150;
else return;
TArray<int> processedTags;
DukeStatIterator it(STAT_RAROR);
while (auto act = it.Next())
{
auto spr = &act->s;
if (spr->picnum == SECTOREFFECTOR && spr->lotag == tag)
{
if (processedTags.Find(spr->hitag) == processedTags.Size())
{
DukeStatIterator it2(STAT_RAROR);
while (auto act2 = it2.Next())
{
auto spr2 = &act2->s;
if (spr2->picnum == SECTOREFFECTOR && spr2->lotag == tag + 1 && spr2->hitag == spr->hitag)
{
if (processedTags.Find(spr->hitag) == processedTags.Size())
{
int s1 = spr->sectnum, s2 = spr2->sectnum;
sector[s1].portalflags = PORTAL_SECTOR_FLOOR;
sector[s2].portalflags = PORTAL_SECTOR_CEILING;
sector[s1].portalnum = portalAdd(PORTAL_SECTOR_FLOOR, s2, spr2->x - spr->x, spr2->y - spr->y, spr->hitag);
sector[s2].portalnum = portalAdd(PORTAL_SECTOR_CEILING, s1, spr->x - spr2->x, spr->y - spr2->y, spr->hitag);
processedTags.Push(spr->hitag);
}
else
{
for (auto& p : allPortals)
{
if (p.type == PORTAL_SECTOR_FLOOR && p.dz == spr->hitag)
{
p.targets.Push(spr2->sectnum);
}
}
}
}
}
}
else
{
for (auto& p : allPortals)
{
if (p.type == PORTAL_SECTOR_CEILING && p.dz == spr->hitag)
{
p.targets.Push(spr->sectnum);
}
}
}
}
}
// Unfortunately the above still isn't enough. We got to do one more check to add stuff to the portals.
// There is one map where a sector neighboring a portal is not marked as part of the portal itself.
for (int i = 0; i < numsectors; i++)
{
if (sector[i].floorpicnum == FOF && sector[i].portalflags != PORTAL_SECTOR_FLOOR)
{
for (auto& pt : allPortals)
{
if (pt.type == PORTAL_SECTOR_CEILING)
{
for (auto& t : pt.targets)
{
if (findwallbetweensectors(i, t) >= 0)
{
sector[i].portalflags = PORTAL_SECTOR_FLOOR;
sector[i].portalnum = uint8_t(&pt - allPortals.Data());
pt.targets.Push(i);
goto nexti;
}
}
}
}
}
else if (sector[i].ceilingpicnum == FOF && sector[i].portalflags != PORTAL_SECTOR_CEILING)
{
for (auto& pt : allPortals)
{
if (pt.type == PORTAL_SECTOR_FLOOR)
{
for (auto& t : pt.targets)
{
if (findwallbetweensectors(i, t) >= 0)
{
sector[i].portalflags = PORTAL_SECTOR_CEILING;
sector[i].portalnum = uint8_t(&pt - allPortals.Data());
pt.targets.Push(i);
goto nexti;
}
}
}
}
}
nexti:;
}
for (auto& p : allPortals) p.dz = 0;
mergePortals();
}
//---------------------------------------------------------------------------
//
//
@ -853,12 +972,6 @@ static int LoadTheMap(MapRecord *mi, struct player_struct *p, int gamemode)
}
engineLoadBoard(mi->fileName, isShareware(), &p->pos, &lbang, &p->cursectnum);
for(int i = 0; i < numsectors; i++)
{
if (sector[i].ceilingpicnum == FOF) sector[i].portalflags |= PORTAL_SECTOR_CEILING;
if (sector[i].floorpicnum == FOF) sector[i].portalflags |= PORTAL_SECTOR_FLOOR;
if (wall[i].overpicnum == TILE_MIRROR) wall[i].portalflags |= PORTAL_WALL_MIRROR;
}
currentLevel = mi;
SECRET_SetMapName(mi->DisplayName(), mi->name);
@ -877,6 +990,8 @@ static int LoadTheMap(MapRecord *mi, struct player_struct *p, int gamemode)
if (isRR()) prelevel_r(gamemode);
else prelevel_d(gamemode);
SpawnPortals();
if (isRRRA() && mi->levelNumber == levelnum(2, 0))
{
for (int i = PISTOL_WEAPON; i < MAX_WEAPONS; i++)