diff --git a/src/k_collide.c b/src/k_collide.c index e4a536403..978993339 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -66,17 +66,22 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) if (t1->type == MT_BANANA && t1->health > 1) S_StartSound(t2, sfx_bsnipe); + damageitem = true; + if (t2->player->flamedash && t2->player->itemtype == KITEM_FLAMESHIELD) { // Melt item S_StartSound(t2, sfx_s3k43); } + else if (K_IsRidingFloatingTop(t2->player)) + { + // Float over silly banana + damageitem = false; + } else { P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL|DMG_WOMBO); } - - damageitem = true; } else if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD || t2->type == MT_ORBINAUT || t2->type == MT_ORBINAUT_SHIELD @@ -774,11 +779,13 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) // Clash instead of damage if both parties have any of these conditions t1Condition = (K_IsBigger(t1, t2) == true) || (t1->player->invincibilitytimer > 0) - || (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD); + || (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD) + || (t1->player->curshield == KSHIELD_TOP && !K_IsHoldingDownTop(t1->player)); t2Condition = (K_IsBigger(t2, t1) == true) || (t2->player->invincibilitytimer > 0) - || (t2->player->flamedash > 0 && t2->player->itemtype == KITEM_FLAMESHIELD); + || (t2->player->flamedash > 0 && t2->player->itemtype == KITEM_FLAMESHIELD) + || (t2->player->curshield == KSHIELD_TOP && !K_IsHoldingDownTop(t2->player)); if (t1Condition == true && t2Condition == true) { diff --git a/src/k_kart.c b/src/k_kart.c index dee43b1a0..df403b881 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1374,7 +1374,13 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against) if (!mobj->player) return weight; - if (against && !P_MobjWasRemoved(against) && against->player + if (against && (against->type == MT_GARDENTOP || (against->player && against->player->curshield == KSHIELD_TOP))) + { + /* Players bumping into a Top get zero weight -- the + Top rider is immovable. */ + weight = 0; + } + else if (against && !P_MobjWasRemoved(against) && against->player && ((!P_PlayerInPain(against->player) && P_PlayerInPain(mobj->player)) // You're hurt || (against->player->itemtype == KITEM_BUBBLESHIELD && mobj->player->itemtype != KITEM_BUBBLESHIELD))) // They have a Bubble Shield { @@ -1962,6 +1968,18 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur #undef CHAOTIXBANDLEN } +static boolean K_HasInfiniteTether(player_t *player) +{ + switch (player->curshield) + { + case KSHIELD_LIGHTNING: + case KSHIELD_TOP: + return true; + } + + return false; +} + /** \brief Updates the player's drafting values once per frame \param player player object passed from K_KartPlayerThink @@ -1976,7 +1994,7 @@ static void K_UpdateDraft(player_t *player) UINT8 leniency; UINT8 i; - if (player->itemtype == KITEM_LIGHTNINGSHIELD) + if (K_HasInfiniteTether(player)) { // Lightning Shield gets infinite draft distance as its (other) passive effect. draftdistance = 0; @@ -3267,6 +3285,8 @@ boolean K_ApplyOffroad(player_t *player) { if (player->invincibilitytimer || player->hyudorotimer || player->sneakertimer) return false; + if (K_IsRidingFloatingTop(player)) + return false; return true; } @@ -3274,6 +3294,8 @@ boolean K_SlopeResistance(player_t *player) { if (player->invincibilitytimer || player->sneakertimer || player->tiregrease || player->flamedash) return true; + if (player->curshield == KSHIELD_TOP) + return true; return false; } @@ -3320,6 +3342,9 @@ boolean K_WaterRun(player_t *player) boolean K_WaterSkip(player_t *player) { + if (player->curshield == KSHIELD_TOP) + return false; + if (player->speed/3 > abs(player->mo->momz)) // Going more forward than horizontal, so you can skip across the water. return true; @@ -3531,7 +3556,7 @@ static void K_GetKartBoostPower(player_t *player) draftspeed *= 2; } - if (player->itemtype == KITEM_LIGHTNINGSHIELD) + if (K_HasInfiniteTether(player)) { // infinite tether draftspeed *= 2; @@ -3653,6 +3678,10 @@ fixed_t K_GetKartAccel(player_t *player) if (gametype == GT_BATTLE && player->bumpers <= 0) k_accel *= 2; + // Marble Garden Top gets 800% accel + if (player->curshield == KSHIELD_TOP) + k_accel *= 8; + return FixedMul(k_accel, (FRACUNIT + player->accelboost) / 4); } @@ -3742,17 +3771,35 @@ SINT8 K_GetForwardMove(player_t *player) forwardmove = MAXPLMOVE; } + if (player->curshield == KSHIELD_TOP) + { + if (forwardmove < 0 || + (K_GetKartButtons(player) & BT_DRIFT)) + { + forwardmove = 0; + } + else + { + forwardmove = MAXPLMOVE; + } + } + return forwardmove; } fixed_t K_GetNewSpeed(player_t *player) { const fixed_t accelmax = 4000; - const fixed_t p_speed = K_GetKartSpeed(player, true, true); + fixed_t p_speed = K_GetKartSpeed(player, true, true); fixed_t p_accel = K_GetKartAccel(player); fixed_t newspeed, oldspeed, finalspeed; + if (player->curshield == KSHIELD_TOP) + { + p_speed = 11 * p_speed / 10; + } + if (K_PlayerUsesBotMovement(player) == true && player->botvars.rubberband > 0) { // Acceleration is tied to top speed... @@ -8964,13 +9011,25 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) if ((currentSpeed <= 0) // Not moving && ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK) // Not e-braking && (player->respawn.state == RESPAWNST_NONE) // Not respawning + && (player->curshield != KSHIELD_TOP) // Not riding a Top && (P_IsObjectOnGround(player->mo) == true)) // On the ground { return 0; } p_maxspeed = K_GetKartSpeed(player, false, true); - p_speed = min(currentSpeed, (p_maxspeed * 2)); + + if (player->curshield == KSHIELD_TOP) + { + // Do not downscale turning speed with faster + // movement speed; behaves as if turning in place. + p_speed = 0; + } + else + { + p_speed = min(currentSpeed, (p_maxspeed * 2)); + } + weightadjust = FixedDiv((p_maxspeed * 3) - p_speed, (p_maxspeed * 3) + (player->kartweight * FRACUNIT)); if (K_PlayerUsesBotMovement(player)) @@ -8997,7 +9056,9 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) turnfixed = FixedMul(turnfixed, FRACUNIT + player->handleboost); } - if ((player->mo->eflags & MFE_UNDERWATER) && + if (player->curshield == KSHIELD_TOP) + ; + else if ((player->mo->eflags & MFE_UNDERWATER) && player->speed > 11 * player->mo->scale) { turnfixed /= 2; @@ -10013,6 +10074,11 @@ void K_AdjustPlayerFriction(player_t *player) player->mo->friction += ((FRACUNIT - prevfriction) / greasetics) * player->tiregrease; } + if (player->curshield == KSHIELD_TOP) + { + player->mo->friction += 1024; + } + /* if (K_PlayerEBrake(player) == true) { diff --git a/src/p_map.c b/src/p_map.c index c2b688730..bb6b2de15 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2850,6 +2850,11 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->terrain = NULL; } + if (thing->player && K_IsRidingFloatingTop(thing->player)) + { + stairjank = false; + } + /* FIXME: slope step down (even up) has some false positives, so just ignore them entirely. */ if (stairjank && !oldslope && !thing->standingslope && diff --git a/src/p_mobj.c b/src/p_mobj.c index cfbea3185..1e9264ab1 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1133,7 +1133,11 @@ fixed_t P_GetMobjGravity(mobj_t *mo) gravityadd = FixedMul(TUMBLEGRAVITY, gravityadd); } - if (mo->player->fastfall != 0) + if (K_IsHoldingDownTop(mo->player)) + { + gravityadd = (5*gravityadd)/2; + } + else if (mo->player->fastfall != 0) { // Fast falling gravityadd *= 4; @@ -3092,13 +3096,26 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) fixed_t clip = flip ? (surfaceheight - playerbottom) : (playerbottom - surfaceheight); fixed_t span = player->mo->watertop - player->mo->waterbottom; - return - clip > -(player->mo->height / 2) && - span > player->mo->height && - player->speed / 5 > abs(player->mo->momz) && - player->speed > K_GetKartSpeed(player, false, false) && - K_WaterRun(player) && - (rover->flags & FF_SWIMMABLE); + if (!(rover->flags & FF_SWIMMABLE) || + clip < -(player->mo->height / 2) || + span < player->mo->height) + { + return false; + } + + if (player->curshield == KSHIELD_TOP) + { + return (K_GetKartButtons(player) & BT_DRIFT) != BT_DRIFT; + } + + if (K_WaterRun(player) && + player->speed / 5 > abs(player->mo->momz) && + player->speed > K_GetKartSpeed(player, false, false)) + { + return true; + } + + return false; } boolean P_CheckSolidFFloorSurface(player_t *player, ffloor_t *rover) diff --git a/src/p_spec.c b/src/p_spec.c index b8c103f70..7e3624036 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4426,7 +4426,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers switch (special) { case 1: // Damage (Generic) - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) + if (!K_IsRidingFloatingTop(player) && (roversector || P_MobjReadyToTrigger(player->mo, sector))) P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL); break; case 2: // Damage (Water) // SRB2kart - These three damage types are now offroad sectors @@ -4434,7 +4434,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers case 4: // Damage (Electrical) break; case 5: // Spikes - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) + if (!K_IsRidingFloatingTop(player) && (roversector || P_MobjReadyToTrigger(player->mo, sector))) P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL); break; case 6: // Death Pit (Camera Mod) diff --git a/src/p_user.c b/src/p_user.c index 8e03c1d43..622299bf8 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1801,7 +1801,7 @@ static void P_3dMovement(player_t *player) // Get the old momentum; this will be needed at the end of the function! -SH oldMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0); - if (player->stairjank > 8 && leveltime & 3) + if ((player->stairjank > 8 && leveltime & 3) || K_IsRidingFloatingTop(player)) { movepushangle = K_MomentumAngle(player->mo); } @@ -1884,6 +1884,7 @@ static void P_3dMovement(player_t *player) if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration... movepushforward = FixedMul(movepushforward, player->mo->movefactor); + if (player->curshield != KSHIELD_TOP) { INT32 a = K_GetUnderwaterTurnAdjust(player); INT32 adj = 0; @@ -1967,6 +1968,24 @@ static void P_3dMovement(player_t *player) player->mo->momx += totalthrust.x; player->mo->momy += totalthrust.y; + // Releasing a drift while on the Top translates all your + // momentum (and even then some) into whichever direction + // you're facing + if (onground && player->curshield == KSHIELD_TOP && (K_GetKartButtons(player) & BT_DRIFT) != BT_DRIFT && (player->oldcmd.buttons & BT_DRIFT)) + { + const fixed_t gmin = FRACUNIT/4; + const fixed_t gmax = 5*FRACUNIT/2; + + const fixed_t grindfactor = (gmax - gmin) / GARDENTOP_MAXGRINDTIME; + const fixed_t grindscale = gmin + (player->topdriftheld * grindfactor); + + const fixed_t speed = R_PointToDist2(0, 0, player->mo->momx, player->mo->momy); + + P_InstaThrust(player->mo, player->mo->angle, FixedMul(speed, grindscale)); + + player->topdriftheld = 0;/* reset after release */ + } + if (!onground) { const fixed_t airspeedcap = (50*mapobjectscale);