From e67e225ff2f796ba8cb78c9bacc5c91f052d5271 Mon Sep 17 00:00:00 2001 From: Lactozilla Date: Sun, 19 May 2024 20:40:40 -0300 Subject: [PATCH] Improve slope physics on solid middle textures --- src/p_local.h | 1 + src/p_map.c | 27 ++++++++-- src/p_maputl.c | 5 ++ src/p_maputl.h | 1 + src/p_mobj.c | 31 ++++++++---- src/p_mobj.h | 4 +- src/p_saveg.c | 9 +++- src/p_slopes.c | 130 +++++++++++++++++++++++++++++++++++++++++++------ src/p_slopes.h | 10 +++- src/p_user.c | 6 +-- 10 files changed, 189 insertions(+), 35 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index 249c3cd4b..6a4aa241c 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -399,6 +399,7 @@ extern camera_t *mapcampointer; extern fixed_t tmx; extern fixed_t tmy; extern pslope_t *tmfloorslope, *tmceilingslope; +extern line_t *tmfloorline, *tmceilingline; /* cphipps 2004/08/30 */ extern void P_MapStart(void); diff --git a/src/p_map.c b/src/p_map.c index f97ddfa3c..aeeeda056 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -55,6 +55,7 @@ mobj_t *tmfloorthing; // the thing corresponding to tmfloorz or NULL if tmfloorz mobj_t *tmhitthing; // the solid thing you bumped into (for collisions) ffloor_t *tmfloorrover, *tmceilingrover; pslope_t *tmfloorslope, *tmceilingslope; +line_t *tmfloorline, *tmceilingline; // keep track of the line that lowers the ceiling, // so missiles don't explode against sky hack walls @@ -1760,6 +1761,7 @@ static unsigned PIT_DoCheckThing(mobj_t *thing) tmfloorz = thing->z + thing->height; tmfloorrover = NULL; tmfloorslope = NULL; + tmfloorline = NULL; } return CHECKTHING_COLLIDE; } @@ -1779,6 +1781,7 @@ static unsigned PIT_DoCheckThing(mobj_t *thing) tmfloorz = tmceilingz = topz; // block while in air tmceilingrover = NULL; tmceilingslope = NULL; + tmceilingline = NULL; tmfloorthing = thing; // needed for side collision collide = CHECKTHING_COLLIDE; @@ -1788,6 +1791,7 @@ static unsigned PIT_DoCheckThing(mobj_t *thing) tmceilingz = topz; tmceilingrover = NULL; tmceilingslope = NULL; + tmceilingline = NULL; tmfloorthing = thing; // thing we may stand on collide = CHECKTHING_COLLIDE; @@ -1805,6 +1809,7 @@ static unsigned PIT_DoCheckThing(mobj_t *thing) tmceilingz = thing->z; tmceilingrover = NULL; tmceilingslope = NULL; + tmceilingline = NULL; } return CHECKTHING_COLLIDE; } @@ -1824,6 +1829,7 @@ static unsigned PIT_DoCheckThing(mobj_t *thing) tmfloorz = tmceilingz = topz; // block while in air tmfloorrover = NULL; tmfloorslope = NULL; + tmfloorline = NULL; tmfloorthing = thing; // needed for side collision collide = CHECKTHING_COLLIDE; @@ -1833,6 +1839,7 @@ static unsigned PIT_DoCheckThing(mobj_t *thing) tmfloorz = topz; tmfloorrover = NULL; tmfloorslope = NULL; + tmfloorline = NULL; tmfloorthing = thing; // thing we may stand on collide = CHECKTHING_COLLIDE; @@ -2000,6 +2007,7 @@ static boolean PIT_CheckLine(line_t *ld) ceilingline = ld; tmceilingrover = openceilingrover; tmceilingslope = opentopslope; + tmceilingline = opentopline; } if (openbottom > tmfloorz) @@ -2007,6 +2015,7 @@ static boolean PIT_CheckLine(line_t *ld) tmfloorz = openbottom; tmfloorrover = openfloorrover; tmfloorslope = openbottomslope; + tmfloorline = openbottomline; } if (highceiling > tmdrpoffceilz) @@ -2057,6 +2066,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) tmceilingz = P_GetCeilingZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->ceilingheight; tmfloorrover = NULL; tmceilingrover = NULL; + tmfloorline = NULL; + tmceilingline = NULL; tmfloorslope = newsubsec->sector->f_slope; tmceilingslope = newsubsec->sector->c_slope; @@ -2642,6 +2653,8 @@ boolean PIT_PushableMoved(mobj_t *thing) ffloor_t *oldceilrover = tmceilingrover; pslope_t *oldfslope = tmfloorslope; pslope_t *oldcslope = tmceilingslope; + line_t *oldfline = tmfloorline; + line_t *oldcline = tmceilingline; // Move the player P_TryMove(thing, thing->x+stand->momx, thing->y+stand->momy, true); @@ -2658,6 +2671,8 @@ boolean PIT_PushableMoved(mobj_t *thing) tmceilingrover = oldceilrover; tmfloorslope = oldfslope; tmceilingslope = oldcslope; + tmfloorline = oldfline; + tmceilingline = oldcline; thing->momz = stand->momz; } else @@ -2899,11 +2914,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) // Assign thing's standingslope if needed if (thing->z <= tmfloorz && !(thing->eflags & MFE_VERTICALFLIP)) { if (!startingonground && tmfloorslope) - P_HandleSlopeLanding(thing, tmfloorslope); + P_HandleSlopeLanding(thing, tmfloorslope, tmfloorline); if (thing->momz <= 0) { thing->standingslope = tmfloorslope; + thing->standingline = tmfloorline; P_SetPitchRollFromSlope(thing, thing->standingslope); if (thing->momz == 0 && thing->player && !startingonground) @@ -2912,11 +2928,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } else if (thing->z+thing->height >= tmceilingz && (thing->eflags & MFE_VERTICALFLIP)) { if (!startingonground && tmceilingslope) - P_HandleSlopeLanding(thing, tmceilingslope); + P_HandleSlopeLanding(thing, tmceilingslope, tmceilingline); if (thing->momz >= 0) { thing->standingslope = tmceilingslope; + thing->standingline = tmceilingline; P_SetPitchRollFromSlope(thing, thing->standingslope); if (thing->momz == 0 && thing->player && !startingonground) @@ -2924,8 +2941,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } } } - else // don't set standingslope if you're not going to clip against it + else + { + // don't set standingslope or standingline if you're not going to clip against them thing->standingslope = NULL; + thing->standingline = NULL; + } thing->x = x; thing->y = y; diff --git a/src/p_maputl.c b/src/p_maputl.c index 18a15a928..7de5b5369 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -280,6 +280,7 @@ fixed_t P_InterceptVector(divline_t *v2, divline_t *v1) fixed_t opentop, openbottom, openrange, lowfloor, highceiling; pslope_t *opentopslope, *openbottomslope; ffloor_t *openfloorrover, *openceilingrover; +line_t *opentopline, *openbottomline; // P_CameraLineOpening // P_LineOpening, but for camera @@ -440,6 +441,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) I_Assert(back != NULL); openfloorrover = openceilingrover = NULL; + opentopline = openbottomline = NULL; + if (linedef->polyobj) { // set these defaults so that polyobjects don't interfere with collision above or below them @@ -544,6 +547,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if ((linedef->flags & ML_MIDPEG) != 0) { opentopslope = openbottomslope; } + opentopline = linedef; } } else { // Above if (openbottom < textop) { @@ -551,6 +555,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) if ((linedef->flags & ML_MIDPEG) == 0) { openbottomslope = opentopslope; } + openbottomline = linedef; } } } diff --git a/src/p_maputl.h b/src/p_maputl.h index e894c08a2..ca29fc203 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -57,6 +57,7 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y); extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling; extern pslope_t *opentopslope, *openbottomslope; extern ffloor_t *openfloorrover, *openceilingrover; +extern line_t *opentopline, *openbottomline; void P_LineOpening(line_t *plinedef, mobj_t *mobj); diff --git a/src/p_mobj.c b/src/p_mobj.c index 9cdd2628d..221149f70 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1672,6 +1672,7 @@ void P_XYMovement(mobj_t *mo) fixed_t oldx, oldy; // reducing bobbing/momentum on ice when up against walls boolean moved; pslope_t *oldslope = NULL; + line_t *oldstandingline = NULL; vector3_t slopemom = {0,0,0}; fixed_t predictedz = 0; @@ -1704,7 +1705,10 @@ void P_XYMovement(mobj_t *mo) oldy = mo->y; if (mo->flags & MF_NOCLIPHEIGHT) + { mo->standingslope = NULL; + mo->standingline = NULL; + } // adjust various things based on slope if (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8) { @@ -1716,7 +1720,7 @@ void P_XYMovement(mobj_t *mo) slopemom.x = xmove; slopemom.y = ymove; slopemom.z = 0; - P_QuantizeMomentumToSlope(&slopemom, mo->standingslope); + P_QuantizeObjectMomentumToSlope(mo, &slopemom); xmove = slopemom.x; ymove = slopemom.y; @@ -1724,6 +1728,7 @@ void P_XYMovement(mobj_t *mo) predictedz = mo->z + slopemom.z; // We'll use this later... oldslope = mo->standingslope; + oldstandingline = mo->standingline; } } else if (P_IsObjectOnGround(mo) && !mo->momz) predictedz = mo->z; @@ -1799,12 +1804,16 @@ void P_XYMovement(mobj_t *mo) { // try to slide along it // Wall transfer part 1. pslope_t *transferslope = NULL; + line_t *transferline = NULL; fixed_t transfermomz = 0; if (oldslope && (P_MobjFlip(mo)*(predictedz - mo->z) > 0)) // Only for moving up (relative to gravity), otherwise there's a failed launch when going down slopes and hitting walls { + angle_t zangle; transferslope = ((mo->standingslope) ? mo->standingslope : oldslope); - if (((transferslope->zangle < ANGLE_180) ? transferslope->zangle : InvAngle(transferslope->zangle)) >= ANGLE_45) // Prevent some weird stuff going on on shallow slopes. - transfermomz = P_GetWallTransferMomZ(mo, transferslope); + transferline = ((mo->standingline) ? mo->standingline : oldstandingline); + zangle = P_GetStandingSlopeZAngle(transferslope, transferline); + if (((zangle < ANGLE_180) ? zangle : InvAngle(zangle)) >= ANGLE_45) // Prevent some weird stuff going on on shallow slopes. + transfermomz = P_GetWallTransferMomZ(mo, transferslope, transferline); } P_SlideMove(mo); @@ -1817,7 +1826,7 @@ void P_XYMovement(mobj_t *mo) { angle_t relation; // Scale transfer momentum based on how head-on it is to the slope. if (mo->momx || mo->momy) // "Guess" the angle of the wall you hit using new momentum - relation = transferslope->xydirection - R_PointToAngle2(0, 0, mo->momx, mo->momy); + relation = P_GetStandingSlopeDirection(transferslope, transferline) - R_PointToAngle2(0, 0, mo->momx, mo->momy); else // Give it for free, I guess. relation = ANGLE_90; transfermomz = FixedMul(transfermomz, @@ -1826,6 +1835,7 @@ void P_XYMovement(mobj_t *mo) { mo->momz = transfermomz; mo->standingslope = NULL; + mo->standingline = NULL; if (player) { player->powers[pw_justlaunched] = 2; @@ -1875,7 +1885,7 @@ void P_XYMovement(mobj_t *mo) oldangle = FixedMul((signed)oldslope->zangle, FINECOSINE((moveangle - oldslope->xydirection) >> ANGLETOFINESHIFT)); if (mo->standingslope) - newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT)); + newangle = FixedMul((signed)P_GetObjectStandingSlopeZAngle(mo), FINECOSINE((moveangle - P_GetObjectStandingSlopeDirection(mo)) >> ANGLETOFINESHIFT)); else newangle = 0; @@ -1899,7 +1909,7 @@ void P_XYMovement(mobj_t *mo) } } else if (moved && mo->standingslope && predictedz) { angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); - angle_t newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT)); + angle_t newangle = FixedMul((signed)P_GetObjectStandingSlopeZAngle(mo), FINECOSINE((moveangle - P_GetObjectStandingSlopeDirection(mo)) >> ANGLETOFINESHIFT)); /*CONS_Printf("flat to angle %f - predicted z of %f\n", FIXED_TO_FLOAT(AngleFixed(ANGLE_MAX-newangle)), @@ -2432,8 +2442,9 @@ boolean P_ZMovement(mobj_t *mo) if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM)) { mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope; + mo->standingline = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingline : tmfloorline; P_SetPitchRollFromSlope(mo, mo->standingslope); - P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope); + P_ReverseQuantizeObjectMomentumToSlope(mo, &mom); } // hit the floor @@ -2579,7 +2590,7 @@ boolean P_ZMovement(mobj_t *mo) mom.z = tmfloorthing->momz; if (mo->standingslope) { // MT_STEAM will never have a standingslope, see above. - P_QuantizeMomentumToSlope(&mom, mo->standingslope); + P_QuantizeObjectMomentumToSlope(mo, &mom); } mo->momx = mom.x; @@ -2825,7 +2836,9 @@ void P_PlayerZMovement(mobj_t *mo) if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)) { // Handle landing on slope during Z movement - P_HandleSlopeLanding(mo, (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)); + P_HandleSlopeLanding(mo, + (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope), + (mo->eflags & MFE_VERTICALFLIP ? tmceilingline : tmfloorline)); } if (P_MobjFlip(mo)*mo->momz < 0) // falling diff --git a/src/p_mobj.h b/src/p_mobj.h index 2f013a2f3..ae4c5a51d 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -412,7 +412,9 @@ typedef struct mobj_s INT32 cusval; INT32 cvmem; - struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?) + struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?) (it does) + + struct line_s *standingline; // The line that the object is standing on boolean resetinterp; // if true, some fields should not be interpolated (see R_InterpolateMobjState implementation) boolean colorized; // Whether the mobj uses the rainbow colormap diff --git a/src/p_saveg.c b/src/p_saveg.c index 5e4d6d076..675d68acd 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1746,7 +1746,8 @@ typedef enum MD2_DISPOFFSET = 1<<23, MD2_DRAWONLYFORPLAYER = 1<<24, MD2_DONTDRAWFORVIEWMOBJ = 1<<25, - MD2_TRANSLATION = 1<<26 + MD2_TRANSLATION = 1<<26, + MD2_STANDINGLINE = 1<<27 } mobj_diff2_t; typedef enum @@ -1953,6 +1954,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_CEILINGROVER; if (mobj->standingslope) diff2 |= MD2_SLOPE; + if (mobj->standingline) + diff2 |= MD2_STANDINGLINE; if (mobj->colorized) diff2 |= MD2_COLORIZED; if (mobj->mirrored) @@ -2125,6 +2128,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEUINT32(save_p, mobj->hprev->mobjnum); if (diff2 & MD2_SLOPE) WRITEUINT16(save_p, mobj->standingslope->id); + if (diff2 & MD2_STANDINGLINE) + WRITEUINT32(save_p, SaveLine(mobj->standingline)); if (diff2 & MD2_COLORIZED) WRITEUINT8(save_p, mobj->colorized); if (diff2 & MD2_MIRRORED) @@ -3181,6 +3186,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->hprev = (mobj_t *)(size_t)READUINT32(save_p); if (diff2 & MD2_SLOPE) mobj->standingslope = P_SlopeById(READUINT16(save_p)); + if (diff2 & MD2_STANDINGLINE) + mobj->standingline = LoadLine(READUINT32(save_p)); if (diff2 & MD2_COLORIZED) mobj->colorized = READUINT8(save_p); if (diff2 & MD2_MIRRORED) diff --git a/src/p_slopes.c b/src/p_slopes.c index e75d36ede..745be2eac 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -859,11 +859,10 @@ fixed_t P_GetLightZAt(const lightlist_t *light, fixed_t x, fixed_t y) // When given a vector, rotates it and aligns it to a slope void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope) { - vector3_t axis; // Fuck you, C90. - if (slope->flags & SL_NOPHYSICS) return; // No physics, no quantizing. + vector3_t axis; axis.x = -slope->d.y; axis.y = slope->d.x; axis.z = 0; @@ -877,9 +876,91 @@ void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope) // When given a vector, rotates and aligns it to a flat surface (from being relative to a given slope) void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope) { - slope->zangle = InvAngle(slope->zangle); - P_QuantizeMomentumToSlope(momentum, slope); - slope->zangle = InvAngle(slope->zangle); + if (slope->flags & SL_NOPHYSICS) + return; // No physics, no quantizing. + + vector3_t axis; + axis.x = -slope->d.y; + axis.y = slope->d.x; + axis.z = 0; + + FV3_Rotate(momentum, &axis, InvAngle(slope->zangle) >> ANGLETOFINESHIFT); +} + +angle_t P_GetStandingSlopeZAngle(pslope_t *slope, line_t *line) +{ + angle_t zangle = slope->zangle; + + if (line) + { + zangle = R_PointToAngle2(0, P_GetSlopeZAt(slope, line->v1->x, line->v1->y), + R_PointToDist2(line->v1->x, line->v1->y, line->v2->x, line->v2->y), P_GetSlopeZAt(slope, line->v2->x, line->v2->y)); + } + + return zangle; +} + +angle_t P_GetStandingSlopeDirection(pslope_t *slope, line_t *line) +{ + angle_t xydirection = slope->xydirection; + + if (line) + { + xydirection = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); + } + + return xydirection; +} + +angle_t P_GetObjectStandingSlopeZAngle(mobj_t *mo) +{ + return P_GetStandingSlopeZAngle(mo->standingslope, mo->standingline); +} + +angle_t P_GetObjectStandingSlopeDirection(mobj_t *mo) +{ + return P_GetStandingSlopeDirection(mo->standingslope, mo->standingline); +} + +static void QuantizeMomentumToSlope(pslope_t *slope, line_t *line, vector3_t *momentum, boolean reverse) +{ + if (!slope || slope->flags & SL_NOPHYSICS) + return; + + angle_t zangle = P_GetStandingSlopeZAngle(slope, line); + + if (reverse) + zangle = InvAngle(zangle); + + vector3_t axis; + axis.z = 0; + + if (line) + { + fixed_t len = R_PointToDist2(0, 0, line->dx, line->dy); + axis.x = FixedDiv(line->dy, len); + axis.y = -FixedDiv(line->dx, len); + } + else + { + axis.x = -slope->d.y; + axis.y = slope->d.x; + } + + FV3_Rotate(momentum, &axis, zangle >> ANGLETOFINESHIFT); +} + +// Given a vector of the object's momentum, rotates it and aligns it to the slope the object is standing on +void P_QuantizeObjectMomentumToSlope(mobj_t *mo, vector3_t *momentum) +{ + QuantizeMomentumToSlope(mo->standingslope, mo->standingline, momentum, false); +} + +// Given a vector of the object's momentum, rotates and aligns it to a flat surface +// (from being relative to the slope the object is standing on) +void P_ReverseQuantizeObjectMomentumToSlope(mobj_t *mo, vector3_t *momentum) +{ + QuantizeMomentumToSlope(mo->standingslope, mo->standingline, momentum, true); } // @@ -899,7 +980,7 @@ void P_SlopeLaunch(mobj_t *mo) slopemom.x = mo->momx; slopemom.y = mo->momy; slopemom.z = mo->momz*2; - P_QuantizeMomentumToSlope(&slopemom, mo->standingslope); + P_QuantizeObjectMomentumToSlope(mo, &slopemom); mo->momx = slopemom.x; mo->momy = slopemom.y; @@ -919,7 +1000,7 @@ void P_SlopeLaunch(mobj_t *mo) // It would be nice to have a single function that does everything necessary for slope-to-wall transfer. // However, it needs to be seperated out in P_XYMovement to take into account momentum before and after hitting the wall. // This just performs the necessary calculations for getting the base vertical momentum; the horizontal is already reasonably calculated by P_SlideMove. -fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope) +fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope, line_t *line) { vector3_t slopemom, axis; angle_t ang; @@ -927,18 +1008,30 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope) if (slope->flags & SL_NOPHYSICS) return 0; + angle_t zangle = P_GetStandingSlopeZAngle(slope, line); + // If there's physics, time for launching. // Doesn't kill the vertical momentum as much as P_SlopeLaunch does. - ang = slope->zangle + ANG15*((slope->zangle > 0) ? 1 : -1); + ang = zangle + ANG15*((zangle > 0) ? 1 : -1); if (ang > ANGLE_90 && ang < ANGLE_180) - ang = ((slope->zangle > 0) ? ANGLE_90 : InvAngle(ANGLE_90)); // hard cap of directly upwards + ang = ((zangle > 0) ? ANGLE_90 : InvAngle(ANGLE_90)); // hard cap of directly upwards slopemom.x = mo->momx; slopemom.y = mo->momy; slopemom.z = 3*(mo->momz/2); - axis.x = -slope->d.y; - axis.y = slope->d.x; + if (line) + { + fixed_t len = R_PointToDist2(0, 0, line->dx, line->dy); + axis.x = FixedDiv(line->dy, len); + axis.y = -FixedDiv(line->dx, len); + } + else + { + axis.x = -slope->d.y; + axis.y = slope->d.x; + } + axis.z = 0; FV3_Rotate(&slopemom, &axis, ang >> ANGLETOFINESHIFT); @@ -947,7 +1040,7 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope) } // Function to help handle landing on slopes -void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) +void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope, line_t *line) { vector3_t mom; // Ditto. if (slope->flags & SL_NOPHYSICS || (slope->normal.x == 0 && slope->normal.y == 0)) { // No physics, no need to make anything complicated. @@ -966,12 +1059,13 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) mom.y = thing->momy; mom.z = thing->momz*2; - P_ReverseQuantizeMomentumToSlope(&mom, slope); + QuantizeMomentumToSlope(slope, line, &mom, true); if (P_MobjFlip(thing)*mom.z < 0) { // falling, land on slope thing->momx = mom.x; thing->momy = mom.y; thing->standingslope = slope; + thing->standingline = line; P_SetPitchRollFromSlope(thing, slope); if (!thing->player || !(thing->player->pflags & PF_BOUNCING)) thing->momz = -P_MobjFlip(thing); @@ -983,6 +1077,7 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) void P_ButteredSlope(mobj_t *mo) { fixed_t thrust; + angle_t zangle, xydirection; if (!mo->standingslope) return; @@ -1001,12 +1096,15 @@ void P_ButteredSlope(mobj_t *mo) return; // Allow the player to stand still on slopes below a certain steepness } - thrust = FINESINE(mo->standingslope->zangle>>ANGLETOFINESHIFT) * 3 / 2 * (mo->eflags & MFE_VERTICALFLIP ? 1 : -1); + zangle = P_GetStandingSlopeZAngle(mo->standingslope, mo->standingline); + xydirection = P_GetStandingSlopeDirection(mo->standingslope, mo->standingline); + + thrust = FINESINE(zangle>>ANGLETOFINESHIFT) * 3 / 2 * (mo->eflags & MFE_VERTICALFLIP ? 1 : -1); if (mo->player && (mo->player->pflags & PF_SPINNING)) { fixed_t mult = 0; if (mo->momx || mo->momy) { - angle_t angle = R_PointToAngle2(0, 0, mo->momx, mo->momy) - mo->standingslope->xydirection; + angle_t angle = R_PointToAngle2(0, 0, mo->momx, mo->momy) - xydirection; if (P_MobjFlip(mo) * mo->standingslope->zdelta < 0) angle ^= ANGLE_180; @@ -1027,5 +1125,5 @@ void P_ButteredSlope(mobj_t *mo) // ... and its friction against the ground for good measure (divided by original friction to keep behaviour for normal slopes the same). thrust = FixedMul(thrust, FixedDiv(mo->friction, ORIG_FRICTION)); - P_Thrust(mo, mo->standingslope->xydirection, thrust); + P_Thrust(mo, xydirection, thrust); } diff --git a/src/p_slopes.h b/src/p_slopes.h index fdc07f67e..f33053ac1 100644 --- a/src/p_slopes.h +++ b/src/p_slopes.h @@ -84,9 +84,15 @@ fixed_t P_GetLightZAt(const lightlist_t *light, fixed_t x, fixed_t y); // Lots of physics-based bullshit void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope); void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope); +void P_QuantizeObjectMomentumToSlope(mobj_t *mo, vector3_t *momentum); +void P_ReverseQuantizeObjectMomentumToSlope(mobj_t *mo, vector3_t *momentum); +angle_t P_GetStandingSlopeZAngle(pslope_t *slope, line_t *line); +angle_t P_GetStandingSlopeDirection(pslope_t *slope, line_t *line); +angle_t P_GetObjectStandingSlopeZAngle(mobj_t *mo); +angle_t P_GetObjectStandingSlopeDirection(mobj_t *mo); void P_SlopeLaunch(mobj_t *mo); -fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope); -void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope); +fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope, line_t *line); +void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope, line_t *line); void P_ButteredSlope(mobj_t *mo); pslope_t *P_MakeSlopeViaEquationConstants(const double a, const double b, const double c, const double d); diff --git a/src/p_user.c b/src/p_user.c index 7cd128cf0..1782c5386 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -6257,15 +6257,15 @@ static void P_3dMovement(player_t *player) && player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && abs(player->mo->standingslope->zdelta) > FRACUNIT/2) { // Factor thrust to slope, but only for the part pushing up it! // The rest is unaffected. - angle_t thrustangle = R_PointToAngle2(0, 0, totalthrust.x, totalthrust.y)-player->mo->standingslope->xydirection; + angle_t thrustangle = R_PointToAngle2(0, 0, totalthrust.x, totalthrust.y)-P_GetObjectStandingSlopeDirection(player->mo); if (player->mo->standingslope->zdelta < 0) { // Direction goes down, so thrustangle needs to face toward if (thrustangle < ANGLE_90 || thrustangle > ANGLE_270) { - P_QuantizeMomentumToSlope(&totalthrust, player->mo->standingslope); + P_QuantizeObjectMomentumToSlope(player->mo, &totalthrust); } } else { // Direction goes up, so thrustangle needs to face away if (thrustangle > ANGLE_90 && thrustangle < ANGLE_270) { - P_QuantizeMomentumToSlope(&totalthrust, player->mo->standingslope); + P_QuantizeObjectMomentumToSlope(player->mo, &totalthrust); } } }