diff --git a/src/k_battle.c b/src/k_battle.c index e6a971163..ce5b3db37 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -609,6 +609,7 @@ static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale) for (i = 0; i <= r_splitscreen; i++) { + camera_t *cam = &camera[i]; player_t *player = &players[displayplayers[i]]; fixed_t zpos; SINT8 flip; @@ -620,13 +621,13 @@ static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale) if (player->mo->eflags & MFE_VERTICALFLIP) { - zpos = player->mo->z + player->mo->height; - zpos = min(zpos + heightPadding, player->mo->ceilingz); + zpos = cam->z + player->mo->height; + zpos = min(zpos + heightPadding, cam->ceilingz); } else { - zpos = player->mo->z; - zpos = max(zpos - heightPadding, player->mo->floorz); + zpos = cam->z; + zpos = max(zpos - heightPadding, cam->floorz); } flip = P_MobjFlip(player->mo); diff --git a/src/k_collide.cpp b/src/k_collide.cpp index 04e0025e7..525248fdf 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -1046,8 +1046,7 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) || (t1->player->invincibilitytimer > 0) || (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD) || (t1->player->curshield == KSHIELD_TOP && !K_IsHoldingDownTop(t1->player)) - || (t1->player->bubbleblowup > 0) - || (t1->player->spheres > 0 && K_PlayerEBrake(t1->player)); + || (t1->player->bubbleblowup > 0); }; if (canClash(t1, t2) && canClash(t2, t1)) @@ -1150,7 +1149,7 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) bool stung = false; - if (t2->player->rings <= 0 && t2->player->spheres <= 0) + if (t2->player->rings <= 0 && t2->health == 1) // no bumpers { P_DamageMobj(t2, t1, t1, 1, DMG_STING|DMG_WOMBO); stung = true; diff --git a/src/k_kart.c b/src/k_kart.c index b5ae9b39e..32dae6bdf 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1016,9 +1016,14 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2) if (mobj1->type == MT_PLAYER && mobj2->type == MT_PLAYER) { - if (K_PlayerGuard(mobj1->player)) + boolean guard1 = K_PlayerGuard(mobj1->player); + boolean guard2 = K_PlayerGuard(mobj2->player); + + if (guard1 && guard2) + K_DoPowerClash(mobj1, mobj2); + else if (guard1) K_DoGuardBreak(mobj1, mobj2); - if (K_PlayerGuard(mobj2->player)) + else if (guard2) K_DoGuardBreak(mobj2, mobj1); } @@ -3281,7 +3286,9 @@ static void K_GetKartBoostPower(player_t *player) if (player->invincibilitytimer) // Invincibility { - ADDBOOST(3*FRACUNIT/8 + (FRACUNIT / 1400 * (player->invincibilitytimer)), 3*FRACUNIT, SLIPTIDEHANDLING/2); // + 37.5 + ?% top speed, + 300% acceleration, +25% handling + // S-Monitor: no extra % + fixed_t extra = FRACUNIT / 1400 * (player->invincibilitytimer - K_PowerUpRemaining(player, POWERUP_SMONITOR)); + ADDBOOST(3*FRACUNIT/8 + extra, 3*FRACUNIT, SLIPTIDEHANDLING/2); // + 37.5 + ?% top speed, + 300% acceleration, +25% handling } if (player->growshrinktimer > 0) // Grow @@ -8475,7 +8482,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (K_PlayerGuard(player) && !K_PowerUpRemaining(player, POWERUP_BARRIER) && (player->ebrakefor%6 == 0)) player->spheres--; - if (player->instaWhipCharge && !K_PowerUpRemaining(players, POWERUP_BADGE) && leveltime%6 == 0) + if (player->instaWhipCharge && !K_PowerUpRemaining(players, POWERUP_BADGE) && leveltime%6 == 0 && !P_PlayerInPain(player)) player->spheres--; } else @@ -8582,9 +8589,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) S_StartSound(player->mo, sfx_s1af); player->oldGuard = true; - - if (!K_PowerUpRemaining(player, POWERUP_BARRIER)) - player->instaWhipCharge = 0; } else if (player->oldGuard) { @@ -10827,6 +10831,11 @@ boolean K_PlayerGuard(const player_t *player) return true; } + if (player->instaWhipCharge != 0) + { + return false; + } + if (player->spheres == 0) return false; @@ -11676,7 +11685,19 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->instaWhipCharge = 0; } - if (chargingwhip) + if (chargingwhip && K_PressingEBrake(player)) + { + // 1) E-braking on the ground: cancels Insta-Whip. + // Still lets you keep your Whip while fast-falling. + // 2) Do not interrupt Guard. + if (P_IsObjectOnGround(player->mo) || K_PlayerGuard(player)) + { + if (player->instaWhipCharge) + player->defenseLockout = PUNISHWINDOW; + player->instaWhipCharge = 0; + } + } + else if (chargingwhip) { player->instaWhipCharge = min(player->instaWhipCharge + 1, INSTAWHIP_TETHERBLOCK + 1); diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index 69bbddc36..5ec9f8a99 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -50,6 +50,8 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) Obj_SpawnPowerUpAura(player); } + player->flashing = 2*TICRATE; + switch (powerup) { case POWERUP_SMONITOR: diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index 5abb0cf91..76f29a5cb 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -12,6 +12,7 @@ #include "../p_local.h" #include "../k_battle.h" #include "../k_objects.h" +#include "../k_powerup.h" #include "../k_kart.h" #include "../k_hud.h" // K_AddMessage @@ -151,26 +152,30 @@ void Obj_BattleUFODeath(mobj_t *mobj, mobj_t *inflictor) { UFO* ufo = static_cast(mobj); const SINT8 flip = P_MobjFlip(ufo); + const kartitems_t pwrup = static_cast(P_RandomRange(PR_BATTLEUFO, FIRSTPOWERUP, LASTPOWERUP)); ufo->momz = -(8*mapobjectscale)/2; - mobj_t* drop = K_CreatePaperItem( - ufo->x, - ufo->y, - ufo->z + (flip), - 0, - flip, - P_RandomRange(PR_BATTLEUFO, FIRSTPOWERUP, LASTPOWERUP), - BATTLE_POWERUP_TIME - ); - - if (!P_MobjWasRemoved(inflictor) && inflictor->type == MT_INSTAWHIP) + if (!P_MobjWasRemoved(inflictor) && inflictor->type == MT_INSTAWHIP && + !P_MobjWasRemoved(inflictor->target) && inflictor->target->player) { - // Take momentum of player who whips - inflictor = inflictor->target; + // Just give it to the player, they earned it. + K_GivePowerUp(inflictor->target->player, pwrup, BATTLE_POWERUP_TIME); } + else + { + mobj_t *drop = K_CreatePaperItem( + ufo->x, + ufo->y, + ufo->z + ufo->sprzoff() + (flip), + 0, + flip, + pwrup, + BATTLE_POWERUP_TIME + ); - drop->momz = !P_MobjWasRemoved(inflictor) ? inflictor->momz : 0; + drop->hitlag = ufo->hitlag(); + } if (ufo->spawner()) { diff --git a/src/p_inter.c b/src/p_inter.c index a36f74262..5a11f7101 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -402,7 +402,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; K_GivePowerUp(player, special->threshold, special->movecount); - player->flashing = 2*TICRATE; } else { @@ -3471,7 +3470,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (source && source->player && target) G_GhostAddHit((INT32) (source->player - players), target); - if ((gametyperules & GTR_BUMPERS) && !battleprisons) + // Insta-Whip (DMG_WHUMBLE): do not reduce hitlag because + // this can leave room for double-damage. + if ((damagetype & DMG_TYPEMASK) != DMG_WHUMBLE && (gametyperules & GTR_BUMPERS) && !battleprisons) laglength /= 2; K_SetHitLagForObjects(target, inflictor, source, laglength, true); diff --git a/src/p_map.c b/src/p_map.c index 95e509cca..b700a4b5e 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -781,7 +781,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (thing->type == MT_BATTLEUFO) { - if (tm.thing->type != MT_PLAYER) + if (!tm.thing->player) { return BMIT_CONTINUE; // not a player } @@ -801,7 +801,12 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; // underneath } - if (!tm.thing->player || !tm.thing->player->fastfall) + if (P_PlayerInPain(tm.thing->player)) + { + return BMIT_CONTINUE; // spinout would cause a softlock + } + + if (!tm.thing->player->fastfall) { fixed_t tractorHeight = 211*mapobjectscale; fixed_t zRange = FixedDiv(thing->z - tm.thing->z, tractorHeight);