From d138f7e14fc0aba6cc878eb1532f5e4987b2ac90 Mon Sep 17 00:00:00 2001 From: RedEnchilada Date: Sun, 17 May 2015 11:53:28 -0500 Subject: [PATCH] Collision with FOF slopes (might be unfinished, idk) --- src/p_local.h | 2 + src/p_map.c | 31 ++---- src/p_maputl.c | 68 +++++++----- src/p_mobj.c | 289 +++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 323 insertions(+), 67 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index 2fd7bcbe..472c0706 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -234,6 +234,8 @@ void P_SceneryThinker(mobj_t *mobj); fixed_t P_GetFloorZ(mobj_t *mobj, sector_t *sector, fixed_t x, fixed_t y, line_t *line); fixed_t P_GetCeilingZ(mobj_t *mobj, sector_t *sector, fixed_t x, fixed_t y, line_t *line); +fixed_t P_GetFOFTopZ(mobj_t *mobj, sector_t *sector, ffloor_t *fof, fixed_t x, fixed_t y, line_t *line); +fixed_t P_GetFOFBottomZ(mobj_t *mobj, sector_t *sector, ffloor_t *fof, fixed_t x, fixed_t y, line_t *line); boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover); boolean P_CheckDeathPitCollide(mobj_t *mo); diff --git a/src/p_map.c b/src/p_map.c index 4b74b0f0..6257ede1 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1244,15 +1244,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (!(rover->flags & FF_EXISTS)) continue; - fixed_t topheight = *rover->topheight; - fixed_t bottomheight = *rover->bottomheight; - -/*#ifdef ESLOPE - if (rover->t_slope) - topheight = P_GetZAt(rover->t_slope, thing->x, thing->y); - if (rover->b_slope) - bottomheight = P_GetZAt(rover->b_slope, thing->x, thing->y); -#endif*/ + fixed_t topheight = P_GetFOFTopZ(thing, newsubsec->sector, rover, x, y, NULL); + fixed_t bottomheight = P_GetFOFBottomZ(thing, newsubsec->sector, rover, x, y, NULL); if (rover->flags & FF_GOOWATER && !(thing->flags & MF_NOGRAVITY)) { @@ -1276,7 +1269,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (tmfloorz < topheight - sinklevel) { tmfloorz = topheight - sinklevel; #ifdef ESLOPE - tmfloorslope = NULL; + tmfloorslope = *rover->t_slope; #endif } } @@ -1285,7 +1278,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (tmceilingz > bottomheight + sinklevel) { tmceilingz = bottomheight + sinklevel; #ifdef ESLOPE - tmceilingslope = NULL; + tmceilingslope = *rover->b_slope; #endif } } @@ -1327,7 +1320,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { tmfloorz = tmdropoffz = topheight; #ifdef ESLOPE - tmfloorslope = NULL; + tmfloorslope = *rover->t_slope; #endif } if (bottomheight < tmceilingz && abs(delta1) >= abs(delta2) @@ -1336,7 +1329,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { tmceilingz = tmdrpoffceilz = bottomheight; #ifdef ESLOPE - tmceilingslope = NULL; + tmceilingslope = *rover->b_slope; #endif } } @@ -4010,12 +4003,12 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) fixed_t topheight = *rover->topheight; fixed_t bottomheight = *rover->bottomheight; -/*#ifdef ESLOPE - if (rover->t_slope) - topheight = P_GetZAt(rover->t_slope, x, y); - if (rover->b_slope) - bottomheight = P_GetZAt(rover->b_slope, x, y); -#endif*/ +#ifdef ESLOPE + if (*rover->t_slope) + topheight = P_GetZAt(*rover->t_slope, x, y); + if (*rover->b_slope) + bottomheight = P_GetZAt(*rover->b_slope, x, y); +#endif if (rover->flags & FF_QUICKSAND) { diff --git a/src/p_maputl.c b/src/p_maputl.c index b5ac2950..4037d769 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -659,6 +659,10 @@ void P_LineOpening(line_t *linedef) fixed_t highestfloor = openbottom; fixed_t lowestfloor = lowfloor; fixed_t delta1, delta2; +#ifdef ESLOPE + pslope_t *ceilingslope = opentopslope; + pslope_t *floorslope = openbottomslope; +#endif // Check for frontsector's fake floors for (rover = front->ffloors; rover; rover = rover->next) @@ -672,32 +676,32 @@ void P_LineOpening(line_t *linedef) || (rover->flags & FF_BLOCKOTHERS && !tmthing->player))) continue; - fixed_t topheight = *rover->topheight; - fixed_t bottomheight = *rover->bottomheight; - -/*#ifdef ESLOPE - if (rover->t_slope) - topheight = P_GetZAt(rover->t_slope, camera.x, camera.y); - - if (rover->b_slope) - bottomheight = P_GetZAt(rover->b_slope, camera.x, camera.y); -#endif*/ + fixed_t topheight = P_GetFOFTopZ(tmthing, front, rover, tmx, tmy, linedef); + fixed_t bottomheight = P_GetFOFBottomZ(tmthing, front, rover, tmx, tmy, linedef); delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2))); delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF { - if (bottomheight < lowestceiling) + if (bottomheight < lowestceiling) { lowestceiling = bottomheight; +#ifdef ESLOPE + ceilingslope = *rover->b_slope; +#endif + } else if (bottomheight < highestceiling) highestceiling = bottomheight; } if (delta1 < delta2 && !(rover->flags & FF_REVERSEPLATFORM)) // thing is above FOF { - if (topheight > highestfloor) + if (topheight > highestfloor) { highestfloor = topheight; +#ifdef ESLOPE + floorslope = *rover->t_slope; +#endif + } else if (topheight > lowestfloor) lowestfloor = topheight; } @@ -715,32 +719,32 @@ void P_LineOpening(line_t *linedef) || (rover->flags & FF_BLOCKOTHERS && !tmthing->player))) continue; - fixed_t topheight = *rover->topheight; - fixed_t bottomheight = *rover->bottomheight; - -/*#ifdef ESLOPE - if (rover->t_slope) - topheight = P_GetZAt(rover->t_slope, tmthing->x, tmthing->y); - - if (rover->b_slope) - bottomheight = P_GetZAt(rover->b_slope, tmthing->x, tmthing->y); -#endif*/ + fixed_t topheight = P_GetFOFTopZ(tmthing, back, rover, tmx, tmy, linedef); + fixed_t bottomheight = P_GetFOFBottomZ(tmthing, back, rover, tmx, tmy, linedef); delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2))); delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF { - if (bottomheight < lowestceiling) + if (bottomheight < lowestceiling) { lowestceiling = bottomheight; +#ifdef ESLOPE + ceilingslope = *rover->b_slope; +#endif + } else if (bottomheight < highestceiling) highestceiling = bottomheight; } if (delta1 < delta2 && !(rover->flags & FF_REVERSEPLATFORM)) // thing is above FOF { - if (topheight > highestfloor) + if (topheight > highestfloor) { highestfloor = topheight; +#ifdef ESLOPE + floorslope = *rover->t_slope; +#endif + } else if (topheight > lowestfloor) lowestfloor = topheight; } @@ -754,13 +758,21 @@ void P_LineOpening(line_t *linedef) delta1 = abs(tmthing->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2))); delta2 = abs(thingtop - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2))); - if (polysec->floorheight < lowestceiling && delta1 >= delta2) + if (polysec->floorheight < lowestceiling && delta1 >= delta2) { lowestceiling = polysec->floorheight; +#ifdef ESLOPE + ceilingslope = NULL; +#endif + } else if (polysec->floorheight < highestceiling && delta1 >= delta2) highestceiling = polysec->floorheight; - if (polysec->ceilingheight > highestfloor && delta1 < delta2) + if (polysec->ceilingheight > highestfloor && delta1 < delta2) { highestfloor = polysec->ceilingheight; +#ifdef ESLOPE + floorslope = NULL; +#endif + } else if (polysec->ceilingheight > lowestfloor && delta1 < delta2) lowestfloor = polysec->ceilingheight; } @@ -771,14 +783,14 @@ void P_LineOpening(line_t *linedef) if (highestfloor > openbottom) { openbottom = highestfloor; #ifdef ESLOPE - openbottomslope = NULL; + openbottomslope = floorslope; #endif } if (lowestceiling < opentop) { opentop = lowestceiling; #ifdef ESLOPE - opentopslope = NULL; + opentopslope = ceilingslope; #endif } diff --git a/src/p_mobj.c b/src/p_mobj.c index af832d58..421ec400 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -706,12 +706,12 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover) fixed_t topheight = *rover->topheight; fixed_t bottomheight = *rover->bottomheight; -/*#ifdef ESLOPE - if (rover->t_slope) - topheight = P_GetZAt(rover->t_slope, mobj->x, mobj->y); - if (rover->b_slope) - bottomheight = P_GetZAt(rover->b_slope, mobj->x, mobj->y); -#endif*/ +#ifdef ESLOPE + if (*rover->t_slope) + topheight = P_GetZAt(*rover->t_slope, mobj->x, mobj->y); + if (*rover->b_slope) + bottomheight = P_GetZAt(*rover->b_slope, mobj->x, mobj->y); +#endif if (mobj->z > topheight) return false; @@ -967,6 +967,251 @@ fixed_t P_GetCeilingZ(mobj_t *mobj, sector_t *sector, fixed_t x, fixed_t y, line return sector->ceilingheight; } +// Do the same as above, but for FOFs! +fixed_t P_GetFOFTopZ(mobj_t *mobj, sector_t *sector, ffloor_t *fof, fixed_t x, fixed_t y, line_t *line) // SRB2CBTODO: This needs to be over all the code +{ + I_Assert(mobj != NULL); + I_Assert(sector != NULL); + I_Assert(fof != NULL); +#ifdef ESLOPE + if (*fof->t_slope) { + fixed_t testx, testy; + pslope_t *slope = *fof->t_slope; + + // Get the corner of the object that should be the highest on the slope + if (slope->d.x < 0) + testx = mobj->radius; + else + testx = -mobj->radius; + + if (slope->d.y < 0) + testy = mobj->radius; + else + testy = -mobj->radius; + + if (slope->zdelta > 0) { + testx = -testx; + testy = -testy; + } + + testx += x; + testy += y; + + // If the highest point is in the sector, then we have it easy! Just get the Z at that point + if (R_PointInSubsector(testx, testy)->sector == sector) + return P_GetZAt(slope, testx, testy); + + // If we're just testing for base sector location (no collision line), just go for the center's spot... + // It'll get fixed when we test for collision anyway, and the final result can't be lower than this + if (line == NULL) + return P_GetZAt(slope, x, y); + + // Alright, so we're sitting on a line that contains our slope sector, and need to figure out the highest point we're touching... + // The solution is simple! Get the line's vertices, and pull each one in along its line until it touches the object's bounding box + // (assuming it isn't already inside), then test each point's slope Z and return the higher of the two. + { + vertex_t v1, v2; + v1.x = line->v1->x; + v1.y = line->v1->y; + v2.x = line->v2->x; + v2.y = line->v2->y; + + /*CONS_Printf("BEFORE: v1 = %f %f %f\n", + FIXED_TO_FLOAT(v1.x), + FIXED_TO_FLOAT(v1.y), + FIXED_TO_FLOAT(P_GetZAt(slope, v1.x, v1.y)) + ); + CONS_Printf(" v2 = %f %f %f\n", + FIXED_TO_FLOAT(v2.x), + FIXED_TO_FLOAT(v2.y), + FIXED_TO_FLOAT(P_GetZAt(slope, v2.x, v2.y)) + );*/ + + if (abs(v1.x-x) > mobj->radius) { + // v1's x is out of range, so rein it in + fixed_t diff = abs(v1.x-x) - mobj->radius; + + if (v1.x < x) { // Moving right + v1.x += diff; + v1.y += FixedMul(diff, FixedDiv(line->dy, line->dx)); + } else { // Moving left + v1.x -= diff; + v1.y -= FixedMul(diff, FixedDiv(line->dy, line->dx)); + } + } + + if (abs(v1.y-y) > mobj->radius) { + // v1's y is out of range, so rein it in + fixed_t diff = abs(v1.y-y) - mobj->radius; + + if (v1.y < y) { // Moving up + v1.y += diff; + v1.x += FixedMul(diff, FixedDiv(line->dx, line->dy)); + } else { // Moving down + v1.y -= diff; + v1.x -= FixedMul(diff, FixedDiv(line->dx, line->dy)); + } + } + + if (abs(v2.x-x) > mobj->radius) { + // v1's x is out of range, so rein it in + fixed_t diff = abs(v2.x-x) - mobj->radius; + + if (v2.x < x) { // Moving right + v2.x += diff; + v2.y += FixedMul(diff, FixedDiv(line->dy, line->dx)); + } else { // Moving left + v2.x -= diff; + v2.y -= FixedMul(diff, FixedDiv(line->dy, line->dx)); + } + } + + if (abs(v2.y-y) > mobj->radius) { + // v2's y is out of range, so rein it in + fixed_t diff = abs(v2.y-y) - mobj->radius; + + if (v2.y < y) { // Moving up + v2.y += diff; + v2.x += FixedMul(diff, FixedDiv(line->dx, line->dy)); + } else { // Moving down + v2.y -= diff; + v2.x -= FixedMul(diff, FixedDiv(line->dx, line->dy)); + } + } + + /*CONS_Printf("AFTER: v1 = %f %f %f\n", + FIXED_TO_FLOAT(v1.x), + FIXED_TO_FLOAT(v1.y), + FIXED_TO_FLOAT(P_GetZAt(slope, v1.x, v1.y)) + ); + CONS_Printf(" v2 = %f %f %f\n", + FIXED_TO_FLOAT(v2.x), + FIXED_TO_FLOAT(v2.y), + FIXED_TO_FLOAT(P_GetZAt(slope, v2.x, v2.y)) + );*/ + + // Return the higher of the two points + return max( + P_GetZAt(slope, v1.x, v1.y), + P_GetZAt(slope, v2.x, v2.y) + ); + } + } else // Well, that makes it easy. Just get the top height +#endif + return *fof->topheight; +} + +fixed_t P_GetFOFBottomZ(mobj_t *mobj, sector_t *sector, ffloor_t *fof, fixed_t x, fixed_t y, line_t *line) // SRB2CBTODO: This needs to be over all the code +{ + I_Assert(mobj != NULL); + I_Assert(sector != NULL); + I_Assert(fof != NULL); +#ifdef ESLOPE + if (*fof->t_slope) { + fixed_t testx, testy; + pslope_t *slope = *fof->t_slope; + + // Get the corner of the object that should be the lowest on the slope + if (slope->d.x < 0) + testx = mobj->radius; + else + testx = -mobj->radius; + + if (slope->d.y < 0) + testy = mobj->radius; + else + testy = -mobj->radius; + + if (slope->zdelta < 0) { + testx = -testx; + testy = -testy; + } + + testx += x; + testy += y; + + // If the lowest point is in the sector, then we have it easy! Just get the Z at that point + if (R_PointInSubsector(testx, testy)->sector == sector) + return P_GetZAt(slope, testx, testy); + + // If we're just testing for base sector location (no collision line), just go for the center's spot... + // It'll get fixed when we test for collision anyway, and the final result can't be higher than this + if (line == NULL) + return P_GetZAt(slope, x, y); + + // Alright, so we're sitting on a line that contains our slope sector, and need to figure out the highest point we're touching... + // The solution is simple! Get the line's vertices, and pull each one in along its line until it touches the object's bounding box + // (assuming it isn't already inside), then test each point's slope Z and return the lower of the two. + { + vertex_t v1, v2; + v1.x = line->v1->x; + v1.y = line->v1->y; + v2.x = line->v2->x; + v2.y = line->v2->y; + + if (abs(v1.x-x) > mobj->radius) { + // v1's x is out of range, so rein it in + fixed_t diff = abs(v1.x-x) - mobj->radius; + + if (v1.x < x) { // Moving right + v1.x += diff; + v1.y += FixedMul(diff, FixedDiv(line->dy, line->dx)); + } else { // Moving left + v1.x -= diff; + v1.y -= FixedMul(diff, FixedDiv(line->dy, line->dx)); + } + } + + if (abs(v1.y-y) > mobj->radius) { + // v1's y is out of range, so rein it in + fixed_t diff = abs(v1.y-y) - mobj->radius; + + if (v1.y < y) { // Moving up + v1.y += diff; + v1.x += FixedMul(diff, FixedDiv(line->dx, line->dy)); + } else { // Moving down + v1.y -= diff; + v1.x -= FixedMul(diff, FixedDiv(line->dx, line->dy)); + } + } + + if (abs(v2.x-x) > mobj->radius) { + // v1's x is out of range, so rein it in + fixed_t diff = abs(v2.x-x) - mobj->radius; + + if (v2.x < x) { // Moving right + v2.x += diff; + v2.y += FixedMul(diff, FixedDiv(line->dy, line->dx)); + } else { // Moving left + v2.x -= diff; + v2.y -= FixedMul(diff, FixedDiv(line->dy, line->dx)); + } + } + + if (abs(v2.y-y) > mobj->radius) { + // v2's y is out of range, so rein it in + fixed_t diff = abs(v2.y-y) - mobj->radius; + + if (v2.y < y) { // Moving up + v2.y += diff; + v2.x += FixedMul(diff, FixedDiv(line->dx, line->dy)); + } else { // Moving down + v2.y -= diff; + v2.x -= FixedMul(diff, FixedDiv(line->dx, line->dy)); + } + } + + // Return the lower of the two points + return min( + P_GetZAt(slope, v1.x, v1.y), + P_GetZAt(slope, v2.x, v2.y) + ); + } + } else // Well, that makes it easy. Just get the bottom height +#endif + return *fof->bottomheight; +} + static void P_PlayerFlip(mobj_t *mo) { if (!mo->player) @@ -1710,6 +1955,7 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp { ffloor_t *rover; fixed_t delta1, delta2, thingtop; + fixed_t topheight, bottomheight; I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -1721,6 +1967,9 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp if (!(rover->flags & FF_EXISTS)) continue; + topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL); + bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL); + if (mo->player && (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))) // only the player should be affected ; else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only @@ -1735,14 +1984,14 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp switch (motype) { case 2: // scenery does things differently for some reason - if (mo->z < *rover->topheight && *rover->bottomheight < thingtop) + if (mo->z < topheight && bottomheight < thingtop) { mo->floorz = mo->z; continue; } break; default: - if (mo->z < *rover->topheight && *rover->bottomheight < thingtop) + if (mo->z < topheight && bottomheight < thingtop) { if (mo->floorz < mo->z) mo->floorz = mo->z; @@ -1751,17 +2000,17 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp } } - delta1 = mo->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)); - delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)); - if (*rover->topheight > mo->floorz && abs(delta1) < abs(delta2) + delta1 = mo->z - (bottomheight + ((topheight - bottomheight)/2)); + delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); + if (topheight > mo->floorz && abs(delta1) < abs(delta2) && !(rover->flags & FF_REVERSEPLATFORM)) { - mo->floorz = *rover->topheight; + mo->floorz = topheight; } - if (*rover->bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2) + if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2) && !(rover->flags & FF_PLATFORM)) { - mo->ceilingz = *rover->bottomheight; + mo->ceilingz = bottomheight; } } } @@ -2804,13 +3053,13 @@ void P_MobjCheckWater(mobj_t *mobj) fixed_t topheight = *rover->topheight; fixed_t bottomheight = *rover->bottomheight; -/*#ifdef ESLOPE - if (rover->t_slope) - topheight = P_GetZAt(rover->t_slope, mobj->x, mobj->y); +#ifdef ESLOPE + if (*rover->t_slope) + topheight = P_GetZAt(*rover->t_slope, mobj->x, mobj->y); - if (rover->b_slope) - bottomheight = P_GetZAt(rover->b_slope, mobj->x, mobj->y); -#endif*/ + if (*rover->b_slope) + bottomheight = P_GetZAt(*rover->b_slope, mobj->x, mobj->y); +#endif if (mobj->eflags & MFE_VERTICALFLIP) {