diff --git a/src/k_collide.c b/src/k_collide.c index 7413804d9..96fe30182 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -46,7 +46,7 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) { // Player Damage P_DamageMobj(t2, t1, t1->target, 1, DMG_WIPEOUT); - K_KartBouncing(t2, t1, false, false); + K_KartBouncing(t2, t1); S_StartSound(t2, sfx_s3k7b); } @@ -430,7 +430,7 @@ boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2) boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2) { if (t2->player || t2->type == MT_FALLINGROCK) - K_KartBouncing(t2, t1, false, false); + K_KartBouncing(t2, t1); return true; } @@ -457,8 +457,8 @@ boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2) return true; */ - K_KartBouncing(t2, t1, false, true); - return false; + K_KartSolidBounce(t1, t2); + return true; } boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) @@ -537,25 +537,24 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) if (t1Condition == true) { + P_PlayerRingBurst(t2->player, 1); + if (t2->player->rings <= 0) { P_DamageMobj(t2, t1, t1, 1, DMG_STING); stung = true; } - - P_PlayerRingBurst(t2->player, 1); - stung = true; } if (t2Condition == true) { + P_PlayerRingBurst(t1->player, 1); + if (t1->player->rings <= 0) { P_DamageMobj(t1, t2, t2, 1, DMG_STING); stung = true; } - - P_PlayerRingBurst(t2->player, 1); } return stung; diff --git a/src/k_kart.c b/src/k_kart.c index dedf9dddc..6abd51aa9 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1123,16 +1123,137 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) return FixedMul(weight, mobj->scale); } -boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) +static void K_SpawnBumpForObjs(mobj_t *mobj1, mobj_t *mobj2) { - mobj_t *fx; + mobj_t *fx = P_SpawnMobj( + mobj1->x/2 + mobj2->x/2, + mobj1->y/2 + mobj2->y/2, + mobj1->z/2 + mobj2->z/2, + MT_BUMP + ); + fixed_t avgScale = (mobj1->scale + mobj2->scale) / 2; + + if (mobj1->eflags & MFE_VERTICALFLIP) + { + fx->eflags |= MFE_VERTICALFLIP; + } + else + { + fx->eflags &= ~MFE_VERTICALFLIP; + } + + P_SetScale(fx, (fx->destscale = avgScale)); + + if ((mobj1->player && mobj1->player->itemtype == KITEM_BUBBLESHIELD) + || (mobj2->player && mobj2->player->itemtype == KITEM_BUBBLESHIELD)) + { + S_StartSound(mobj1, sfx_s3k44); + } + else + { + S_StartSound(mobj1, sfx_s3k49); + } +} + +static void K_PlayerJustBumped(player_t *player) +{ + mobj_t *playerMobj = NULL; + + if (player == NULL) + { + return; + } + + playerMobj = player->mo; + + if (playerMobj == NULL || P_MobjWasRemoved(playerMobj)) + { + return; + } + + if (abs(player->rmomx) < playerMobj->scale && abs(player->rmomy) < playerMobj->scale) + { + // Because this is done during collision now, rmomx and rmomy need to be recalculated + // so that friction doesn't immediately decide to stop the player if they're at a standstill + player->rmomx = playerMobj->momx - player->cmomx; + player->rmomy = playerMobj->momy - player->cmomy; + } + + player->justbumped = bumptime; + player->spindash = 0; + + if (player->spinouttimer) + { + player->wipeoutslow = wipeoutslowtime+1; + player->spinouttimer = max(wipeoutslowtime+1, player->spinouttimer); + //player->spinouttype = KSPIN_WIPEOUT; // Enforce type + } +} + +static fixed_t K_GetBounceForce(mobj_t *mobj1, mobj_t *mobj2, fixed_t distx, fixed_t disty) +{ + const fixed_t forceMul = (4 * FRACUNIT) / 10; // Multiply by this value to make it feel like old bumps. + fixed_t momdifx, momdify; - fixed_t distx, disty; - fixed_t dot, force; + fixed_t dot; + fixed_t force = 0; + + momdifx = mobj1->momx - mobj2->momx; + momdify = mobj1->momy - mobj2->momy; + + if (distx == 0 && disty == 0) + { + // if there's no distance between the 2, they're directly on top of each other, don't run this + return 0; + } + + { // Normalize distance to the sum of the two objects' radii, since in a perfect world that would be the distance at the point of collision... + fixed_t dist = P_AproxDistance(distx, disty); + fixed_t nx, ny; + + dist = dist ? dist : 1; + + nx = FixedDiv(distx, dist); + ny = FixedDiv(disty, dist); + + distx = FixedMul(mobj1->radius + mobj2->radius, nx); + disty = FixedMul(mobj1->radius + mobj2->radius, ny); + + if (momdifx == 0 && momdify == 0) + { + // If there's no momentum difference, they're moving at exactly the same rate. Pretend they moved into each other. + momdifx = -nx; + momdify = -ny; + } + } + + dot = FixedMul(momdifx, distx) + FixedMul(momdify, disty); + + if (dot >= 0) + { + // They're moving away from each other + return 0; + } + + // Return the push force! + force = FixedDiv(dot, FixedMul(distx, distx) + FixedMul(disty, disty)); + + return FixedMul(force, forceMul); +} + +boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2) +{ + const fixed_t minBump = 25*mapobjectscale; + mobj_t *goombaBounce = NULL; + fixed_t distx, disty, dist; + fixed_t force; fixed_t mass1, mass2; - if (!mobj1 || !mobj2) + if ((!mobj1 || P_MobjWasRemoved(mobj1)) + || (!mobj2 || P_MobjWasRemoved(mobj2))) + { return false; + } // Don't bump when you're being reborn if ((mobj1->player && mobj1->player->playerstate != PST_LIVE) @@ -1176,135 +1297,145 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean sol return false; } - mass1 = K_GetMobjWeight(mobj1, mobj2); + // Adds the OTHER object's momentum times a bunch, for the best chance of getting the correct direction + distx = (mobj1->x + mobj2->momx) - (mobj2->x + mobj1->momx); + disty = (mobj1->y + mobj2->momy) - (mobj2->y + mobj1->momy); - if (solid == true && mass1 > 0) - mass2 = mass1; - else - mass2 = K_GetMobjWeight(mobj2, mobj1); + force = K_GetBounceForce(mobj1, mobj2, distx, disty); - momdifx = mobj1->momx - mobj2->momx; - momdify = mobj1->momy - mobj2->momy; - - // Adds the OTHER player's momentum times a bunch, for the best chance of getting the correct direction - distx = (mobj1->x + mobj2->momx*3) - (mobj2->x + mobj1->momx*3); - disty = (mobj1->y + mobj2->momy*3) - (mobj2->y + mobj1->momy*3); - - if (distx == 0 && disty == 0) + if (force == 0) { - // if there's no distance between the 2, they're directly on top of each other, don't run this return false; } - { // Normalize distance to the sum of the two objects' radii, since in a perfect world that would be the distance at the point of collision... - fixed_t dist = P_AproxDistance(distx, disty); - fixed_t nx, ny; + mass1 = K_GetMobjWeight(mobj1, mobj2); + mass2 = K_GetMobjWeight(mobj2, mobj1); - dist = dist ? dist : 1; - - nx = FixedDiv(distx, dist); - ny = FixedDiv(disty, dist); - - distx = FixedMul(mobj1->radius+mobj2->radius, nx); - disty = FixedMul(mobj1->radius+mobj2->radius, ny); - - if (momdifx == 0 && momdify == 0) - { - // If there's no momentum difference, they're moving at exactly the same rate. Pretend they moved into each other. - momdifx = -nx; - momdify = -ny; - } + if ((P_IsObjectOnGround(mobj1) && mobj2->momz < 0) // Grounded + || (mass2 == 0 && mass1 > 0)) // The other party is immovable + { + goombaBounce = mobj2; } + else if ((P_IsObjectOnGround(mobj2) && mobj1->momz < 0) // Grounded + || (mass1 == 0 && mass2 > 0)) // The other party is immovable + { + goombaBounce = mobj1; + } + + if (goombaBounce != NULL) + { + // Perform a Goomba Bounce by reversing your z momentum. + goombaBounce->momz = -goombaBounce->momz; + } + else + { + // Trade z momentum values. + fixed_t newz = mobj1->momz; + mobj1->momz = mobj2->momz; + mobj2->momz = newz; + } + + // Multiply by force + distx = FixedMul(force, distx); + disty = FixedMul(force, disty); + dist = FixedHypot(distx, disty); // if the speed difference is less than this let's assume they're going proportionately faster from each other - if (P_AproxDistance(momdifx, momdify) < (25*mapobjectscale)) + if (dist < minBump) { - fixed_t momdiflength = P_AproxDistance(momdifx, momdify); - fixed_t normalisedx = FixedDiv(momdifx, momdiflength); - fixed_t normalisedy = FixedDiv(momdify, momdiflength); - momdifx = FixedMul((25*mapobjectscale), normalisedx); - momdify = FixedMul((25*mapobjectscale), normalisedy); - } + fixed_t normalisedx = FixedDiv(distx, dist); + fixed_t normalisedy = FixedDiv(disty, dist); - dot = FixedMul(momdifx, distx) + FixedMul(momdify, disty); - - if (dot >= 0) - { - // They're moving away from each other - return false; - } - - force = FixedDiv(dot, FixedMul(distx, distx)+FixedMul(disty, disty)); - - if (bounce == true && mass2 > 0) // Perform a Goomba Bounce. - mobj1->momz = -mobj1->momz; - else - { - fixed_t newz = mobj1->momz; - if (mass2 > 0) - mobj1->momz = mobj2->momz; - if (mass1 > 0 && solid == false) - mobj2->momz = newz; + distx = FixedMul(minBump, normalisedx); + disty = FixedMul(minBump, normalisedy); } if (mass2 > 0) { - mobj1->momx = mobj1->momx - FixedMul(FixedMul(FixedDiv(2*mass2, mass1 + mass2), force), distx); - mobj1->momy = mobj1->momy - FixedMul(FixedMul(FixedDiv(2*mass2, mass1 + mass2), force), disty); + mobj1->momx = mobj1->momx - FixedMul(FixedDiv(2*mass2, mass1 + mass2), distx); + mobj1->momy = mobj1->momy - FixedMul(FixedDiv(2*mass2, mass1 + mass2), disty); } - if (mass1 > 0 && solid == false) + if (mass1 > 0) { - mobj2->momx = mobj2->momx - FixedMul(FixedMul(FixedDiv(2*mass1, mass1 + mass2), force), -distx); - mobj2->momy = mobj2->momy - FixedMul(FixedMul(FixedDiv(2*mass1, mass1 + mass2), force), -disty); + mobj2->momx = mobj2->momx - FixedMul(FixedDiv(2*mass1, mass1 + mass2), -distx); + mobj2->momy = mobj2->momy - FixedMul(FixedDiv(2*mass1, mass1 + mass2), -disty); } - // Do the bump fx when we've CONFIRMED we can bump. - if ((mobj1->player && mobj1->player->itemtype == KITEM_BUBBLESHIELD) || (mobj2->player && mobj2->player->itemtype == KITEM_BUBBLESHIELD)) - S_StartSound(mobj1, sfx_s3k44); - else - S_StartSound(mobj1, sfx_s3k49); + K_SpawnBumpForObjs(mobj1, mobj2); - fx = P_SpawnMobj(mobj1->x/2 + mobj2->x/2, mobj1->y/2 + mobj2->y/2, mobj1->z/2 + mobj2->z/2, MT_BUMP); - if (mobj1->eflags & MFE_VERTICALFLIP) - fx->eflags |= MFE_VERTICALFLIP; - else - fx->eflags &= ~MFE_VERTICALFLIP; - P_SetScale(fx, mobj1->scale); + K_PlayerJustBumped(mobj1->player); + K_PlayerJustBumped(mobj2->player); - // Because this is done during collision now, rmomx and rmomy need to be recalculated - // so that friction doesn't immediately decide to stop the player if they're at a standstill - // Also set justbumped here - if (mobj1->player) + return true; +} + +// K_KartBouncing, but simplified to act like P_BouncePlayerMove +boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj) +{ + const fixed_t minBump = 25*mapobjectscale; + fixed_t distx, disty, dist; + fixed_t force; + + if ((!bounceMobj || P_MobjWasRemoved(bounceMobj)) + || (!solidMobj || P_MobjWasRemoved(solidMobj))) { - mobj1->player->rmomx = mobj1->momx - mobj1->player->cmomx; - mobj1->player->rmomy = mobj1->momy - mobj1->player->cmomy; - mobj1->player->justbumped = bumptime; - mobj1->player->spindash = 0; - - if (mobj1->player->spinouttimer) - { - mobj1->player->wipeoutslow = wipeoutslowtime+1; - mobj1->player->spinouttimer = max(wipeoutslowtime+1, mobj1->player->spinouttimer); - //mobj1->player->spinouttype = KSPIN_WIPEOUT; // Enforce type - } + return false; } - if (mobj2->player) + // Don't bump when you're being reborn + if (bounceMobj->player && bounceMobj->player->playerstate != PST_LIVE) + return false; + + if (bounceMobj->player && bounceMobj->player->respawn.state != RESPAWNST_NONE) + return false; + + // Don't bump if you've recently bumped + if (bounceMobj->player && bounceMobj->player->justbumped) { - mobj2->player->rmomx = mobj2->momx - mobj2->player->cmomx; - mobj2->player->rmomy = mobj2->momy - mobj2->player->cmomy; - mobj2->player->justbumped = bumptime; - mobj2->player->spindash = 0; - - if (mobj2->player->spinouttimer) - { - mobj2->player->wipeoutslow = wipeoutslowtime+1; - mobj2->player->spinouttimer = max(wipeoutslowtime+1, mobj2->player->spinouttimer); - //mobj2->player->spinouttype = KSPIN_WIPEOUT; // Enforce type - } + bounceMobj->player->justbumped = bumptime; + return false; } + // Adds the OTHER object's momentum times a bunch, for the best chance of getting the correct direction + { + distx = (bounceMobj->x + solidMobj->momx) - (solidMobj->x + bounceMobj->momx); + disty = (bounceMobj->y + solidMobj->momy) - (solidMobj->y + bounceMobj->momy); + } + + force = K_GetBounceForce(bounceMobj, solidMobj, distx, disty); + + if (force == 0) + { + return false; + } + + // Multiply by force + distx = FixedMul(force, distx); + disty = FixedMul(force, disty); + dist = FixedHypot(distx, disty); + + { + // Normalize to the desired push value. + fixed_t normalisedx = FixedDiv(distx, dist); + fixed_t normalisedy = FixedDiv(disty, dist); + fixed_t bounceSpeed; + + bounceSpeed = FixedHypot(bounceMobj->momx, bounceMobj->momy); + bounceSpeed = FixedMul(bounceSpeed, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + bounceSpeed += minBump; + + distx = FixedMul(bounceSpeed, normalisedx); + disty = FixedMul(bounceSpeed, normalisedy); + } + + bounceMobj->momx = bounceMobj->momx - distx; + bounceMobj->momy = bounceMobj->momy - disty; + bounceMobj->momz = -bounceMobj->momz; + + K_SpawnBumpForObjs(bounceMobj, solidMobj); + K_PlayerJustBumped(bounceMobj->player); + return true; } diff --git a/src/k_kart.h b/src/k_kart.h index ad254822c..598479b56 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -37,7 +37,8 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush, boolean bot, boolean rival); INT32 K_GetShieldFromItem(INT32 item); fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against); -boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); +boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2); +boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj); void K_KartPainEnergyFling(player_t *player); void K_FlipFromObject(mobj_t *mo, mobj_t *master); void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index abf0224d2..c9e1a8e4f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3381,14 +3381,12 @@ static int lib_kKartBouncing(lua_State *L) { mobj_t *mobj1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); mobj_t *mobj2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); - boolean bounce = lua_optboolean(L, 3); - boolean solid = lua_optboolean(L, 4); NOHUD if (!mobj1) return LUA_ErrInvalid(L, "mobj_t"); if (!mobj2) return LUA_ErrInvalid(L, "mobj_t"); - K_KartBouncing(mobj1, mobj2, bounce, solid); + K_KartBouncing(mobj1, mobj2); return 0; } diff --git a/src/p_map.c b/src/p_map.c index 4a34ed7f0..a7ca2f18c 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1247,33 +1247,19 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } + // The bump has to happen last + if (P_IsObjectOnGround(thing) && tmthing->momz < 0 && tmthing->player->trickpanel) { - // The bump has to happen last - mobj_t *mo1 = tmthing; - mobj_t *mo2 = thing; - boolean zbounce = false; + P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT|DMG_STEAL); + } + else if (P_IsObjectOnGround(tmthing) && thing->momz < 0 && thing->player->trickpanel) + { + P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL); + } - if (P_IsObjectOnGround(thing) && tmthing->momz < 0) - { - zbounce = true; - mo1 = thing; - mo2 = tmthing; - - if (tmthing->player->trickpanel) - P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT|DMG_STEAL); - } - else if (P_IsObjectOnGround(tmthing) && thing->momz < 0) - { - zbounce = true; - - if (thing->player->trickpanel) - P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL); - } - - if (K_KartBouncing(mo1, mo2, zbounce, false)) - { - K_PvPTouchDamage(mo1, mo2); - } + if (K_KartBouncing(tmthing, thing) == true) + { + K_PvPTouchDamage(tmthing, thing); } return true; @@ -1300,8 +1286,8 @@ static boolean PIT_CheckThing(mobj_t *thing) } else { - K_KartBouncing(tmthing, thing, false, true); - return false; + K_KartSolidBounce(tmthing, thing); + return true; } } else if (thing->type == MT_SMK_PIPE) @@ -1322,8 +1308,8 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // kill } - K_KartBouncing(tmthing, thing, false, true); - return false; + K_KartSolidBounce(tmthing, thing); + return true; } else if (thing->type == MT_SMK_THWOMP) { @@ -1362,12 +1348,13 @@ static boolean PIT_CheckThing(mobj_t *thing) P_DamageMobj(tmthing, thing, thing, 1, DMG_TUMBLE); else { - if (thing->flags2 & MF2_AMBUSH) + if ((K_KartSolidBounce(tmthing, thing) == true) && (thing->flags2 & MF2_AMBUSH)) + { P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT); - K_KartBouncing(tmthing, thing, false, true); + } } - return false; + return true; } else if (thing->type == MT_KART_LEFTOVER) { @@ -1377,12 +1364,8 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (P_IsObjectOnGround(thing) && tmthing->momz < 0) - K_KartBouncing(tmthing, thing, true, false); - else - K_KartBouncing(tmthing, thing, false, false); - - return false; + K_KartBouncing(tmthing, thing); + return true; } else if (thing->flags & MF_SOLID) { @@ -1392,12 +1375,8 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (P_IsObjectOnGround(thing) && tmthing->momz < 0) - K_KartBouncing(tmthing, thing, true, true); - else - K_KartBouncing(tmthing, thing, false, true); - - return false; + K_KartSolidBounce(tmthing, thing); + return true; } }