Make linedef type 6 closer to ZDoom's Sector_SetPortal

This commit is contained in:
Lactozilla 2023-08-23 15:04:50 -03:00
parent 03daf721ef
commit 5b387ec94a
11 changed files with 236 additions and 108 deletions

View file

@ -4285,7 +4285,6 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
// Portal objects // Portal objects
"MT_SKYBOX", "MT_SKYBOX",
"MT_PORTALREFPOINT",
// Debris // Debris
"MT_SPARK", //spark "MT_SPARK", //spark

View file

@ -2352,11 +2352,11 @@ static void HWR_AddLine(seg_t * line)
gl_backsector = R_FakeFlat(gl_backsector, &tempsec, NULL, NULL, true); gl_backsector = R_FakeFlat(gl_backsector, &tempsec, NULL, NULL, true);
if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum if (gl_backsector->ceilingpic == skyflatnum && gl_frontsector->ceilingpic == skyflatnum
&& !(gl_backsector->portal_ceiling.exists || gl_frontsector->portal_ceiling.exists)) && !(P_SectorHasCeilingPortal(gl_backsector) || P_SectorHasCeilingPortal(gl_frontsector)))
bothceilingssky = true; bothceilingssky = true;
if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum if (gl_backsector->floorpic == skyflatnum && gl_frontsector->floorpic == skyflatnum
&& !(gl_backsector->portal_floor.exists || gl_frontsector->portal_floor.exists)) && !(P_SectorHasFloorPortal(gl_backsector) || P_SectorHasFloorPortal(gl_frontsector)))
bothfloorssky = true; bothfloorssky = true;
if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then

View file

@ -20759,33 +20759,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_PORTALREFPOINT
781, // doomednum
S_INVISIBLE, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
12*FRACUNIT, // radius
24*FRACUNIT, // height
0, // display offset
10, // mass
0, // damage
sfx_None, // activesound
MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_SPARK { // MT_SPARK
-1, // doomednum -1, // doomednum
S_SPRK1, // spawnstate S_SPRK1, // spawnstate

View file

@ -5116,7 +5116,6 @@ typedef enum mobj_type
// Portal objects // Portal objects
MT_SKYBOX, MT_SKYBOX,
MT_PORTALREFPOINT,
// Debris // Debris
MT_SPARK, //spark MT_SPARK, //spark

View file

@ -980,9 +980,7 @@ static void P_LoadVertices(UINT8 *data)
static void InitializeSectorPortal(sectorportal_t *secportal) static void InitializeSectorPortal(sectorportal_t *secportal)
{ {
secportal->exists = false; memset(secportal, 0, sizeof(*secportal));
secportal->target.x = secportal->target.y = secportal->target.z = 0;
secportal->target.angle = 0;
} }
static void P_InitializeSector(sector_t *ss) static void P_InitializeSector(sector_t *ss)

View file

@ -6186,22 +6186,54 @@ fixed_t P_GetSectorGravityFactor(sector_t *sec)
return sec->gravity; return sec->gravity;
} }
boolean P_CompareSectorPortals(sectorportal_t *a, sectorportal_t *b) static boolean P_IsSectorPortalValid(sectorportal_t *secportal)
{ {
return !memcmp(a, b, sizeof(sectorportal_t)); switch (secportal->type)
{
case SECPORTAL_LINE:
case SECPORTAL_FLOOR:
case SECPORTAL_CEILING:
return true;
case SECPORTAL_OBJECT:
return secportal->mobj && !P_MobjWasRemoved(secportal->mobj);
case SECPORTAL_SKYBOX:
return skyboxmo[0] && !P_MobjWasRemoved(skyboxmo[0]);
default:
return false;
}
} }
static void SetSectorPortal(sectorportal_t *secportal, sector_t *target_sector, fixed_t default_z, INT32 viewpoint_tag) boolean P_SectorHasFloorPortal(sector_t *sector)
{ {
secportal->exists = target_sector; return P_IsSectorPortalValid(&sector->portal_floor);
secportal->target.x = target_sector->soundorg.x; }
secportal->target.y = target_sector->soundorg.y;
secportal->target.z = default_z;
secportal->target.angle = 0;
if (viewpoint_tag <= 0) boolean P_SectorHasCeilingPortal(sector_t *sector)
return; {
return P_IsSectorPortalValid(&sector->portal_ceiling);
}
boolean P_CompareSectorPortals(sectorportal_t *a, sectorportal_t *b)
{
if (a->type != b->type)
return false;
switch (a->type)
{
case SECPORTAL_LINE:
return a->line.start == b->line.start && a->line.dest == b->line.dest;
case SECPORTAL_FLOOR:
case SECPORTAL_CEILING:
return a->sector == b->sector;
case SECPORTAL_OBJECT:
return a->mobj == b->mobj;
default:
return true;
}
}
static mobj_t *GetSectorPortalObject(INT32 tag)
{
for (thinker_t *th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (thinker_t *th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
@ -6209,18 +6241,14 @@ static void SetSectorPortal(sectorportal_t *secportal, sector_t *target_sector,
mobj_t *mo = (mobj_t *)th; mobj_t *mo = (mobj_t *)th;
if (mo->type != MT_PORTALREFPOINT || mo->spawnpoint == NULL) if (mo->spawnpoint == NULL)
continue; continue;
if (!Tag_Find(&mo->spawnpoint->tags, viewpoint_tag)) if (Tag_Find(&mo->spawnpoint->tags, tag))
continue; return mo;
secportal->target.x = mo->x;
secportal->target.y = mo->y;
secportal->target.z = mo->z;
secportal->target.angle = mo->angle;
return;
} }
return NULL;
} }
/** After the map has loaded, scans for specials that spawn 3Dfloors and /** After the map has loaded, scans for specials that spawn 3Dfloors and
@ -6390,26 +6418,97 @@ void P_SpawnSpecials(boolean fromnetsave)
case 6: // Sector portal case 6: // Sector portal
{ {
INT32 s1, s2; int target_sector_tag = lines[i].args[0];
TAG_ITER_SECTORS(lines[i].args[0], s1) // Target sector tag int portal_type = lines[i].args[1];
int plane_type = lines[i].args[2];
int misc = lines[i].args[3];
boolean floor, ceiling;
if (plane_type == TMP_BOTH)
floor = ceiling = true;
else
{ {
TAG_ITER_SECTORS(lines[i].args[1], s2) // Sector tag to make a portal to floor = plane_type == TMP_FLOOR;
ceiling = plane_type == TMP_CEILING;
}
INT32 s1 = -1;
TAG_ITER_SECTORS(target_sector_tag, s1) // Target sector tag
{
sectorportal_t *floorportal = &sectors[s1].portal_floor;
sectorportal_t *ceilportal = &sectors[s1].portal_ceiling;
// Line portal
if (portal_type == 0)
{ {
sector_t *target_sector = &sectors[s2]; INT32 linenum = -1;
boolean floor, ceiling; TAG_ITER_LINES(misc, linenum)
if (lines[i].args[2] == TMP_BOTH)
floor = ceiling = true;
else
{ {
floor = lines[i].args[2] == TMP_FLOOR; if (lines[linenum].special == 6
ceiling = lines[i].args[2] == TMP_CEILING; && lines[linenum].args[0] == target_sector_tag
&& lines[linenum].args[1] == portal_type
&& lines[linenum].args[2] == plane_type
&& lines[linenum].args[3] == 1)
{
if (floor)
{
floorportal->type = SECPORTAL_LINE;
floorportal->line.start = &lines[i];
floorportal->line.dest = &lines[linenum];
}
if (ceiling)
{
ceilportal->type = SECPORTAL_LINE;
ceilportal->line.start = &lines[i];
ceilportal->line.dest = &lines[linenum];
}
}
} }
}
// Skybox portal
else if (portal_type == 2)
{
if (floor) if (floor)
SetSectorPortal(&sectors[s1].portal_floor, target_sector, target_sector->ceilingheight, lines[i].args[3]); floorportal->type = SECPORTAL_SKYBOX;
if (ceiling) if (ceiling)
SetSectorPortal(&sectors[s1].portal_ceiling, target_sector, target_sector->floorheight, lines[i].args[3]); ceilportal->type = SECPORTAL_SKYBOX;
}
// Plane portal
else if (portal_type == 7)
{
INT32 s2 = -1;
TAG_ITER_SECTORS(misc, s2) // Sector tag to make a portal to
{
sector_t *target_sector = &sectors[s2];
if (floor)
{
floorportal->type = SECPORTAL_CEILING;
floorportal->sector = target_sector;
}
if (ceiling)
{
ceilportal->type = SECPORTAL_FLOOR;
ceilportal->sector = target_sector;
}
}
}
// Use mobj as viewpoint
else if (portal_type == 8)
{
mobj_t *mobj = GetSectorPortalObject(misc);
if (!mobj)
break;
if (floor)
{
floorportal->type = SECPORTAL_OBJECT;
floorportal->mobj = mobj;
}
if (ceiling)
{
ceilportal->type = SECPORTAL_OBJECT;
ceilportal->mobj = mobj;
}
} }
} }
break; break;

View file

@ -521,6 +521,8 @@ INT32 P_FindMinSurroundingLight(sector_t *sector, INT32 max);
void P_SetupSignExit(player_t *player); void P_SetupSignExit(player_t *player);
boolean P_IsFlagAtBase(mobjtype_t flag); boolean P_IsFlagAtBase(mobjtype_t flag);
boolean P_SectorHasFloorPortal(sector_t *sector);
boolean P_SectorHasCeilingPortal(sector_t *sector);
boolean P_CompareSectorPortals(sectorportal_t *a, sectorportal_t *b); boolean P_CompareSectorPortals(sectorportal_t *a, sectorportal_t *b);
boolean P_IsMobjTouchingSectorPlane(mobj_t *mo, sector_t *sec); boolean P_IsMobjTouchingSectorPlane(mobj_t *mo, sector_t *sec);

View file

@ -488,12 +488,12 @@ static void R_AddLine(seg_t *line)
// hack to allow height changes in outdoor areas // hack to allow height changes in outdoor areas
// This is what gets rid of the upper textures if there should be sky // This is what gets rid of the upper textures if there should be sky
if (backsector->ceilingpic == skyflatnum && frontsector->ceilingpic == skyflatnum if (backsector->ceilingpic == skyflatnum && frontsector->ceilingpic == skyflatnum
&& !(backsector->portal_ceiling.exists || frontsector->portal_ceiling.exists)) && !(P_SectorHasCeilingPortal(backsector) || P_SectorHasCeilingPortal(frontsector)))
bothceilingssky = true; bothceilingssky = true;
// likewise, but for floors and upper textures // likewise, but for floors and upper textures
if (backsector->floorpic == skyflatnum && frontsector->floorpic == skyflatnum if (backsector->floorpic == skyflatnum && frontsector->floorpic == skyflatnum
&& !(backsector->portal_floor.exists || frontsector->portal_floor.exists)) && !(P_SectorHasFloorPortal(backsector) || P_SectorHasFloorPortal(frontsector)))
bothfloorssky = true; bothfloorssky = true;
if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then
@ -918,7 +918,7 @@ static void R_Subsector(size_t num)
|| (frontsector->heightsec != -1 && sectors[frontsector->heightsec].ceilingpic == skyflatnum)) || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].ceilingpic == skyflatnum))
{ {
floorplane = R_FindPlane(frontsector, frontsector->floorheight, frontsector->floorpic, floorlightlevel, floorplane = R_FindPlane(frontsector, frontsector->floorheight, frontsector->floorpic, floorlightlevel,
frontsector->floorxoffset, frontsector->flooryoffset, frontsector->floorangle, floorcolormap, NULL, NULL, frontsector->f_slope, frontsector->portal_floor.exists ? &frontsector->portal_floor : NULL); frontsector->floorxoffset, frontsector->flooryoffset, frontsector->floorangle, floorcolormap, NULL, NULL, frontsector->f_slope, P_SectorHasFloorPortal(frontsector) ? &frontsector->portal_floor : NULL);
} }
else else
floorplane = NULL; floorplane = NULL;
@ -929,7 +929,7 @@ static void R_Subsector(size_t num)
{ {
ceilingplane = R_FindPlane(frontsector, frontsector->ceilingheight, frontsector->ceilingpic, ceilingplane = R_FindPlane(frontsector, frontsector->ceilingheight, frontsector->ceilingpic,
ceilinglightlevel, frontsector->ceilingxoffset, frontsector->ceilingyoffset, frontsector->ceilingangle, ceilinglightlevel, frontsector->ceilingxoffset, frontsector->ceilingyoffset, frontsector->ceilingangle,
ceilingcolormap, NULL, NULL, frontsector->c_slope, frontsector->portal_ceiling.exists ? &frontsector->portal_ceiling : NULL); ceilingcolormap, NULL, NULL, frontsector->c_slope, P_SectorHasCeilingPortal(frontsector) ? &frontsector->portal_ceiling : NULL);
} }
else else
ceilingplane = NULL; ceilingplane = NULL;

View file

@ -208,13 +208,27 @@ typedef enum
BT_STRONG, BT_STRONG,
} busttype_e; } busttype_e;
typedef enum
{
SECPORTAL_NONE,
SECPORTAL_LINE,
SECPORTAL_OBJECT,
SECPORTAL_SKYBOX,
SECPORTAL_FLOOR,
SECPORTAL_CEILING,
} secportaltype_e;
typedef struct sectorportal_s typedef struct sectorportal_s
{ {
boolean exists; secportaltype_e type;
struct { union {
fixed_t x, y, z; struct {
angle_t angle; struct line_s *start;
} target; struct line_s *dest;
} line;
struct sector_s *sector;
struct mobj_s *mobj;
};
} sectorportal_t; } sectorportal_t;
typedef struct ffloor_s typedef struct ffloor_s

View file

@ -141,30 +141,17 @@ void Portal_Remove (portal_t* portal)
Z_Free(portal); Z_Free(portal);
} }
/** Creates a portal out of two lines and a determined screen range. static void Portal_GetViewpointForLine(portal_t *portal, line_t *start, line_t *dest)
*
* line1 determines the entrance, and line2 the exit.
* x1 and x2 determine the screen's column bounds.
* The view's offset from the entry line center is obtained,
* and then rotated&translated to the exit line's center.
* When the portal renders, it will create the illusion of
* the two lines being seamed together.
*/
void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2)
{ {
portal_t* portal = Portal_Add(x1, x2);
// Offset the portal view by the linedef centers // Offset the portal view by the linedef centers
line_t* start = &lines[line1];
line_t* dest = &lines[line2];
angle_t dangle = R_PointToAngle2(0,0,dest->dx,dest->dy) - R_PointToAngle2(start->dx,start->dy,0,0); angle_t dangle = R_PointToAngle2(0,0,dest->dx,dest->dy) - R_PointToAngle2(start->dx,start->dy,0,0);
fixed_t disttopoint; fixed_t disttopoint;
angle_t angtopoint; angle_t angtopoint;
vertex_t dest_c, start_c; struct {
fixed_t x, y;
} dest_c, start_c;
// looking glass center // looking glass center
start_c.x = (start->v1->x + start->v2->x) / 2; start_c.x = (start->v1->x + start->v2->x) / 2;
@ -182,6 +169,26 @@ void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, con
portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint);
portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight; portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight;
portal->viewangle = viewangle + dangle; portal->viewangle = viewangle + dangle;
}
/** Creates a portal out of two lines and a determined screen range.
*
* line1 determines the entrance, and line2 the exit.
* x1 and x2 determine the screen's column bounds.
* The view's offset from the entry line center is obtained,
* and then rotated&translated to the exit line's center.
* When the portal renders, it will create the illusion of
* the two lines being seamed together.
*/
void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2)
{
portal_t* portal = Portal_Add(x1, x2);
line_t* start = &lines[line1];
line_t* dest = &lines[line2];
Portal_GetViewpointForLine(portal, start, dest);
portal->clipline = line2; portal->clipline = line2;
@ -314,9 +321,17 @@ void Portal_AddSkybox (const visplane_t* plane)
void Portal_AddSectorPortal (const visplane_t* plane) void Portal_AddSectorPortal (const visplane_t* plane)
{ {
INT16 start, end; INT16 start, end;
sector_t *source = plane->sector; fixed_t x, y, z, angle;
sectorportal_t *secportal = plane->portalsector; sectorportal_t *secportal = plane->portalsector;
if (secportal->type == SECPORTAL_NONE)
return;
else if (secportal->type == SECPORTAL_SKYBOX)
{
Portal_AddSkybox(plane);
return;
}
if (TrimVisplaneBounds(plane, &start, &end)) if (TrimVisplaneBounds(plane, &start, &end))
return; return;
@ -324,24 +339,53 @@ void Portal_AddSectorPortal (const visplane_t* plane)
Portal_ClipVisplane(plane, portal); Portal_ClipVisplane(plane, portal);
fixed_t refx = source->soundorg.x - viewx; portal->clipline = -1;
fixed_t refy = source->soundorg.y - viewy;
// Rotate the X/Y to match the target angle switch (secportal->type)
if (secportal->target.angle)
{ {
fixed_t x = refx, y = refy; case SECPORTAL_LINE:
angle_t ang = secportal->target.angle >> ANGLETOFINESHIFT; Portal_GetViewpointForLine(portal, secportal->line.start, secportal->line.dest);
refx = FixedMul(x, FINECOSINE(ang)) - FixedMul(y, FINESINE(ang)); return;
refy = FixedMul(x, FINESINE(ang)) + FixedMul(y, FINECOSINE(ang)); case SECPORTAL_OBJECT:
if (!secportal->mobj || P_MobjWasRemoved(secportal->mobj))
return;
x = secportal->mobj->x;
y = secportal->mobj->y;
z = secportal->mobj->z;
angle = secportal->mobj->angle;
break;
case SECPORTAL_FLOOR:
x = secportal->sector->soundorg.x;
y = secportal->sector->soundorg.y;
z = secportal->sector->floorheight;
angle = 0;
break;
case SECPORTAL_CEILING:
x = secportal->sector->soundorg.x;
y = secportal->sector->soundorg.y;
z = secportal->sector->ceilingheight;
angle = 0;
break;
default:
return;
} }
portal->viewx = secportal->target.x - refx; fixed_t refx = plane->sector->soundorg.x - viewx;
portal->viewy = secportal->target.y - refy; fixed_t refy = plane->sector->soundorg.y - viewy;
portal->viewz = secportal->target.z + viewz;
portal->viewangle = secportal->target.angle + viewangle;
portal->clipline = -1; // Rotate the X/Y to match the target angle
if (angle != 0)
{
fixed_t tr_x = refx, tr_y = refy;
angle_t ang = angle >> ANGLETOFINESHIFT;
refx = FixedMul(tr_x, FINECOSINE(ang)) - FixedMul(tr_y, FINESINE(ang));
refy = FixedMul(tr_x, FINESINE(ang)) + FixedMul(tr_y, FINECOSINE(ang));
}
portal->viewx = x - refx;
portal->viewy = y - refy;
portal->viewz = z + viewz;
portal->viewangle = angle + viewangle;
} }
/** Creates portals for the currently existing sky visplanes. /** Creates portals for the currently existing sky visplanes.

View file

@ -1930,7 +1930,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|| !P_CompareSectorPortals(&frontsector->portal_ceiling, &backsector->portal_ceiling) || !P_CompareSectorPortals(&frontsector->portal_ceiling, &backsector->portal_ceiling)
|| (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags)))
{ {
markceiling = true; markceiling = true;
} }
else else
{ {