diff --git a/src/dehacked.c b/src/dehacked.c index 57571b0c0..d71bc6da6 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -5217,12 +5217,18 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_KART_DRIFT_R_OUT", "S_KART_DRIFT_R_IN", "S_KART_SPINOUT", - "S_KART_SQUISH", + "S_KART_DEAD", "S_KART_SIGN", // technically the player goes here but it's an infinite tic state "S_OBJPLACE_DUMMY", + "S_KART_LEFTOVER", + "S_KART_LEFTOVER_NOTIRES", + + "S_KART_TIRE1", + "S_KART_TIRE2", + // Blue Crawla "S_POSS_STND", "S_POSS_RUN1", @@ -9421,6 +9427,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_THOK", // Thok! mobj "MT_PLAYER", + "MT_KART_LEFTOVER", + "MT_KART_TIRE", // Enemies "MT_BLUECRAWLA", // Crawla (Blue) diff --git a/src/info.c b/src/info.c index d804c5978..7e8ad8c17 100644 --- a/src/info.c +++ b/src/info.c @@ -32,6 +32,8 @@ char sprnames[NUMSPRITES + 1][5] = "THOK", // Thok! mobj "PLAY", + "KART", + "TIRE", // Enemies "POSS", // Crawla (Blue) @@ -753,7 +755,7 @@ char spr2names[NUMPLAYERSPRITES][5] = "DRLN", "DRLO", "DRLI", // Drifting left "DRRN", "DRRO", "DRRI", // Drifting right "SPIN", // Spinout - "SQSH", // Squish + "DEAD", // Dead "SIGN", // Finish signpost "XTRA", // Three Faces of Darkness }; @@ -781,7 +783,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_DRRN, // SPR2_DRRI 0, // SPR2_SPIN - SPR2_SPIN, // SPR2_SQSH + 0, // SPR2_DEAD 0, // SPR2_SIGN }; @@ -827,11 +829,17 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_DRRO, 1, {NULL}, 0, 0, S_KART_DRIFT_R_OUT}, // S_KART_DRIFT_R_OUT {SPR_PLAY, SPR2_DRRI, 1, {NULL}, 0, 0, S_KART_DRIFT_R_IN}, // S_KART_DRIFT_R_IN {SPR_PLAY, SPR2_SPIN|FF_ANIMATE, 350, {NULL}, 0, 1, S_KART_STILL}, // S_KART_SPINOUT - {SPR_PLAY, SPR2_SQSH|FF_ANIMATE, 350, {NULL}, 0, 1, S_KART_STILL}, // S_KART_SQUISH + {SPR_PLAY, SPR2_DEAD, 3, {NULL}, 0, 0, S_KART_DEAD}, // S_KART_DEAD {SPR_PLAY, SPR2_SIGN|FF_PAPERSPRITE, 1, {NULL}, 0, 0, S_KART_SIGN}, // S_KART_SIGN {SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, // S_OBJPLACE_DUMMY + {SPR_KART, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KART_LEFTOVER + {SPR_KART, 1, -1, {NULL}, 0, 0, S_NULL}, // S_KART_LEFTOVER_NOTIRES + + {SPR_TIRE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KART_TIRE1 + {SPR_TIRE, 1, -1, {NULL}, 0, 0, S_NULL}, // S_KART_TIRE2 + // Blue Crawla {SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND}, // S_POSS_STND {SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2}, // S_POSS_RUN1 @@ -5227,7 +5235,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_KART_SPINOUT, // deathstate + S_KART_DEAD, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 1, // speed @@ -5241,6 +5249,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = (statenum_t)MT_THOK // raisestate }, + { // MT_KART_LEFTOVER + 4095, // doomednum + S_KART_LEFTOVER, // spawnstate + 2, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // 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 + 1, // speed + 16*FRACUNIT, // radius + 48*FRACUNIT, // height + -1, // display offset + 1000, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_KART_TIRE + -1, // doomednum + S_KART_TIRE1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // 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 + 1, // speed + 6*FRACUNIT, // radius + 12*FRACUNIT, // height + -1, // display offset + 1000, // mass + 0, // damage + sfx_None, // activesound + MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_BLUECRAWLA 100, // doomednum S_POSS_STND, // spawnstate diff --git a/src/info.h b/src/info.h index 099f9c412..236279097 100644 --- a/src/info.h +++ b/src/info.h @@ -303,6 +303,8 @@ typedef enum sprite SPR_THOK, // Thok! mobj SPR_PLAY, + SPR_KART, + SPR_TIRE, // Enemies SPR_POSS, // Crawla (Blue) @@ -1031,7 +1033,7 @@ typedef enum playersprite SPR2_DRLN, SPR2_DRLO, SPR2_DRLI, SPR2_DRRN, SPR2_DRRO, SPR2_DRRI, SPR2_SPIN, - SPR2_SQSH, + SPR2_DEAD, SPR2_SIGN, SPR2_XTRA, SPR2_FIRSTFREESLOT, @@ -1072,12 +1074,18 @@ typedef enum state S_KART_DRIFT_R_OUT, S_KART_DRIFT_R_IN, S_KART_SPINOUT, - S_KART_SQUISH, + S_KART_DEAD, S_KART_SIGN, // technically the player goes here but it's an infinite tic state S_OBJPLACE_DUMMY, + S_KART_LEFTOVER, + S_KART_LEFTOVER_NOTIRES, + + S_KART_TIRE1, + S_KART_TIRE2, + // Blue Crawla S_POSS_STND, S_POSS_RUN1, @@ -5315,6 +5323,8 @@ typedef enum mobj_type MT_THOK, // Thok! mobj MT_PLAYER, + MT_KART_LEFTOVER, + MT_KART_TIRE, // Enemies MT_BLUECRAWLA, // Crawla (Blue) diff --git a/src/k_kart.c b/src/k_kart.c index 5b259a050..3006d1f66 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1010,6 +1010,14 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) break; weight = K_PlayerWeight(mobj, against); break; + case MT_KART_LEFTOVER: + weight = 5*FRACUNIT/2; + + if (mobj->extravalue1 > 0) + { + weight = mobj->extravalue1 * (FRACUNIT >> 1); + } + break; case MT_BUBBLESHIELD: weight = K_PlayerWeight(mobj->target, against); break; diff --git a/src/p_inter.c b/src/p_inter.c index 5be3cc736..9d677069b 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1371,13 +1371,47 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget case MT_PLAYER: { + angle_t flingAngle; + mobj_t *kart; + target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player) target->momx = target->momy = target->momz = 0; - if (target->player && target->player->pflags & PF_GAMETYPEOVER) - break; + kart = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_KART_LEFTOVER); + if (kart && !P_MobjWasRemoved(kart)) + { + kart->angle = target->angle; + kart->color = target->color; + kart->hitlag = target->hitlag; + P_SetObjectMomZ(kart, 6*FRACUNIT, false); + kart->extravalue1 = target->player->kartweight; + } + + if (source && !P_MobjWasRemoved(source)) + { + flingAngle = R_PointToAngle2( + source->x - source->momx, source->y - source->momy, + target->x, target->y + ); + } + else + { + flingAngle = target->angle + ANGLE_180; + + if (P_RandomByte() & 1) + { + flingAngle -= ANGLE_45; + } + else + { + flingAngle += ANGLE_45; + } + } + + P_InstaThrust(target, flingAngle, 14 * target->scale); P_SetObjectMomZ(target, 14*FRACUNIT, false); + P_PlayDeathSound(target); } break; diff --git a/src/p_map.c b/src/p_map.c index 8c9db9ce4..a8ff6a5a8 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1398,6 +1398,21 @@ static boolean PIT_CheckThing(mobj_t *thing) return false; } + else if (thing->type == MT_KART_LEFTOVER) + { + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + 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; + } else if (thing->flags & MF_SOLID) { // see if it went over / under diff --git a/src/p_mobj.c b/src/p_mobj.c index 2cbabfd9a..3033256d5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -242,7 +242,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) player->panim = PA_DASH; break; case S_KART_SPINOUT: - case S_KART_SQUISH: + case S_KART_DEAD: player->panim = PA_PAIN; break; default: @@ -2334,6 +2334,68 @@ boolean P_ZMovement(mobj_t *mo) if (mo->flags2 & MF2_SKULLFLY) // the skull slammed into something mom.z = -mom.z; + else if (mo->type == MT_KART_LEFTOVER) + { + if (mo->health > 1) + { + const fixed_t tireOffset = 32; + const angle_t aOffset = ANGLE_22h; + + UINT8 i; + angle_t tireAngle; + mobj_t *tire; + + // Spawn tires! + mo->health = 1; + P_SetMobjState(mo, S_KART_LEFTOVER_NOTIRES); + + // Front tires + tireAngle = mo->angle - aOffset; + for (i = 0; i < 2; i++) + { + tire = P_SpawnMobjFromMobj( + mo, + tireOffset * FINECOSINE(tireAngle >> ANGLETOFINESHIFT), + tireOffset * FINESINE(tireAngle >> ANGLETOFINESHIFT), + 0, + MT_KART_TIRE + ); + + tire->angle = mo->angle; + tire->fuse = 3*TICRATE; + P_InstaThrust(tire, tireAngle, 4 * mo->scale); + P_SetObjectMomZ(tire, 4*FRACUNIT, false); + + tireAngle += (aOffset * 2); + } + + // Back tires + tireAngle = (mo->angle + ANGLE_180) - aOffset; + for (i = 0; i < 2; i++) + { + tire = P_SpawnMobjFromMobj( + mo, + tireOffset * FINECOSINE(tireAngle >> ANGLETOFINESHIFT), + tireOffset * FINESINE(tireAngle >> ANGLETOFINESHIFT), + 0, + MT_KART_TIRE + ); + + tire->angle = mo->angle; + tire->fuse = 3*TICRATE; + P_InstaThrust(tire, tireAngle, 4 * mo->scale); + P_SetObjectMomZ(tire, 4*FRACUNIT, false); + + P_SetMobjState(tire, S_KART_TIRE2); + + tireAngle += (aOffset * 2); + } + } + } + else if (mo->type == MT_KART_TIRE) + { + mom.z = -mom.z; + } else if (mo->type == MT_BIGTUMBLEWEED || mo->type == MT_LITTLETUMBLEWEED || mo->type == MT_CANNONBALLDECOR @@ -5867,8 +5929,11 @@ static boolean P_MobjDeadThink(mobj_t *mobj) { // Go away. /// \todo Actually go ahead and remove mobj completely, and fix any bugs and crashes doing this creates. Chasecam should stop moving, and F12 should never return to it. mobj->momz = 0; + if (mobj->player) + { mobj->drawflags |= MFD_DONTDRAW; + } else // safe to remove, nobody's going to complain! { P_RemoveMobj(mobj); @@ -5877,16 +5942,6 @@ static boolean P_MobjDeadThink(mobj_t *mobj) } else // Apply gravity to fall downwards. { - if (mobj->player && !(mobj->fuse % 8) && (mobj->player->charflags & SF_MACHINE)) - { - fixed_t r = mobj->radius >> FRACBITS; - mobj_t *explosion = P_SpawnMobj( - mobj->x + (P_RandomRange(r, -r) << FRACBITS), - mobj->y + (P_RandomRange(r, -r) << FRACBITS), - mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS), - MT_SONIC3KBOSSEXPLODE); - S_StartSound(explosion, sfx_s3kb4); - } P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true); } break; @@ -9079,6 +9134,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) switch (thing->type) { case MT_PLAYER: + case MT_KART_LEFTOVER: case MT_SMALLMACE: case MT_BIGMACE: case MT_PUMA: @@ -9371,6 +9427,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->color = (P_RandomChance(FRACUNIT/2) ? SKINCOLOR_RED : SKINCOLOR_AQUAMARINE); break; case MT_BALLOON: + case MT_KART_LEFTOVER: mobj->color = SKINCOLOR_RED; break; case MT_EGGROBO1: diff --git a/src/p_user.c b/src/p_user.c index 0df4aa756..adaa9333b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3075,7 +3075,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall mo = player->mo; - if (mo->hitlag > 0) + if (mo->hitlag > 0 || player->playerstate == PST_DEAD) { // Do not move the camera while in hitlag! // The camera zooming out after you got hit makes it hard to focus on the vibration.