Merge branch 'slopethinkers' into thinkerlists

Signed-off-by: Nev3r <apophycens@gmail.com>
This commit is contained in:
Nev3r 2019-04-21 11:45:59 +02:00
commit d264d06879
8 changed files with 425 additions and 450 deletions

View file

@ -8191,10 +8191,8 @@ struct {
#endif #endif
#ifdef ESLOPE #ifdef ESLOPE
// Slope flags // Slope flags
{"SL_NOPHYSICS",SL_NOPHYSICS}, // Don't do momentum adjustment with this slope {"SL_NOPHYSICS",SL_NOPHYSICS},
{"SL_NODYNAMIC",SL_NODYNAMIC}, // Slope will never need to move during the level, so don't fuss with recalculating it {"SL_DYNAMIC",SL_DYNAMIC},
{"SL_ANCHORVERTEX",SL_ANCHORVERTEX},// Slope is using a Slope Vertex Thing to anchor its position
{"SL_VERTEXSLOPE",SL_VERTEXSLOPE}, // Slope is built from three Slope Vertex Things
#endif #endif
// Angles // Angles

View file

@ -292,8 +292,6 @@ enum slope_e {
slope_normal, slope_normal,
slope_zangle, slope_zangle,
slope_xydirection, slope_xydirection,
slope_sourceline,
slope_refpos,
slope_flags slope_flags
}; };
@ -305,8 +303,6 @@ static const char *const slope_opt[] = {
"normal", "normal",
"zangle", "zangle",
"xydirection", "xydirection",
"sourceline",
"refpos",
"flags", "flags",
NULL}; NULL};
@ -1831,12 +1827,6 @@ static int slope_get(lua_State *L)
case slope_xydirection: // xydirection case slope_xydirection: // xydirection
lua_pushangle(L, slope->xydirection); lua_pushangle(L, slope->xydirection);
return 1; return 1;
case slope_sourceline: // source linedef
LUA_PushUserdata(L, slope->sourceline, META_LINE);
return 1;
case slope_refpos: // refpos
lua_pushinteger(L, slope->refpos);
return 1;
case slope_flags: // flags case slope_flags: // flags
lua_pushinteger(L, slope->flags); lua_pushinteger(L, slope->flags);
return 1; return 1;
@ -1858,11 +1848,9 @@ static int slope_set(lua_State *L)
switch(field) // todo: reorganize this shit switch(field) // todo: reorganize this shit
{ {
case slope_valid: // valid case slope_valid: // valid
case slope_sourceline: // sourceline
case slope_d: // d case slope_d: // d
case slope_flags: // flags case slope_flags: // flags
case slope_normal: // normal case slope_normal: // normal
case slope_refpos: // refpos
default: default:
return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]); return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]);
case slope_o: { // o case slope_o: { // o

View file

@ -1304,6 +1304,10 @@ typedef enum
tc_fade, tc_fade,
tc_fadecolormap, tc_fadecolormap,
tc_planedisplace, tc_planedisplace,
#ifdef ESLOPE
tc_dynslopeline,
tc_dynslopevert,
#endif // ESLOPE
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
tc_polyrotate, // haleyjd 03/26/06: polyobjects tc_polyrotate, // haleyjd 03/26/06: polyobjects
tc_polymove, tc_polymove,
@ -1342,6 +1346,14 @@ static inline UINT32 SavePlayer(const player_t *player)
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }
#ifdef ESLOPE
static UINT32 SaveSlope(const pslope_t *slope)
{
if (slope) return (UINT32)(slope->id);
return 0xFFFFFFFF;
}
#endif // ESLOPE
// //
// SaveMobjThinker // SaveMobjThinker
// //
@ -1979,6 +1991,23 @@ static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type)
WRITEFIXED(save_p, ht->speed); WRITEFIXED(save_p, ht->speed);
WRITEUINT8(save_p, ht->type); WRITEUINT8(save_p, ht->type);
} }
#ifdef ESLOPE
/// Save a dynamic slope thinker.
static inline void SaveDynamicSlopeThinker(const thinker_t *th, const UINT8 type)
{
const dynplanethink_t* ht = (const void*)th;
WRITEUINT8(save_p, type);
WRITEUINT8(save_p, ht->type);
WRITEUINT32(save_p, SaveSlope(ht->slope));
WRITEUINT32(save_p, SaveLine(ht->sourceline));
WRITEFIXED(save_p, ht->extent);
WRITEMEM(save_p, ht->tags, sizeof(ht->tags));
WRITEMEM(save_p, ht->vex, sizeof(ht->vex));
}
#endif // ESLOPE
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
// //
@ -2313,7 +2342,7 @@ static void P_NetArchiveThinkers(void)
SavePlaneDisplaceThinker(th, tc_planedisplace); SavePlaneDisplaceThinker(th, tc_planedisplace);
continue; continue;
} }
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate) else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate)
{ {
SavePolyrotatetThinker(th, tc_polyrotate); SavePolyrotatetThinker(th, tc_polyrotate);
@ -2360,6 +2389,18 @@ static void P_NetArchiveThinkers(void)
continue; continue;
} }
#endif #endif
#ifdef ESLOPE
else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeLine)
{
SaveDynamicSlopeThinker(th, tc_dynslopeline);
continue;
}
else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeVert)
{
SaveDynamicSlopeThinker(th, tc_dynslopevert);
continue;
}
#endif // ESLOPE
#ifdef PARANOIA #ifdef PARANOIA
else if (th->function.acv != P_RemoveThinkerDelayed) // wait garbage collection else if (th->function.acv != P_RemoveThinkerDelayed) // wait garbage collection
I_Error("unknown thinker type %p", th->function.acp1); I_Error("unknown thinker type %p", th->function.acp1);
@ -2418,6 +2459,20 @@ static inline player_t *LoadPlayer(UINT32 player)
return &players[player]; return &players[player];
} }
#ifdef ESLOPE
static inline pslope_t *LoadSlope(UINT32 slopeid)
{
pslope_t *p = slopelist;
if (slopeid > slopecount) return NULL;
do
{
if (p->id == slopeid)
return p;
} while ((p = p->next));
return NULL;
}
#endif // ESLOPE
// //
// LoadMobjThinker // LoadMobjThinker
// //
@ -3110,6 +3165,7 @@ static inline thinker_t* LoadPlaneDisplaceThinker(actionf_p1 thinker)
{ {
planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker; ht->thinker.function.acp1 = thinker;
ht->affectee = READINT32(save_p); ht->affectee = READINT32(save_p);
ht->control = READINT32(save_p); ht->control = READINT32(save_p);
ht->last_height = READFIXED(save_p); ht->last_height = READFIXED(save_p);
@ -3118,6 +3174,23 @@ static inline thinker_t* LoadPlaneDisplaceThinker(actionf_p1 thinker)
return &ht->thinker; return &ht->thinker;
} }
#ifdef ESLOPE
/// Save a dynamic slope thinker.
static inline thinker_t* LoadDynamicSlopeThinker(actionf_p1 thinker)
{
dynplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
ht->type = READUINT8(save_p);
ht->slope = LoadSlope(READUINT32(save_p));
ht->sourceline = LoadLine(READUINT32(save_p));
ht->extent = READFIXED(save_p);
READMEM(save_p, ht->tags, sizeof(ht->tags));
READMEM(save_p, ht->vex, sizeof(ht->vex));
return &ht->thinker;
}
#endif // ESLOPE
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
// //
@ -3457,7 +3530,7 @@ static void P_NetUnArchiveThinkers(void)
case tc_planedisplace: case tc_planedisplace:
th = LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace); th = LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace);
break; break;
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
case tc_polyrotate: case tc_polyrotate:
th = LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate); th = LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate);
break; break;
@ -3493,7 +3566,17 @@ static void P_NetUnArchiveThinkers(void)
case tc_polyfade: case tc_polyfade:
th = LoadPolyfadeThinker((actionf_p1)T_PolyObjFade); th = LoadPolyfadeThinker((actionf_p1)T_PolyObjFade);
break; break;
#endif #endif
#ifdef ESLOPE
case tc_dynslopeline:
th = LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeLine);
break;
case tc_dynslopevert:
th = LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeVert);
break;
#endif // ESLOPE
case tc_scroll: case tc_scroll:
th = LoadScrollThinker((actionf_p1)T_Scroll); th = LoadScrollThinker((actionf_p1)T_Scroll);
break; break;

View file

@ -2911,7 +2911,8 @@ boolean P_SetupLevel(boolean skipprecip)
P_InitSpecials(); P_InitSpecials();
#ifdef ESLOPE #ifdef ESLOPE
P_ResetDynamicSlopes(); P_ResetDynamicSlopes(fromnetsave);
P_LinkSlopeThinkers(); // Spawn slope thinkers just after plane move thinkers to avoid movement/update delays.
#endif #endif
P_LoadThings(loademblems); P_LoadThings(loademblems);

View file

@ -25,68 +25,106 @@
#ifdef ESLOPE #ifdef ESLOPE
static pslope_t *slopelist = NULL; pslope_t *slopelist = NULL;
static UINT16 slopecount = 0; UINT16 slopecount = 0;
thinker_t *dynthinklist;
size_t dynthinknum;
/// Links previously queued thinker list to the main thinker list.
void P_LinkSlopeThinkers (void)
{
size_t i;
thinker_t *th = dynthinklist;
CONS_Printf("Number of dynamic thinkers: %d\n", dynthinknum);
for (i = 0; i < dynthinknum; i++)
{
thinker_t *next = th->next;
P_AddThinker(th);
th = next;
}
}
/// Queues a thinker to a partial linked list to be immediately incorporated later via P_LinkSlopeThinkers().
static void P_QueueSlopeThinker (thinker_t* th)
{
thinker_t* last = dynthinklist;
// First entry.
if (!last)
{
dynthinklist = th;
dynthinknum++;
return;
}
while (last->next)
last = last->next;
last->next = th;
dynthinknum++;
}
// Calculate line normal // Calculate line normal
void P_CalculateSlopeNormal(pslope_t *slope) { void P_CalculateSlopeNormal(pslope_t *slope) {
slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT); slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT);
slope->normal.x = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.x); slope->normal.x = FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.x);
slope->normal.y = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y); slope->normal.y = FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y);
} }
// With a vertex slope that has its vertices set, configure relevant slope info /// Setup slope via 3 vertexes.
static void P_ReconfigureVertexSlope(pslope_t *slope) static void ReconfigureViaVertexes (pslope_t *slope, const vector3_t v1, const vector3_t v2, const vector3_t v3)
{ {
vector3_t vec1, vec2; vector3_t vec1, vec2;
// Set slope normal // Set origin.
vec1.x = (slope->vertices[1]->x - slope->vertices[0]->x) << FRACBITS; FV3_Copy(&slope->o, &v1);
vec1.y = (slope->vertices[1]->y - slope->vertices[0]->y) << FRACBITS;
vec1.z = (slope->vertices[1]->z - slope->vertices[0]->z) << FRACBITS;
vec2.x = (slope->vertices[2]->x - slope->vertices[0]->x) << FRACBITS; // Get slope's normal.
vec2.y = (slope->vertices[2]->y - slope->vertices[0]->y) << FRACBITS; FV3_SubEx(&v2, &v1, &vec1);
vec2.z = (slope->vertices[2]->z - slope->vertices[0]->z) << FRACBITS; FV3_SubEx(&v3, &v1, &vec2);
// ugggggggh fixed-point maaaaaaath // Set some defaults for a non-sloped "slope"
slope->extent = max( if (vec1.z == 0 && vec2.z == 0)
max(max(abs(vec1.x), abs(vec1.y)), abs(vec1.z)), {
max(max(abs(vec2.x), abs(vec2.y)), abs(vec2.z)) /// \todo Fix fully flat cases.
) >> (FRACBITS+5);
vec1.x /= slope->extent;
vec1.y /= slope->extent;
vec1.z /= slope->extent;
vec2.x /= slope->extent;
vec2.y /= slope->extent;
vec2.z /= slope->extent;
FV3_Cross(&vec1, &vec2, &slope->normal);
slope->extent = R_PointToDist2(0, 0, R_PointToDist2(0, 0, slope->normal.x, slope->normal.y), slope->normal.z);
if (slope->normal.z < 0)
slope->extent = -slope->extent;
slope->normal.x = FixedDiv(slope->normal.x, slope->extent);
slope->normal.y = FixedDiv(slope->normal.y, slope->extent);
slope->normal.z = FixedDiv(slope->normal.z, slope->extent);
// Set origin
slope->o.x = slope->vertices[0]->x << FRACBITS;
slope->o.y = slope->vertices[0]->y << FRACBITS;
slope->o.z = slope->vertices[0]->z << FRACBITS;
if (slope->normal.x == 0 && slope->normal.y == 0) { // Set some defaults for a non-sloped "slope"
slope->zangle = slope->xydirection = 0; slope->zangle = slope->xydirection = 0;
slope->zdelta = slope->d.x = slope->d.y = 0; slope->zdelta = slope->d.x = slope->d.y = 0;
} else { }
else
{
/// \note Using fixed point for vectorial products easily leads to overflows so we work around by downscaling them.
fixed_t m = max(
max(max(abs(vec1.x), abs(vec1.y)), abs(vec1.z)),
max(max(abs(vec2.x), abs(vec2.y)), abs(vec2.z))
) >> 5; // shifting right by 5 is good enough.
FV3_Cross(
FV3_Divide(&vec1, m),
FV3_Divide(&vec2, m),
&slope->normal
);
// NOTE: FV3_Magnitude() doesn't work properly in some cases, and chaining FixedHypot() seems to give worse results.
m = R_PointToDist2(0, 0, R_PointToDist2(0, 0, slope->normal.x, slope->normal.y), slope->normal.z);
// Invert normal if it's facing down.
if (slope->normal.z < 0)
m = -m;
FV3_Divide(&slope->normal, m);
// Get direction vector // Get direction vector
slope->extent = R_PointToDist2(0, 0, slope->normal.x, slope->normal.y); m = FixedHypot(slope->normal.x, slope->normal.y);
slope->d.x = -FixedDiv(slope->normal.x, slope->extent); slope->d.x = -FixedDiv(slope->normal.x, m);
slope->d.y = -FixedDiv(slope->normal.y, slope->extent); slope->d.y = -FixedDiv(slope->normal.y, m);
// Z delta // Z delta
slope->zdelta = FixedDiv(slope->extent, slope->normal.z); slope->zdelta = FixedDiv(m, slope->normal.z);
// Get angles // Get angles
slope->xydirection = R_PointToAngle2(0, 0, slope->d.x, slope->d.y)+ANGLE_180; slope->xydirection = R_PointToAngle2(0, 0, slope->d.x, slope->d.y)+ANGLE_180;
@ -94,88 +132,95 @@ static void P_ReconfigureVertexSlope(pslope_t *slope)
} }
} }
// Recalculate dynamic slopes /// Recalculate dynamic slopes.
void P_RunDynamicSlopes(void) { void T_DynamicSlopeLine (dynplanethink_t* th)
pslope_t *slope; {
pslope_t* slope = th->slope;
line_t* srcline = th->sourceline;
for (slope = slopelist; slope; slope = slope->next) { fixed_t zdelta;
fixed_t zdelta;
if (slope->flags & SL_NODYNAMIC) switch(th->type) {
continue; case DP_FRONTFLOOR:
zdelta = srcline->backsector->floorheight - srcline->frontsector->floorheight;
slope->o.z = srcline->frontsector->floorheight;
break;
switch(slope->refpos) { case DP_FRONTCEIL:
case 1: // front floor zdelta = srcline->backsector->ceilingheight - srcline->frontsector->ceilingheight;
zdelta = slope->sourceline->backsector->floorheight - slope->sourceline->frontsector->floorheight; slope->o.z = srcline->frontsector->ceilingheight;
slope->o.z = slope->sourceline->frontsector->floorheight; break;
break;
case 2: // front ceiling
zdelta = slope->sourceline->backsector->ceilingheight - slope->sourceline->frontsector->ceilingheight;
slope->o.z = slope->sourceline->frontsector->ceilingheight;
break;
case 3: // back floor
zdelta = slope->sourceline->frontsector->floorheight - slope->sourceline->backsector->floorheight;
slope->o.z = slope->sourceline->backsector->floorheight;
break;
case 4: // back ceiling
zdelta = slope->sourceline->frontsector->ceilingheight - slope->sourceline->backsector->ceilingheight;
slope->o.z = slope->sourceline->backsector->ceilingheight;
break;
case 5: // vertices
{
mapthing_t *mt;
size_t i;
INT32 l;
line_t *line;
for (i = 0; i < 3; i++) { case DP_BACKFLOOR:
mt = slope->vertices[i]; zdelta = srcline->frontsector->floorheight - srcline->backsector->floorheight;
l = P_FindSpecialLineFromTag(799, mt->angle, -1); slope->o.z = srcline->backsector->floorheight;
if (l != -1) { break;
line = &lines[l];
mt->z = line->frontsector->floorheight >> FRACBITS;
}
}
P_ReconfigureVertexSlope(slope); case DP_BACKCEIL:
} zdelta = srcline->frontsector->ceilingheight - srcline->backsector->ceilingheight;
continue; // TODO slope->o.z = srcline->backsector->ceilingheight;
break;
default: default:
I_Error("P_RunDynamicSlopes: slope has invalid type!"); return;
} }
if (slope->zdelta != FixedDiv(zdelta, slope->extent)) { if (slope->zdelta != FixedDiv(zdelta, th->extent)) {
slope->zdelta = FixedDiv(zdelta, slope->extent); slope->zdelta = FixedDiv(zdelta, th->extent);
slope->zangle = R_PointToAngle2(0, 0, slope->extent, -zdelta); slope->zangle = R_PointToAngle2(0, 0, th->extent, -zdelta);
P_CalculateSlopeNormal(slope); P_CalculateSlopeNormal(slope);
}
} }
} }
// /// Mapthing-defined
// P_MakeSlope void T_DynamicSlopeVert (dynplanethink_t* th)
//
// Alocates and fill the contents of a slope structure.
//
static pslope_t *P_MakeSlope(const vector3_t *o, const vector2_t *d,
const fixed_t zdelta, UINT8 flags)
{ {
pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL); pslope_t* slope = th->slope;
memset(ret, 0, sizeof(*ret));
ret->o.x = o->x; size_t i;
ret->o.y = o->y; INT32 l;
ret->o.z = o->z;
ret->d.x = d->x; for (i = 0; i < 3; i++) {
ret->d.y = d->y; l = P_FindSpecialLineFromTag(799, th->tags[i], -1);
if (l != -1) {
th->vex[i].z = lines[l].frontsector->floorheight;
}
else
th->vex[i].z = 0;
}
ret->zdelta = zdelta; ReconfigureViaVertexes(slope, th->vex[0], th->vex[1], th->vex[2]);
}
static inline void P_AddDynSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent, const INT16 tags[3], const vector3_t vx[3])
{
dynplanethink_t* th = Z_Calloc(sizeof (*th), PU_LEVSPEC, NULL);
switch (type)
{
case DP_VERTEX:
th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeVert;
memcpy(th->tags, tags, sizeof(th->tags));
memcpy(th->vex, vx, sizeof(th->vex));
break;
default:
th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeLine;
th->sourceline = sourceline;
th->extent = extent;
}
th->slope = slope;
th->type = type;
P_QueueSlopeThinker(&th->thinker);
}
/// Create a new slope and add it to the slope list.
static inline pslope_t* Slope_Add (const UINT8 flags)
{
pslope_t *ret = Z_Calloc(sizeof(pslope_t), PU_LEVEL, NULL);
ret->flags = flags; ret->flags = flags;
// Add to the slope list
ret->next = slopelist; ret->next = slopelist;
slopelist = ret; slopelist = ret;
@ -185,13 +230,24 @@ static pslope_t *P_MakeSlope(const vector3_t *o, const vector2_t *d,
return ret; return ret;
} }
// /// Alocates and fill the contents of a slope structure.
// P_GetExtent static pslope_t *MakeViaVectors(const vector3_t *o, const vector2_t *d,
// const fixed_t zdelta, UINT8 flags)
// Returns the distance to the first line within the sector that {
// is intersected by a line parallel to the plane normal with the point (ox, oy) pslope_t *ret = Slope_Add(flags);
//
static fixed_t P_GetExtent(sector_t *sector, line_t *line) FV3_Copy(&ret->o, o);
FV2_Copy(&ret->d, d);
ret->zdelta = zdelta;
ret->flags = flags;
return ret;
}
/// Get furthest perpendicular distance from all vertexes in a sector for a given line.
static fixed_t GetExtent(sector_t *sector, line_t *line)
{ {
// ZDoom code reference: v3float_t = vertex_t // ZDoom code reference: v3float_t = vertex_t
fixed_t fardist = -FRACUNIT; fixed_t fardist = -FRACUNIT;
@ -224,14 +280,8 @@ static fixed_t P_GetExtent(sector_t *sector, line_t *line)
return fardist; return fardist;
} }
/// Creates one or more slopes based on the given line type and front/back sectors.
// static void line_SpawnViaLine(const int linenum, const boolean spawnthinker)
// P_SpawnSlope_Line
//
// Creates one or more slopes based on the given line type and front/back
// sectors.
//
void P_SpawnSlope_Line(int linenum)
{ {
// With dynamic slopes, it's fine to just leave this function as normal, // With dynamic slopes, it's fine to just leave this function as normal,
// because checking to see if a slope had changed will waste more memory than // because checking to see if a slope had changed will waste more memory than
@ -251,10 +301,8 @@ void P_SpawnSlope_Line(int linenum)
UINT8 flags = 0; // Slope flags UINT8 flags = 0; // Slope flags
if (line->flags & ML_NOSONIC) if (line->flags & ML_NOSONIC)
flags |= SL_NOPHYSICS; flags |= SL_NOPHYSICS;
if (!(line->flags & ML_NOTAILS)) if (line->flags & ML_NOTAILS)
flags |= SL_NODYNAMIC; flags |= SL_DYNAMIC;
if (line->flags & ML_NOKNUX)
flags |= SL_ANCHORVERTEX;
if(!frontfloor && !backfloor && !frontceil && !backceil) if(!frontfloor && !backfloor && !frontceil && !backceil)
{ {
@ -274,6 +322,7 @@ void P_SpawnSlope_Line(int linenum)
ny = -FixedDiv(line->dx, len); ny = -FixedDiv(line->dx, len);
} }
// Set origin to line's center.
origin.x = line->v1->x + (line->v2->x - line->v1->x)/2; origin.x = line->v1->x + (line->v2->x - line->v1->x)/2;
origin.y = line->v1->y + (line->v2->y - line->v1->y)/2; origin.y = line->v1->y + (line->v2->y - line->v1->y)/2;
@ -286,7 +335,7 @@ void P_SpawnSlope_Line(int linenum)
direction.x = nx; direction.x = nx;
direction.y = ny; direction.y = ny;
extent = P_GetExtent(line->frontsector, line); extent = GetExtent(line->frontsector, line);
if(extent < 0) if(extent < 0)
{ {
@ -304,104 +353,43 @@ void P_SpawnSlope_Line(int linenum)
if(frontfloor) if(frontfloor)
{ {
fixed_t highest, lowest;
size_t l;
point.z = line->frontsector->floorheight; // Startz point.z = line->frontsector->floorheight; // Startz
dz = FixedDiv(origin.z - point.z, extent); // Destinationz dz = FixedDiv(origin.z - point.z, extent); // Destinationz
// In P_SpawnSlopeLine the origin is the centerpoint of the sourcelinedef // In P_SpawnSlopeLine the origin is the centerpoint of the sourcelinedef
fslope = line->frontsector->f_slope = fslope = line->frontsector->f_slope =
P_MakeSlope(&point, &direction, dz, flags); MakeViaVectors(&point, &direction, dz, flags);
// Set up some shit
fslope->extent = extent;
fslope->refpos = 1;
// Now remember that f_slope IS a vector // Now remember that f_slope IS a vector
// fslope->o = origin 3D point 1 of the vector // fslope->o = origin 3D point 1 of the vector
// fslope->d = destination 3D point 2 of the vector // fslope->d = destination 3D point 2 of the vector
// fslope->normal is a 3D line perpendicular to the 3D vector // fslope->normal is a 3D line perpendicular to the 3D vector
// Sync the linedata of the line that started this slope
// TODO: Anything special for control sector based slopes later?
fslope->sourceline = line;
// To find the real highz/lowz of a slope, you need to check all the vertexes
// in the slope's sector with P_GetZAt to get the REAL lowz & highz
// Although these slopes are set by floorheights the ANGLE is what a slope is,
// so technically any slope can extend on forever (they are just bound by sectors)
// *You can use sourceline as a reference to see if two slopes really are the same
// Default points for high and low
highest = point.z > origin.z ? point.z : origin.z;
lowest = point.z < origin.z ? point.z : origin.z;
// Now check to see what the REAL high and low points of the slope inside the sector
// TODO: Is this really needed outside of FOFs? -Red
for (l = 0; l < line->frontsector->linecount; l++)
{
fixed_t height = P_GetZAt(line->frontsector->f_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y);
if (height > highest)
highest = height;
if (height < lowest)
lowest = height;
}
// Sets extra clipping data for the frontsector's slope
fslope->highz = highest;
fslope->lowz = lowest;
fslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z); fslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y); fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
P_CalculateSlopeNormal(fslope); P_CalculateSlopeNormal(fslope);
if (spawnthinker && (flags & SL_DYNAMIC))
P_AddDynSlopeThinker(fslope, DP_FRONTFLOOR, line, extent, NULL, NULL);
} }
if(frontceil) if(frontceil)
{ {
fixed_t highest, lowest;
size_t l;
origin.z = line->backsector->ceilingheight; origin.z = line->backsector->ceilingheight;
point.z = line->frontsector->ceilingheight; point.z = line->frontsector->ceilingheight;
dz = FixedDiv(origin.z - point.z, extent); dz = FixedDiv(origin.z - point.z, extent);
cslope = line->frontsector->c_slope = cslope = line->frontsector->c_slope =
P_MakeSlope(&point, &direction, dz, flags); MakeViaVectors(&point, &direction, dz, flags);
// Set up some shit
cslope->extent = extent;
cslope->refpos = 2;
// Sync the linedata of the line that started this slope
// TODO: Anything special for control sector based slopes later?
cslope->sourceline = line;
// Remember the way the slope is formed
highest = point.z > origin.z ? point.z : origin.z;
lowest = point.z < origin.z ? point.z : origin.z;
for (l = 0; l < line->frontsector->linecount; l++)
{
fixed_t height = P_GetZAt(line->frontsector->c_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y);
if (height > highest)
highest = height;
if (height < lowest)
lowest = height;
}
// This line special sets extra clipping data for the frontsector's slope
cslope->highz = highest;
cslope->lowz = lowest;
cslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z); cslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y); cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
P_CalculateSlopeNormal(cslope); P_CalculateSlopeNormal(cslope);
if (spawnthinker && (flags & SL_DYNAMIC))
P_AddDynSlopeThinker(cslope, DP_FRONTCEIL, line, extent, NULL, NULL);
} }
} }
if(backfloor || backceil) if(backfloor || backceil)
@ -413,7 +401,7 @@ void P_SpawnSlope_Line(int linenum)
direction.x = -nx; direction.x = -nx;
direction.y = -ny; direction.y = -ny;
extent = P_GetExtent(line->backsector, line); extent = GetExtent(line->backsector, line);
if(extent < 0) if(extent < 0)
{ {
@ -429,88 +417,36 @@ void P_SpawnSlope_Line(int linenum)
if(backfloor) if(backfloor)
{ {
fixed_t highest, lowest;
size_t l;
point.z = line->backsector->floorheight; point.z = line->backsector->floorheight;
dz = FixedDiv(origin.z - point.z, extent); dz = FixedDiv(origin.z - point.z, extent);
fslope = line->backsector->f_slope = fslope = line->backsector->f_slope =
P_MakeSlope(&point, &direction, dz, flags); MakeViaVectors(&point, &direction, dz, flags);
// Set up some shit
fslope->extent = extent;
fslope->refpos = 3;
// Sync the linedata of the line that started this slope
// TODO: Anything special for control sector based slopes later?
fslope->sourceline = line;
// Remember the way the slope is formed
highest = point.z > origin.z ? point.z : origin.z;
lowest = point.z < origin.z ? point.z : origin.z;
for (l = 0; l < line->backsector->linecount; l++)
{
fixed_t height = P_GetZAt(line->backsector->f_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y);
if (height > highest)
highest = height;
if (height < lowest)
lowest = height;
}
// This line special sets extra clipping data for the frontsector's slope
fslope->highz = highest;
fslope->lowz = lowest;
fslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z); fslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y); fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
P_CalculateSlopeNormal(fslope); P_CalculateSlopeNormal(fslope);
if (spawnthinker && (flags & SL_DYNAMIC))
P_AddDynSlopeThinker(fslope, DP_BACKFLOOR, line, extent, NULL, NULL);
} }
if(backceil) if(backceil)
{ {
fixed_t highest, lowest;
size_t l;
origin.z = line->frontsector->ceilingheight; origin.z = line->frontsector->ceilingheight;
point.z = line->backsector->ceilingheight; point.z = line->backsector->ceilingheight;
dz = FixedDiv(origin.z - point.z, extent); dz = FixedDiv(origin.z - point.z, extent);
cslope = line->backsector->c_slope = cslope = line->backsector->c_slope =
P_MakeSlope(&point, &direction, dz, flags); MakeViaVectors(&point, &direction, dz, flags);
// Set up some shit
cslope->extent = extent;
cslope->refpos = 4;
// Sync the linedata of the line that started this slope
// TODO: Anything special for control sector based slopes later?
cslope->sourceline = line;
// Remember the way the slope is formed
highest = point.z > origin.z ? point.z : origin.z;
lowest = point.z < origin.z ? point.z : origin.z;
for (l = 0; l < line->backsector->linecount; l++)
{
fixed_t height = P_GetZAt(line->backsector->c_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y);
if (height > highest)
highest = height;
if (height < lowest)
lowest = height;
}
// This line special sets extra clipping data for the backsector's slope
cslope->highz = highest;
cslope->lowz = lowest;
cslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z); cslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y); cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
P_CalculateSlopeNormal(cslope); P_CalculateSlopeNormal(cslope);
if (spawnthinker && (flags & SL_DYNAMIC))
P_AddDynSlopeThinker(cslope, DP_BACKCEIL, line, extent, NULL, NULL);
} }
} }
@ -518,63 +454,99 @@ void P_SpawnSlope_Line(int linenum)
return; return;
} }
// /// Creates a new slope from three mapthings with the specified IDs
// P_NewVertexSlope static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flags, const boolean spawnthinker)
//
// Creates a new slope from three vertices with the specified IDs
//
static pslope_t *P_NewVertexSlope(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flags)
{ {
size_t i; size_t i;
mapthing_t *mt = mapthings; mapthing_t* mt = mapthings;
mapthing_t* vertices[3] = {0};
INT16 tags[3] = {tag1, tag2, tag3};
pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL); vector3_t vx[3];
memset(ret, 0, sizeof(*ret)); pslope_t* ret = Slope_Add(flags);
// Start by setting flags
ret->flags = flags;
// Now set up the vertex list
ret->vertices = Z_Malloc(3*sizeof(mapthing_t), PU_LEVEL, NULL);
memset(ret->vertices, 0, 3*sizeof(mapthing_t));
// And... look for the vertices in question. // And... look for the vertices in question.
for (i = 0; i < nummapthings; i++, mt++) { for (i = 0; i < nummapthings; i++, mt++) {
if (mt->type != 750) // Haha, I'm hijacking the old Chaos Spawn thingtype for something! if (mt->type != 750) // Haha, I'm hijacking the old Chaos Spawn thingtype for something!
continue; continue;
if (!ret->vertices[0] && mt->angle == tag1) if (!vertices[0] && mt->angle == tag1)
ret->vertices[0] = mt; vertices[0] = mt;
else if (!ret->vertices[1] && mt->angle == tag2) else if (!vertices[1] && mt->angle == tag2)
ret->vertices[1] = mt; vertices[1] = mt;
else if (!ret->vertices[2] && mt->angle == tag3) else if (!vertices[2] && mt->angle == tag3)
ret->vertices[2] = mt; vertices[2] = mt;
} }
// Now set heights for each vertex, because they haven't been set yet // Now set heights for each vertex, because they haven't been set yet
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
mt = ret->vertices[i]; mt = vertices[i];
if (!mt) // If a vertex wasn't found, it's game over. There's nothing you can do to recover (except maybe try and kill the slope instead - TODO?) if (!mt) // If a vertex wasn't found, it's game over. There's nothing you can do to recover (except maybe try and kill the slope instead - TODO?)
I_Error("P_NewVertexSlope: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1); I_Error("MakeViaMapthings: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1);
vx[i].x = mt->x << FRACBITS;
vx[i].y = mt->y << FRACBITS;
if (mt->extrainfo) if (mt->extrainfo)
mt->z = mt->options; vx[i].z = mt->options << FRACBITS;
else else
mt->z = (R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector->floorheight >> FRACBITS) + (mt->options >> ZSHIFT); vx[i].z = (R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector->floorheight) + ((mt->options >> ZSHIFT) << FRACBITS);
} }
P_ReconfigureVertexSlope(ret); ReconfigureViaVertexes(ret, vx[0], vx[1], vx[2]);
ret->refpos = 5;
// Add to the slope list if (spawnthinker && (flags & SL_DYNAMIC))
ret->next = slopelist; P_AddDynSlopeThinker(ret, DP_VERTEX, NULL, 0, tags, vx);
slopelist = ret;
slopecount++;
ret->id = slopecount;
return ret; return ret;
} }
/// Create vertex based slopes.
static void line_SpawnViaVertexes(const int linenum, const boolean spawnthinker)
{
line_t *line = lines + linenum;
side_t *side;
pslope_t **slopetoset;
UINT16 tag1, tag2, tag3;
UINT8 flags = 0;
if (line->flags & ML_NOSONIC)
flags |= SL_NOPHYSICS;
if (line->flags & ML_NOTAILS)
flags |= SL_DYNAMIC;
switch(line->special)
{
case 704:
slopetoset = &line->frontsector->f_slope;
side = &sides[line->sidenum[0]];
break;
case 705:
slopetoset = &line->frontsector->c_slope;
side = &sides[line->sidenum[0]];
break;
case 714:
slopetoset = &line->backsector->f_slope;
side = &sides[line->sidenum[1]];
break;
case 715:
slopetoset = &line->backsector->c_slope;
side = &sides[line->sidenum[1]];
default:
return;
}
if (line->flags & ML_NOKNUX)
{
tag1 = line->tag;
tag2 = side->textureoffset >> FRACBITS;
tag3 = side->rowoffset >> FRACBITS;
}
else
tag1 = tag2 = tag3 = line->tag;
*slopetoset = MakeViaMapthings(tag1, tag2, tag3, flags, spawnthinker);
side->sector->hasslope = true;
}
// //
@ -615,56 +587,23 @@ pslope_t *P_SlopeById(UINT16 id)
return ret; return ret;
} }
// Reset the dynamic slopes pointer, and read all of the fancy schmancy slopes /// Reset slopes and read them from special lines.
void P_ResetDynamicSlopes(void) { void P_ResetDynamicSlopes(const UINT32 fromsave) {
size_t i; size_t i;
#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
boolean warned = false; boolean spawnthinkers = !(boolean)fromsave;
#endif
slopelist = NULL; slopelist = NULL;
slopecount = 0; slopecount = 0;
// We'll handle copy slopes later, after all the tag lists have been made. dynthinklist = NULL;
// Yes, this means copied slopes won't affect things' spawning heights. Too bad for you. dynthinknum = 0;
/// Generates line special-defined slopes.
for (i = 0; i < numlines; i++) for (i = 0; i < numlines; i++)
{ {
switch (lines[i].special) switch (lines[i].special)
{ {
#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
#define WARNME if (!warned) {warned = true; CONS_Alert(CONS_WARNING, "This level uses old slope specials.\nA conversion will be needed before 2.2's release.\n");}
case 386:
case 387:
case 388:
lines[i].special += 700-386;
WARNME
P_SpawnSlope_Line(i);
break;
case 389:
case 390:
case 391:
case 392:
lines[i].special += 710-389;
WARNME
P_SpawnSlope_Line(i);
break;
case 393:
lines[i].special = 703;
WARNME
P_SpawnSlope_Line(i);
break;
case 394:
case 395:
case 396:
lines[i].special += 720-394;
WARNME
break;
#endif
case 700: case 700:
case 701: case 701:
case 702: case 702:
@ -673,63 +612,35 @@ void P_ResetDynamicSlopes(void) {
case 711: case 711:
case 712: case 712:
case 713: case 713:
P_SpawnSlope_Line(i); line_SpawnViaLine(i, spawnthinkers);
break; break;
case 704: case 704:
case 705: case 705:
case 714: case 714:
case 715: case 715:
{ line_SpawnViaVertexes(i, spawnthinkers);
pslope_t **slopetoset;
size_t which = lines[i].special;
UINT8 flags = SL_VERTEXSLOPE;
if (lines[i].flags & ML_NOSONIC)
flags |= SL_NOPHYSICS;
if (!(lines[i].flags & ML_NOTAILS))
flags |= SL_NODYNAMIC;
if (which == 704)
{
slopetoset = &lines[i].frontsector->f_slope;
which = 0;
}
else if (which == 705)
{
slopetoset = &lines[i].frontsector->c_slope;
which = 0;
}
else if (which == 714)
{
slopetoset = &lines[i].backsector->f_slope;
which = 1;
}
else // 715
{
slopetoset = &lines[i].backsector->c_slope;
which = 1;
}
if (lines[i].flags & ML_NOKNUX)
*slopetoset = P_NewVertexSlope(lines[i].tag, sides[lines[i].sidenum[which]].textureoffset >> FRACBITS,
sides[lines[i].sidenum[which]].rowoffset >> FRACBITS, flags);
else
*slopetoset = P_NewVertexSlope(lines[i].tag, lines[i].tag, lines[i].tag, flags);
sides[lines[i].sidenum[which]].sector->hasslope = true;
}
break; break;
default: default:
break; break;
} }
} }
/// Copies slopes from tagged sectors via line specials.
/// \note Doesn't actually copy, but instead they share the same pointers.
for (i = 0; i < numlines; i++)
switch (lines[i].special)
{
case 720:
case 721:
case 722:
P_CopySectorSlope(&lines[i]);
default:
break;
}
} }
// ============================================================================ // ============================================================================
// //
// Various utilities related to slopes // Various utilities related to slopes

View file

@ -10,17 +10,17 @@
/// \file p_slopes.c /// \file p_slopes.c
/// \brief ZDoom + Eternity Engine Slopes, ported and enhanced by Kalaron /// \brief ZDoom + Eternity Engine Slopes, ported and enhanced by Kalaron
#ifndef P_SLOPES_H__ #include "m_fixed.h" // Vectors
#define P_SLOPES_H__
#ifdef ESLOPE #ifdef ESLOPE
extern pslope_t *slopelist;
extern UINT16 slopecount;
void P_LinkSlopeThinkers (void);
void P_CalculateSlopeNormal(pslope_t *slope); void P_CalculateSlopeNormal(pslope_t *slope);
void P_ResetDynamicSlopes(void); void P_ResetDynamicSlopes(const UINT32 fromsave);
void P_RunDynamicSlopes(void);
// P_SpawnSlope_Line
// Creates one or more slopes based on the given line type and front/back
// sectors.
void P_SpawnSlope_Line(int linenum);
// //
// P_CopySectorSlope // P_CopySectorSlope
@ -42,7 +42,33 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope);
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope); void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope);
void P_ButteredSlope(mobj_t *mo); void P_ButteredSlope(mobj_t *mo);
#endif
// EOF /// Dynamic plane type enum for the thinker. Will have a different functionality depending on this.
typedef enum {
DP_FRONTFLOOR,
DP_FRONTCEIL,
DP_BACKFLOOR,
DP_BACKCEIL,
DP_VERTEX
} dynplanetype_t;
/// Permit slopes to be dynamically altered through a thinker.
typedef struct
{
thinker_t thinker;
pslope_t* slope;
dynplanetype_t type;
// Used by line slopes.
line_t* sourceline;
fixed_t extent;
// Used by mapthing vertex slopes.
INT16 tags[3];
vector3_t vex[3];
} dynplanethink_t;
void T_DynamicSlopeLine (dynplanethink_t* th);
void T_DynamicSlopeVert (dynplanethink_t* th);
#endif // #ifdef ESLOPE #endif // #ifdef ESLOPE

View file

@ -5558,11 +5558,6 @@ void P_UpdateSpecials(void)
// POINT LIMIT // POINT LIMIT
P_CheckPointLimit(); P_CheckPointLimit();
#ifdef ESLOPE
// Dynamic slopeness
P_RunDynamicSlopes();
#endif
// ANIMATE TEXTURES // ANIMATE TEXTURES
for (anim = anims; anim < lastanim; anim++) for (anim = anims; anim < lastanim; anim++)
{ {
@ -7356,14 +7351,6 @@ void P_SpawnSpecials(INT32 fromnetsave)
sectors[s].extra_colormap = sectors[s].spawn_extra_colormap = sides[lines[i].sidenum[0]].colormap_data; sectors[s].extra_colormap = sectors[s].spawn_extra_colormap = sides[lines[i].sidenum[0]].colormap_data;
break; break;
#ifdef ESLOPE // Slope copy specials. Handled here for sanity.
case 720:
case 721:
case 722:
P_CopySectorSlope(&lines[i]);
break;
#endif
default: default:
break; break;
} }

View file

@ -237,46 +237,27 @@ typedef struct linechain_s
// Slopes // Slopes
#ifdef ESLOPE #ifdef ESLOPE
typedef enum { typedef enum {
SL_NOPHYSICS = 1, // Don't do momentum adjustment with this slope SL_NOPHYSICS = 1, /// This plane will have no physics applied besides the positioning.
SL_NODYNAMIC = 1<<1, // Slope will never need to move during the level, so don't fuss with recalculating it SL_DYNAMIC = 1<<1, /// This plane slope will be assigned a thinker to make it dynamic.
SL_ANCHORVERTEX = 1<<2, // Slope is using a Slope Vertex Thing to anchor its position
SL_VERTEXSLOPE = 1<<3, // Slope is built from three Slope Vertex Things
} slopeflags_t; } slopeflags_t;
typedef struct pslope_s typedef struct pslope_s
{ {
UINT16 id; // The number of the slope, mostly used for netgame syncing purposes UINT16 id; // The number of the slope, mostly used for netgame syncing purposes
struct pslope_s *next; // Make a linked list of dynamic slopes, for easy reference later
// --- Information used in clipping/projection --- // The plane's definition.
// Origin vector for the plane vector3_t o; /// Plane origin.
vector3_t o; vector3_t normal; /// Plane normal.
// 2-Dimentional vector (x, y) normalized. Used to determine distance from vector2_t d; /// Precomputed normalized projection of the normal over XY.
// the origin in 2d mapspace. (Basically a thrust of FRACUNIT in xydirection angle) fixed_t zdelta; /// Precomputed Z unit increase per XY unit.
vector2_t d;
// The rate at which z changes based on distance from the origin plane.
fixed_t zdelta;
// The normal of the slope; will always point upward, and thus be inverted on ceilings. I think it's only needed for physics? -Red
vector3_t normal;
// For comparing when a slope should be rendered
fixed_t lowz;
fixed_t highz;
// This values only check and must be updated if the slope itself is modified // This values only check and must be updated if the slope itself is modified
angle_t zangle; // Angle of the plane going up from the ground (not mesured in degrees) angle_t zangle; /// Precomputed angle of the plane going up from the ground (not measured in degrees).
angle_t xydirection; // The direction the slope is facing (north, west, south, etc.) angle_t xydirection;/// Precomputed angle of the normal's projection on the XY plane.
struct line_s *sourceline; // The line that generated the slope
fixed_t extent; // Distance value used for recalculating zdelta
UINT8 refpos; // 1=front floor 2=front ceiling 3=back floor 4=back ceiling (used for dynamic sloping)
UINT8 flags; // Slope options UINT8 flags; // Slope options
mapthing_t **vertices; // List should be three long for slopes made by vertex things, or one long for slopes using one vertex thing to anchor
struct pslope_s *next; // Make a linked list of dynamic slopes, for easy reference later
} pslope_t; } pslope_t;
#endif #endif