diff --git a/src/d_player.h b/src/d_player.h index 7d0f20058..ad7b75b86 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -590,6 +590,8 @@ typedef struct player_s UINT8 shrinkLaserDelay; + mobj_t *stumbleIndicator; + #ifdef HWRENDER fixed_t fovadd; // adjust FOV for hw rendering #endif diff --git a/src/deh_tables.c b/src/deh_tables.c index 7bb649d2b..9b8774f4c 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3832,6 +3832,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_TRIPWIREBOOST_BLAST_TOP", "S_TRIPWIREBOOST_BLAST_BOTTOM", + "S_SMOOTHLANDING", + // DEZ respawn laser "S_DEZLASER", "S_DEZLASER_TRAIL1", @@ -5376,6 +5378,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_TRIPWIREBOOST", + "MT_SMOOTHLANDING", + "MT_DEZLASER", "MT_WAYPOINT", diff --git a/src/info.c b/src/info.c index e80098499..110c1e906 100644 --- a/src/info.c +++ b/src/info.c @@ -587,6 +587,7 @@ char sprnames[NUMSPRITES + 1][5] = "BEXB", // Battle Bumper Explosion: Blast "TWBS", // Tripwire Boost "TWBT", // Tripwire BLASTER + "SMLD", // Smooth landing "DEZL", // DEZ Laser respawn // Additional Kart Objects @@ -4392,6 +4393,8 @@ state_t states[NUMSTATES] = {SPR_TWBT, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE, -1, {NULL}, 6, 2, S_NULL}, // S_TRIPWIREBOOST_BLAST_TOP {SPR_TWBT, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE|FF_VERTICALFLIP|FF_HORIZONTALFLIP, -1, {NULL}, 6, 2, S_NULL}, // S_TRIPWIREBOOST_BLAST_BOTTOM + {SPR_SMLD, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL}, // S_SMOOTHLANDING + {SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE, 8, {NULL}, 0, 0, S_NULL}, // S_DEZLASER {SPR_DEZL, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL2}, // S_DEZLASER_TRAIL1 {SPR_DEZL, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL3}, // S_DEZLASER_TRAIL2 @@ -24411,6 +24414,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SMOOTHLANDING + -1, // doomednum + S_SMOOTHLANDING, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 16*FRACUNIT, // height + -1, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_DEZLASER -1, // doomednum S_DEZLASER, // spawnstate diff --git a/src/info.h b/src/info.h index 8305e1400..0d07f2775 100644 --- a/src/info.h +++ b/src/info.h @@ -1133,6 +1133,7 @@ typedef enum sprite SPR_BEXB, // Battle Bumper Explosion: Blast SPR_TWBS, // Tripwire Boost SPR_TWBT, // Tripwire BLASTER + SPR_SMLD, // Smooth landing SPR_DEZL, // DEZ Laser respawn // Additional Kart Objects @@ -4826,6 +4827,8 @@ typedef enum state S_TRIPWIREBOOST_BLAST_TOP, S_TRIPWIREBOOST_BLAST_BOTTOM, + S_SMOOTHLANDING, + // DEZ Laser respawn S_DEZLASER, S_DEZLASER_TRAIL1, @@ -6407,6 +6410,8 @@ typedef enum mobj_type MT_TRIPWIREBOOST, + MT_SMOOTHLANDING, + MT_DEZLASER, MT_WAYPOINT, diff --git a/src/k_bot.c b/src/k_bot.c index f77cbe882..1b5a183b0 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -987,7 +987,7 @@ static angle_t K_BotSmoothLanding(player_t *player, angle_t destangle) { testDeltas[i] = AngleDelta(testAngles[i], destangle); } -' + if (testDeltas[1] < testDeltas[0]) { return testAngles[1]; diff --git a/src/k_kart.c b/src/k_kart.c index bad2c1da0..9d888cfbd 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3797,10 +3797,10 @@ void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) P_StartQuake(64<angle >> ANGLETOFINESHIFT); - fixed_t rollMul = FINECOSINE(mobj->angle >> ANGLETOFINESHIFT); + fixed_t pitchMul = -FINESINE(angle >> ANGLETOFINESHIFT); + fixed_t rollMul = FINECOSINE(angle >> ANGLETOFINESHIFT); angle_t slope = FixedMul(pitch, pitchMul) + FixedMul(roll, rollMul); @@ -3844,7 +3844,7 @@ boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, bool steepVal = STUMBLE_STEEP_VAL; } - oldSlope = K_StumbleSlope(player->mo, oldPitch, oldRoll); + oldSlope = K_StumbleSlope(player->mo->angle, oldPitch, oldRoll); if (oldSlope <= steepVal) { @@ -3853,7 +3853,7 @@ boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, bool return false; } - newSlope = K_StumbleSlope(player->mo, player->mo->pitch, player->mo->roll); + newSlope = K_StumbleSlope(player->mo->angle, player->mo->pitch, player->mo->roll); slopeDelta = AngleDelta(oldSlope, newSlope); if (slopeDelta <= steepVal) @@ -3896,6 +3896,134 @@ boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, bool return true; } +void K_InitStumbleIndicator(player_t *player) +{ + mobj_t *new = NULL; + + if (player == NULL) + { + return; + } + + if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + return; + } + + if (player->stumbleIndicator != NULL && P_MobjWasRemoved(player->stumbleIndicator) == false) + { + P_RemoveMobj(player->stumbleIndicator); + } + + new = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_SMOOTHLANDING); + + P_SetTarget(&player->stumbleIndicator, new); + P_SetTarget(&new->target, player->mo); +} + +void K_UpdateStumbleIndicator(player_t *player) +{ + mobj_t *mobj = NULL; + + boolean air = false; + angle_t steepVal = STUMBLE_STEEP_VAL; + angle_t slopeSteep = 0; + angle_t steepRange = ANGLE_90; + + INT32 delta = 0; + INT32 trans = 0; + + if (player == NULL) + { + return; + } + + if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + return; + } + + if (player->stumbleIndicator == NULL || P_MobjWasRemoved(player->stumbleIndicator) == true) + { + K_InitStumbleIndicator(player); + return; + } + + mobj = player->stumbleIndicator; + + P_MoveOrigin(mobj, player->mo->x, player->mo->y, player->mo->z + (player->mo->height / 2)); + + air = !P_IsObjectOnGround(player->mo); + steepVal = air ? STUMBLE_STEEP_VAL_AIR : STUMBLE_STEEP_VAL; + slopeSteep = max(AngleDelta(player->mo->pitch, 0), AngleDelta(player->mo->roll, 0)); + + delta = 0; + + if (slopeSteep > steepVal) + { + angle_t testAngles[2]; + INT32 testDeltas[2]; + UINT8 i; + + testAngles[0] = R_PointToAngle2(0, 0, player->mo->pitch, player->mo->roll); + testAngles[1] = R_PointToAngle2(0, 0, -player->mo->pitch, -player->mo->roll); + + for (i = 0; i < 2; i++) + { + testDeltas[i] = AngleDeltaSigned(player->mo->angle, testAngles[i]); + } + + if (abs(testDeltas[1]) < abs(testDeltas[0])) + { + delta = testDeltas[1]; + } + else + { + delta = testDeltas[0]; + } + } + + if (delta < 0) + { + mobj->renderflags |= RF_HORIZONTALFLIP; + } + else + { + mobj->renderflags &= ~RF_HORIZONTALFLIP; + } + + steepRange = ANGLE_90 - steepVal; + delta = max(0, abs(delta) - ((signed)steepVal)); + trans = ((FixedDiv(AngleFixed(delta), AngleFixed(steepRange)) * (NUMTRANSMAPS+1)) + (FRACUNIT/2)) / FRACUNIT; + + if (trans < 0) + { + trans = 0; + } + + if (trans > NUMTRANSMAPS) + { + trans = NUMTRANSMAPS; + } + + // invert + trans = NUMTRANSMAPS - trans; + + if (trans >= NUMTRANSMAPS) + { + mobj->renderflags |= RF_DONTDRAW; + } + else + { + mobj->renderflags &= ~(RF_TRANSMASK|RF_DONTDRAW); + + if (trans != 0) + { + mobj->renderflags |= (trans << RF_TRANSSHIFT); + } + } +} + static boolean K_LastTumbleBounceCondition(player_t *player) { return (player->tumbleBounces > TUMBLEBOUNCES && player->tumbleHeight < 60); @@ -7999,6 +8127,8 @@ void K_KartPlayerAfterThink(player_t *player) { K_KartResetPlayerColor(player); + K_UpdateStumbleIndicator(player); + // Move held objects (Bananas, Orbinaut, etc) K_MoveHeldObjects(player); diff --git a/src/k_kart.h b/src/k_kart.h index 9d91ef240..b44258a9a 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -78,8 +78,10 @@ void K_RemoveGrowShrink(player_t *player); void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type); void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_TumbleInterrupt(player_t *player); -angle_t K_StumbleSlope(mobj_t *mobj, angle_t pitch, angle_t roll); +angle_t K_StumbleSlope(angle_t angle, angle_t pitch, angle_t roll); boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir); +void K_InitStumbleIndicator(player_t *player); +void K_UpdateStumbleIndicator(player_t *player); INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_DebtStingPlayer(player_t *player, mobj_t *source); void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers); diff --git a/src/p_mobj.c b/src/p_mobj.c index c71238928..3f0521b12 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2847,20 +2847,14 @@ void P_PlayerZMovement(mobj_t *mo) P_CheckGravity(mo, true); } - // Even out pitch & roll slowly over time when falling. - // Helps give OpenGL models a bit of the tumble tell. - if (P_MobjFlip(mo) * mo->momz <= 0) + // Even out pitch & roll slowly over time when respawning. + if (mo->player->respawn.state != RESPAWNST_NONE) { const angle_t speed = ANG2; //FixedMul(ANG2, abs(mo->momz) / 8); - angle_t dest = ANG60 - ANG10; + angle_t dest = 0; INT32 pitchDelta = AngleDeltaSigned(mo->pitch, 0); INT32 rollDelta = AngleDeltaSigned(mo->roll, 0); - if (mo->player->respawn.state != RESPAWNST_NONE) - { - dest = 0; - } - if (abs(pitchDelta) <= speed && dest == 0) { mo->pitch = 0; @@ -11389,6 +11383,8 @@ void P_SpawnPlayer(INT32 playernum) P_SetScale(mobj, mobj->destscale); P_FlashPal(p, 0, 0); // Resets + K_InitStumbleIndicator(p); + if (gametyperules & GTR_BUMPERS) { mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height + 16*FRACUNIT, MT_PLAYERARROW); diff --git a/src/p_saveg.c b/src/p_saveg.c index da85dac77..f1e51d3fb 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -64,6 +64,7 @@ typedef enum SKYBOXVIEW = 0x08, SKYBOXCENTER = 0x10, HOVERHYUDORO = 0x20, + STUMBLE = 0x40, } player_saveflags; static inline void P_ArchivePlayer(void) @@ -202,6 +203,9 @@ static void P_NetArchivePlayers(void) if (players[i].hoverhyudoro) flags |= HOVERHYUDORO; + if (players[i].stumbleIndicator) + flags |= STUMBLE; + WRITEUINT16(save_p, flags); if (flags & SKYBOXVIEW) @@ -219,6 +223,9 @@ static void P_NetArchivePlayers(void) if (flags & HOVERHYUDORO) WRITEUINT32(save_p, players[i].hoverhyudoro->mobjnum); + if (flags & STUMBLE) + WRITEUINT32(save_p, players[i].stumbleIndicator->mobjnum); + WRITEUINT32(save_p, (UINT32)players[i].followitem); WRITEUINT32(save_p, players[i].charflags); @@ -509,6 +516,9 @@ static void P_NetUnArchivePlayers(void) if (flags & HOVERHYUDORO) players[i].hoverhyudoro = (mobj_t *)(size_t)READUINT32(save_p); + if (flags & STUMBLE) + players[i].stumbleIndicator = (mobj_t *)(size_t)READUINT32(save_p); + players[i].followitem = (mobjtype_t)READUINT32(save_p); //SetPlayerSkinByNum(i, players[i].skin); @@ -4289,6 +4299,13 @@ static void P_RelinkPointers(void) if (!P_SetTarget(&mobj->player->hoverhyudoro, P_FindNewPosition(temp))) CONS_Debug(DBG_GAMELOGIC, "hoverhyudoro not found on %d\n", mobj->type); } + if (mobj->player->stumbleIndicator) + { + temp = (UINT32)(size_t)mobj->player->stumbleIndicator; + mobj->player->stumbleIndicator = NULL; + if (!P_SetTarget(&mobj->player->stumbleIndicator, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "stumbleIndicator not found on %d\n", mobj->type); + } } } }