diff --git a/src/m_vector.c b/src/m_vector.c index 53b869adc..274a806a6 100644 --- a/src/m_vector.c +++ b/src/m_vector.c @@ -409,6 +409,50 @@ angles3d_t *M_VectorAlignTo(float Pitch, float Yaw, float Roll, v3float_t v, byt } +// +// RotateVector +// +// Rotates a vector around another vector +// +void M_VecRotate(v3fixed_t *rotVec, const v3fixed_t *axisVec, const angle_t angle) +{ + // Rotate the point (x,y,z) around the vector (u,v,w) + fixed_t ux = FixedMul(axisVec->x, rotVec->x); + fixed_t uy = FixedMul(axisVec->x, rotVec->y); + fixed_t uz = FixedMul(axisVec->x, rotVec->z); + fixed_t vx = FixedMul(axisVec->y, rotVec->x); + fixed_t vy = FixedMul(axisVec->y, rotVec->y); + fixed_t vz = FixedMul(axisVec->y, rotVec->z); + fixed_t wx = FixedMul(axisVec->z, rotVec->x); + fixed_t wy = FixedMul(axisVec->z, rotVec->y); + fixed_t wz = FixedMul(axisVec->z, rotVec->z); + fixed_t sa = FINESINE(angle>>ANGLETOFINESHIFT); + fixed_t ca = FINECOSINE(angle>>ANGLETOFINESHIFT); + fixed_t ua = ux+vy+wz; + fixed_t ax = FixedMul(axisVec->x,ua); + fixed_t ay = FixedMul(axisVec->y,ua); + fixed_t az = FixedMul(axisVec->z,ua); + fixed_t xs = FixedMul(axisVec->x,axisVec->x); + fixed_t ys = FixedMul(axisVec->y,axisVec->y); + fixed_t zs = FixedMul(axisVec->z,axisVec->z); + fixed_t bx = FixedMul(rotVec->x,ys+zs); + fixed_t by = FixedMul(rotVec->y,xs+zs); + fixed_t bz = FixedMul(rotVec->z,xs+ys); + fixed_t cx = FixedMul(axisVec->x,vy+wz); + fixed_t cy = FixedMul(axisVec->y,ux+wz); + fixed_t cz = FixedMul(axisVec->z,ux+vy); + fixed_t dx = FixedMul(bx-cx, ca); + fixed_t dy = FixedMul(by-cy, ca); + fixed_t dz = FixedMul(bz-cz, ca); + fixed_t ex = FixedMul(vz-wy, sa); + fixed_t ey = FixedMul(wx-uz, sa); + fixed_t ez = FixedMul(uy-vx, sa); + + rotVec->x = ax+dx+ex; + rotVec->y = ay+dy+ey; + rotVec->z = az+dz+ez; +} + @@ -977,50 +1021,6 @@ boolean FV_IntersectedPolygon(const fvector_t *vPoly, const fvector_t *vLine, co return false; } -// -// RotateVector -// -// Rotates a vector around another vector -// -void FV_Rotate(fvector_t *rotVec, const fvector_t *axisVec, const angle_t angle) -{ - // Rotate the point (x,y,z) around the vector (u,v,w) - fixed_t ux = FixedMul(axisVec->x, rotVec->x); - fixed_t uy = FixedMul(axisVec->x, rotVec->y); - fixed_t uz = FixedMul(axisVec->x, rotVec->z); - fixed_t vx = FixedMul(axisVec->y, rotVec->x); - fixed_t vy = FixedMul(axisVec->y, rotVec->y); - fixed_t vz = FixedMul(axisVec->y, rotVec->z); - fixed_t wx = FixedMul(axisVec->z, rotVec->x); - fixed_t wy = FixedMul(axisVec->z, rotVec->y); - fixed_t wz = FixedMul(axisVec->z, rotVec->z); - fixed_t sa = FINESINE(angle); - fixed_t ca = FINECOSINE(angle); - fixed_t ua = ux+vy+wz; - fixed_t ax = FixedMul(axisVec->x,ua); - fixed_t ay = FixedMul(axisVec->y,ua); - fixed_t az = FixedMul(axisVec->z,ua); - fixed_t xs = FixedMul(axisVec->x,axisVec->x); - fixed_t ys = FixedMul(axisVec->y,axisVec->y); - fixed_t zs = FixedMul(axisVec->z,axisVec->z); - fixed_t bx = FixedMul(rotVec->x,ys+zs); - fixed_t by = FixedMul(rotVec->y,xs+zs); - fixed_t bz = FixedMul(rotVec->z,xs+ys); - fixed_t cx = FixedMul(axisVec->x,vy+wz); - fixed_t cy = FixedMul(axisVec->y,ux+wz); - fixed_t cz = FixedMul(axisVec->z,ux+vy); - fixed_t dx = FixedMul(bx-cx, ca); - fixed_t dy = FixedMul(by-cy, ca); - fixed_t dz = FixedMul(bz-cz, ca); - fixed_t ex = FixedMul(vz-wy, sa); - fixed_t ey = FixedMul(wx-uz, sa); - fixed_t ez = FixedMul(uy-vx, sa); - - rotVec->x = ax+dx+ex; - rotVec->y = ay+dy+ey; - rotVec->z = az+dz+ez; -} - void FM_Rotate(fmatrix_t *dest, angle_t angle, fixed_t x, fixed_t y, fixed_t z) { #define M(row,col) dest->m[row * 4 + col] diff --git a/src/m_vector.h b/src/m_vector.h index 743a26023..37d30c746 100644 --- a/src/m_vector.h +++ b/src/m_vector.h @@ -1,4 +1,4 @@ -// Emacs style mode select -*- C++ -*- +// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // Copyright(C) 2004 Stephen McGranahan @@ -7,12 +7,12 @@ // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -114,6 +114,8 @@ float M_VectorYaw(v3float_t v); float M_VectorPitch(v3float_t v); angles3d_t *M_VectorAlignTo(float Pitch, float Yaw, float Roll, v3float_t v, byte AngleAxis, float Rate); +void M_VecRotate(v3fixed_t *rotVec, const v3fixed_t *axisVec, const angle_t angle); + #endif diff --git a/src/p_mobj.c b/src/p_mobj.c index d57e398ec..e0e5cc9e9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1239,7 +1239,11 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy) } else if (abs(player->rmomx) < FixedMul(STOPSPEED, mo->scale) && abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale) - && (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING))) + && (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING)) +#ifdef ESLOPE + && !(player->mo->standingslope && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2) +#endif + ) { // if in a walking frame, stop moving if (player->panim == PA_WALK) @@ -1383,6 +1387,11 @@ void P_XYMovement(mobj_t *mo) fixed_t xmove, ymove; fixed_t oldx, oldy; // reducing bobbing/momentum on ice when up against walls boolean moved; +#ifdef ESLOPE + pslope_t *oldslope = NULL; + v3fixed_t slopemom; + fixed_t predictedz; +#endif I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -1414,6 +1423,29 @@ void P_XYMovement(mobj_t *mo) oldx = mo->x; oldy = mo->y; +#ifdef ESLOPE + // adjust various things based on slope + if (mo->standingslope) { + if (!P_IsObjectOnGround(mo)) { // We fell off at some point? Do the twisty thing! + P_SlopeLaunch(mo); + xmove = mo->momx; + ymove = mo->momy; + } else { // Still on the ground. + slopemom.x = xmove; + slopemom.y = ymove; + slopemom.z = 0; + P_QuantizeMomentumToSlope(&slopemom, mo->standingslope); + + xmove = slopemom.x; + ymove = slopemom.y; + + predictedz = mo->z + slopemom.z; // We'll use this later... + + oldslope = mo->standingslope; + } + } +#endif + // Pushables can break some blocks if (CheckForBustableBlocks && mo->flags & MF_PUSHABLE) P_PushableCheckBustables(mo); @@ -1534,6 +1566,29 @@ void P_XYMovement(mobj_t *mo) if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;; return; +#ifdef ESLOPE + if (moved && oldslope) { // Check to see if we ran off + if (oldslope != mo->standingslope) { // First, compare different slopes + // Start by quantizing momentum on this slope + v3fixed_t test; + test.x = mo->momx; + test.y = mo->momy; + test.z = 0; + if (mo->standingslope) // Don't fuss with the rotation if we don't HAVE a slope + P_QuantizeMomentumToSlope(&test, mo->standingslope); + + // Now compare the Zs of the different quantizations + if (slopemom.z - test.z > 2*FRACUNIT) { // Allow for a bit of sticking - this value can be adjusted later + mo->standingslope = oldslope; + P_SlopeLaunch(mo); + } + } else if (predictedz-mo->z > 2*FRACUNIT) { // Now check if we were supposed to stick to this slope + mo->standingslope = oldslope; + P_SlopeLaunch(mo); + } + } +#endif + // Check the gravity status. P_CheckGravity(mo, false); @@ -1819,6 +1874,11 @@ static boolean P_ZMovement(mobj_t *mo) I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); +#ifdef ESLOPE + if (mo->standingslope && !P_IsObjectOnGround(mo)) + P_SlopeLaunch(mo); +#endif + // Intercept the stupid 'fall through 3dfloors' bug if (mo->subsector->sector->ffloors) P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0); @@ -2231,6 +2291,11 @@ static void P_PlayerZMovement(mobj_t *mo) if (!mo->player) return; +#ifdef ESLOPE + if (mo->standingslope && !P_IsObjectOnGround(mo)) + P_SlopeLaunch(mo); +#endif + // Intercept the stupid 'fall through 3dfloors' bug if (mo->subsector->sector->ffloors) P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0); @@ -3183,6 +3248,10 @@ static void P_PlayerMobjThinker(mobj_t *mobj) P_MobjCheckWater(mobj); +#ifdef ESLOPE + P_ButteredSlope(mobj); +#endif + // momentum movement mobj->eflags &= ~MFE_JUSTSTEPPEDDOWN; diff --git a/src/p_slopes.c b/src/p_slopes.c index 518599849..6b6f147d9 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -768,6 +768,69 @@ float P_DistFromPlanef(const v3float_t *point, const v3float_t *pori, (point->z - pori->z) * pnormal->z; } +// +// P_QuantizeMomentumToSlope +// +// When given a vector, rotates it and aligns it to a slope +void P_QuantizeMomentumToSlope(v3fixed_t *momentum, pslope_t *slope) +{ + v3fixed_t axis; + axis.x = -slope->d.y; + axis.y = slope->d.x; + axis.z = 0; + + M_VecRotate(momentum, &axis, slope->zangle); +} + +// +// P_SlopeLaunch +// +// Handles slope ejection for objects +void P_SlopeLaunch(mobj_t *mo) +{ + // Double the pre-rotation Z, then halve the post-rotation Z. This reduces the + // vertical launch given from slopes while increasing the horizontal launch + // given. Good for SRB2's gravity and horizontal speeds. + v3fixed_t slopemom; + slopemom.x = mo->momx; + slopemom.y = mo->momy; + slopemom.z = mo->momz*2; + P_QuantizeMomentumToSlope(&slopemom, mo->standingslope); + + mo->momx = slopemom.x; + mo->momy = slopemom.y; + mo->momz = slopemom.z/2; + + CONS_Printf("Launched off of slope.\n"); + mo->standingslope = NULL; +} + +// https://yourlogicalfallacyis.com/slippery-slope +// Handles sliding down slopes, like if they were made of butter :) +void P_ButteredSlope(mobj_t *mo) +{ + fixed_t thrust; + + if (!mo->standingslope) + return; + + if (abs(mo->standingslope->zdelta) < FRACUNIT/2) + return; // Don't apply physics to slopes that aren't steep enough + + thrust = FINESINE(mo->standingslope->zangle>>ANGLETOFINESHIFT) * (mo->eflags & MFE_VERTICALFLIP ? 1 : -1); + + if (!(mo->player && (mo->player->pflags & PF_SPINNING))) { + if (mo->momx || mo->momy) // Slightly increase thrust based on the object's speed parallel to the slope direction + thrust = FixedMul(thrust, FRACUNIT+P_AproxDistance(mo->momx, mo->momy)/4); + // This solves the issue of being able to zigzag up steep slopes + } + + // Multiply by gravity + thrust = FixedMul(thrust, FRACUNIT/2); // TODO actually get this + + P_Thrust(mo, mo->standingslope->xydirection, thrust); +} + // EOF #endif // #ifdef ESLOPE diff --git a/src/p_slopes.h b/src/p_slopes.h index 8f408d6f0..f82d8a83d 100644 --- a/src/p_slopes.h +++ b/src/p_slopes.h @@ -76,6 +76,11 @@ float P_GetZAtf(pslope_t *slope, float x, float y); float P_DistFromPlanef(const v3float_t *point, const v3float_t *pori, const v3float_t *pnormal); +// Lots of physics-based bullshit +void P_QuantizeMomentumToSlope(v3fixed_t *momentum, pslope_t *slope); +void P_SlopeLaunch(mobj_t *mo); +void P_ButteredSlope(mobj_t *mo); + #endif // EOF