diff --git a/src/k_collide.c b/src/k_collide.c index 6239d5cdf..f5bb39457 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -68,7 +68,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); + K_KartBouncing(t2, t1, false, false); S_StartSound(t2, sfx_s3k7b); } @@ -542,7 +542,7 @@ boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2) angle_t t2angle = R_PointToAngle2(t2->momx, t2->momy, 0, 0); angle_t t2deflect; fixed_t t1speed, t2speed; - K_KartBouncing(t1, t2); + K_KartBouncing(t1, t2, false, false); t1speed = FixedHypot(t1->momx, t1->momy); t2speed = FixedHypot(t2->momx, t2->momy); @@ -796,7 +796,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); + K_KartBouncing(t2, t1, false, false); return true; } @@ -824,7 +824,7 @@ boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2) return true; */ - K_KartBouncing(t1, t2); + K_KartBouncing(t2, t1, false, true); return false; } diff --git a/src/k_kart.c b/src/k_kart.c index 33f7e0c8b..75e880e1d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1697,143 +1697,16 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) return weight; } -static void K_SpawnBumpForObjs(mobj_t *mobj1, mobj_t *mobj2) +boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) { - 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 if (mobj1->type == MT_DROPTARGET || mobj1->type == MT_DROPTARGET_SHIELD) // no need to check the other way around - { - // Sound handled in K_DropTargetCollide - // S_StartSound(mobj2, sfx_s258); - fx->colorized = true; - fx->color = mobj1->color; - } - 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; - - 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. - + mobj_t *fx; fixed_t momdifx, momdify; - 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 distx, disty; + fixed_t dot, force; fixed_t mass1, mass2; - if ((!mobj1 || P_MobjWasRemoved(mobj1)) - || (!mobj2 || P_MobjWasRemoved(mobj2))) - { + if (!mobj1 || !mobj2) return false; - } // Don't bump when you're being reborn if ((mobj1->player && mobj1->player->playerstate != PST_LIVE) @@ -1883,145 +1756,133 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2) return false; } - // 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); + mass1 = K_GetMobjWeight(mobj1, mobj2); - force = K_GetBounceForce(mobj1, mobj2, distx, disty); + if (solid == true && mass1 > 0) + mass2 = mass1; + else + mass2 = K_GetMobjWeight(mobj2, mobj1); - if (force == 0) + 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 there's no distance between the 2, they're directly on top of each other, don't run this return false; } - mass1 = K_GetMobjWeight(mobj1, mobj2); - mass2 = K_GetMobjWeight(mobj2, mobj1); + { // 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; - 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; - } + dist = dist ? dist : 1; - 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; - } + nx = FixedDiv(distx, dist); + ny = FixedDiv(disty, dist); - // Multiply by force - distx = FixedMul(force, distx); - disty = FixedMul(force, disty); - dist = FixedHypot(distx, disty); + 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 the speed difference is less than this let's assume they're going proportionately faster from each other - if (dist < minBump) + if (P_AproxDistance(momdifx, momdify) < (25*mapobjectscale)) { - fixed_t normalisedx = FixedDiv(distx, dist); - fixed_t normalisedy = FixedDiv(disty, dist); + 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); + } - distx = FixedMul(minBump, normalisedx); - disty = FixedMul(minBump, normalisedy); + 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; } if (mass2 > 0) { - mobj1->momx = mobj1->momx - FixedMul(FixedDiv(2*mass2, mass1 + mass2), distx); - mobj1->momy = mobj1->momy - FixedMul(FixedDiv(2*mass2, mass1 + mass2), disty); + 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); } - if (mass1 > 0) + if (mass1 > 0 && solid == false) { - mobj2->momx = mobj2->momx - FixedMul(FixedDiv(2*mass1, mass1 + mass2), -distx); - mobj2->momy = mobj2->momy - FixedMul(FixedDiv(2*mass1, mass1 + mass2), -disty); + 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); } - K_SpawnBumpForObjs(mobj1, mobj2); + // 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_PlayerJustBumped(mobj1->player); - K_PlayerJustBumped(mobj2->player); + 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); - 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))) + // 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 false; + mobj1->player->rmomx = mobj1->momx - mobj1->player->cmomx; + mobj1->player->rmomy = mobj1->momy - mobj1->player->cmomy; + mobj1->player->justbumped = bumptime; + + 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 + } } - // Don't bump when you're being reborn - if (bounceMobj->player && bounceMobj->player->playerstate != PST_LIVE) - return false; - - if (bounceMobj->player && bounceMobj->player->respawn) - return false; - - // Don't bump if you've recently bumped - if (bounceMobj->player && bounceMobj->player->justbumped) + if (mobj2->player) { - bounceMobj->player->justbumped = bumptime; - return false; + mobj2->player->rmomx = mobj2->momx - mobj2->player->cmomx; + mobj2->player->rmomy = mobj2->momy - mobj2->player->cmomy; + mobj2->player->justbumped = bumptime; + + 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 + } } - // 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 f012ab212..43bf67d59 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -67,8 +67,7 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, b INT32 K_KartGetLegacyItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush); 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 K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj); +boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); 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 c0b678234..840909eb8 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3548,12 +3548,14 @@ 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); + K_KartBouncing(mobj1, mobj2, bounce, solid); return 0; } diff --git a/src/p_map.c b/src/p_map.c index 14c0cacaa..f65e23140 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1165,19 +1165,35 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; } - // The bump has to happen last - if (P_IsObjectOnGround(thing) && tm.thing->momz < 0 && tm.thing->player->pogospring) { - P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_WIPEOUT|DMG_STEAL); - } - else if (P_IsObjectOnGround(tm.thing) && thing->momz < 0 && thing->player->pogospring) - { - P_DamageMobj(tm.thing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL); + // The bump has to happen last + mobj_t *mo1 = tm.thing; + mobj_t *mo2 = thing; + boolean zbounce = false; + + if (P_IsObjectOnGround(thing) && tm.thing->momz < 0) + { + zbounce = true; + mo1 = thing; + mo2 = tm.thing; + + if (tm.thing->player->pogospring) + P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_WIPEOUT|DMG_STEAL); + } + else if (P_IsObjectOnGround(tm.thing) && thing->momz < 0) + { + zbounce = true; + + if (thing->player->pogospring) + P_DamageMobj(tm.thing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL); + } + + if (K_KartBouncing(mo1, mo2, zbounce, false)) + { + K_PvPTouchDamage(mo1, mo2); + } } - K_PvPTouchDamage(tm.thing, thing); - K_KartBouncing(tm.thing, thing); - return BMIT_CONTINUE; } else if (thing->type == MT_BLUEROBRA_HEAD || thing->type == MT_BLUEROBRA_JOINT) @@ -1202,7 +1218,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } else { - K_KartSolidBounce(tm.thing, thing); + K_KartBouncing(tm.thing, thing, false, true); return BMIT_CONTINUE; } } @@ -1224,7 +1240,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; // kill } - K_KartSolidBounce(tm.thing, thing); + K_KartBouncing(tm.thing, thing, false, true); return BMIT_CONTINUE; } else if (thing->type == MT_SMK_THWOMP) @@ -1264,14 +1280,28 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) P_DamageMobj(tm.thing, thing, thing, 1, DMG_SQUISH); else { - if ((K_KartSolidBounce(tm.thing, thing) == true) && (thing->flags2 & MF2_AMBUSH)) - { + if (thing->flags2 & MF2_AMBUSH) P_DamageMobj(tm.thing, thing, thing, 1, DMG_WIPEOUT); - } + K_KartBouncing(tm.thing, thing, false, true); } return BMIT_CONTINUE; } + else if (thing->type == MT_KART_LEFTOVER) + { + // see if it went over / under + if (tm.thing->z > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + if (tm.thing->z + tm.thing->height < thing->z) + return BMIT_CONTINUE; // underneath + + if (P_IsObjectOnGround(thing) && tm.thing->momz < 0) + K_KartBouncing(tm.thing, thing, true, false); + else + K_KartBouncing(tm.thing, thing, false, false); + + return BMIT_CONTINUE; + } else if (thing->flags & MF_SOLID) { // see if it went over / under @@ -1280,7 +1310,11 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - K_KartSolidBounce(tm.thing, thing); + if (P_IsObjectOnGround(thing) && tm.thing->momz < 0) + K_KartBouncing(tm.thing, thing, true, true); + else + K_KartBouncing(tm.thing, thing, false, true); + return BMIT_CONTINUE; } }