diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f5a063875..e49f37e2a 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -531,6 +531,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->deadtimer = players[i].deadtimer; rsp->exiting = (tic_t)LONG(players[i].exiting); rsp->homing = players[i].homing; + rsp->dashmode = (tic_t)LONG(players[i].dashmode); rsp->skidtime = (tic_t)LONG(players[i].skidtime); rsp->cmomx = (fixed_t)LONG(players[i].cmomx); rsp->cmomy = (fixed_t)LONG(players[i].cmomy); @@ -657,6 +658,7 @@ static void resynch_read_player(resynch_pak *rsp) players[i].deadtimer = rsp->deadtimer; players[i].exiting = (tic_t)LONG(rsp->exiting); players[i].homing = rsp->homing; + players[i].dashmode = (tic_t)LONG(rsp->dashmode); players[i].skidtime = (tic_t)LONG(rsp->skidtime); players[i].cmomx = (fixed_t)LONG(rsp->cmomx); players[i].cmomy = (fixed_t)LONG(rsp->cmomy); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 14b590926..f9e33dc4c 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -191,6 +191,7 @@ typedef struct INT32 deadtimer; tic_t exiting; UINT8 homing; + tic_t dashmode; tic_t skidtime; fixed_t cmomx; fixed_t cmomy; diff --git a/src/d_player.h b/src/d_player.h index f2e6fe735..4a5d0e702 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -57,7 +57,8 @@ typedef enum CA_FALLSWITCH, CA_JUMPBOOST, CA_AIRDRILL, - CA_JUMPTHOK + CA_JUMPTHOK, + CA_DASHMODE } charability_t; //Secondary skin abilities @@ -164,6 +165,7 @@ typedef enum PA_EDGE, PA_WALK, PA_RUN, + PA_PEEL, PA_PAIN, PA_ROLL, PA_SPRING, @@ -351,6 +353,7 @@ typedef struct player_s tic_t exiting; // Exitlevel timer UINT8 homing; // Are you homing? + tic_t dashmode; // counter for dashmode ability tic_t skidtime; // Skid timer diff --git a/src/dehacked.c b/src/dehacked.c index 36dc862cb..4909c4900 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3794,6 +3794,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_PLAY_WAIT", "S_PLAY_WALK", "S_PLAY_RUN", + "S_PLAY_PEEL", "S_PLAY_PAIN", "S_PLAY_DEAD", "S_PLAY_DRWN", @@ -3819,6 +3820,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_PLAY_SUPER_STND", "S_PLAY_SUPER_WALK", "S_PLAY_SUPER_RUN", + "S_PLAY_SUPER_PEEL", "S_PLAY_SUPER_PAIN", "S_PLAY_SUPER_STUN", "S_PLAY_SUPER_DEAD", @@ -7141,6 +7143,7 @@ struct { {"CA_JUMPBOOST",CA_JUMPBOOST}, {"CA_AIRDRILL",CA_AIRDRILL}, {"CA_JUMPTHOK",CA_JUMPTHOK}, + {"CA_DASHMODE",CA_DASHMODE}, // Secondary {"CA2_NONE",CA2_NONE}, // now slot 0! {"CA2_SPINDASH",CA2_SPINDASH}, @@ -7191,6 +7194,7 @@ struct { {"PA_EDGE",PA_EDGE}, {"PA_WALK",PA_WALK}, {"PA_RUN",PA_RUN}, + {"PA_PEEL",PA_PEEL}, {"PA_PAIN",PA_PAIN}, {"PA_ROLL",PA_ROLL}, {"PA_SPRING",PA_SPRING}, diff --git a/src/info.c b/src/info.c index dc71ad163..8eec24818 100644 --- a/src/info.c +++ b/src/info.c @@ -62,6 +62,7 @@ char spr2names[NUMPLAYERSPRITES][5] = "WAIT", "WALK", "RUN_", + "PEEL", "PAIN", "DEAD", "DRWN", @@ -88,6 +89,7 @@ char spr2names[NUMPLAYERSPRITES][5] = "SSTD", "SWLK", "SRUN", + "SPEE", "SPAN", "SMSL", "SDTH", @@ -132,6 +134,7 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_WAIT, 16, {NULL}, 0, 0, S_PLAY_WAIT}, // S_PLAY_WAIT {SPR_PLAY, SPR2_WALK, 4, {NULL}, 0, 0, S_PLAY_WALK}, // S_PLAY_WALK {SPR_PLAY, SPR2_RUN , 2, {NULL}, 0, 0, S_PLAY_RUN}, // S_PLAY_RUN + {SPR_PLAY, SPR2_PEEL, 2, {NULL}, 0, 0, S_PLAY_PEEL}, // S_PLAY_PEEL {SPR_PLAY, SPR2_PAIN, 350, {NULL}, 0, 0, S_PLAY_FALL}, // S_PLAY_PAIN {SPR_PLAY, SPR2_DEAD, 4, {NULL}, 0, 0, S_PLAY_DEAD}, // S_PLAY_DEAD {SPR_PLAY, SPR2_DRWN, 4, {NULL}, 0, 0, S_PLAY_DRWN}, // S_PLAY_DRWN @@ -157,6 +160,7 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_SSTD, 7, {NULL}, 0, 0, S_PLAY_SUPER_STND}, // S_PLAY_SUPER_STND {SPR_PLAY, SPR2_SWLK, 7, {NULL}, 0, 0, S_PLAY_SUPER_WALK}, // S_PLAY_SUPER_WALK {SPR_PLAY, SPR2_SRUN, 7, {NULL}, 0, 0, S_PLAY_SUPER_RUN}, // S_PLAY_SUPER_RUN + {SPR_PLAY, SPR2_SPEE, 7, {NULL}, 0, 0, S_PLAY_SUPER_PEEL}, // S_PLAY_SUPER_PEEL {SPR_PLAY, SPR2_SPAN, -1, {NULL}, 0, 0, S_PLAY_SUPER_STND}, // S_PLAY_SUPER_PAIN {SPR_PLAY, SPR2_SMSL, -1, {NULL}, 0, 0, S_PLAY_SUPER_STND}, // S_PLAY_SUPER_STUN {SPR_PLAY, SPR2_SDTH, 4, {NULL}, 0, 0, S_PLAY_SUPER_DEAD}, // S_PLAY_SUPER_DEAD diff --git a/src/info.h b/src/info.h index 46fdde46b..46b76096b 100644 --- a/src/info.h +++ b/src/info.h @@ -581,6 +581,7 @@ enum playersprite SPR2_WAIT, SPR2_WALK, SPR2_RUN , + SPR2_PEEL, SPR2_PAIN, SPR2_DEAD, SPR2_DRWN, @@ -607,6 +608,7 @@ enum playersprite SPR2_SSTD, SPR2_SWLK, SPR2_SRUN, + SPR2_SPEE, SPR2_SPAN, SPR2_SMSL, SPR2_SDTH, @@ -645,6 +647,7 @@ typedef enum state S_PLAY_WAIT, S_PLAY_WALK, S_PLAY_RUN, + S_PLAY_PEEL, S_PLAY_PAIN, S_PLAY_DEAD, S_PLAY_DRWN, @@ -670,6 +673,7 @@ typedef enum state S_PLAY_SUPER_STND, S_PLAY_SUPER_WALK, S_PLAY_SUPER_RUN, + S_PLAY_SUPER_PEEL, S_PLAY_SUPER_PAIN, S_PLAY_SUPER_STUN, S_PLAY_SUPER_DEAD, diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index bd5605f23..60119deae 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -202,6 +202,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->exiting); else if (fastcmp(field,"homing")) lua_pushinteger(L, plr->homing); + else if (fastcmp(field,"dashmode")) + lua_pushinteger(L, plr->dashmode); else if (fastcmp(field,"skidtime")) lua_pushinteger(L, plr->skidtime); else if (fastcmp(field,"cmomx")) @@ -459,6 +461,8 @@ static int player_set(lua_State *L) plr->exiting = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"homing")) plr->homing = (UINT8)luaL_checkinteger(L, 3); + else if (fastcmp(field,"dashmode")) + plr->dashmode = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"skidtime")) plr->skidtime = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"cmomx")) diff --git a/src/p_map.c b/src/p_map.c index a91e5fd11..c902b0774 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -448,6 +448,35 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } + // Dashmode users destroy spikes and monitors. + if ((tmthing->player) && (tmthing->player->charability == CA_DASHMODE) && (tmthing->player->dashmode >= 3*TICRATE) + && (thing->flags & (MF_MONITOR) || thing->type == MT_SPIKE)) + { + if ((thing->flags & (MF_MONITOR)) && (thing->health <= 0 || !(thing->flags & MF_SHOOTABLE))) + return true; + blockdist = thing->radius + tmthing->radius; + if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) + return true; // didn't hit it + // 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 (thing->type == MT_SPIKE) + { + S_StartSound(tmthing, thing->info->deathsound); + for (thing = thing->subsector->sector->thinglist; thing; thing = thing->snext) + if (thing->type == MT_SPIKE && thing->health > 0 && thing->flags & MF_SOLID && P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y) < FixedMul(56*FRACUNIT, thing->scale)) + P_KillMobj(thing, tmthing, tmthing, 0); + } + else + { + thing->health = 0; + P_KillMobj(thing, tmthing, tmthing, 0); + } + return true; + } + if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE))) return true; diff --git a/src/p_mobj.c b/src/p_mobj.c index 999f2bf72..3c2715512 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -175,6 +175,8 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_WALK); case S_PLAY_RUN: return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_RUN); + case S_PLAY_PEEL: + return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_PEEL); case S_PLAY_PAIN: return P_SetPlayerMobjState(mobj, S_PLAY_SUPER_PAIN); case S_PLAY_DEAD: @@ -231,6 +233,10 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) case S_PLAY_SUPER_RUN: player->panim = PA_RUN; break; + case S_PLAY_PEEL: + case S_PLAY_SUPER_PEEL: + player->panim = PA_PEEL; + break; case S_PLAY_PAIN: case S_PLAY_SUPER_PAIN: case S_PLAY_SUPER_STUN: @@ -316,7 +322,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) else mobj->tics = 4; } - else if (player->panim == PA_RUN) + else if ((player->panim == PA_RUN) || (player->panim == PA_PEEL)) { if (speed > 52<tics = 1; @@ -339,6 +345,9 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) { switch(spr2) { + case SPR2_PEEL: + spr2 = SPR2_RUN; + break; case SPR2_RUN: spr2 = SPR2_WALK; break; @@ -393,6 +402,9 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) case SPR2_SRUN: spr2 = SPR2_RUN; break; + case SPR2_SPEE: + spr2 = SPR2_PEEL; + break; case SPR2_SPAN: spr2 = SPR2_PAIN; break; @@ -2969,7 +2981,9 @@ static void P_PlayerZMovement(mobj_t *mo) { if (mo->player->cmomx || mo->player->cmomy) { - if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale) && mo->player->panim != PA_RUN) + if (mo->player->dashmode >= 3*TICRATE && mo->player->panim != PA_PEEL) + P_SetPlayerMobjState(mo, S_PLAY_PEEL); + else if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale) && mo->player->panim != PA_RUN) P_SetPlayerMobjState(mo, S_PLAY_RUN); else if ((mo->player->rmomx || mo->player->rmomy) && (mo->player->panim != PA_WALK || mo->state-states == S_PLAY_SUPER_FLOAT)) P_SetPlayerMobjState(mo, S_PLAY_WALK); @@ -2978,6 +2992,8 @@ static void P_PlayerZMovement(mobj_t *mo) } else { + if (mo->player->dashmode >= 3*TICRATE && mo->player->panim != PA_PEEL) + P_SetPlayerMobjState(mo, S_PLAY_PEEL); if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale) && mo->player->panim != PA_RUN) P_SetPlayerMobjState(mo, S_PLAY_RUN); else if ((mo->momx || mo->momy) && (mo->player->panim != PA_WALK || mo->state-states == S_PLAY_SUPER_FLOAT)) diff --git a/src/p_saveg.c b/src/p_saveg.c index 48f283bd3..964e8b774 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -162,6 +162,7 @@ static void P_NetArchivePlayers(void) WRITEINT32(save_p, players[i].deadtimer); WRITEUINT32(save_p, players[i].exiting); WRITEUINT8(save_p, players[i].homing); + WRITEUINT32(save_p, players[i].dashmode); WRITEUINT32(save_p, players[i].skidtime); //////////////////////////// @@ -337,6 +338,7 @@ static void P_NetUnArchivePlayers(void) players[i].deadtimer = READINT32(save_p); // End game if game over lasts too long players[i].exiting = READUINT32(save_p); // Exitlevel timer players[i].homing = READUINT8(save_p); // Are you homing? + players[i].dashmode = READUINT32(save_p); // counter for dashmode ability players[i].skidtime = READUINT32(save_p); // Skid timer //////////////////////////// diff --git a/src/p_user.c b/src/p_user.c index 09941745b..18846a5ca 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3452,6 +3452,9 @@ static void P_DoSuperStuff(player_t *player) case S_PLAY_SUPER_RUN: P_SetPlayerMobjState(player->mo, S_PLAY_RUN); break; + case S_PLAY_SUPER_PEEL: + P_SetPlayerMobjState(player->mo, S_PLAY_PEEL); + break; case S_PLAY_SUPER_PAIN: P_SetPlayerMobjState(player->mo, S_PLAY_PAIN); break; @@ -3991,19 +3994,26 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) case CA_THOK: case CA_HOMINGTHOK: case CA_JUMPTHOK: // Credit goes to CZ64 and Sryder13 for the original + case CA_DASHMODE: // Credit goes to Iceman404 // Now it's Sonic's abilities turn! // THOK! if (!(player->pflags & PF_THOKKED) || (player->charability2 == CA2_MULTIABILITY)) { // Catapult the player fixed_t actionspd = player->actionspd; + + if (player->charability == CA_DASHMODE) + actionspd = max(player->normalspeed, FixedDiv(player->speed, player->mo->scale)); + if (player->mo->eflags & MFE_UNDERWATER) actionspd >>= 1; + if ((player->charability == CA_JUMPTHOK) && !(player->pflags & PF_THOKKED)) { player->pflags &= ~PF_JUMPED; P_DoJump(player, false); } + P_InstaThrust(player->mo, player->mo->angle, FixedMul(actionspd, player->mo->scale)); if (maptol & TOL_2D) @@ -6451,9 +6461,12 @@ static void P_MovePlayer(player_t *player) if ((cmd->forwardmove != 0 || cmd->sidemove != 0) || (player->powers[pw_super] && !onground)) { + // If the player is in dashmode, here's their peelout. + if (player->charability == CA_DASHMODE && player->dashmode >= 3*TICRATE && player->panim == PA_RUN && !player->skidtime && (onground || player->powers[pw_super])) + P_SetPlayerMobjState (player->mo, S_PLAY_PEEL); // If the player is moving fast enough, // break into a run! - if (player->speed >= runspd && player->panim == PA_WALK && !player->skidtime && (onground || player->powers[pw_super])) + else if (player->speed >= runspd && player->panim == PA_WALK && !player->skidtime && (onground || player->powers[pw_super])) P_SetPlayerMobjState (player->mo, S_PLAY_RUN); // Super floating at slow speeds has its own special animation. @@ -6465,6 +6478,11 @@ static void P_MovePlayer(player_t *player) P_SetPlayerMobjState (player->mo, S_PLAY_WALK); } + // If your peelout animation is playing, and you're + // going too slow, switch back to the run. + if (player->panim == PA_PEEL && player->dashmode < 3*TICRATE) + P_SetPlayerMobjState(player->mo, S_PLAY_RUN); + // If your running animation is playing, and you're // going too slow, switch back to the walking frames. if (player->panim == PA_RUN && player->speed < runspd) @@ -6795,7 +6813,7 @@ static void P_MovePlayer(player_t *player) #endif } // Otherwise, face the direction you're travelling. - else if (player->panim == PA_WALK || player->panim == PA_RUN || player->panim == PA_ROLL + else if (player->panim == PA_WALK || player->panim == PA_RUN || player->panim == PA_PEEL || player->panim == PA_ROLL || (player->mo->state-states == S_PLAY_FLY || player->mo->state-states == S_PLAY_FLY_TIRED)) player->mo->angle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); @@ -9113,6 +9131,49 @@ void P_PlayerThink(player_t *player) player->pflags &= ~PF_SLIDING; +#define dashmode player->dashmode + // Dash mode ability for Metal Sonic + if ((player->charability == CA_DASHMODE) && !(maptol & TOL_NIGHTS)) // woo, dashmode! no nights tho. + { + if (player->speed >= FixedMul(player->runspeed, player->mo->scale) || (player->pflags & PF_STARTDASH)) + { + dashmode++; // Counter. Adds 1 to dash mode per tic in top speed. + if (dashmode == 3*TICRATE) // This isn't in the ">=" equation because it'd cause the sound to play infinitely. + S_StartSound(player->mo, sfx_s3ka2); // If the player enters dashmode, play this sound on the the tic it starts. + } + else if (!(player->pflags & PF_SPINNING)) + { + if (dashmode > 3) + dashmode -= 3; // Rather than lose it all, it gently counts back down! + else + dashmode = 0; + } + + if (dashmode < 3*TICRATE) // Exits Dash Mode if you drop below speed/dash counter tics. Not in the above block so it doesn't keep disabling in midair. + { + player->normalspeed = skins[player->skin].normalspeed; // Reset to default if not capable of entering dash mode. + player->jumpfactor = skins[player->skin].jumpfactor; + } + else if (P_IsObjectOnGround(player->mo)) // Activate dash mode if we're on the ground. + { + if (player->normalspeed < skins[player->skin].actionspd) // If the player normalspeed is not currently at actionspd in dash mode, add speed each tic + player->normalspeed = player->normalspeed + 1*FRACUNIT/5; // Enter Dash Mode smoothly. + + if (player->jumpfactor < FixedMul(skins[player->skin].jumpfactor, 5*FRACUNIT/4)) // Boost jump height. + player->jumpfactor = player->jumpfactor + 1*FRACUNIT/300; + } + + dashmode = min(dashmode, 3*TICRATE + 3); + + if (player->normalspeed >= skins[player->skin].actionspd) + { + mobj_t *ghost = P_SpawnGhostMobj(player->mo); // Spawns afterimages + ghost->fuse = 2; // Makes the images fade quickly + } + } + else + dashmode = 0; +#undef dashmode /* // Colormap verification {