diff --git a/src/g_game.c b/src/g_game.c index 8b4af1536..cf32b67ea 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2452,6 +2452,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) growshrinktimer = 0; bumper = ((gametyperules & GTR_BUMPERS) ? K_StartingBumperCount() : 0); rings = ((gametyperules & GTR_SPHERES) ? 0 : 5); + if (modeattacking & ATTACKING_SPB) + rings = 20; spheres = 0; kickstartaccel = 0; khudfault = 0; diff --git a/src/k_menu.h b/src/k_menu.h index 4bbd752c4..06753e754 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -799,6 +799,7 @@ void M_StartTimeAttack(INT32 choice); void M_ReplayTimeAttack(INT32 choice); void M_HandleStaffReplay(INT32 choice); void M_SetGuestReplay(INT32 choice); +boolean M_TimeAttackInputs (INT32 choice); // MP selection void M_MPOptSelect(INT32 choice); @@ -1143,6 +1144,14 @@ void M_DrawAddons(void); #define TILEFLIP_MAX 16 +extern struct timeattackmenu_s { + + tic_t ticker; // How long the menu's been open for + tic_t spbflicker; // used for SPB flicker-in + +} timeattackmenu; + + // Keep track of some pause menu data for visual goodness. extern struct challengesmenu_s { diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 9c3fe3233..6957e4e35 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2371,6 +2371,26 @@ void M_DrawTimeAttack(void) V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST TIME:"); K_drawKartTimestamp(timerec, 162+t, timeheight+6, 0, 1); + + + + const UINT8 anim_duration = 16; + const UINT8 anim = (timeattackmenu.ticker % (anim_duration * 2)) < anim_duration; + + INT32 buttonx = 162 + t; + INT32 buttony = timeheight; + + if (anim) + V_DrawScaledPatch(buttonx + 35, buttony - 3, V_SNAPTOLEFT, W_CachePatchName("TLB_I", PU_CACHE)); + else + V_DrawScaledPatch(buttonx + 35, buttony - 3, V_SNAPTOLEFT, W_CachePatchName("TLB_IB", PU_CACHE)); + + if (timeattackmenu.ticker > (timeattackmenu.spbflicker + TICRATE/6) || timeattackmenu.ticker % 2) + { + if (cv_dummyspbattack.value) + V_DrawMappedPatch(buttonx + 7, buttony - 1, 0, W_CachePatchName("K_STKARM", PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_RED, GTC_MENUCACHE)); + } + } else opty = 80; diff --git a/src/menus/play-local-race-time-attack.c b/src/menus/play-local-race-time-attack.c index 406e4aef8..fedb71b35 100644 --- a/src/menus/play-local-race-time-attack.c +++ b/src/menus/play-local-race-time-attack.c @@ -17,14 +17,44 @@ static void CV_SPBAttackChanged(void) consvar_t cv_dummyspbattack = CVAR_INIT ("dummyspbattack", "Off", CV_HIDDEN|CV_CALL, CV_OnOff, CV_SPBAttackChanged); +struct timeattackmenu_s timeattackmenu; + +boolean M_TimeAttackInputs(INT32 ch) +{ + const UINT8 pid = 0; + const boolean buttonR = M_MenuButtonPressed(pid, MBT_R); + (void) ch; + + timeattackmenu.ticker++; + + if (buttonR) + { + cv_dummyspbattack.value = !(cv_dummyspbattack.value); + CV_SPBAttackChanged(); + timeattackmenu.spbflicker = timeattackmenu.ticker; + if (cv_dummyspbattack.value) + { + S_StartSound(NULL, sfx_s3k9f); + S_StopSoundByID(NULL, sfx_s3k92); + } + else + { + S_StartSound(NULL, sfx_s3k92); + S_StopSoundByID(NULL, sfx_s3k9f); + } + + return true; + } + + return false; +} + // 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}, }; @@ -42,7 +72,7 @@ menu_t PLAY_TimeAttackDef = { NULL, NULL, NULL, - NULL + M_TimeAttackInputs }; diff --git a/src/p_inter.c b/src/p_inter.c index f4ce507ac..09036f117 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 || modeattacking & ATTACKING_SPB)) + if ((!player->exiting && specialstageinfo.valid == true) || (modeattacking & ATTACKING_SPB)) { player->pflags |= PF_NOCONTEST; P_DoPlayerExit(player);