From d5ca5516de029a3f33fe9eb60fc5eefcaa953df9 Mon Sep 17 00:00:00 2001 From: yamamama Date: Mon, 16 Feb 2026 02:59:17 -0500 Subject: [PATCH] Split Classic and Alt. Invincibility - It's what the people want, why bother to complain? - Alt is now its own separate item titled the S-Monitor - Several variables, macros, functions, and comments have been renamed to fit this change --- extras/Items.md | 30 ++-- src/d_netcmd.c | 31 ++--- src/d_netcmd.h | 19 ++- src/d_player.h | 10 +- src/deh_tables.c | 6 +- src/g_input.c | 4 + src/h_timers.cpp | 8 +- src/hardware/hw_main.c | 4 +- src/info/kartitems.h | 1 + src/k_botitem.cpp | 1 + src/k_collide.c | 18 ++- src/k_color.c | 8 +- src/k_color.h | 6 +- src/k_hud.c | 149 ++++++++++---------- src/k_items.c | 43 ++++-- src/k_items.h | 2 +- src/k_kart.c | 302 ++++++++++++++++++++--------------------- src/k_kart.h | 40 +++--- src/lua_baselib.c | 28 ++-- src/lua_playerlib.c | 47 ++++--- src/p_enemy.c | 3 + src/p_inter.c | 13 +- src/p_mobj.c | 24 ++-- src/p_saveg.c | 9 +- src/p_spec.c | 3 +- src/p_user.c | 34 +++-- src/r_patch.h | 2 +- src/r_patchrotation.c | 12 +- src/r_things.cpp | 4 +- 29 files changed, 462 insertions(+), 399 deletions(-) diff --git a/extras/Items.md b/extras/Items.md index 94b174af5..08d788fe4 100644 --- a/extras/Items.md +++ b/extras/Items.md @@ -8,24 +8,8 @@ Alternative items are secondary versions of existing SRB2Kart items that **reint To toggle on/off these alternate versions, you can do so with the following commands: -- ``altitem_invincibility`` (for Invincibility) - ``altitem_shrink`` (for Shrink) -### Alt. Invincibility (Power: Occupies Slot) -Invincibility, in its normal form, is a power item that appears in the lower ranks, letting players cut through offroad and spin out opponents with prejudice. **Alt. Invincibility** works significantly different, trading its aggression for speed and optimized recovery. - -To begin, Alt. Invincibility's item odds work as an inversion of the Self-Propelled Bomb's: Like how the S.P.B. only appears when first is extremely far ahead of the pack, Alt. Invincibility only reveals itself to players who are **extremely far behind the pack**. In some extreme cases, Alt. Invincibilty will override the race-start cooldown to power-up players already left in the dust. - -Unlike the standard Invincibility, **you can't damage players with Alt. Invincibility**, instead bumping them like you would normally. - -Its time limit (and power) is directly tied to your distance from the "cluster player", the player closest to the largest collection on the map of (losing) players. If you notice yourself falling super far behind on the minimap, you're likely to roll Alt. Invincibility. **The further the distance, the stronger your invincibility**, and the faster you'll go. Think of it like a non-autopilot version of Mario Kart's Bullet Bill, or Sonic Racing's Drill Wisp. _Make huge comebacks, and don't lose hope!_ - -Do note, though: Alt. Invincibility is designed as a "gap closer", and not traditional catchup. Once you pass the cluster player, the timer **decreases at an exponentially fast rate**; don't count on it to let you steal wins from the leader! - -As you run out of power (your Invincibility drops below 5 seconds), **offroad will gradually begin to affect you again**. A warning signal usually sounds as your invincibility is about to run out, as well. Be careful when you see the rainbow color begin to fade! - -If you want something else, or your invincibility is running low, hold ITEM to cancel your Invincibility; the same as you would Grow. - ### Alt. Shrink (Power) Shrink, in its normal form, functions much like Mario Kart's Lightning item. Most servers keep it off due to how frequent and disruptive it is to races. @@ -60,5 +44,15 @@ If you overcharge the Flame Shield, the Flamometer **catches fire**, and you'll If you run into players while charging your Flame Shield, **you'll flip them over**, making them lose a significant amount of speed. You however, rush right through them. -### Land Mine (Drop Behind) -This is an item exclusive to first. Drop a discreet mine onto the track; anyone who runs into it **flips over and loses speed**. +### S-Monitor (Power: Occupies Slot) +The **S-Monitor** is a special power item that works significantly different from most others, trading aggression for speed and optimized recovery. + +To begin, the S-Monitor's item odds work as an inversion of the Self-Propelled Bomb's: Like how the S.P.B. only appears when first is extremely far ahead of the pack, the S-Monitor only reveals itself to players who are **extremely far behind the pack**. In some extreme cases, the S-Monitor will override the race-start cooldown to power-up players already left in the dust. + +Its time limit (and power) is directly tied to your distance from the "cluster player", the player closest to the largest collection on the map of (losing) players. If you notice yourself falling super far behind on the minimap, you're likely to roll an S-Monitor. **The further the distance, the stronger your invincibility**, and the faster you'll go. Your invincibility under the effects of the S-Monitor won't run out until you pass the cluster player. Think of it like a non-autopilot version of Mario Kart's Bullet Bill, or Sonic Racing's Drill Wisp. _Make huge comebacks, and don't lose hope!_ + +Do note, though: the S-Monitor is designed as a "gap closer", and not traditional catchup. Once you pass the cluster player, your power **will decay at a very fast rate**; don't count on it to let you steal wins from the leader! + +As you run out of power, **offroad will gradually begin to affect you again**. A warning signal usually sounds as your invincibility is about to run out, as well. Be careful when you see the rainbow color begin to fade! + +If you want something else, hold ITEM to cancel the S-Monitor; the same as you would Grow. diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9a1dfad96..cec6402c3 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -492,17 +492,19 @@ consvar_t cv_kartstacking_panel_maxgrade = CVAR_INIT ("vanillaboost_panel_maxgra // // Invincibility // - -// Classic boosts -consvar_t cv_kartstacking_invincibility_classicspeedboost = CVAR_INIT ("vanillaboost_invincibility_classicspeedboost", "0.375", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); -consvar_t cv_kartstacking_invincibility_classicaccelboost = CVAR_INIT ("vanillaboost_invincibility_classicaccelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); -consvar_t cv_kartstacking_invincibility_classichandleboost = CVAR_INIT ("vanillaboost_invincibility_classichandleboost", "0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); -// Alternate boosts -consvar_t cv_kartstacking_invincibility_alternatespeedboost = CVAR_INIT ("vanillaboost_invincibility_alternatespeedboost", "0.75", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); -consvar_t cv_kartstacking_invincibility_alternateaccelboost = CVAR_INIT ("vanillaboost_invincibility_alternateaccelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); -consvar_t cv_kartstacking_invincibility_alternatehandleboost = CVAR_INIT ("vanillaboost_invincibility_alternatehandleboost", "0.48", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); +consvar_t cv_kartstacking_invincibility_speedboost = CVAR_INIT ("vanillaboost_invincibility_speedboost", "0.375", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); +consvar_t cv_kartstacking_invincibility_accelboost = CVAR_INIT ("vanillaboost_invincibility_accelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); +consvar_t cv_kartstacking_invincibility_handleboost = CVAR_INIT ("vanillaboost_invincibility_handleboost", "0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); consvar_t cv_kartstacking_invincibility_stackable = CVAR_INIT ("vanillaboost_invincibility_stackable", "On", CV_NETVAR|CV_GUARD, CV_OnOff, NULL); +// +// S-Monitor +// +consvar_t cv_kartstacking_smonitor_speedboost = CVAR_INIT ("vanillaboost_smonitor_speedboost", "0.75", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); +consvar_t cv_kartstacking_smonitor_accelboost = CVAR_INIT ("vanillaboost_smonitor_accelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); +consvar_t cv_kartstacking_smonitor_handleboost = CVAR_INIT ("vanillaboost_smonitor_handleboost", "0.48", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); +consvar_t cv_kartstacking_smonitor_stackable = CVAR_INIT ("vanillaboost_smonitor_stackable", "On", CV_NETVAR|CV_GUARD, CV_OnOff, NULL); + consvar_t cv_kartstacking_grow_speedboost = CVAR_INIT ("vanillaboost_grow_speedboost", "0.2", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); consvar_t cv_kartstacking_grow_accelboost = CVAR_INIT ("vanillaboost_grow_accelboost", "0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); consvar_t cv_kartstacking_grow_handleboost = CVAR_INIT ("vanillaboost_grow_handleboost", "0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); @@ -662,14 +664,9 @@ consvar_t cv_kartaltshrinktime = CVAR_INIT ("kartaltshrinktime", "14", CV_NETVAR static CV_PossibleValue_t kartinvintheme_cons_t[] = {{0, "Standard"}, {1, "Full"}, {0, NULL}}; consvar_t cv_kartinvintheme = CVAR_INIT ("kartinvintheme", "Standard", CV_SAVE, kartinvintheme_cons_t, NULL); -// How far the player must be from the cluster to begin frequently rolling Invincibility. -static CV_PossibleValue_t invindist_cons_t[] = {{1, "MIN"}, {32000, "MAX"}, {0, NULL}}; -consvar_t cv_kartinvindist = CVAR_INIT ("kartinvindist", "17000", CV_NETVAR|CV_CHEAT|CV_GUARD, invindist_cons_t, NULL); - -consvar_t cv_kartinvindistmul = CVAR_INIT ("kartinvindistmul", "0.54", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); - -consvar_t cv_kartinvin_maxtime = CVAR_INIT ("kartinvin_maxtime", "35.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); -consvar_t cv_kartinvin_midtime = CVAR_INIT ("kartinvin_midtime", "23.333", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL); +// How far the player must be from the cluster to roll an S-Monitor. +static CV_PossibleValue_t smonitordist_cons_t[] = {{1, "MIN"}, {32000, "MAX"}, {0, NULL}}; +consvar_t cv_kartsmonitordist = CVAR_INIT ("smonitordist", "17000", CV_NETVAR|CV_CHEAT|CV_GUARD, smonitordist_cons_t, NULL); // opinionated stuff for testing balance tweaks on the shields consvar_t cv_kartbubble_defense_canidle = CVAR_INIT ("kartbubble_defense_canidle", "On", CV_NETVAR, CV_OnOff, NULL); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 7cca831ac..5cb674b19 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -116,14 +116,16 @@ extern consvar_t cv_kartstacking_panel_separate; extern consvar_t cv_kartstacking_panel_maxgrade; -extern consvar_t cv_kartstacking_invincibility_classicspeedboost; -extern consvar_t cv_kartstacking_invincibility_classicaccelboost; -extern consvar_t cv_kartstacking_invincibility_classichandleboost; -extern consvar_t cv_kartstacking_invincibility_alternatespeedboost; -extern consvar_t cv_kartstacking_invincibility_alternateaccelboost; -extern consvar_t cv_kartstacking_invincibility_alternatehandleboost; +extern consvar_t cv_kartstacking_invincibility_speedboost; +extern consvar_t cv_kartstacking_invincibility_accelboost; +extern consvar_t cv_kartstacking_invincibility_handleboost; extern consvar_t cv_kartstacking_invincibility_stackable; +extern consvar_t cv_kartstacking_smonitor_speedboost; +extern consvar_t cv_kartstacking_smonitor_accelboost; +extern consvar_t cv_kartstacking_smonitor_handleboost; +extern consvar_t cv_kartstacking_smonitor_stackable; + extern consvar_t cv_kartstacking_flame_speedval; extern consvar_t cv_kartstacking_flame_accelboost; extern consvar_t cv_kartstacking_flame_handleboost; @@ -210,10 +212,7 @@ extern consvar_t cv_kartexplosion_limitlifetime_cap; extern consvar_t cv_kartslipdash; extern consvar_t cv_kartslopeboost; extern consvar_t cv_kartinvintheme; -extern consvar_t cv_kartinvindist; -extern consvar_t cv_kartinvindistmul; -extern consvar_t cv_kartinvin_maxtime; -extern consvar_t cv_kartinvin_midtime; +extern consvar_t cv_kartsmonitordist; // opinionated stuff for testing extern consvar_t cv_kartbubble_defense_canidle; diff --git a/src/d_player.h b/src/d_player.h index 5dd11b9ec..ad51e070e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -735,10 +735,12 @@ struct player_t UINT16 rocketsneakertimer; // Rocket Sneaker duration timer UINT16 invincibilitytimer; // Invincibility timer - UINT16 maxinvincibilitytime; // (Alternate) Initial time for Invincibility, used for the item bar. - UINT16 invincibilitybottleneck; // (Alternate) Prevents breakaways by gradienting towards a heavier decrement. - INT16 invincibilitycancel; // (Alternate) Duration of Invincibility canceling. - UINT8 invincibilitywarning; // (Alternate) "Timer warning" boolean to signal Alt. Invin. is running out. + + UINT16 smonitortimer; // S-Monitor timer + UINT16 maxsmonitortime; // Initial time for the S-Monitor, used for the item bar. + UINT16 smonitorexpiring; // Once you pass the cluster player, this starts the time limit for your S-Monitor invincibility. + INT16 smonitorcancel; // Duration of S-Monitor canceling. + UINT8 smonitorwarning; // "Timer warning" boolean to signal the S-Monitor is running out. UINT8 eggmanexplode; // Fake item recieved, explode in a few seconds SINT8 eggmanblame; // (-1 to 15) - Fake item recieved, who set this fake diff --git a/src/deh_tables.c b/src/deh_tables.c index 078c223c6..8ef973c8d 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -875,7 +875,7 @@ struct menu_drawer_s const MENU_DRAWERS[] = { }; struct odds_func_s const USEODDS_FUNCS[] = { - { "ALTINVINODDS", &KO_AltInvinOdds }, + { "SMONITORODDS", &KO_SMonitorOdds }, { "SPBRACEODDS", &KO_SPBRaceOdds }, { NULL, NULL } }; @@ -1760,8 +1760,8 @@ struct int_const_s const INT_CONST[] = { // invin constants {"KART_NUMINVSPARKLESANIM", KART_NUMINVSPARKLESANIM}, - {"BASEINVINTIME", BASEINVINTIME}, - {"MININVINTIME", MININVINTIME}, + {"INVINTIME", INVINTIME}, + {"SMONITORTIME", SMONITORTIME}, // grow/shrink scale {"GROW_SCALE", GROW_SCALE}, diff --git a/src/g_input.c b/src/g_input.c index 1e1881fde..2aa6cab8d 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -748,6 +748,10 @@ void G_ControllerRumbleTick(void) { high = RUMBLE_MODERATE; } + else if (player->smonitortimer) + { + high = RUMBLE_MODERATE; + } else { low = high = RUMBLE_MODERATE; diff --git a/src/h_timers.cpp b/src/h_timers.cpp index 70d840551..d561f53bc 100644 --- a/src/h_timers.cpp +++ b/src/h_timers.cpp @@ -257,8 +257,14 @@ void K_DisplayItemTimers(void) stplyr->invincibilitytimer, {qche("K_TIINV1"), qche("K_TIINV2"), qche("K_TIINV3"), qche("K_TIINV4"), qche("K_TIINV5"), qche("K_TIINV6")}, 3, + }, + { // s-monitor + "s-monitor", + stplyr->smonitortimer, + {qche("K_TISMR1")/*, qche("K_TIINV2"), qche("K_TIINV3"), qche("K_TIINV4"), qche("K_TIINV5"), qche("K_TIINV6")*/}, + 3, // Hide the timer until it's necessary - static_cast(((stplyr->invincibilitytimer >= MININVINTIME) && K_IsKartItemAlternate(KITEM_INVINCIBILITY)) ? TIMER_NONUMBER : 0), + static_cast(((stplyr->smonitortimer >= SMONITORTIME)) ? TIMER_NONUMBER : 0), }, { // grow "grow", diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 20e4773c9..3036b5d6f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4837,7 +4837,7 @@ static void HWR_ProjectSprite(mobj_t *thing) interptarg = thing; - if (R_IsOverlayingInvinciblePlayer(thing)) + if (R_IsOverlayingSMonitorPlayer(thing)) { // Kill overlay misalignment interptarg = thing->target; @@ -5282,7 +5282,7 @@ static void HWR_ProjectSprite(mobj_t *thing) if (thing->colorized) { vis->colormap = R_GetTranslationColormap( - R_IsOverlayingInvinciblePlayer(thing) ? TC_BLINK : TC_RAINBOW, + R_IsOverlayingSMonitorPlayer(thing) ? TC_BLINK : TC_RAINBOW, thing->color, GTC_CACHE); } diff --git a/src/info/kartitems.h b/src/info/kartitems.h index 279c1b77d..7f09027e8 100644 --- a/src/info/kartitems.h +++ b/src/info/kartitems.h @@ -20,3 +20,4 @@ _(LANDMINE) _(BUBBLESHIELD) _(FLAMESHIELD) _(EGGBRICK) +_(S_MONITOR) diff --git a/src/k_botitem.cpp b/src/k_botitem.cpp index 8916cc795..32e3d45ff 100644 --- a/src/k_botitem.cpp +++ b/src/k_botitem.cpp @@ -1263,6 +1263,7 @@ void K_BotItemUsage(botdata_t *bd, const player_t *player) case KITEM_GROW: case KITEM_SHRINK: case KITEM_SUPERRING: + case KITEM_S_MONITOR: K_BotItemGenericTap(bd); break; case KITEM_ROCKETSNEAKER: diff --git a/src/k_collide.c b/src/k_collide.c index 0887acd83..52e9013c3 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -721,7 +721,7 @@ static boolean K_BubbleReflectingTrapItem(const mobj_t *t) static boolean K_StrongPlayerBump(const player_t *player) { - return (((!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && (player->invincibilitytimer)) + return ((player->invincibilitytimer) || (player->growshrinktimer > 0)); } @@ -968,12 +968,10 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) boolean t1Condition = false; boolean t2Condition = false; - // Rim suggestion: Flipover damage is negligible at best, just cull it from Invincibility as a whole. - if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) - { - t1Condition = (t1->player->invincibilitytimer > 0); - t2Condition = (t2->player->invincibilitytimer > 0); - } + t1Condition = (t1->player->invincibilitytimer > 0); + t2Condition = (t2->player->invincibilitytimer > 0); + + UINT8 invindamage = DMG_WIPEOUT; // TODO: make this a cvar value if ((t1Condition == true || flameT1 == true) && (t2Condition == true || flameT2 == true)) { @@ -981,16 +979,16 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) K_DoInstashield(t2->player); return false; } - else if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) + else { if (t1Condition == true && t2Condition == false) { - P_DamageMobj(t2, t1, t1, 1, DMG_WIPEOUT); + P_DamageMobj(t2, t1, t1, 1, invindamage); return true; } else if (t1Condition == false && t2Condition == true) { - P_DamageMobj(t1, t2, t2, 1, DMG_WIPEOUT); + P_DamageMobj(t1, t2, t2, 1, invindamage); return true; } } diff --git a/src/k_color.c b/src/k_color.c index 1b5a38bc2..a017ed306 100644 --- a/src/k_color.c +++ b/src/k_color.c @@ -17,7 +17,7 @@ #include "r_things.h" #include "v_video.h" -UINT16 altinvinccolors[16] = { +UINT16 smonitorcolors[16] = { SKINCOLOR_BLOODCELL, // 0 SKINCOLOR_FUCHSIA, // 1 SKINCOLOR_MOON, // 2 @@ -69,14 +69,14 @@ UINT16 K_RainbowColor(tic_t time) } /*-------------------------------------------------- - UINT16 K_AltInvincibilityColor(tic_t time) + UINT16 K_SMonitorColor(tic_t time) See header file for description. --------------------------------------------------*/ -UINT16 K_AltInvincibilityColor(tic_t time) +UINT16 K_SMonitorColor(tic_t time) { - return (UINT16)(altinvinccolors[(time) & 15]); + return (UINT16)(smonitorcolors[(time) & 15]); } /*-------------------------------------------------- diff --git a/src/k_color.h b/src/k_color.h index e57ec3783..3b99b378c 100644 --- a/src/k_color.h +++ b/src/k_color.h @@ -55,9 +55,9 @@ UINT8 K_ColorRelativeLuminance(UINT8 r, UINT8 g, UINT8 b); UINT16 K_RainbowColor(tic_t time); /*-------------------------------------------------- - UINT16 K_AltInvincibilityColor(tic_t time) + UINT16 K_SMonitorColor(tic_t time) - Gives you a color from the "alt Invincibility" color table, for less + Gives you a color from the S-Monitor color table, for less aggressive rainbow coloring. Input Arguments:- @@ -67,7 +67,7 @@ UINT16 K_RainbowColor(tic_t time); Skincolor value. --------------------------------------------------*/ -UINT16 K_AltInvincibilityColor(tic_t time); +UINT16 K_SMonitorColor(tic_t time); /*-------------------------------------------------- void K_RainbowColormap(UINT8 *dest_colormap, skincolornum_t skincolor); diff --git a/src/k_hud.c b/src/k_hud.c index bbf6b3572..81c97fc2c 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -161,8 +161,8 @@ static patch_t *kp_flamefire[18]; // Frames of animation for the fire #define MAXFLAMOFIRETICS 8 -// Rotating Alt. Invin. sparkles -static patch_t *kp_altinvinsparkle; +// Rotating S-Monitor sparkles +static patch_t *kp_smonitorsparkle; static patch_t *kp_rankbumper; static patch_t *kp_tinybumper[2]; @@ -421,12 +421,12 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_driftgaugeparts[3], "K_WDGM4"); HU_UpdatePatch(&kp_driftgaugeparts[4], "K_DGAU3M"); - // Alt. Invin. Sparkles - HU_UpdatePatch(&kp_altinvinsparkle, "ALTISPRK"); + // S-Monitor. Sparkles + HU_UpdatePatch(&kp_smonitorsparkle, "ALTISPRK"); - kp_altinvinsparkle->pivot.x = kp_altinvinsparkle->width / 2; - kp_altinvinsparkle->pivot.y = kp_altinvinsparkle->height / 2; - kp_altinvinsparkle->alignflags |= PATCHALIGN_USEPIVOTS; + kp_smonitorsparkle->pivot.x = kp_smonitorsparkle->width / 2; + kp_smonitorsparkle->pivot.y = kp_smonitorsparkle->height / 2; + kp_smonitorsparkle->alignflags |= PATCHALIGN_USEPIVOTS; // Flamometer UI Elements HU_UpdatePatch(&kp_flamometer[0], "THERMOBACK"); @@ -1387,17 +1387,17 @@ static void K_drawKartItem(void) else localpatch = kp_nodraw; } - else if ((stplyr->invincibilitytimer) && (K_IsKartItemAlternate(KITEM_INVINCIBILITY))) + else if (stplyr->smonitortimer) { - if (stplyr->invincibilitytimer < MININVINTIME) - itembar = FixedDiv(stplyr->invincibilitytimer, max(1, stplyr->maxinvincibilitytime)); + if (stplyr->smonitortimer < SMONITORTIME) + itembar = FixedDiv(stplyr->smonitortimer, max(1, stplyr->maxsmonitortime)); - if (stplyr->invincibilitycancel > 0) - flamebar = FixedDiv(stplyr->invincibilitycancel, 26); + if (stplyr->smonitorcancel > 0) + flamebar = FixedDiv(stplyr->smonitorcancel, 26); if (leveltime & 1) { - localpatch = K_GetCachedItemPatch(KITEM_INVINCIBILITY, tiny, 0); + localpatch = K_GetCachedItemPatch(KITEM_S_MONITOR, tiny, 0); isalt = true; } else @@ -1517,7 +1517,7 @@ static void K_drawKartItem(void) // RadioRacers if (shouldDrawOnPlayer) { - boolean rocketinvinbar = ((stplyr->rocketsneakertimer > 1) || ((stplyr->invincibilitytimer) && (K_IsKartItemAlternate(KITEM_INVINCIBILITY)))); + boolean rocketsmonitorbar = ((stplyr->rocketsneakertimer > 1) || (stplyr->smonitortimer)); /** * RadioRacers @@ -1530,10 +1530,10 @@ static void K_drawKartItem(void) * For rocket sneakers, it's the duration bar. */ - // For Blan, Alt. Invincibility also needs duration visibility, so we dim the icon there, too. + // For Blan, the S-Monitor also needs duration visibility, so we dim the icon there, too. // Nice-to-have: some way for custom items to have this feature? Not sure yet. - if (stplyr->itemtype == KITEM_FLAMESHIELD || stplyr->eggmanexplode > 1 || (rocketinvinbar)) { + if (stplyr->itemtype == KITEM_FLAMESHIELD || stplyr->eggmanexplode > 1 || (rocketsmonitorbar)) { roulettetrans = (INT32)((float)(roulettetrans) * 0.57143f); } @@ -1653,7 +1653,7 @@ static void K_drawKartItem(void) V_DrawFixedPatch(fx< BUMPSPARK_NOCHARGE, true}, {"Bump Spring", 0, &cv_kartbumpspring, -1, true} //TODO: separate drawer that enumerates item changes? - // {"Alt. Invin.", 0, NULL, K_IsKartItemAlternate(KITEM_INVINCIBILITY), true} }; for (j = 0; j < 2; j++) @@ -3499,7 +3498,7 @@ static void K_drawKartPlayerCheck(void) continue; } - if ((checkplayer->invincibilitytimer <= 0) && (leveltime & 2)) + if ((checkplayer->invincibilitytimer <= 0) && (checkplayer->smonitortimer <= 0) && (leveltime & 2)) { pnum++; // white frames } @@ -3520,6 +3519,11 @@ static void K_drawKartPlayerCheck(void) { pnum += 2; } + else if (checkplayer->itemtype == KITEM_S_MONITOR || checkplayer->smonitortimer) + { + // FIXME: Separate "CHECK" icon(?) + pnum += 2; + } K_ObjectTracking(&result, &v, true); @@ -4216,7 +4220,7 @@ static void K_drawKartMinimap(void) spbdraw_t spb; UINT16 usecolor; boolean colorizeplayer; - fixed_t invingradient = 0; + fixed_t smntrgradient = 0; #ifdef ROTSPRITE angle_t rollangle = 0; @@ -4225,7 +4229,7 @@ static void K_drawKartMinimap(void) patch_t *rotsparkle; boolean halftrans = false; fixed_t transmul = 0; - UINT32 invintrans = 0; + UINT32 smonitortrans = 0; #endif vector2_t iconoffsets; @@ -4439,11 +4443,16 @@ static void K_drawKartMinimap(void) colorizeplayer = mobj->colorized; - invingradient = K_InvincibilityGradient(players[i].invincibilitytimer); + smntrgradient = K_SMonitorGradient(players[i].smonitortimer); - if ((players[i].invincibilitytimer) && ((invingradient > (FRACUNIT/2)) || (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)))) + if (players[i].invincibilitytimer) { - usecolor = ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) ? K_AltInvincibilityColor(leveltime / 2) : K_RainbowColor(leveltime / 2)); + usecolor = (K_RainbowColor(leveltime / 2)); + colorizeplayer = true; + } + else if ((players[i].smonitortimer) && (smntrgradient > (FRACUNIT/2))) + { + usecolor = (K_SMonitorColor(leveltime / 2)); colorizeplayer = true; } else @@ -4476,14 +4485,13 @@ static void K_drawKartMinimap(void) K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap, &iconoffsets); #ifdef ROTSPRITE - if ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && - (players[i].invincibilitytimer) && (invingradient)) + if ((players[i].smonitortimer) && (smntrgradient)) { - // Draw Alt. Invin. sparkles + // Draw S-Monitor sparkles halftrans = ((splitflags & V_HUDTRANSHALF) == V_HUDTRANSHALF); transmul = 0; - invintrans = 0; + smonitortrans = 0; sparkleflags = splitflags & (~(V_HUDTRANS | V_HUDTRANSHALF)); @@ -4499,52 +4507,52 @@ static void K_drawKartMinimap(void) FRACUNIT - (V_GetHudTrans() * FRACUNIT / 10); } - invintrans = + smonitortrans = max(0, min(9, - 10 - FixedMul(FixedMul(10, invingradient), + 10 - FixedMul(FixedMul(10, smntrgradient), transmul))) << V_ALPHASHIFT; - sparkleflags |= invintrans; + sparkleflags |= smonitortrans; - if (kp_altinvinsparkle) + if (kp_smonitorsparkle) { rot = R_GetRollAngle(-TICTOANGLE(leveltime)); if (rot) { rotsparkle = Patch_GetRotated( - kp_altinvinsparkle, rot, false); + kp_smonitorsparkle, rot, false); } else { - rotsparkle = kp_altinvinsparkle; + rotsparkle = kp_smonitorsparkle; } if (rotsparkle) { - widthhalf = ((kp_altinvinsparkle->width) / 2); - heighthalf = ((kp_altinvinsparkle->height) / 2); + widthhalf = ((kp_smonitorsparkle->width) / 2); + heighthalf = ((kp_smonitorsparkle->height) / 2); if (cv_minihead.value) { adjustx = FixedMul( 4, (widthhalf - - kp_altinvinsparkle->leftoffset) * + kp_smonitorsparkle->leftoffset) * FRACUNIT / widthhalf); adjusty = FixedMul( 4, (heighthalf - - kp_altinvinsparkle->topoffset) * + kp_smonitorsparkle->topoffset) * FRACUNIT / heighthalf); } iconoffsets.x = widthhalf - - kp_altinvinsparkle->leftoffset - + kp_smonitorsparkle->leftoffset - adjustx; iconoffsets.y = heighthalf - - kp_altinvinsparkle->topoffset - + kp_smonitorsparkle->topoffset - adjusty; K_drawKartMinimapIcon(interpx, @@ -4763,17 +4771,21 @@ static void K_drawKartMinimap(void) #endif colorizeplayer = mobj->colorized; - invingradient = - K_InvincibilityGradient( - players[localplayers[i]].invincibilitytimer); + smntrgradient = + K_SMonitorGradient( + players[localplayers[i]].smonitortimer); - if ((players[localplayers[i]].invincibilitytimer) && - ((invingradient > (FRACUNIT / 2)) || - (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)))) + if (players[localplayers[i]].invincibilitytimer) { usecolor = (K_RainbowColor(leveltime / 2)); colorizeplayer = true; } + else if ((players[localplayers[i]].smonitortimer) + && ((smntrgradient > (FRACUNIT / 2)))) + { + usecolor = (K_SMonitorColor(leveltime / 2)); + colorizeplayer = true; + } else { usecolor = mobj->color; @@ -4839,13 +4851,12 @@ static void K_drawKartMinimap(void) K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap, &iconoffsets); #ifdef ROTSPRITE - if ((!nocontest) && (K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && - (players[localplayers[i]].invincibilitytimer) && (invingradient)) + if ((!nocontest) && (players[localplayers[i]].smonitortimer) && (smntrgradient)) { - // Draw Alt. Invin. sparkles + // Draw S-Monitor sparkles halftrans = ((splitflags & V_HUDTRANSHALF) == V_HUDTRANSHALF); transmul = 0; - invintrans = 0; + smonitortrans = 0; sparkleflags = splitflags & (~(V_HUDTRANS | V_HUDTRANSHALF)); @@ -4860,48 +4871,48 @@ static void K_drawKartMinimap(void) transmul *= 2; - invintrans = + smonitortrans = max(0, min(9, - 10 - FixedMul(FixedMul(10, invingradient), transmul))) + 10 - FixedMul(FixedMul(10, smntrgradient), transmul))) << V_ALPHASHIFT; - sparkleflags |= invintrans; + sparkleflags |= smonitortrans; - if (kp_altinvinsparkle) + if (kp_smonitorsparkle) { rot = R_GetRollAngle(-TICTOANGLE(leveltime)); if (rot) { rotsparkle = Patch_GetRotated( - kp_altinvinsparkle, rot, false); + kp_smonitorsparkle, rot, false); } else { - rotsparkle = kp_altinvinsparkle; + rotsparkle = kp_smonitorsparkle; } if (rotsparkle) { - widthhalf = ((kp_altinvinsparkle->width) / 2); - heighthalf = ((kp_altinvinsparkle->height) / 2); + widthhalf = ((kp_smonitorsparkle->width) / 2); + heighthalf = ((kp_smonitorsparkle->height) / 2); if (cv_minihead.value) { adjustx = FixedMul( 4, - (widthhalf - kp_altinvinsparkle->leftoffset) * + (widthhalf - kp_smonitorsparkle->leftoffset) * FRACUNIT / widthhalf); adjusty = FixedMul( 4, - (heighthalf - kp_altinvinsparkle->topoffset) * + (heighthalf - kp_smonitorsparkle->topoffset) * FRACUNIT / heighthalf); } iconoffsets.x = - widthhalf - kp_altinvinsparkle->leftoffset - adjustx; + widthhalf - kp_smonitorsparkle->leftoffset - adjustx; iconoffsets.y = - heighthalf - kp_altinvinsparkle->topoffset - adjusty; + heighthalf - kp_smonitorsparkle->topoffset - adjusty; K_drawKartMinimapIcon(interpx, interpy, diff --git a/src/k_items.c b/src/k_items.c index e25ac2096..7c39eff70 100644 --- a/src/k_items.c +++ b/src/k_items.c @@ -358,7 +358,7 @@ static boolean K_DontDoubleMyItems(kartitemtype_e type, UINT8 amount) || type == KITEM_INVINCIBILITY || type == KITEM_GROW || type == KITEM_BUBBLESHIELD || type == KITEM_FLAMESHIELD || type == KITEM_ROCKETSNEAKER || type == KITEM_SHRINK - || type == KITEM_HYUDORO + || type == KITEM_HYUDORO || type == KITEM_S_MONITOR || (type == KITEM_BANANA && amount >= 4) || (type == KITEM_ORBINAUT && amount >= 3) || (type == KITEM_SNEAKER && amount >= 3) @@ -498,24 +498,24 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush) #define INVODDS 30 // Prevent integer overflows; don't let this go past 16383 -#define INVINDESPERATION 4 -#define MAXINVODDS ((MAXPROBABILITY * 2) * INVINDESPERATION) +#define SMONITOR_DESPERATION 4 +#define MAXSMONITORODDS ((MAXPROBABILITY * 2) * SMONITOR_DESPERATION) -// Odds value for Alt. Invin. to force itself on trailing players. -#define INVFORCEODDS (MAXINVODDS / 2) +// Odds value for the S-Monitor to force itself on trailing players. +#define SMONITOR_FORCEODDS (MAXSMONITORODDS / 2) -static INT32 K_KartGetInvincibilityOdds(UINT32 dist) +static INT32 K_KartGetSMonitorOdds(UINT32 dist) { // I'm tired; use floating-point distances for this fuckshit. - INT32 invdist = INVINDIST; + INT32 monitordist = SMONITORDIST; - float fac_f = (float)(dist) / ((float)(invdist)); + float fac_f = (float)(dist) / ((float)(monitordist)); if (fac_f < 1.0f) return 0; // If you're far enough for this to be in your item slot, you're far enough to SERIOUSLY need this. - return MAXINVODDS; + return MAXSMONITORODDS; } // updates all result cooldown timers, and sets cooldowns for "unique" items @@ -1556,8 +1556,8 @@ void K_SetPlayerItemCooldown(player_t *player, tic_t timer, boolean force) // Unique odds functions, for REAL this time -// Alt. Invin. odds -INT32 KO_AltInvinOdds(INT32 odds, const kartroulette_t *roulette, const kartresult_t *result, UINT8 *forceme) +// S-Monitor odds +INT32 KO_SMonitorOdds(INT32 odds, const kartroulette_t *roulette, const kartresult_t *result, UINT8 *forceme) { (void)result; @@ -1569,10 +1569,10 @@ INT32 KO_AltInvinOdds(INT32 odds, const kartroulette_t *roulette, const kartresu cdist = (9 * cdist / 5); } - odds = K_KartGetInvincibilityOdds(cdist); + odds = K_KartGetSMonitorOdds(cdist); // Special case: if you're SERIOUSLY far behind before the cooldown finishes, ignore it and start forcing, - if (odds >= INVFORCEODDS) + if (odds >= SMONITOR_FORCEODDS) { *forceme = 3; // Take priority over SPBs } @@ -1665,6 +1665,10 @@ static void K_DoGrowShrink(player_t *player, boolean shrinking) { ; // invincibility has priority in P_RestoreMusic, no point in starting here } + else if (player->smonitortimer > 0) + { + ; // Ditto for S-Monitor + } else if (P_IsLocalPlayer(player) == true) { S_ChangeMusicSpecial((shrinking) ? "kshrnk" : "kgrow"); @@ -2054,9 +2058,18 @@ void K_PlayerItemThink(player_t *player, boolean onground) } break; case KITEM_INVINCIBILITY: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) // Doesn't hold your item slot hostage in Legacy, so you're free to waste it if you have multiple + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) // Doesn't hold your item slot hostage, so you're free to waste it if you have multiple { - K_DoInvincibility(player, K_GetInvincibilityTime(player)); + K_DoInvincibility(player, INVINTIME); + K_PlayPowerGloatSound(player->mo); + player->itemamount--; + K_BotResetItemConfirm(player, false); + } + break; + case KITEM_S_MONITOR: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + K_DoSMonitor(player, SMONITORTIME); K_PlayPowerGloatSound(player->mo); player->itemamount--; K_BotResetItemConfirm(player, false); diff --git a/src/k_items.h b/src/k_items.h index 991c74495..231dd835b 100644 --- a/src/k_items.h +++ b/src/k_items.h @@ -214,7 +214,7 @@ void K_StartRoulette(player_t *player, kartroulettetype_e roulettetype); void K_SetPlayerItemCooldown(player_t *player, tic_t timer, boolean force); -useoddsfunc_f KO_AltInvinOdds; +useoddsfunc_f KO_SMonitorOdds; useoddsfunc_f KO_SPBRaceOdds; void K_DoThunderShield(player_t *player); diff --git a/src/k_kart.c b/src/k_kart.c index efbd422d0..1602e99e0 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -310,14 +310,16 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartstacking_panel_separate); CV_RegisterVar(&cv_kartstacking_panel_maxgrade); - CV_RegisterVar(&cv_kartstacking_invincibility_classicspeedboost); - CV_RegisterVar(&cv_kartstacking_invincibility_classicaccelboost); - CV_RegisterVar(&cv_kartstacking_invincibility_classichandleboost); - CV_RegisterVar(&cv_kartstacking_invincibility_alternatespeedboost); - CV_RegisterVar(&cv_kartstacking_invincibility_alternateaccelboost); - CV_RegisterVar(&cv_kartstacking_invincibility_alternatehandleboost); + CV_RegisterVar(&cv_kartstacking_invincibility_speedboost); + CV_RegisterVar(&cv_kartstacking_invincibility_accelboost); + CV_RegisterVar(&cv_kartstacking_invincibility_handleboost); CV_RegisterVar(&cv_kartstacking_invincibility_stackable); + CV_RegisterVar(&cv_kartstacking_smonitor_speedboost); + CV_RegisterVar(&cv_kartstacking_smonitor_accelboost); + CV_RegisterVar(&cv_kartstacking_smonitor_handleboost); + CV_RegisterVar(&cv_kartstacking_smonitor_stackable); + CV_RegisterVar(&cv_kartstacking_grow_speedboost); CV_RegisterVar(&cv_kartstacking_grow_accelboost); CV_RegisterVar(&cv_kartstacking_grow_handleboost); @@ -432,11 +434,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartinvintheme); - CV_RegisterVar(&cv_kartinvindist); - CV_RegisterVar(&cv_kartinvindistmul); - - CV_RegisterVar(&cv_kartinvin_maxtime); - CV_RegisterVar(&cv_kartinvin_midtime); + CV_RegisterVar(&cv_kartsmonitordist); // experimental stuff CV_RegisterVar(&cv_kartbubble_defense_canidle); @@ -527,7 +525,6 @@ static fixed_t K_PlayerWeight(mobj_t* mobj, mobj_t* against) { fixed_t weight = 5 * FRACUNIT; fixed_t bubbleMultiplier = FRACUNIT; - const boolean invinisalt = K_IsKartItemAlternate(KITEM_INVINCIBILITY); if (!mobj->player) return weight; @@ -543,11 +540,12 @@ static fixed_t K_PlayerWeight(mobj_t* mobj, mobj_t* against) { return 0; // This player does not cause any bump action } - else if (invinisalt && against->player->invincibilitytimer) + else if (against->player->smonitortimer) { - // Scale Alt. Invin. weight to their power. At full power, you get shoved - // off! Might cause less shitty-feeling bumpcheck moments. - return max(0, FRACUNIT - against->player->kartweight * K_InvincibilityGradient(against->player->invincibilitytimer)); + // Scale S-Monitor weight to their power. At full power, you get shoved off! + // Might cause less shitty-feeling bumpcheck moments. + return max(0, FRACUNIT - against->player->kartweight * + K_SMonitorGradient(against->player->smonitortimer)); } } @@ -557,12 +555,12 @@ static fixed_t K_PlayerWeight(mobj_t* mobj, mobj_t* against) weight = (mobj->player->kartweight) * FRACUNIT; - if (invinisalt && mobj->player->invincibilitytimer) + if (mobj->player->smonitortimer) { // Cap the gradient at 1.0 to prevent exaggerated nonsense. - fixed_t mygradient = min(FRACUNIT, K_InvincibilityGradient(mobj->player->invincibilitytimer)); + fixed_t mygradient = min(FRACUNIT, K_SMonitorGradient(mobj->player->smonitortimer)); - // Scale Alt. Invin. weight to your power. At full power, they get shoved off! + // Scale S-Monitor weight weight to your power. At full power, they get shoved off! // Might cause less shitty-feeling bumpcheck moments. weight = FixedMul(weight, mygradient); @@ -617,7 +615,7 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) case MT_FALLINGROCK: if (against->player) { - if (against->player->invincibilitytimer || against->player->growshrinktimer > 0 || (K_GetShieldFromPlayer(against->player) == KSHIELD_BUBBLE)) + if (against->player->invincibilitytimer || against->player->smonitortimer || against->player->growshrinktimer > 0 || (K_GetShieldFromPlayer(against->player) == KSHIELD_BUBBLE)) weight = 0; else weight = K_PlayerWeight(against, NULL); @@ -1010,11 +1008,17 @@ static fixed_t K_CheckOffroadCollide(mobj_t *mo) return 0; // couldn't find any offroad } -static fixed_t K_OffroadGradient(player_t *player, fixed_t offroad) +static fixed_t K_OffroadGradient(player_t* player, fixed_t offroad) { - // At 50% or lower Invincibility, offroad creeps up on you. - fixed_t invinoffroad = (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) ? ((player->invincibilitytimer) ? FRACUNIT : 0) : min(FRACUNIT, K_InvincibilityGradient(player->invincibilitytimer)); - fixed_t fac = CLAMP(FRACUNIT - invinoffroad, 0, FRACUNIT); + // Invincibility: Just ignore everything. + fixed_t invinoffroad = (player->invincibilitytimer) ? FRACUNIT : 0; + + // S-Monitor: At 50% or lower power, offroad creeps up on you. + fixed_t smonitoroffroad = min(FRACUNIT, K_SMonitorGradient(player->smonitortimer)); + + fixed_t subtrahend = FixedMul(smonitoroffroad, invinoffroad); + + fixed_t fac = CLAMP(FRACUNIT - subtrahend, 0, FRACUNIT); return FixedMul(offroad, fac); } @@ -1452,6 +1456,11 @@ void K_SpawnNormalSpeedLines(player_t *player) } fast->colorized = true; } + else if (player->smonitortimer) + { + fast->color = K_SMonitorColor(player->smonitortimer); + fast->colorized = true; + } else if (player->tripwireLeniency) { // Make it pink+blue+big when you can go through tripwire @@ -2272,6 +2281,7 @@ tripwirepass_t K_TripwirePassConditions(const player_t *player) { if ( player->invincibilitytimer || + player->smonitortimer || player->bubbleboost || K_IsAltShrunk(player) || (player->sneakertimer && player->realsneakertimer) @@ -2300,7 +2310,8 @@ boolean K_TripwirePass(const player_t *player) boolean K_PlayerCanPunt(const player_t *player) { - return player->invincibilitytimer > 0 || player->growshrinktimer > 0 + return player->invincibilitytimer > 0 || player->smonitortimer > 0 + || player->growshrinktimer > 0 || (player->flamestore > 0 && K_GetShieldFromPlayer(player) == KSHIELD_FLAME) || (player->bubbleblowup > 0 && K_GetShieldFromPlayer(player) == KSHIELD_BUBBLE) || K_AltShrinkArrowBulletCondition(player); @@ -2562,41 +2573,27 @@ static inline fixed_t K_GetSneakerBoostSpeed(void) } // Used to determine the speed and power of Invincibility. -fixed_t K_InvincibilityGradient(UINT16 time) +fixed_t K_SMonitorGradient(UINT16 time) { return (min(936, (fixed_t)time) * FRACUNIT / (6 * TICRATE)); } -UINT16 K_GetInvincibilityTime(player_t *player) +fixed_t K_GetSMonitorSpeed(UINT16 time) { - return (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) ? BASEINVINTIME : MININVINTIME; + fixed_t t = min(FRACUNIT, K_SMonitorGradient(time)); + return Easing_OutCubic(t, 0, SMNTRSPEEDBOOST); } -fixed_t K_GetInvincibilitySpeed(UINT16 time) +fixed_t K_GetSMonitorAccel(UINT16 time) { - if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) - return INVINSPEEDBOOSTCLS; - - fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time)); - return Easing_OutCubic(t, 0, INVINSPEEDBOOSTALT); + fixed_t t = min(FRACUNIT, K_SMonitorGradient(time)); + return Easing_OutCubic(t, 0, SMNTRACCELBOOST); } -fixed_t K_GetInvincibilityAccel(UINT16 time) +fixed_t K_GetSMonitorHandling(UINT16 time) { - if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) - return INVINACCELBOOSTCLS; - - fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time)); - return Easing_OutCubic(t, 0, INVINACCELBOOSTALT); -} - -fixed_t K_GetInvincibilityHandling(UINT16 time) -{ - if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) - return INVINHANDLEBOOSTCLS; - - fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time)); - return Easing_OutCubic(t, 0, INVINHANDLEBOOSTALT); + fixed_t t = min(FRACUNIT, K_SMonitorGradient(time)); + return Easing_OutCubic(t, 0, SMNTRHANDLEBOOST); } static fixed_t diminish(fixed_t speedboost) @@ -2790,13 +2787,18 @@ static void K_GetKartBoostPower(player_t *player) if (player->invincibilitytimer) // Invincibility { - fixed_t invspeedboost = K_GetInvincibilitySpeed(player->invincibilitytimer); - fixed_t invaccelboost = K_GetInvincibilityAccel(player->invincibilitytimer); - fixed_t invhandleboost = K_GetInvincibilityHandling(player->invincibilitytimer); + // + 37.5% top speed, + 300% acceleration + K_DoBoost(player, INVINSPEEDBOOST, INVINACCELBOOST, INVINHANDLEBOOST, INVINSTACKABLE, INVINSTACKABLE); + } - // Legacy: + 37.5% top speed, + 300% acceleration - // Alternative: + ???% top speed, + ???% acceleration - K_DoBoost(player, invspeedboost, invaccelboost, invhandleboost, INVINSTACKABLE, INVINSTACKABLE); + if (player->smonitortimer) // S-Monitor + { + fixed_t smntrspeedboost = K_GetSMonitorSpeed(player->smonitortimer); + fixed_t smntraccelboost = K_GetSMonitorAccel(player->smonitortimer); + fixed_t smntrhandleboost = K_GetSMonitorHandling(player->smonitortimer); + + // + ???% top speed, + ???% acceleration + K_DoBoost(player, smntrspeedboost, smntraccelboost, smntrhandleboost, SMNTRSTACKABLE, SMNTRSTACKABLE); } if (player->growshrinktimer > 0) // Grow @@ -5029,6 +5031,8 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) thrust = FixedMul(thrust, 5*FRACUNIT/4); else if (mo->player->invincibilitytimer) thrust = FixedMul(thrust, 9*FRACUNIT/8); + else if (mo->player->smonitortimer) + thrust = FixedMul(thrust, 9*FRACUNIT/8); else if (mo->player->flamestore) thrust = FixedMul(thrust, 9*FRACUNIT/8); } @@ -5072,42 +5076,49 @@ boolean K_PlayFullInvinTheme(void) void K_DoInvincibility(player_t *player, tic_t time) { - const boolean isalt = K_IsKartItemAlternate(KITEM_INVINCIBILITY); - if (!player->invincibilitytimer) { mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INVULNFLASH); P_SetTarget(&overlay->target, player->mo); overlay->destscale = player->mo->scale; P_SetScale(overlay, player->mo->scale); - - if (isalt) - { - mobj_t *aura = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_OVERLAY); - P_SetTarget(&aura->target, player->mo); - aura->destscale = player->mo->scale; - P_SetScale(aura, player->mo->scale); - aura->extravalue2 = 1; - } } - if (isalt) + player->invincibilitytimer = time; + + if (P_IsLocalPlayer(player) == true) + { + S_ChangeMusicSpecial(K_PlayFullInvinTheme() ? "kinvnf" : "kinvnc"); + } + else //used to be "if (P_IsDisplayPlayer(player) == false)" + { + S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc)); + } + + P_RestoreMusic(player); +} + +void K_DoSMonitor(player_t *player, tic_t time) +{ + if (!player->smonitortimer) + { + mobj_t *aura = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_OVERLAY); + P_SetTarget(&aura->target, player->mo); + aura->destscale = player->mo->scale; + P_SetScale(aura, player->mo->scale); + aura->extravalue2 = 1; + } + + // Rim suggestion: Don't allow already invincible players to chain. + if (K_SMonitorGradient(player->smonitortimer) < (FRACUNIT/2)) { - // Rim suggestion: Don't allow already invincible players to chain. - if (K_InvincibilityGradient(player->invincibilitytimer) < (FRACUNIT/2)) - { - // Be nice to players at half-power or less. - player->invincibilitytimer = max(player->invincibilitytimer, time); - } - } - else - { - player->invincibilitytimer = time; + // Be nice to players at half-power or less. + player->smonitortimer = max(player->smonitortimer, time); } - player->maxinvincibilitytime = player->invincibilitytimer; - player->invincibilitybottleneck = 0; - player->invincibilitywarning = 0; + player->maxsmonitortime = player->smonitortimer; + player->smonitorexpiring = 0; + player->smonitorwarning = 0; if (P_IsLocalPlayer(player) == true) { @@ -6391,9 +6402,13 @@ static void K_UpdateInvincibilitySounds(player_t *player) if (player->mo->health > 0) { + const boolean invinsound = + ((player->invincibilitytimer) || + ((player->smonitortimer > 0) && (!player->smonitorwarning))); + if (player->growshrinktimer > 0 && (!localplayer || cv_growmusic.value == 2)) // Prioritize Grow sfxnum = cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow; - else if ((player->invincibilitytimer > 0) && (!player->invincibilitywarning) && (!localplayer || cv_supermusic.value == 2)) + else if (invinsound && (!localplayer || cv_supermusic.value == 2)) sfxnum = cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc; // FIXME: Does Alt. Shrink need an alarm? } @@ -7433,10 +7448,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->dashRainbowPogo--; if (player->invincibilitytimer) + player->invincibilitytimer--; + + if (player->smonitortimer) { - INT16 invinfac = 1; - if ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && - (player->invincibilitytimer > 2)) + if (player->smonitortimer > 2) { INT16 pingame = 0; INT32 i; @@ -7452,46 +7468,44 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) continue; } - // Value to subtract from the Invincibility timer. - INT16 invin_subtrahend = (pingame > 1) ? 2 : 1; + // Value to subtract from the S-Monitor timer. + INT16 smonitor_subtrahend = (pingame > 1) ? 2 : 1; - if ((player->distancefromcluster > 0) && (!player->invincibilitybottleneck) && (pingame > 1)) + if ((player->distancefromcluster > 0) && (!player->smonitorexpiring) && (pingame > 1)) { // Don't subtract shit until we get past the cluster player. - invin_subtrahend = 0; + smonitor_subtrahend = 0; } - player->invincibilitytimer = (UINT16)(max( - 2, (INT32)(player->invincibilitytimer) - invin_subtrahend)); + player->smonitortimer = (UINT16)(max( + 2, (INT32)(player->smonitortimer) - smonitor_subtrahend)); - const boolean warning_cond_standard = - (K_InvincibilityGradient(player->invincibilitytimer) < INVINWARNINGTIME); - - const boolean warning_cond = warning_cond_standard; + const boolean warning_cond = + (K_SMonitorGradient(player->smonitortimer) < SMONITORWARNINGTIME); if (warning_cond) { - if (!player->invincibilitywarning) + if (!player->smonitorwarning) { S_StartSound(player->mo, sfx_cdfm71); - player->invincibilitywarning = 1; - player->invincibilitybottleneck = 1; + player->smonitorwarning = 1; + player->smonitorexpiring = 1; } } } else { - player->invincibilitytimer--; - player->invincibilitybottleneck = 0; - player->invincibilitywarning = 0; + player->smonitortimer--; + player->smonitorexpiring = 0; + player->smonitorwarning = 0; } } else { - player->invincibilitybottleneck = 0; // No need for bottlenecking. - player->maxinvincibilitytime = 0; - player->invincibilitywarning = 0; - player->invincibilitycancel = -1; + player->smonitorexpiring = 0; // No need for bottlenecking. + player->maxsmonitortime = 0; + player->smonitorwarning = 0; + player->smonitorcancel = -1; } if (player->checkskip) @@ -7852,11 +7866,8 @@ static void K_KartResetPlayerFullbright(player_t *player) if (player->invincibilitytimer || player->powers[pw_invulnerability]) // You're gonna kiiiiill { - if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) - { - fullbright = true; - goto finalise; - } + fullbright = true; + goto finalise; } if (player->growshrinktimer) // Ditto, for grow/shrink @@ -7937,24 +7948,14 @@ void K_KartResetPlayerColor(player_t *player) if (player->invincibilitytimer || player->powers[pw_invulnerability]) // You're gonna kiiiiill { - boolean skip = false; + player->mo->color = K_RainbowColor(leveltime / 2); - if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) + if (player->invincibilitytimer) { - player->mo->color = K_RainbowColor(leveltime / 2); - - if (player->invincibilitytimer) - { - player->mo->colorized = true; - } - - skip = true; - } - - if (skip) - { - return; + player->mo->colorized = true; } + + return; } if (player->growshrinktimer) // Ditto, for grow/shrink @@ -9184,7 +9185,7 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue) if (K_SlipdashActive() && K_Sliptiding(player)) // slight handling boost based on weight turnvalue = FixedMul(turnvalue, FRACUNIT + (10 - player->kartweight)*FRACUNIT/48); - if ((player->invincibilitytimer && (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))) + if (player->invincibilitytimer || player->sneakertimer || player->bubbleboost || player->growshrinktimer > 0 || K_IsAltShrunk(player)) { @@ -9268,17 +9269,11 @@ static void K_SpawnDriftEFX(player_t *player, SINT8 level) } } -// Sliptide conditions for Alternative Invincibility. -static boolean K_AltInvinSliptideCondition(player_t *player) +// Sliptide conditions for the S-Monitor. +static boolean K_SMonitorSliptideCondition(player_t *player) { - if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) - { - // Not in Alternative, hit the bricks! - return false; - } - // Allow sliptides if you're above half power. - return (K_InvincibilityGradient(player->invincibilitytimer) > (FRACUNIT/2)); + return (K_SMonitorGradient(player->smonitortimer) > (FRACUNIT/2)); } fixed_t K_GetSpeedPercentage(const player_t *player) @@ -9326,7 +9321,7 @@ boolean K_InterceptArrowBullet(player_t *player) if (!player) return false; - return ((player->invincibilitytimer && !K_IsKartItemAlternate(KITEM_INVINCIBILITY)) || (player->growshrinktimer > 0) || (player->flamestore >= FLAMESTOREMAX-1)); + return ((player->invincibilitytimer) || (player->growshrinktimer > 0) || (player->flamestore >= FLAMESTOREMAX-1)); } // 0.25 fracunits @@ -9340,7 +9335,7 @@ static boolean K_OtherSliptideCondition(player_t* player) return false; return ( - K_AltInvinSliptideCondition(player) || K_AltShrinkSliptideCondition(player) || + K_SMonitorSliptideCondition(player) || K_AltShrinkSliptideCondition(player) || (cv_handleboostslip.value && (player->handleboost >= HANDLEBOOSTTHRESHOLD))); } @@ -10610,8 +10605,10 @@ void K_StripOther(player_t *player) player->roulettetype = KROULETTETYPE_NORMAL; player->invincibilitytimer = 0; - player->invincibilitywarning = 0; - player->invincibilitycancel = -1; + + player->smonitortimer = 0; + player->smonitorwarning = 0; + player->smonitorcancel = -1; if (player->growshrinktimer) { @@ -10841,12 +10838,9 @@ INT32 K_GetShieldFromItem(INT32 item) } } -static boolean K_InvincibilitySlotHogging(player_t *player) +static boolean K_SMonitorSlotHogging(player_t *player) { - if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) - return false; - - return ((player->invincibilitytimer) != 0); + return ((player->smonitortimer) != 0); } // @@ -10885,7 +10879,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) || player->itemroulette || player->rocketsneakertimer || player->eggmanexplode - || ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && player->invincibilitytimer) + || player->smonitortimer || (player->growshrinktimer > 0) || player->flametimer || (leveltime < starttime) @@ -11090,30 +11084,30 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->growcancel = 0; } } - // Invincibility - else if (K_InvincibilitySlotHogging(player)) + // S-Monitor + else if (K_SMonitorSlotHogging(player)) { - // (Alternate) Cancel Invincibility - if (player->invincibilitycancel >= 0) + // Cancel the S-Monitor + if (player->smonitorcancel >= 0) { if (buttons & BT_ATTACK) { - player->invincibilitycancel++; - if (player->invincibilitycancel > 25) + player->smonitorcancel++; + if (player->smonitorcancel > 25) { // Don't fully cancel due to how the music handling works. - player->invincibilitytimer = 1; + player->smonitortimer = 1; } } else - player->invincibilitycancel = 0; + player->smonitorcancel = 0; } else { if ((buttons & BT_ATTACK) || (player->oldcmd.buttons & BT_ATTACK)) - player->invincibilitycancel = -1; + player->smonitorcancel = -1; else - player->invincibilitycancel = 0; + player->smonitorcancel = 0; } } else if (player->itemamount == 0) diff --git a/src/k_kart.h b/src/k_kart.h index eddd1b686..daff3f833 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -28,8 +28,8 @@ If states are ever added or removed Make sure this matches the actual number of states */ #define KART_NUMINVSPARKLESANIM 12 -#define BASEINVINTIME (10 * TICRATE) -#define MININVINTIME (7 * TICRATE) +#define INVINTIME (10 * TICRATE) +#define SMONITORTIME (7 * TICRATE) #define GROW_SCALE ((3*FRACUNIT)/2) #define SHRINK_SCALE ((6*FRACUNIT)/8) @@ -85,14 +85,8 @@ extern vector3_t clusterpoint, clusterdtf; // Bump weight for a Bubble Shield #define BUBBLEMINWEIGHT (5 * FRACUNIT) -// Invincibility-related constants -#define INVINDIST CV_Get(&cv_kartinvindist) -#define INVINDISTMUL CV_Get(&cv_kartinvindistmul) -#define INVINMIDTIME CV_Get(&cv_kartinvin_midtime) -#define INVINMAXTIME CV_Get(&cv_kartinvin_maxtime) - -// 1.22 * FRACUNIT -#define LEGACYALTINVINMUL (122 * FRACUNIT / 100) +// S-Monitor distance value +#define SMONITORDIST CV_Get(&cv_kartsmonitordist) // Precalculated constants for stacked boost diminishing // *Somewhat* matches old calc but doesn't use arrays, which makes it faster and more memory efficent @@ -114,14 +108,16 @@ extern vector3_t clusterpoint, clusterdtf; #define SEPARATEPANELS CV_Get(&cv_kartstacking_panel_separate) #define MAXPANELSTACK CV_Get(&cv_kartstacking_panel_maxgrade) -#define INVINSPEEDBOOSTCLS CV_Get(&cv_kartstacking_invincibility_classicspeedboost) -#define INVINACCELBOOSTCLS CV_Get(&cv_kartstacking_invincibility_classicaccelboost) -#define INVINHANDLEBOOSTCLS CV_Get(&cv_kartstacking_invincibility_classichandleboost) -#define INVINSPEEDBOOSTALT CV_Get(&cv_kartstacking_invincibility_alternatespeedboost) -#define INVINACCELBOOSTALT CV_Get(&cv_kartstacking_invincibility_alternateaccelboost) -#define INVINHANDLEBOOSTALT CV_Get(&cv_kartstacking_invincibility_alternatehandleboost) +#define INVINSPEEDBOOST CV_Get(&cv_kartstacking_invincibility_speedboost) +#define INVINACCELBOOST CV_Get(&cv_kartstacking_invincibility_accelboost) +#define INVINHANDLEBOOST CV_Get(&cv_kartstacking_invincibility_handleboost) #define INVINSTACKABLE CV_Get(&cv_kartstacking_invincibility_stackable) +#define SMNTRSPEEDBOOST CV_Get(&cv_kartstacking_smonitor_speedboost) +#define SMNTRACCELBOOST CV_Get(&cv_kartstacking_smonitor_accelboost) +#define SMNTRHANDLEBOOST CV_Get(&cv_kartstacking_smonitor_handleboost) +#define SMNTRSTACKABLE CV_Get(&cv_kartstacking_smonitor_stackable) + #define GROWSPEEDBOOST CV_Get(&cv_kartstacking_grow_speedboost) #define GROWACCELBOOST CV_Get(&cv_kartstacking_grow_accelboost) #define GROWHANDLEBOOST CV_Get(&cv_kartstacking_grow_handleboost) @@ -276,12 +272,12 @@ void K_ResetPogoSpring(player_t *player); extern boolean forcefullinvintheme; boolean K_PlayFullInvinTheme(void); void K_DoInvincibility(player_t *player, tic_t time); -#define INVINWARNINGTIME (fixed_t)(0.833333333f * (float)(FRACUNIT)) -fixed_t K_InvincibilityGradient(UINT16 time); -UINT16 K_GetInvincibilityTime(player_t *player); -fixed_t K_GetInvincibilitySpeed(UINT16 time); -fixed_t K_GetInvincibilityAccel(UINT16 time); -fixed_t K_GetInvincibilityHandling(UINT16 time); +void K_DoSMonitor(player_t *player, tic_t time); +#define SMONITORWARNINGTIME (fixed_t)(0.833333333f * (float)(FRACUNIT)) +fixed_t K_SMonitorGradient(UINT16 time); +fixed_t K_GetSMonitorSpeed(UINT16 time); +fixed_t K_GetSMonitorAccel(UINT16 time); +fixed_t K_GetSMonitorHandling(UINT16 time); void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source); void K_UpdateHnextList(player_t *player, boolean clean); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 007c26d4e..779873617 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -4518,30 +4518,39 @@ static int lib_kGetNewSpeed(lua_State *L) return 1; } -static int lib_kInvincibilityGradient(lua_State *L) +static int lib_kSMonitorGradient(lua_State *L) { UINT16 time = (UINT16)luaL_checkinteger(L, 1); // HUDSAFE - lua_pushinteger(L, K_InvincibilityGradient(time)); + lua_pushinteger(L, K_SMonitorGradient(time)); return 1; } -static int lib_kGetInvincibilitySpeed(lua_State *L) +static int lib_kGetSMonitorSpeed(lua_State *L) { UINT16 time = (UINT16)luaL_checkinteger(L, 1); // HUDSAFE - lua_pushinteger(L, K_GetInvincibilitySpeed(time)); + lua_pushinteger(L, K_GetSMonitorSpeed(time)); return 1; } -static int lib_kGetInvincibilityAccel(lua_State *L) +static int lib_kGetSMonitorAccel(lua_State *L) { UINT16 time = (UINT16)luaL_checkinteger(L, 1); // HUDSAFE - lua_pushinteger(L, K_GetInvincibilityAccel(time)); + lua_pushinteger(L, K_GetSMonitorAccel(time)); + return 1; +} + +static int lib_kGetSMonitorHandling(lua_State *L) +{ + UINT16 time = (UINT16)luaL_checkinteger(L, 1); + // HUDSAFE + + lua_pushinteger(L, K_GetSMonitorHandling(time)); return 1; } @@ -5774,9 +5783,10 @@ static luaL_Reg lib[] = { {"K_BoostChain",lib_kBoostChain}, {"K_ChainOrDeincrementTime",lib_kChainOrDeincrementTime}, {"K_GetNewSpeed", lib_kGetNewSpeed}, - {"K_InvincibilityGradient", lib_kInvincibilityGradient}, - {"K_GetInvincibilitySpeed", lib_kGetInvincibilitySpeed}, - {"K_GetInvincibilityAccel", lib_kGetInvincibilityAccel}, + {"K_SMonitorGradient", lib_kSMonitorGradient}, + {"K_GetSMonitorSpeed", lib_kGetSMonitorSpeed}, + {"K_GetSMonitorAccel", lib_kGetSMonitorAccel}, + {"K_GetSMonitorHandling", lib_kGetSMonitorHandling}, {"K_3dKartMovement", lib_k3dKartMovement}, {"K_MomentumAngle", lib_kMomentumAngle}, {"K_GetKartSpeedFromStat", lib_kGetKartSpeedFromStat}, diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 950b959e0..f85e658af 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -415,10 +415,11 @@ static int lib_lenLocalplayers(lua_State *L) X(arrowbullet) \ X(rocketsneakertimer) \ X(invincibilitytimer) \ - X(maxinvincibilitytime) \ - X(invincibilitybottleneck) \ - X(invincibilitycancel) \ - X(invincibilitywarning) \ + X(smonitortimer) \ + X(maxsmonitortime) \ + X(smonitorexpiring) \ + X(smonitorcancel) \ + X(smonitorwarning) \ X(eggmanexplode) \ X(eggmanblame) \ X(bananadrag) \ @@ -906,18 +907,21 @@ static int player_get(lua_State *L) case player_invincibilitytimer: lua_pushinteger(L, plr->invincibilitytimer); break; - case player_maxinvincibilitytime: - lua_pushinteger(L, plr->maxinvincibilitytime); + case player_smonitortimer: + lua_pushinteger(L, plr->smonitortimer); break; - case player_invincibilitybottleneck: + case player_maxsmonitortime: + lua_pushinteger(L, plr->maxsmonitortime); + break; + case player_smonitorexpiring: // Push as an INT16 due to the negative value signal systems. - lua_pushinteger(L, (INT16)plr->invincibilitybottleneck); + lua_pushinteger(L, (INT16)plr->smonitorexpiring); break; - case player_invincibilitycancel: - lua_pushinteger(L, plr->invincibilitycancel); + case player_smonitorcancel: + lua_pushinteger(L, plr->smonitorcancel); break; - case player_invincibilitywarning: - lua_pushboolean(L, (boolean)plr->invincibilitywarning); + case player_smonitorwarning: + lua_pushboolean(L, (boolean)plr->smonitorwarning); break; case player_eggmanexplode: lua_pushinteger(L, plr->eggmanexplode); @@ -1699,20 +1703,23 @@ static int player_set(lua_State *L) case player_invincibilitytimer: plr->invincibilitytimer = luaL_checkinteger(L, 3); break; - case player_maxinvincibilitytime: + case player_smonitortimer: + plr->smonitortimer = luaL_checkinteger(L, 3); + break; + case player_maxsmonitortime: { UINT16 maxinv = max(1, (UINT16)luaL_checkinteger(L, 3)); // Prevent zero-divides - plr->maxinvincibilitytime = maxinv; + plr->maxsmonitortime = maxinv; break; } - case player_invincibilitybottleneck: - plr->invincibilitybottleneck = (UINT16)luaL_checkinteger(L, 3); + case player_smonitorexpiring: + plr->smonitorexpiring = (UINT16)luaL_checkinteger(L, 3); break; - case player_invincibilitycancel: - plr->invincibilitycancel = (INT16)luaL_checkinteger(L, 3); + case player_smonitorcancel: + plr->smonitorcancel = (INT16)luaL_checkinteger(L, 3); break; - case player_invincibilitywarning: - plr->invincibilitywarning = (UINT8)luaL_checkboolean(L, 3); + case player_smonitorwarning: + plr->smonitorwarning = (UINT8)luaL_checkboolean(L, 3); break; case player_eggmanexplode: plr->eggmanexplode = luaL_checkinteger(L, 3); diff --git a/src/p_enemy.c b/src/p_enemy.c index b6fb520ad..061d5526a 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -11632,6 +11632,7 @@ void A_RandomShadowFrame(void *thing) { if (actor->target && !actor->target->player->flashing && !actor->target->player->invincibilitytimer + && !actor->target->player->smonitortimer && !actor->target->player->growshrinktimer && !K_IsPlayerDamaged(actor->target->player) && P_IsObjectOnGround(actor->target) @@ -11678,6 +11679,7 @@ void A_RoamingShadowThinker(void *thing) { if (actor->target && !actor->target->player->flashing && !actor->target->player->invincibilitytimer + && !actor->target->player->smonitortimer && !actor->target->player->growshrinktimer && !K_IsPlayerDamaged(actor->target->player)) { @@ -11936,6 +11938,7 @@ void A_ReaperThinker(void *thing) { if (!(actor->target == targetplayermo && actor->target && !actor->target->player->flashing && !actor->target->player->invincibilitytimer + && !actor->target->player->smonitortimer && !actor->target->player->growshrinktimer && !K_IsPlayerDamaged(actor->target->player))) P_SetTarget(&actor->target, actor->hnext); diff --git a/src/p_inter.c b/src/p_inter.c index 7844122f6..ac20db4a4 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -83,6 +83,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) || K_IsPlayerDamaged(player) || player->squishedtimer > 0 || player->invincibilitytimer > 0 + || player->smonitortimer > 0 || player->growshrinktimer > 0 || player->hyudorotimer > 0 || player->flametimer > 0) @@ -99,7 +100,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) if (player->stealingtimer || player->stolentimer || player->rocketsneakertimer || player->eggmanexplode - || ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && (player->invincibilitytimer)) + || player->smonitortimer || (player->growshrinktimer > 0) || player->flametimer) return false; @@ -491,7 +492,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } - if (player->invincibilitytimer > 0 || player->growshrinktimer > 0 || player->hyudorotimer > 0) + if (player->invincibilitytimer > 0 || + player->smonitortimer > 0 || + player->growshrinktimer > 0 || + player->hyudorotimer > 0) { //player->flashing = 0; K_DropHnextList(player); @@ -2199,7 +2203,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } } - if (player->invincibilitytimer > 0 || player->growshrinktimer > 0 || player->hyudorotimer > 0) + if (player->invincibilitytimer > 0 || + player->smonitortimer > 0 || + player->growshrinktimer > 0 || + player->hyudorotimer > 0) { // Full invulnerability K_DoInstashield(player); diff --git a/src/p_mobj.c b/src/p_mobj.c index 2b6f64a27..1d9abc1a1 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6863,7 +6863,7 @@ static void P_RemoveOverlay(mobj_t *thing) } } -static UINT32 P_GetTranslucencyForInvincibility(mobj_t *mo) +static UINT32 P_GetTranslucencyForSMonitor(mobj_t *mo) { if (!mo->player) { @@ -6871,16 +6871,16 @@ static UINT32 P_GetTranslucencyForInvincibility(mobj_t *mo) return 0; } - return max(0, min(9, 10 - FixedMul(10, K_InvincibilityGradient(mo->player->invincibilitytimer))))<player->smonitortimer))))<target != NULL); I_Assert(thing->target->player != NULL); - if (!thing->target->player->invincibilitytimer) + if (!thing->target->player->smonitortimer) { P_SetTarget(&thing->target, NULL); @@ -6896,7 +6896,7 @@ static void P_PlayerInvincibilityOverlay(mobj_t *thing) thing->z += thing->target->height - thing->height; } - thing->color = K_AltInvincibilityColor(leveltime / 2); + thing->color = K_SMonitorColor(leveltime / 2); thing->colorized = true; thing->dispoffset = min(2, thing->target->dispoffset + 1); @@ -6908,7 +6908,7 @@ static void P_PlayerInvincibilityOverlay(mobj_t *thing) thing->sprite2 = thing->target->sprite2; thing->frame = thing->target->frame | FF_FULLBRIGHT | FF_ADD; thing->tics = -1; - thing->renderflags = (thing->target->renderflags & ~RF_TRANSMASK)|P_GetTranslucencyForInvincibility(thing->target); + thing->renderflags = (thing->target->renderflags & ~RF_TRANSMASK)|P_GetTranslucencyForSMonitor(thing->target); thing->skin = thing->target->skin; thing->standingslope = thing->target->standingslope; @@ -7275,8 +7275,8 @@ static void P_MobjSceneryThink(mobj_t *mobj) P_AddOverlay(mobj); if ((mobj->extravalue2) && (mobj->target->player)) { - // Could be overlaying an invincible player. - P_PlayerInvincibilityOverlay(mobj); + // Could be overlaying a player using an S-Monitor. + P_PlayerSMonitorOverlay(mobj); } } break; @@ -8501,7 +8501,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) K_UpdateMobjItemOverlay(part, mobj->threshold, mobj->movecount); - if (mobj->threshold == KITEM_INVINCIBILITY) + if ((mobj->threshold == KITEM_INVINCIBILITY) || (mobj->threshold == KITEM_S_MONITOR)) mobj->color = K_RainbowColor(leveltime); } break; @@ -9043,7 +9043,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->colorized = mobj->target->colorized; break; case MT_INVULNFLASH: - if (!mobj->target || !mobj->target->health || (mobj->target->player && !mobj->target->player->invincibilitytimer)) + if (!mobj->target || + !mobj->target->health || + (mobj->target->player && + !(mobj->target->player->invincibilitytimer || + mobj->target->player->smonitortimer))) { P_RemoveMobj(mobj); return false; diff --git a/src/p_saveg.c b/src/p_saveg.c index 3a4d428cb..6e8779124 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -755,10 +755,11 @@ static void P_NetSyncPlayers(savebuffer_t *save) SYNC(players[i].rocketsneakertimer); SYNC(players[i].invincibilitytimer); - SYNC(players[i].maxinvincibilitytime); - SYNC(players[i].invincibilitybottleneck); - SYNC(players[i].invincibilitycancel); - SYNC(players[i].invincibilitywarning); + SYNC(players[i].smonitortimer); + SYNC(players[i].maxsmonitortime); + SYNC(players[i].smonitorexpiring); + SYNC(players[i].smonitorcancel); + SYNC(players[i].smonitorwarning); SYNC(players[i].eggmanexplode); SYNC(players[i].eggmanblame); diff --git a/src/p_spec.c b/src/p_spec.c index 15b561338..97fd04639 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -9338,7 +9338,8 @@ boolean P_AllowFriction(mobj_t *mobj) || (cv_kartbubble_boost_offroadignore.value && mobj->player->bubbleboost) || mobj->player->growshrinktimer > 0 || mobj->player->flamestore - || K_IsAltShrunk(mobj->player)) + || K_IsAltShrunk(mobj->player) + || mobj->player->smonitortimer) return false; return true; diff --git a/src/p_user.c b/src/p_user.c index 249a5a4cf..c44a3dea6 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -833,8 +833,10 @@ void P_RestoreMusic(player_t *player) { \ if (players[p].growshrinktimer > bestlocaltimer) \ { wantedmus = 1; bestlocaltimer = players[p].growshrinktimer; } \ - else if ((players[p].invincibilitytimer > bestlocaltimer) && (!players[p].invincibilitywarning))\ + else if (players[p].invincibilitytimer > bestlocaltimer) \ { wantedmus = 2; bestlocaltimer = players[p].invincibilitytimer; } \ + else if ((players[p].smonitortimer > bestlocaltimer) && (!players[p].smonitorwarning))\ + { wantedmus = 2; bestlocaltimer = players[p].smonitortimer; } \ else if ((K_IsKartItemAlternate(KITEM_SHRINK)) && \ (K_GetShrinkTime(&players[p]) > bestlocaltimer)) \ { wantedmus = 3; bestlocaltimer = K_GetShrinkTime(&players[p]); } \ @@ -853,7 +855,9 @@ void P_RestoreMusic(player_t *player) { if (player->growshrinktimer > 1) wantedmus = 1; - else if ((player->invincibilitytimer > 1) && (!player->invincibilitywarning)) + else if (player->invincibilitytimer) + wantedmus = 2; + else if (((player->smonitortimer > 1) && (!player->smonitorwarning))) wantedmus = 2; else if ((K_IsKartItemAlternate(KITEM_SHRINK)) && (K_GetShrinkTime(player) > 1)) @@ -1802,12 +1806,16 @@ static void P_CheckQuicksand(player_t *player) // static void P_CheckInvincibilityTimer(player_t *player) { - if (!player->powers[pw_invulnerability] && !player->invincibilitytimer) + if (!player->powers[pw_invulnerability] && !player->invincibilitytimer && !player->smonitortimer) return; // Resume normal music stuff. - if (player->invincibilitytimer == 1 || player->powers[pw_invulnerability] == 1) + if (player->invincibilitytimer == 1 + || player->powers[pw_invulnerability] == 1 + || (player->smonitorwarning == 1)) { + player->smonitorwarning = 2; // Don't attempt to restore music again. + //K_KartResetPlayerColor(player); -- this gets called every tic anyways G_GhostAddColor((INT32) (player - players), GHC_NORMAL); @@ -2321,10 +2329,10 @@ void P_MovePlayer(player_t *player) && onground && (leveltime & 1)) K_SpawnBoostTrail(player); - if ((player->invincibilitytimer > 0) && - (((leveltime % - max(1, 10 - FixedMul(9, K_InvincibilityGradient(player->invincibilitytimer)))) == 0) || - (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)))) + if (((player->invincibilitytimer) || + ((player->smonitortimer > 0) && + (((leveltime % + max(1, 10 - FixedMul(9, K_SMonitorGradient(player->smonitortimer)))) == 0))))) { K_SpawnSparkleTrail(player->mo); } @@ -4392,7 +4400,13 @@ void P_PlayerThink(player_t *player) P_CheckInvincibilityTimer(player); // Spawn Invincibility Sparkles // "Blur" a bit when you have speed shoes and are going fast enough - if ((player->powers[pw_super] || player->powers[pw_sneakers] || player->driftboost || player->sneakertimer || player->startboost || player->ringboost) && !player->invincibilitytimer // SRB2kart + if ((player->powers[pw_super] + || player->powers[pw_sneakers] + || player->driftboost + || player->sneakertimer + || player->startboost + || player->ringboost) + && !(player->invincibilitytimer || player->smonitortimer) // SRB2kart && (player->speed + abs(player->mo->momz)) > FixedMul(20*FRACUNIT,player->mo->scale)) { UINT8 i; @@ -4652,7 +4666,7 @@ void P_ForceLocalAngle(player_t *player, angle_t angle, boolean interp) boolean P_PlayerFullbright(player_t *player) { - return (player->invincibilitytimer > 0); + return (player->invincibilitytimer > 0) || (player->smonitortimer > 0); } void P_ResetPlayerCheats(void) diff --git a/src/r_patch.h b/src/r_patch.h index 50e41b43c..3a66462ba 100644 --- a/src/r_patch.h +++ b/src/r_patch.h @@ -46,7 +46,7 @@ patch_t *Patch_GetRotatedSprite( void *info, INT32 rotationangle); INT32 R_GetRollAngle(angle_t rollangle); -boolean R_IsOverlayingInvinciblePlayer(mobj_t* mobj); +boolean R_IsOverlayingSMonitorPlayer(mobj_t* mobj); angle_t R_GetPitchRollAngle(mobj_t *mobj, player_t *viewPlayer, interpmobjstate_t *interp); angle_t R_ModelRotationAngle(mobj_t *mobj, player_t *viewPlayer); angle_t R_SpriteRotationAngle(mobj_t *mobj, player_t *viewPlayer, interpmobjstate_t *interp); diff --git a/src/r_patchrotation.c b/src/r_patchrotation.c index 9d3c179e3..20673b097 100644 --- a/src/r_patchrotation.c +++ b/src/r_patchrotation.c @@ -89,12 +89,12 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer) return rollAngle; } -// Hacky boolean to check if we're the rainbow Invincibility overlay -boolean R_IsOverlayingInvinciblePlayer(mobj_t* mobj) +// Hacky boolean to check if we're the rainbow S-Monitor overlay +boolean R_IsOverlayingSMonitorPlayer(mobj_t* mobj) { - return ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && (mobj->type == MT_OVERLAY) && + return ((mobj->type == MT_OVERLAY) && (mobj->target) && (mobj->extravalue2) && (mobj->target->player) && - (mobj->target->player->invincibilitytimer)); + (mobj->target->player->smonitortimer)); } angle_t R_ModelRotationAngle(mobj_t *mobj, player_t *viewPlayer) @@ -105,7 +105,7 @@ angle_t R_ModelRotationAngle(mobj_t *mobj, player_t *viewPlayer) { rollAngle += R_PlayerSpriteRotation(mobj->player, viewPlayer); } - else if (R_IsOverlayingInvinciblePlayer(mobj)) + else if (R_IsOverlayingSMonitorPlayer(mobj)) { rollAngle += R_PlayerSpriteRotation(mobj->target->player, viewPlayer); } @@ -117,7 +117,7 @@ angle_t R_SpriteRotationAngle(mobj_t *mobj, player_t *viewPlayer, interpmobjstat { angle_t rollOrPitch; - if (R_IsOverlayingInvinciblePlayer(mobj)) + if (R_IsOverlayingSMonitorPlayer(mobj)) { rollOrPitch = R_GetPitchRollAngle(mobj->target, viewPlayer, interp); } diff --git a/src/r_things.cpp b/src/r_things.cpp index 67dd0c9d5..246de37a3 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -922,7 +922,7 @@ UINT8 *R_GetSpriteTranslation(vissprite_t *vis) if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) { - return R_GetTranslationColormap(R_IsOverlayingInvinciblePlayer(vis->mobj) ? TC_BLINK : TC_RAINBOW, + return R_GetTranslationColormap(R_IsOverlayingSMonitorPlayer(vis->mobj) ? TC_BLINK : TC_RAINBOW, static_cast(vis->mobj->color), GTC_CACHE); } @@ -1838,7 +1838,7 @@ static void R_ProjectSprite(mobj_t *thing) interpmobjstate_t interp = {0}; mobj_t *interptarg = thing; - if (R_IsOverlayingInvinciblePlayer(thing)) + if (R_IsOverlayingSMonitorPlayer(thing)) { // Kill overlay misalignment interptarg = thing->target;