diff --git a/src/command.h b/src/command.h index c8b90f0a1..dc99f4a2f 100644 --- a/src/command.h +++ b/src/command.h @@ -186,6 +186,9 @@ extern CV_PossibleValue_t CV_Natural[]; #define KARTGP_MASTER 4 // Not a speed setting, gives hard speed with maxed out bots #define KARTGP_NIGHTMARE 5 // Not a speed setting, gives expert speed with maxed out bots extern CV_PossibleValue_t kartspeed_cons_t[]; +// Invincibility types. +#define KARTINVIN_LEGACY 0 +#define KARTINVIN_ALTERN 1 extern consvar_t cv_execversion; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a03713fe4..03f9762fd 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -154,6 +154,7 @@ static void KartStacking_OnChange(void); static void KartChaining_OnChange(void); static void KartSlipdash_OnChange(void); static void KartItemBreaker_OnChange(void); +static void KartInvinType_OnChange(void); static void Schedule_OnChange(void); @@ -462,8 +463,10 @@ consvar_t cv_kartstacking_sneaker_accelboost = CVAR_INIT ("vanillaboost_sneaker_ consvar_t cv_kartstacking_sneaker_maxgrade = CVAR_INIT ("vanillaboost_sneaker_maxgrade", "3", CV_NETVAR|CV_CHEAT, CV_Natural, NULL); consvar_t cv_kartstacking_sneaker_stackable = CVAR_INIT ("vanillaboost_sneaker_stackable", "On", CV_NETVAR, CV_OnOff, NULL); -consvar_t cv_kartstacking_invincibility_speedboost = CVAR_INIT ("vanillaboost_invincibility_speedboost", "0.68", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); -consvar_t cv_kartstacking_invincibility_accelboost = CVAR_INIT ("vanillaboost_invincibility_accelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_invincibility_legacyspeedboost = CVAR_INIT ("vanillaboost_invincibility_legacyspeedboost", "0.375", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_invincibility_legacyaccelboost = CVAR_INIT ("vanillaboost_invincibility_legacyaccelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_invincibility_alternatespeedboost = CVAR_INIT ("vanillaboost_invincibility_alternatespeedboost", "0.68", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartstacking_invincibility_alternateaccelboost = CVAR_INIT ("vanillaboost_invincibility_alternateaccelboost", "3.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); consvar_t cv_kartstacking_invincibility_stackable = CVAR_INIT ("vanillaboost_invincibility_stackable", "Off", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_kartstacking_grow_speedboost = CVAR_INIT ("vanillaboost_grow_speedboost", "0.2", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); @@ -503,12 +506,19 @@ consvar_t cv_kartbumpspring = CVAR_INIT ("kartbumpspring", "No", CV_NETVAR, CV_Y consvar_t cv_kartslipdash = CVAR_INIT ("kartslipdash", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, KartSlipdash_OnChange); +// Invincibility modifiers +static CV_PossibleValue_t invintype_cons_t[] = {{0, "Legacy"}, {1, "Alternative"}, {0, NULL}}; +consvar_t cv_kartinvintype = CVAR_INIT ("kartinvintype", "Legacy", CV_NETVAR|CV_CALL, invintype_cons_t, KartInvinType_OnChange); + // 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", "8400", CV_NETVAR|CV_CHEAT, invindist_cons_t, NULL); consvar_t cv_kartinvindistmul = CVAR_INIT ("kartinvindistmul", "0.54", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartinvin_maxtime = CVAR_INIT ("kartinvin_maxtime", "21.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); +consvar_t cv_kartinvin_midtime = CVAR_INIT ("kartinvin_midtime", "14.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, CV_Unsigned, NULL); + static CV_PossibleValue_t kartdebugitem_cons_t[] = { #define FOREACH( name, n ) { n, #name } @@ -7318,6 +7328,24 @@ static void KartItemBreaker_OnChange(void) } } +static void KartInvinType_OnChange(void) +{ + if (K_CanChangeRules() == false) + { + return; + } + + if (leveltime < starttime) + { + CONS_Printf(M_GetText("Invincibility type has been changed to \"%s\".\n"), cv_kartinvintype.string); + invintype = (UINT8)cv_kartinvintype.value; + } + else + { + CONS_Printf(M_GetText("Invincibility type will be changed to \"%s\" next round.\n"), cv_kartinvintype.string); + } +} + static void Schedule_OnChange(void) { size_t i; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 77099e1b4..b6b5a367f 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -138,8 +138,10 @@ extern consvar_t cv_kartstacking_sneaker_accelboost; extern consvar_t cv_kartstacking_sneaker_maxgrade; extern consvar_t cv_kartstacking_sneaker_stackable; -extern consvar_t cv_kartstacking_invincibility_speedboost; -extern consvar_t cv_kartstacking_invincibility_accelboost; +extern consvar_t cv_kartstacking_invincibility_legacyspeedboost; +extern consvar_t cv_kartstacking_invincibility_legacyaccelboost; +extern consvar_t cv_kartstacking_invincibility_alternatespeedboost; +extern consvar_t cv_kartstacking_invincibility_alternateaccelboost; extern consvar_t cv_kartstacking_invincibility_stackable; extern consvar_t cv_kartstacking_flame_speedval; @@ -171,8 +173,11 @@ extern consvar_t cv_kartpurpledrift; extern consvar_t cv_kartbumpspark; extern consvar_t cv_kartbumpspring; extern consvar_t cv_kartslipdash; +extern consvar_t cv_kartinvintype; 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_encorevotes; diff --git a/src/doomstat.h b/src/doomstat.h index 5301c1b8b..41194842c 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -664,6 +664,7 @@ extern INT32 cheats; // SRB2kart extern UINT8 numlaps; extern UINT8 gamespeed; +extern UINT8 invintype; extern boolean franticitems; extern boolean encoremode, prevencoremode; extern boolean comeback; diff --git a/src/g_game.c b/src/g_game.c index 0e9076a0c..2bc02c72f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -282,6 +282,7 @@ INT32 cheats; //for multiplayer cheat commands // Cvars that we don't want changed mid-game UINT8 numlaps; // Removed from Cvar hell UINT8 gamespeed; // Game's current speed (or difficulty, or cc, or etc); 0 for easy, 1 for normal, 2 for hard +UINT8 invintype; // How Invincibility functions. 0 for Legacy/Vanilla, 1 for Alternative. boolean encoremode = false; // Encore Mode currently enabled? boolean prevencoremode; boolean franticitems; // Frantic items currently enabled? diff --git a/src/k_collide.c b/src/k_collide.c index b734db9d8..57441cad0 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -687,11 +687,6 @@ boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2) return false; } -boolean K_CanInvincibilityDamage(UINT16 timer) -{ - return (K_InvincibilityGradient(timer) > (FRACUNIT/2)); -} - boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) { const boolean flameT1 = ((t1->player->flamedash > 0) && (t1->player->flametimer > 0)); @@ -700,8 +695,12 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) boolean t1Condition = false; boolean t2Condition = false; - t1Condition = ((t1->player->invincibilitytimer > 0) && (K_CanInvincibilityDamage(t1->player->invincibilitytimer))); - t2Condition = ((t2->player->invincibilitytimer > 0) && (K_CanInvincibilityDamage(t2->player->invincibilitytimer))); + // Rim suggestion: Flipover damage is negligible at best, just cull it from Invincibility as a whole. + if (invintype == KARTINVIN_LEGACY) + { + t1Condition = (t1->player->invincibilitytimer > 0); + t2Condition = (t2->player->invincibilitytimer > 0); + } if ((t1Condition == true || flameT1 == true) && (t2Condition == true || flameT2 == true)) { @@ -709,15 +708,18 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) K_DoInstashield(t2->player); return false; } - else if (t1Condition == true && t2Condition == false) + else if (invintype == KARTINVIN_LEGACY) { - P_DamageMobj(t2, t1, t1, 1, DMG_FLIPOVER); - return true; - } - else if (t1Condition == false && t2Condition == true) - { - P_DamageMobj(t1, t2, t2, 1, DMG_FLIPOVER); - return true; + if (t1Condition == true && t2Condition == false) + { + P_DamageMobj(t2, t1, t1, 1, DMG_WIPEOUT); + return true; + } + else if (t1Condition == false && t2Condition == true) + { + P_DamageMobj(t1, t2, t2, 1, DMG_WIPEOUT); + return true; + } } t1Condition = (t1->scale > t2->scale + (mapobjectscale/8)); diff --git a/src/k_hud.c b/src/k_hud.c index 377fec8ee..b83a1b0dd 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1873,7 +1873,7 @@ static boolean K_drawKartPositionFaces(void) V_DrawMappedPatch(FACE_X, Y, V_HUDTRANS|V_SNAPTOLEFT, faceprefix[players[rankplayer[i]].skin][FACE_RANK], colormap); - if (players[rankplayer[i]].invincibilitytimer) + if ((players[rankplayer[i]].invincibilitytimer) && (invintype == KARTINVIN_ALTERN)) { colormap = R_GetTranslationColormap(TC_RAINBOW, K_RainbowColor(leveltime / 2), GTC_CACHE); invinchudtrans = K_InvincibilityHUDVisibility(players[rankplayer[i]].invincibilitytimer); @@ -3657,7 +3657,7 @@ static void K_drawKartMinimap(void) colorizeplayer = players[i].mo->colorized; - if ((players[i].invincibilitytimer) && (K_InvincibilityGradient(players[i].invincibilitytimer) > (FRACUNIT/2))) + if ((players[i].invincibilitytimer) && ((K_InvincibilityGradient(players[i].invincibilitytimer) > (FRACUNIT/2)) || (invintype == KARTINVIN_LEGACY))) { usecolor = (K_RainbowColor(leveltime / 2)); colorizeplayer = true; @@ -3820,7 +3820,9 @@ static void K_drawKartMinimap(void) colorizeplayer = players[localplayers[i]].mo->colorized; - if ((players[localplayers[i]].invincibilitytimer) && (K_InvincibilityGradient(players[localplayers[i]].invincibilitytimer) > (FRACUNIT/2))) + if ((players[localplayers[i]].invincibilitytimer) && + ((K_InvincibilityGradient(players[localplayers[i]].invincibilitytimer) > + (FRACUNIT / 2)) || (invintype == KARTINVIN_LEGACY))) { usecolor = (K_RainbowColor(leveltime / 2)); colorizeplayer = true; diff --git a/src/k_kart.c b/src/k_kart.c index 0354c75d7..94b6a9e4a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -312,8 +312,10 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartstacking_sneaker_maxgrade); CV_RegisterVar(&cv_kartstacking_sneaker_stackable); - CV_RegisterVar(&cv_kartstacking_invincibility_speedboost); - CV_RegisterVar(&cv_kartstacking_invincibility_accelboost); + CV_RegisterVar(&cv_kartstacking_invincibility_legacyspeedboost); + CV_RegisterVar(&cv_kartstacking_invincibility_legacyaccelboost); + CV_RegisterVar(&cv_kartstacking_invincibility_alternatespeedboost); + CV_RegisterVar(&cv_kartstacking_invincibility_alternateaccelboost); CV_RegisterVar(&cv_kartstacking_invincibility_stackable); CV_RegisterVar(&cv_kartstacking_grow_speedboost); @@ -352,9 +354,13 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartslipdash); + CV_RegisterVar(&cv_kartinvintype); CV_RegisterVar(&cv_kartinvindist); CV_RegisterVar(&cv_kartinvindistmul); + CV_RegisterVar(&cv_kartinvin_maxtime); + CV_RegisterVar(&cv_kartinvin_midtime); + CV_RegisterVar(&cv_kartdriftsounds); CV_RegisterVar(&cv_kartdriftefx); CV_RegisterVar(&cv_driftsparkpulse); @@ -874,16 +880,19 @@ INT32 K_KartGetItemOdds( notNearEnd = true; break; case KITEM_INVINCIBILITY: - // It's a power item, yes, but we don't want mashing to lessen - // its chances, so we lie to the game's face. - // Nonetheless, apply the start cooldown. - cooldownOnStart = true; + if (invintype == KARTINVIN_ALTERN) + { + // It's a power item, yes, but we don't want mashing to lessen + // its chances, so we lie to the game's face. + // Nonetheless, apply the start cooldown. + cooldownOnStart = true; - // Unique odds for Invincibility. - newodds = K_KartGetInvincibilityOdds(clusterDist); - - newodds *= 4; - break; + // Unique odds for Invincibility. + newodds = K_KartGetInvincibilityOdds(clusterDist); + + newodds *= 4; + break; + } case KITEM_MINE: case KITEM_GROW: case KITEM_BUBBLESHIELD: @@ -1074,16 +1083,19 @@ INT32 K_KartGetLegacyItemOdds(UINT8 pos, SINT8 item, fixed_t clusterDist, fixed_ powerItem = true; break; case KITEM_INVINCIBILITY: - // It's a power item, yes, but we don't want mashing to lessen - // its chances, so we lie to the game's face. - // Nonetheless, apply the start cooldown. - cooldownOnStart = true; + if (invintype == KARTINVIN_ALTERN) + { + // It's a power item, yes, but we don't want mashing to lessen + // its chances, so we lie to the game's face. + // Nonetheless, apply the start cooldown. + cooldownOnStart = true; - // Unique odds for Invincibility. - newodds = K_KartGetInvincibilityOdds(clusterDist); - - newodds *= 4; - break; + // Unique odds for Invincibility. + newodds = K_KartGetInvincibilityOdds(clusterDist); + + newodds *= 4; + break; + } case KITEM_MINE: case KITEM_GROW: case KITEM_BUBBLESHIELD: @@ -3640,10 +3652,10 @@ static fixed_t K_InvincibilityEasing(fixed_t x) u = max(0, (u - FRACUNIT)); if (u < FRACUNIT) - return Easing_InCubic(u, FRACUNIT, 22 * FRACUNIT / 10); + return Easing_InCubic(u, FRACUNIT, (INVINMIDTIME/10)); return Easing_OutCubic( - min(FRACUNIT, FixedMul(u - FRACUNIT, FRACUNIT/4)), 22 * FRACUNIT / 10, 4 * FRACUNIT); + min(FRACUNIT, FixedMul(u - FRACUNIT, FRACUNIT/4)), (INVINMIDTIME/10), (INVINMAXTIME/10)); } @@ -3651,6 +3663,9 @@ UINT16 K_GetInvincibilityTime(player_t *player) { UINT32 i, pingame; + if (invintype == KARTINVIN_LEGACY) + return BASEINVINTIME; + pingame = 0; for (i = 0; i < MAXPLAYERS; i++) { @@ -3673,14 +3688,20 @@ UINT16 K_GetInvincibilityTime(player_t *player) static fixed_t K_GetInvincibilitySpeed(UINT16 time) { + if (invintype == KARTINVIN_LEGACY) + return INVINSPEEDBOOSTLGC; + fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time)); - return Easing_OutCubic(t, 0, INVINSPEEDBOOST); + return Easing_OutCubic(t, 0, INVINSPEEDBOOSTALT); } static fixed_t K_GetInvincibilityAccel(UINT16 time) { + if (invintype == KARTINVIN_LEGACY) + return INVINACCELBOOSTLGC; + fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time)); - return Easing_OutCubic(t, 0, INVINACCELBOOST); + return Easing_OutCubic(t, 0, INVINACCELBOOSTALT); } static fixed_t diminish(fixed_t speedboost) @@ -5925,16 +5946,29 @@ void K_DoInvincibility(player_t *player, tic_t time) overlay->destscale = player->mo->scale; P_SetScale(overlay, player->mo->scale); - 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 (invintype == KARTINVIN_ALTERN) + { + 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; + } } - // Don't punish a player for spamming. - // That sounds stupid, yes. - player->invincibilitytimer = max(player->invincibilitytimer, time); + if (invintype == KARTINVIN_ALTERN) + { + // 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; + } if (P_IsLocalPlayer(player) == true) { @@ -7782,7 +7816,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->startboost = K_ChainOrDeincrementTime(player, player->startboost, 1, false); if (player->invincibilitytimer) - { + { player->invincibilitytimer--; } @@ -8091,11 +8125,15 @@ void K_KartResetPlayerColor(player_t *player) { boolean skip = false; - //fullbright = true; + if (invintype == KARTINVIN_LEGACY) + { + fullbright = true; - // player->mo->color = K_RainbowColor(leveltime / 2); - // player->mo->colorized = true; - skip = true; + player->mo->color = K_RainbowColor(leveltime / 2); + player->mo->colorized = true; + + skip = true; + } if (skip) { diff --git a/src/k_kart.h b/src/k_kart.h index 1356bb335..33b1b6c17 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -71,6 +71,12 @@ extern vector3_t clusterpoint, clusterdtf; // :) #define MAXODDS 8 +// Invincibility-related constants +#define INVINDIST K_RAGuard(cv_kartinvindist) +#define INVINDISTMUL K_RAGuard(cv_kartinvindistmul) +#define INVINMIDTIME K_RAGuard(cv_kartinvin_midtime) +#define INVINMAXTIME K_RAGuard(cv_kartinvin_maxtime) + // Precalculated constants for stacked boost diminishing // *Somewhat* matches old calc but doesn't use arrays, which makes it faster and more memory efficent #define DIMINISHPARAM K_RAGuard(cv_kartstacking_diminishparam) @@ -87,10 +93,10 @@ extern vector3_t clusterpoint, clusterdtf; #define SNEAKERACCELBOOST K_RAGuard(cv_kartstacking_sneaker_accelboost) #define MAXSNEAKERSTACK K_RAGuard(cv_kartstacking_sneaker_maxgrade) #define SNEAKERSTACKABLE K_RAGuard(cv_kartstacking_sneaker_stackable) -#define INVINDIST K_RAGuard(cv_kartinvindist) -#define INVINDISTMUL K_RAGuard(cv_kartinvindistmul) -#define INVINSPEEDBOOST K_RAGuard(cv_kartstacking_invincibility_speedboost) -#define INVINACCELBOOST K_RAGuard(cv_kartstacking_invincibility_accelboost) +#define INVINSPEEDBOOSTLGC K_RAGuard(cv_kartstacking_invincibility_legacyspeedboost) +#define INVINACCELBOOSTLGC K_RAGuard(cv_kartstacking_invincibility_legacyaccelboost) +#define INVINSPEEDBOOSTALT K_RAGuard(cv_kartstacking_invincibility_alternatespeedboost) +#define INVINACCELBOOSTALT K_RAGuard(cv_kartstacking_invincibility_alternateaccelboost) #define INVINSTACKABLE K_RAGuard(cv_kartstacking_invincibility_stackable) #define GROWSPEEDBOOST K_RAGuard(cv_kartstacking_grow_speedboost) #define GROWACCELBOOST K_RAGuard(cv_kartstacking_grow_accelboost) diff --git a/src/p_setup.c b/src/p_setup.c index 2b0e73309..9c1f5bbad 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7961,6 +7961,8 @@ static void P_InitLevelSettings(boolean reloadinggamestate) if (cv_kartslipdash.value) slipdashactive = true; + invintype = (UINT8)cv_kartinvintype.value; + // emerald hunt hunt1 = hunt2 = hunt3 = NULL; diff --git a/src/p_user.c b/src/p_user.c index e0fa678f4..26ab5879e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2242,13 +2242,12 @@ void P_MovePlayer(player_t *player) K_SpawnBoostTrail(player); if ((player->invincibilitytimer > 0) && - ((leveltime % max(1, - 10 - FixedMul(9, - K_InvincibilityGradient( - player->invincibilitytimer)))) == 0)) - { - K_SpawnSparkleTrail(player->mo); - } + (((leveltime % + max(1, 10 - FixedMul(9, K_InvincibilityGradient(player->invincibilitytimer)))) == 0) || + (invintype == KARTINVIN_LEGACY))) + { + K_SpawnSparkleTrail(player->mo); + } if (player->wipeoutslow > 1 && (leveltime & 1)) K_SpawnWipeoutTrail(player->mo, false);