diff --git a/src/d_player.h b/src/d_player.h index 298c65485..98dee8e9a 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -671,6 +671,8 @@ struct player_t UINT8 eggmanTransferDelay; + fixed_t SPBdistance; + UINT8 tripwireReboundDelay; // When failing Tripwire, brieftly lock out speed-based tripwire pass (anti-cheese) mobj_t *stumbleIndicator; diff --git a/src/doomstat.h b/src/doomstat.h index b0375ffa2..871c25b62 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -139,6 +139,7 @@ extern boolean metalrecording; #define ATTACKING_NONE 0 #define ATTACKING_TIME 1 #define ATTACKING_LAP (1<<1) +#define ATTACKING_SPB (1<<2) extern UINT8 modeattacking; // menu demo things diff --git a/src/g_demo.c b/src/g_demo.c index 174511e4d..617dc386b 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -119,7 +119,7 @@ demoghost *ghosts = NULL; #define DEMOVERSION 0x0007 #define DEMOHEADER "\xF0" "KartReplay" "\x0F" -#define DF_ATTACKMASK (ATTACKING_TIME|ATTACKING_LAP) // This demo contains time/lap data +#define DF_ATTACKMASK (ATTACKING_TIME|ATTACKING_LAP|ATTACKING_SPB) // This demo contains time/lap data #define DF_GHOST 0x08 // This demo contains ghost data too! diff --git a/src/k_hud.c b/src/k_hud.c index 8fd7607ec..a3accce03 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1654,6 +1654,23 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, U workx += 6; } } + + if (modeattacking & ATTACKING_SPB && stplyr->SPBdistance > 0) + { + UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE); + int ybar = 180; + int widthbar = 120; + + V_DrawFill(160 - widthbar / 2, ybar, widthbar, 1, 6); + V_DrawMappedPatch(160 + widthbar/2 - 7, ybar - 7, FRACUNIT, faceprefix[stplyr->skin][FACE_MINIMAP], colormap); + + // vibes-based math + int bombxoff = (stplyr->SPBdistance/mapobjectscale - mobjinfo[MT_SPB].radius/FRACUNIT - mobjinfo[MT_PLAYER].radius/FRACUNIT) * 8; + bombxoff = sqrt(bombxoff) - 5; + bombxoff = max(0, min(bombxoff, widthbar)); + V_DrawScaledPatch(160 + widthbar/2 - bombxoff, ybar - 7, FRACUNIT, W_CachePatchName("SPBMMAP", PU_CACHE)); + + } } static fixed_t K_DrawKartPositionNumPatch(UINT8 num, UINT8 *color, fixed_t x, fixed_t y, fixed_t scale, INT32 flags) diff --git a/src/k_kart.c b/src/k_kart.c index ce2827cf7..5e9982648 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4095,6 +4095,13 @@ INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A { if (inflictor->type == MT_SPBEXPLOSION && inflictor->movefactor) { + if (modeattacking & ATTACKING_SPB) + { + P_DamageMobj(player->mo, inflictor, source, 1, DMG_INSTAKILL); + player->SPBdistance = 0; + S_StopMusic(); + } + spbMultiplier = inflictor->movefactor; if (spbMultiplier <= 0) diff --git a/src/k_menu.h b/src/k_menu.h index 3adbf25de..4bbd752c4 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -232,6 +232,7 @@ typedef enum ta_replay = 0, ta_guest, ta_ghosts, + ta_spb, ta_spacer, ta_start, } ta_e; @@ -761,6 +762,8 @@ extern consvar_t cv_dummykartspeed; extern consvar_t cv_dummygpencore; extern consvar_t cv_dummymatchbots; +extern consvar_t cv_dummyspbattack; + void M_SetupDifficultyOptions(INT32 choice); void M_SetupDifficultySelect(INT32 choice); void M_DifficultySelectInputs(INT32 choice); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 8898bee71..ce9b07e2f 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -1138,6 +1138,8 @@ void M_Init(void) CV_RegisterVar(&cv_dummygpencore); CV_RegisterVar(&cv_dummymatchbots); + CV_RegisterVar(&cv_dummyspbattack); + CV_RegisterVar(&cv_dummyaddonsearch); M_UpdateMenuBGImage(true); diff --git a/src/k_roulette.c b/src/k_roulette.c index 0d70b9e87..53bb753db 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -189,6 +189,13 @@ static kartitems_t K_KartItemReelTimeAttack[] = KITEM_NONE }; +static kartitems_t K_KartItemReelSPBAttack[] = +{ + KITEM_GACHABOM, + KITEM_SUPERRING, + KITEM_NONE +}; + static kartitems_t K_KartItemReelBreakTheCapsules[] = { KITEM_GACHABOM, @@ -1238,6 +1245,11 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet presetlist = K_KartItemReelBreakTheCapsules; } + if (modeattacking & ATTACKING_SPB) + { + presetlist = K_KartItemReelSPBAttack; + } + for (i = 0; presetlist[i] != KITEM_NONE; i++) { K_PushToRouletteItemList(roulette, presetlist[i]); diff --git a/src/menus/play-local-race-time-attack.c b/src/menus/play-local-race-time-attack.c index d41f29dca..687c282a6 100644 --- a/src/menus/play-local-race-time-attack.c +++ b/src/menus/play-local-race-time-attack.c @@ -10,12 +10,16 @@ #include "../m_misc.h" // M_MkdirEach #include "../z_zone.h" // Z_StrDup/Z_Free +consvar_t cv_dummyspbattack = CVAR_INIT ("dummyspbattack", "Off", CV_HIDDEN, CV_OnOff, NULL); + // see ta_e menuitem_t PLAY_TimeAttack[] = { {IT_STRING | IT_SUBMENU, "Replay...", NULL, NULL, {.submenu = &PLAY_TAReplayDef}, 0, 0}, {IT_STRING | IT_SUBMENU, "Guest...", NULL, NULL, {.submenu = &PLAY_TAReplayGuestDef}, 0, 0}, {IT_STRING | IT_SUBMENU, "Ghosts...", NULL, NULL, {.submenu = &PLAY_TAGhostsDef}, 0, 0}, + {IT_STRING | IT_CVAR, "SPB Attack", NULL, + NULL, {.cvar = &cv_dummyspbattack}, 0, 0}, {IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0}, {IT_STRING | IT_CALL, "Start", NULL, NULL, {.routine = M_StartTimeAttack}, 0, 0}, }; @@ -426,6 +430,11 @@ void M_StartTimeAttack(INT32 choice) modeattacking |= ATTACKING_LAP; } + if (cv_dummyspbattack.value) + { + modeattacking |= ATTACKING_SPB; + } + // Still need to reset devmode cht_debug = 0; emeralds = 0; diff --git a/src/objects/spb.c b/src/objects/spb.c index af1041049..261245e79 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -83,6 +83,9 @@ static void SPBMantaRings(mobj_t *spb) const fixed_t floatHeight = 24 * spb->scale; fixed_t floorDist = INT32_MAX; + if (modeattacking & ATTACKING_SPB) + return; // no one else to use 'em + if (leveltime % SPB_MANTA_VRATE == 0) { spb_manta_vscale(spb) = max(spb_manta_vscale(spb) - 1, SPB_MANTA_VMAX); @@ -730,6 +733,8 @@ static void SPBChase(mobj_t *spb, mobj_t *bestMobj) dist = P_AproxDistance(P_AproxDistance(spb->x - chase->x, spb->y - chase->y), spb->z - chase->z); + chasePlayer->SPBdistance = dist; + desiredSpeed = FixedMul(baseSpeed, FRACUNIT + FixedDiv(dist - range, range)); if (desiredSpeed < baseSpeed) diff --git a/src/p_inter.c b/src/p_inter.c index 3d69eec25..f4ce507ac 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1921,7 +1921,7 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, return false; } - if (!player->exiting && specialstageinfo.valid == true) + if (!player->exiting && (specialstageinfo.valid == true || modeattacking & ATTACKING_SPB)) { player->pflags |= PF_NOCONTEST; P_DoPlayerExit(player); diff --git a/src/p_mobj.c b/src/p_mobj.c index 3f0481a94..e939478a6 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12225,6 +12225,9 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) if ((i == MT_RANDOMITEM) && (gametyperules & (GTR_PAPERITEMS|GTR_CIRCUIT)) == (GTR_PAPERITEMS|GTR_CIRCUIT)) return MT_PAPERITEMSPOT; + if ((i == MT_RING) && (modeattacking & ATTACKING_SPB)) + return MT_THOK; + return i; } diff --git a/src/p_spec.c b/src/p_spec.c index 5d52da0fb..c881200dd 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1973,6 +1973,13 @@ static void K_HandleLapIncrement(player_t *player) rainbowstartavailable = false; } + if (player->laps == 1 && modeattacking & ATTACKING_SPB) + { + P_SpawnMobj(player->mo->x - FixedMul(8000*mapobjectscale, cos(player->mo->angle)), + player->mo->y - FixedMul(8000*mapobjectscale, sin(player->mo->angle)), + player->mo->z, MT_SPB); + } + if (netgame && player->laps > numlaps) CON_LogMessage(va(M_GetText("%s has finished the race.\n"), player_names[player-players]));