parent
f414006e66
commit
7249273ca3
20 changed files with 772 additions and 67 deletions
|
|
@ -490,9 +490,18 @@ consvar_t cv_kartstacking_sneaker_stackable = CVAR_INIT ("vanillaboost_sneaker_s
|
|||
consvar_t cv_kartstacking_panel_separate = CVAR_INIT ("vanillaboost_panel_separate", "Off", CV_NETVAR|CV_GUARD, CV_OnOff, NULL);
|
||||
consvar_t cv_kartstacking_panel_maxgrade = CVAR_INIT ("vanillaboost_panel_maxgrade", "2", CV_NETVAR|CV_CHEAT|CV_GUARD, CV_Natural, 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);
|
||||
//
|
||||
// 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.67", 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.75", 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);
|
||||
|
||||
consvar_t cv_kartstacking_grow_speedboost = CVAR_INIT ("vanillaboost_grow_speedboost", "0.2", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
|
||||
|
|
@ -634,9 +643,13 @@ static CV_PossibleValue_t kartinvintheme_cons_t[] = {{0, "Standard"}, {1, "Full"
|
|||
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}};
|
||||
static CV_PossibleValue_t invindist_cons_t[] = {{1, "MIN"}, {32000, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_kartinvindist = CVAR_INIT ("kartinvindist", "6800", 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);
|
||||
|
||||
// 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);
|
||||
|
|
|
|||
|
|
@ -118,9 +118,12 @@ extern consvar_t cv_kartstacking_panel_separate;
|
|||
extern consvar_t cv_kartstacking_panel_maxgrade;
|
||||
|
||||
|
||||
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_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_stackable;
|
||||
|
||||
extern consvar_t cv_kartstacking_flame_speedval;
|
||||
|
|
@ -191,7 +194,10 @@ 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_kartinvindist;
|
||||
extern consvar_t cv_kartinvindistmul;
|
||||
extern consvar_t cv_kartinvin_maxtime;
|
||||
extern consvar_t cv_kartinvin_midtime;
|
||||
|
||||
// opinionated stuff for testing
|
||||
extern consvar_t cv_kartbubble_defense_canidle;
|
||||
|
|
|
|||
|
|
@ -552,7 +552,7 @@ struct player_t
|
|||
UINT16 spinouttimer; // Spin-out from a banana peel or oil slick (was "pw_bananacam")
|
||||
UINT8 spinouttype; // Determines the mode of spinout/wipeout, see kartspinoutflags_t
|
||||
|
||||
UINT16 flipovertimer; // Flipped over by a player.
|
||||
UINT16 flipovertimer; // Flipped over by a player using Invincibility.
|
||||
angle_t flipoverangle; // Movement angle for a flipped-over player.
|
||||
|
||||
UINT8 instashield; // Instashield no-damage animation timer
|
||||
|
|
@ -679,6 +679,10 @@ 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.
|
||||
|
||||
UINT8 eggmanexplode; // Fake item recieved, explode in a few seconds
|
||||
SINT8 eggmanblame; // (-1 to 15) - Fake item recieved, who set this fake
|
||||
|
|
|
|||
|
|
@ -862,6 +862,7 @@ struct menu_drawer_s const MENU_DRAWERS[] = {
|
|||
};
|
||||
|
||||
struct odds_func_s const USEODDS_FUNCS[] = {
|
||||
{ "ALTINVINODDS", &KO_AltInvinOdds },
|
||||
{ "SPBRACEODDS", &KO_SPBRaceOdds },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
@ -1745,6 +1746,7 @@ struct int_const_s const INT_CONST[] = {
|
|||
// invin constants
|
||||
{"KART_NUMINVSPARKLESANIM", KART_NUMINVSPARKLESANIM},
|
||||
{"BASEINVINTIME", BASEINVINTIME},
|
||||
{"MININVINTIME", MININVINTIME},
|
||||
|
||||
// grow/shrink scale
|
||||
{"GROW_SCALE", GROW_SCALE},
|
||||
|
|
|
|||
|
|
@ -4772,6 +4772,12 @@ static void HWR_ProjectSprite(mobj_t *thing)
|
|||
|
||||
interptarg = thing;
|
||||
|
||||
if (R_IsOverlayingInvinciblePlayer(thing))
|
||||
{
|
||||
// Kill overlay misalignment
|
||||
interptarg = thing->target;
|
||||
}
|
||||
|
||||
R_InterpolateMobjState(interptarg, R_GetTimeFrac(RTF_LEVEL), &interp);
|
||||
|
||||
dispoffset = thing->dispoffset;
|
||||
|
|
@ -5210,7 +5216,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
|
|||
// New colormap stuff for skins Tails 06-07-2002
|
||||
if (thing->colorized)
|
||||
{
|
||||
vis->colormap = R_GetTranslationColormap(TC_RAINBOW,
|
||||
vis->colormap = R_GetTranslationColormap(
|
||||
R_IsOverlayingInvinciblePlayer(thing) ? TC_BLINK : TC_RAINBOW,
|
||||
thing->color,
|
||||
GTC_CACHE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -679,7 +679,7 @@ static boolean K_BubbleReflectingTrapItem(const mobj_t *t)
|
|||
|
||||
static boolean K_StrongPlayerBump(const player_t *player)
|
||||
{
|
||||
return ((player->invincibilitytimer)
|
||||
return (((!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && (player->invincibilitytimer))
|
||||
|| (player->growshrinktimer > 0));
|
||||
}
|
||||
|
||||
|
|
@ -923,8 +923,15 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
|
|||
const boolean hyudoroT1 = (t1->player->hyudorotimer > 0);
|
||||
const boolean hyudoroT2 = (t2->player->hyudorotimer > 0);
|
||||
|
||||
boolean t1Condition = (t1->player->invincibilitytimer > 0);
|
||||
boolean t2Condition = (t2->player->invincibilitytimer > 0);
|
||||
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);
|
||||
}
|
||||
|
||||
if ((t1Condition == true || flameT1 == true) && (t2Condition == true || flameT2 == true))
|
||||
{
|
||||
|
|
@ -932,7 +939,7 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
|
|||
K_DoInstashield(t2->player);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
else if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))
|
||||
{
|
||||
if (t1Condition == true && t2Condition == false)
|
||||
{
|
||||
|
|
@ -945,10 +952,10 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
t1Condition = (t1->scale > t2->scale + (mapobjectscale/8));
|
||||
t2Condition = (t2->scale > t1->scale + (mapobjectscale/8));
|
||||
|
||||
|
||||
if ((t1Condition == true || flameT1 == true) && (t2Condition == true || flameT2 == true))
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
234
src/k_hud.c
234
src/k_hud.c
|
|
@ -161,6 +161,9 @@ static patch_t *kp_flamefire[18];
|
|||
// Frames of animation for the fire
|
||||
#define MAXFLAMOFIRETICS 8
|
||||
|
||||
// Rotating Alt. Invin. sparkles
|
||||
static patch_t *kp_altinvinsparkle;
|
||||
|
||||
static patch_t *kp_rankbumper;
|
||||
static patch_t *kp_tinybumper[2];
|
||||
static patch_t *kp_ranknobumpers;
|
||||
|
|
@ -416,6 +419,13 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_driftgaugeparts[2], "K_WDGM3");
|
||||
HU_UpdatePatch(&kp_driftgaugeparts[3], "K_WDGM4");
|
||||
HU_UpdatePatch(&kp_driftgaugeparts[4], "K_DGAU3M");
|
||||
|
||||
// Alt. Invin. Sparkles
|
||||
HU_UpdatePatch(&kp_altinvinsparkle, "ALTISPRK");
|
||||
|
||||
kp_altinvinsparkle->pivot.x = kp_altinvinsparkle->width / 2;
|
||||
kp_altinvinsparkle->pivot.y = kp_altinvinsparkle->height / 2;
|
||||
kp_altinvinsparkle->alignflags |= PATCHALIGN_USEPIVOTS;
|
||||
|
||||
// Flamometer UI Elements
|
||||
HU_UpdatePatch(&kp_flamometer[0], "THERMOBACK");
|
||||
|
|
@ -1284,6 +1294,21 @@ static void K_drawKartItem(void)
|
|||
else
|
||||
localpatch = kp_nodraw;
|
||||
}
|
||||
else if ((stplyr->invincibilitytimer) && (K_IsKartItemAlternate(KITEM_INVINCIBILITY)))
|
||||
{
|
||||
itembar = FixedDiv(stplyr->invincibilitytimer, max(1, stplyr->maxinvincibilitytime));
|
||||
|
||||
if (stplyr->invincibilitycancel > 0)
|
||||
flamebar = FixedDiv(stplyr->invincibilitycancel, 26);
|
||||
|
||||
if (leveltime & 1)
|
||||
{
|
||||
localpatch = K_GetCachedItemPatch(KITEM_INVINCIBILITY, tiny, 0);
|
||||
isalt = true;
|
||||
}
|
||||
else
|
||||
localpatch = kp_nodraw;
|
||||
}
|
||||
else if (K_GetShieldFromPlayer(stplyr) == KSHIELD_BUBBLE)
|
||||
{
|
||||
localpatch = K_GetCachedItemPatch(KITEM_BUBBLESHIELD, tiny, 0);
|
||||
|
|
@ -1439,7 +1464,7 @@ static void K_drawKartItem(void)
|
|||
V_DrawFixedPatch(fx<<FRACBITS, fy<<FRACBITS, FRACUNIT, V_HUDTRANS|fflags, K_getItemAltPatch(tiny, false), colmap);
|
||||
}
|
||||
|
||||
// Extensible meter, currently used by Grow, Rocket Sneakers and Flame Shield
|
||||
// Extensible meter, currently used by Invincibilty, Grow, Rocket Sneakers and Flame Shield
|
||||
// ...aren't you forgetting something?
|
||||
if (itembar != -1)
|
||||
K_DrawItemBar(fx, fy, fflags|V_HUDTRANS, itembar, (UINT8 []){0, 8, 12});
|
||||
|
|
@ -1801,6 +1826,15 @@ static void K_DrawKartPositionNum(INT32 num)
|
|||
}
|
||||
}
|
||||
|
||||
static UINT32 K_InvincibilityHUDVisibility(UINT16 t)
|
||||
{
|
||||
UINT32 alphalevel = st_translucency;
|
||||
|
||||
alphalevel = min(10, FixedMul(alphalevel, K_InvincibilityGradient(t)));
|
||||
|
||||
return min(9, 10 - alphalevel)<<V_ALPHASHIFT;
|
||||
}
|
||||
|
||||
static boolean K_RankIconCanSpinout(void)
|
||||
{
|
||||
return ((cv_spinoutroll.value) & 2);
|
||||
|
|
@ -1822,6 +1856,7 @@ static boolean K_drawKartPositionFaces(void)
|
|||
INT32 rankplayer[MAXPLAYERS];
|
||||
INT32 bumperx, numplayersingame = 0;
|
||||
UINT8 *colormap;
|
||||
UINT32 invinchudtrans;
|
||||
vector2_t offsets;
|
||||
|
||||
#ifdef ROTSPRITE
|
||||
|
|
@ -1943,6 +1978,14 @@ static boolean K_drawKartPositionFaces(void)
|
|||
|
||||
V_DrawMappedPatch(FACE_X + offsets.x, Y + offsets.y, V_HUDTRANS|V_SNAPTOLEFT, facerank, colormap);
|
||||
|
||||
if ((players[rankplayer[i]].invincibilitytimer) && (K_IsKartItemAlternate(KITEM_INVINCIBILITY)))
|
||||
{
|
||||
colormap = R_GetTranslationColormap(TC_BLINK, K_AltInvincibilityColor(leveltime / 2), GTC_CACHE);
|
||||
invinchudtrans = K_InvincibilityHUDVisibility(players[rankplayer[i]].invincibilitytimer);
|
||||
|
||||
V_DrawMappedPatch(FACE_X + offsets.x, Y + offsets.y, invinchudtrans|V_SNAPTOLEFT|V_ADD, facerank, colormap);
|
||||
}
|
||||
|
||||
if (LUA_HudEnabled(hud_battlebumpers))
|
||||
{
|
||||
if ((gametyperules & GTR_BUMPERS) && players[rankplayer[i]].bumper > 0)
|
||||
|
|
@ -2302,7 +2345,7 @@ void K_SetScoreboardModStatus(const char *name, SINT8 active)
|
|||
CONS_Alert(CONS_WARNING, "Server mod '%s' does not exist so status cannot be changed.\n", name);
|
||||
}
|
||||
|
||||
#define BASEMODS 15
|
||||
#define BASEMODS 16
|
||||
static void K_DrawServerMods(INT32 x, INT32 y)
|
||||
{
|
||||
UINT8 i, j;
|
||||
|
|
@ -2325,8 +2368,9 @@ static void K_DrawServerMods(INT32 x, INT32 y)
|
|||
{"Bump Spark", 0, &cv_kartbumpspark, -1, true},
|
||||
{"Bump Drift", 0, NULL, K_GetBumpSpark() > 0, true},
|
||||
{"Bump Spark", 0, NULL, K_GetBumpSpark() > BUMPSPARK_NOCHARGE, true},
|
||||
{"Bump Spring", 0, &cv_kartbumpspring, -1, 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++)
|
||||
|
|
@ -3959,10 +4003,16 @@ static void K_drawKartMinimap(void)
|
|||
spbdraw_t spb;
|
||||
UINT16 usecolor;
|
||||
boolean colorizeplayer;
|
||||
fixed_t invingradient = 0;
|
||||
|
||||
#ifdef ROTSPRITE
|
||||
angle_t rollangle = 0;
|
||||
INT32 rot = 0;
|
||||
INT32 sparkleflags;
|
||||
patch_t *rotsparkle;
|
||||
boolean halftrans = false;
|
||||
fixed_t transmul = 0;
|
||||
UINT32 invintrans = 0;
|
||||
#endif
|
||||
|
||||
vector2_t iconoffsets;
|
||||
|
|
@ -4176,9 +4226,11 @@ static void K_drawKartMinimap(void)
|
|||
|
||||
colorizeplayer = mobj->colorized;
|
||||
|
||||
if (players[i].invincibilitytimer)
|
||||
invingradient = K_InvincibilityGradient(players[i].invincibilitytimer);
|
||||
|
||||
if ((players[i].invincibilitytimer) && ((invingradient > (FRACUNIT/2)) || (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))))
|
||||
{
|
||||
usecolor = K_RainbowColor(leveltime / 2);
|
||||
usecolor = ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) ? K_AltInvincibilityColor(leveltime / 2) : K_RainbowColor(leveltime / 2));
|
||||
colorizeplayer = true;
|
||||
}
|
||||
else
|
||||
|
|
@ -4210,6 +4262,93 @@ 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))
|
||||
{
|
||||
// Draw Alt. Invin. sparkles
|
||||
halftrans =
|
||||
((splitflags & V_HUDTRANSHALF) == V_HUDTRANSHALF);
|
||||
transmul = 0;
|
||||
invintrans = 0;
|
||||
|
||||
sparkleflags =
|
||||
splitflags & (~(V_HUDTRANS | V_HUDTRANSHALF));
|
||||
|
||||
if (halftrans)
|
||||
{
|
||||
transmul = FRACUNIT -
|
||||
(V_GetHudTransHalf() * FRACUNIT / 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
transmul =
|
||||
FRACUNIT - (V_GetHudTrans() * FRACUNIT / 10);
|
||||
}
|
||||
|
||||
transmul *= 2;
|
||||
|
||||
invintrans =
|
||||
max(0,
|
||||
min(9,
|
||||
10 - FixedMul(FixedMul(10, invingradient),
|
||||
transmul)))
|
||||
<< V_ALPHASHIFT;
|
||||
sparkleflags |= invintrans;
|
||||
|
||||
if (kp_altinvinsparkle)
|
||||
{
|
||||
rot = R_GetRollAngle(-TICTOANGLE(leveltime));
|
||||
|
||||
if (rot)
|
||||
{
|
||||
rotsparkle = Patch_GetRotated(
|
||||
kp_altinvinsparkle, rot, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
rotsparkle = kp_altinvinsparkle;
|
||||
}
|
||||
|
||||
if (rotsparkle)
|
||||
{
|
||||
widthhalf = ((kp_altinvinsparkle->width) / 2);
|
||||
heighthalf = ((kp_altinvinsparkle->height) / 2);
|
||||
|
||||
if (cv_minihead.value)
|
||||
{
|
||||
adjustx = FixedMul(
|
||||
4,
|
||||
(widthhalf -
|
||||
kp_altinvinsparkle->leftoffset) *
|
||||
FRACUNIT / widthhalf);
|
||||
adjusty = FixedMul(
|
||||
4,
|
||||
(heighthalf -
|
||||
kp_altinvinsparkle->topoffset) *
|
||||
FRACUNIT / heighthalf);
|
||||
}
|
||||
|
||||
iconoffsets.x = widthhalf -
|
||||
kp_altinvinsparkle->leftoffset -
|
||||
adjustx;
|
||||
iconoffsets.y = heighthalf -
|
||||
kp_altinvinsparkle->topoffset -
|
||||
adjusty;
|
||||
|
||||
K_drawKartMinimapIcon(interpx,
|
||||
interpy,
|
||||
x,
|
||||
y,
|
||||
sparkleflags | V_ADD,
|
||||
rotsparkle,
|
||||
colormap,
|
||||
&iconoffsets);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mobj->player)
|
||||
{
|
||||
// Draw the Nametag
|
||||
|
|
@ -4413,8 +4552,13 @@ static void K_drawKartMinimap(void)
|
|||
#endif
|
||||
|
||||
colorizeplayer = mobj->colorized;
|
||||
invingradient =
|
||||
K_InvincibilityGradient(
|
||||
players[localplayers[i]].invincibilitytimer);
|
||||
|
||||
if (players[localplayers[i]].invincibilitytimer)
|
||||
if ((players[localplayers[i]].invincibilitytimer) &&
|
||||
((invingradient > (FRACUNIT / 2)) ||
|
||||
(!K_IsKartItemAlternate(KITEM_INVINCIBILITY))))
|
||||
{
|
||||
usecolor = (K_RainbowColor(leveltime / 2));
|
||||
colorizeplayer = true;
|
||||
|
|
@ -4483,6 +4627,84 @@ 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))
|
||||
{
|
||||
// Draw Alt. Invin. sparkles
|
||||
halftrans = ((splitflags & V_HUDTRANSHALF) == V_HUDTRANSHALF);
|
||||
transmul = 0;
|
||||
invintrans = 0;
|
||||
|
||||
sparkleflags = splitflags & (~(V_HUDTRANS | V_HUDTRANSHALF));
|
||||
|
||||
if (halftrans)
|
||||
{
|
||||
transmul = FRACUNIT - (V_GetHudTransHalf() * FRACUNIT / 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
transmul = FRACUNIT - (V_GetHudTrans() * FRACUNIT / 10);
|
||||
}
|
||||
|
||||
transmul *= 2;
|
||||
|
||||
invintrans =
|
||||
max(0,
|
||||
min(9,
|
||||
10 - FixedMul(FixedMul(10, invingradient), transmul)))
|
||||
<< V_ALPHASHIFT;
|
||||
sparkleflags |= invintrans;
|
||||
|
||||
if (kp_altinvinsparkle)
|
||||
{
|
||||
rot = R_GetRollAngle(-TICTOANGLE(leveltime));
|
||||
|
||||
if (rot)
|
||||
{
|
||||
rotsparkle = Patch_GetRotated(
|
||||
kp_altinvinsparkle, rot, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
rotsparkle = kp_altinvinsparkle;
|
||||
}
|
||||
|
||||
if (rotsparkle)
|
||||
{
|
||||
widthhalf = ((kp_altinvinsparkle->width) / 2);
|
||||
heighthalf = ((kp_altinvinsparkle->height) / 2);
|
||||
|
||||
if (cv_minihead.value)
|
||||
{
|
||||
adjustx = FixedMul(
|
||||
4,
|
||||
(widthhalf - kp_altinvinsparkle->leftoffset) *
|
||||
FRACUNIT / widthhalf);
|
||||
adjusty = FixedMul(
|
||||
4,
|
||||
(heighthalf - kp_altinvinsparkle->topoffset) *
|
||||
FRACUNIT / heighthalf);
|
||||
}
|
||||
|
||||
iconoffsets.x =
|
||||
widthhalf - kp_altinvinsparkle->leftoffset - adjustx;
|
||||
iconoffsets.y =
|
||||
heighthalf - kp_altinvinsparkle->topoffset - adjusty;
|
||||
|
||||
K_drawKartMinimapIcon(interpx,
|
||||
interpy,
|
||||
x,
|
||||
y,
|
||||
sparkleflags | V_ADD,
|
||||
rotsparkle,
|
||||
colormap,
|
||||
&iconoffsets);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Target reticule
|
||||
if ((gametype == GT_RACE && players[localplayers[i]].position == spbplace)
|
||||
|| ((gametyperules & GTR_WANTED) && K_IsPlayerWanted(&players[localplayers[i]])))
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
#include "d_player.h"
|
||||
#include "g_game.h"
|
||||
#include "info.h"
|
||||
/* include "m_easing.h" */
|
||||
#include "m_easing.h" // Invincibility gradienting
|
||||
#include "m_fixed.h"
|
||||
#include "m_random.h"
|
||||
#include "p_local.h"
|
||||
|
|
@ -470,7 +470,6 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush)
|
|||
return distance;
|
||||
}
|
||||
|
||||
/*
|
||||
#define INVODDS 30
|
||||
|
||||
// Prevent integer overflows; don't let this go past 16383
|
||||
|
|
@ -514,7 +513,6 @@ static INT32 K_KartGetInvincibilityOdds(UINT32 dist)
|
|||
}
|
||||
|
||||
#undef FRAC_95pct
|
||||
*/
|
||||
|
||||
// updates all result cooldown timers, and sets cooldowns for "unique" items
|
||||
void K_UpdateItemCooldown(void)
|
||||
|
|
@ -1518,9 +1516,8 @@ void K_SetPlayerItemCooldown(player_t *player, tic_t timer, boolean force)
|
|||
|
||||
// Unique odds functions, for REAL this time
|
||||
|
||||
// Alt. Invin. odds.
|
||||
// Leaving this around because it might have the chance to be repurposed in the future.
|
||||
/*INT32 KO_AltInvinOdds(INT32 odds, const kartroulette_t *roulette, const kartresult_t *result, UINT8 *forceme)
|
||||
// Alt. Invin. odds
|
||||
INT32 KO_AltInvinOdds(INT32 odds, const kartroulette_t *roulette, const kartresult_t *result, UINT8 *forceme)
|
||||
{
|
||||
(void)result;
|
||||
odds = K_KartGetInvincibilityOdds(roulette->clusterDist);
|
||||
|
|
@ -1538,7 +1535,7 @@ void K_SetPlayerItemCooldown(player_t *player, tic_t timer, boolean force)
|
|||
odds *= BASEODDSMUL;
|
||||
|
||||
return odds;
|
||||
}*/
|
||||
}
|
||||
|
||||
// SPB odds
|
||||
INT32 KO_SPBRaceOdds(INT32 odds, const kartroulette_t *roulette, const kartresult_t *result, UINT8 *forceme)
|
||||
|
|
@ -1994,7 +1991,7 @@ 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, 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 in Legacy, so you're free to waste it if you have multiple
|
||||
{
|
||||
K_DoInvincibility(player, K_GetInvincibilityTime(player));
|
||||
K_PlayPowerGloatSound(player->mo);
|
||||
|
|
|
|||
|
|
@ -211,7 +211,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_AltInvinOdds;
|
||||
useoddsfunc_f KO_SPBRaceOdds;
|
||||
|
||||
void K_DoThunderShield(player_t *player);
|
||||
|
|
|
|||
346
src/k_kart.c
346
src/k_kart.c
|
|
@ -309,9 +309,12 @@ void K_RegisterKartStuff(void)
|
|||
CV_RegisterVar(&cv_kartstacking_panel_separate);
|
||||
CV_RegisterVar(&cv_kartstacking_panel_maxgrade);
|
||||
|
||||
CV_RegisterVar(&cv_kartstacking_invincibility_speedboost);
|
||||
CV_RegisterVar(&cv_kartstacking_invincibility_accelboost);
|
||||
CV_RegisterVar(&cv_kartstacking_invincibility_handleboost);
|
||||
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_stackable);
|
||||
|
||||
CV_RegisterVar(&cv_kartstacking_grow_speedboost);
|
||||
|
|
@ -408,6 +411,12 @@ 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);
|
||||
|
||||
// experimental stuff
|
||||
CV_RegisterVar(&cv_kartbubble_defense_canidle);
|
||||
CV_RegisterVar(&cv_kartbubble_defense_damagerate);
|
||||
|
|
@ -490,12 +499,12 @@ fixed_t K_GetKartGameSpeedScalar(SINT8 value)
|
|||
|
||||
#define WORSTINVBUMPPOWER (FRACUNIT / 14)
|
||||
#define INVBUMPBOTTLENECK (FRACUNIT - (WORSTINVBUMPPOWER))
|
||||
#define BUBBLEBUMPBOTTLENECK (FRACUNIT / 150)
|
||||
|
||||
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;
|
||||
|
|
@ -511,6 +520,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)
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
// Applies rubberbanding, to prevent rubberbanding bots
|
||||
|
|
@ -519,24 +534,36 @@ static fixed_t K_PlayerWeight(mobj_t* mobj, mobj_t* against)
|
|||
|
||||
weight = (mobj->player->kartweight) * FRACUNIT;
|
||||
|
||||
if (K_GetShieldFromPlayer(mobj->player) == KSHIELD_BUBBLE)
|
||||
if (invinisalt && mobj->player->invincibilitytimer)
|
||||
{
|
||||
// Cap the gradient at 1.0 to prevent exaggerated nonsense.
|
||||
fixed_t mygradient = min(FRACUNIT, K_InvincibilityGradient(mobj->player->invincibilitytimer));
|
||||
|
||||
// Scale Alt. Invin. weight to your power. At full power, they get shoved off!
|
||||
// Might cause less shitty-feeling bumpcheck moments.
|
||||
weight = FixedMul(weight, mygradient);
|
||||
|
||||
// Like the Bubble Shield, nerf bumps a good bit to make them feel less ridiculous.
|
||||
// As your power depletes, this nerf gets less necessary, so scale it to match.
|
||||
weight = FixedMul(weight, FRACUNIT - FixedMul(INVBUMPBOTTLENECK, mygradient));
|
||||
}
|
||||
else if (K_GetShieldFromPlayer(mobj->player) == KSHIELD_BUBBLE && mobj->player->bubblecool == 0)
|
||||
{
|
||||
weight = max(BUBBLEMINWEIGHT, weight);
|
||||
bubbleMultiplier = BUBBLEBUMPBOTTLENECK;
|
||||
weight = FixedMul(weight, FRACUNIT / 16);
|
||||
}
|
||||
|
||||
if (mobj->player->speed > spd)
|
||||
weight += (mobj->player->speed - spd) / 8;
|
||||
|
||||
if (bubbleMultiplier)
|
||||
{
|
||||
weight = FixedMul(weight, bubbleMultiplier);
|
||||
}
|
||||
|
||||
if (mobj->player->speed > spd)
|
||||
weight += (mobj->player->speed - spd) / 8;
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
#undef BUBBLEBUMPBOTTLENECK
|
||||
#undef INVBUMPBOTTLENECK
|
||||
#undef WORSTINVBUMPPOWER
|
||||
|
||||
|
|
@ -960,6 +987,15 @@ 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)
|
||||
{
|
||||
// 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) << 1);
|
||||
fixed_t fac = CLAMP(FRACUNIT - invinoffroad, 0, FRACUNIT);
|
||||
|
||||
return FixedMul(offroad, fac);
|
||||
}
|
||||
|
||||
/** \brief Updates the Player's offroad value once per frame
|
||||
|
||||
\param player player object passed from K_KartPlayerThink
|
||||
|
|
@ -981,6 +1017,9 @@ static void K_UpdateOffroad(player_t *player)
|
|||
offroadstrength = K_CheckOffroadCollide(player->mo);
|
||||
}
|
||||
|
||||
// Gradient our offroad strength.
|
||||
offroadstrength = K_OffroadGradient(player, offroadstrength);
|
||||
|
||||
// If you are in offroad, a timer starts.
|
||||
if (offroadstrength)
|
||||
{
|
||||
|
|
@ -2118,7 +2157,7 @@ boolean K_ApplyOffroad(const player_t *player)
|
|||
if (modeattacking != ATTACKING_NONE)
|
||||
sneakertimer = player->sneakertimer > 0;
|
||||
|
||||
if (player->invincibilitytimer || player->hyudorotimer || sneakertimer)
|
||||
if (player->hyudorotimer || sneakertimer)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2439,24 +2478,93 @@ static inline fixed_t K_GetSneakerBoostSpeed(void)
|
|||
}
|
||||
}
|
||||
|
||||
// Used to determine the speed and power of Invincibility.
|
||||
fixed_t K_InvincibilityGradient(UINT16 time)
|
||||
{
|
||||
return (min(936, (fixed_t)time) * FRACUNIT / BASEINVINTIME);
|
||||
}
|
||||
|
||||
static fixed_t K_InvincibilityEasing(fixed_t x)
|
||||
{
|
||||
fixed_t u = max(FRACUNIT / 4, (min(32000, x) * FRACUNIT) / INVINDIST);
|
||||
|
||||
if (x < INVINDIST)
|
||||
return u;
|
||||
|
||||
u = max(0, (u - FRACUNIT));
|
||||
|
||||
if (u < FRACUNIT)
|
||||
return Easing_InCubic(u, FRACUNIT, (INVINMIDTIME/10));
|
||||
|
||||
return Easing_OutCubic(
|
||||
min(FRACUNIT, FixedMul(u - FRACUNIT, FRACUNIT/4)), (INVINMIDTIME/10), (INVINMAXTIME/10));
|
||||
}
|
||||
|
||||
UINT16 K_GetInvincibilityTime(player_t *player)
|
||||
{
|
||||
return BASEINVINTIME;
|
||||
UINT32 i, pingame;
|
||||
fixed_t distmul = FRACUNIT;
|
||||
|
||||
if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))
|
||||
return BASEINVINTIME;
|
||||
|
||||
pingame = 0;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS) || players[i].bumper)
|
||||
pingame++;
|
||||
|
||||
if (pingame > 1) // We only want to see if one player is playing.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pingame <= 1)
|
||||
{
|
||||
return BASEINVINTIME;
|
||||
}
|
||||
|
||||
if (K_LegacyOddsMode())
|
||||
{
|
||||
// Legacy waypointing is janky and finicky, so tack on a safety-net multiplier.
|
||||
// If an invincible player gets ahead of the cluster player, bottlenecking activates
|
||||
// regardless.
|
||||
distmul = LEGACYALTINVINMUL;
|
||||
}
|
||||
|
||||
fixed_t clustermul = K_InvincibilityEasing(FixedMul(player->distancefromcluster,distmul));
|
||||
UINT16 invintics = FixedMul(BASEINVINTIME, clustermul);
|
||||
|
||||
return max(MININVINTIME, invintics);
|
||||
}
|
||||
|
||||
fixed_t K_GetInvincibilitySpeed(UINT16 time)
|
||||
{
|
||||
return INVINSPEEDBOOST;
|
||||
if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))
|
||||
return INVINSPEEDBOOSTCLS;
|
||||
|
||||
fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time));
|
||||
return Easing_OutCubic(t, 0, INVINSPEEDBOOSTALT);
|
||||
}
|
||||
|
||||
fixed_t K_GetInvincibilityAccel(UINT16 time)
|
||||
{
|
||||
return INVINACCELBOOST;
|
||||
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)
|
||||
{
|
||||
return INVINHANDLEBOOST;
|
||||
if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))
|
||||
return INVINHANDLEBOOSTCLS;
|
||||
|
||||
fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time));
|
||||
return Easing_OutCubic(t, 0, INVINHANDLEBOOSTALT);
|
||||
}
|
||||
|
||||
static fixed_t diminish(fixed_t speedboost)
|
||||
|
|
@ -4853,15 +4961,47 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
player->invincibilitytimer = time;
|
||||
if (isalt)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
player->maxinvincibilitytime = player->invincibilitytimer;
|
||||
|
||||
if (player->maxinvincibilitytime <= MININVINTIME && isalt)
|
||||
{
|
||||
// Merritt suggestion: Kill bottlenecking if you get a short Invincibility.
|
||||
// Anti-bottleneck code 2: Signify to play the warning signal later than usual!
|
||||
player->invincibilitybottleneck = (UINT16)(-2);
|
||||
}
|
||||
|
||||
if (P_IsLocalPlayer(player) == true)
|
||||
{
|
||||
|
|
@ -7085,11 +7225,98 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
if (player->invincibilitytimer)
|
||||
{
|
||||
player->invincibilitytimer--;
|
||||
INT16 invinfac = 1;
|
||||
if ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) &&
|
||||
(player->invincibilitytimer > 2))
|
||||
{
|
||||
UINT32 invindist = INVINDIST >> 2;
|
||||
|
||||
// Value to subtract from the Invincibility timer during bottlenecking.
|
||||
INT16 invin_subtrahend = 1;
|
||||
|
||||
if ((INT16)(player->invincibilitybottleneck) >= 0)
|
||||
{
|
||||
if (player->distancefromcluster < invindist)
|
||||
{
|
||||
player->invincibilitybottleneck =
|
||||
min(256, player->invincibilitybottleneck + 4);
|
||||
invinfac = FixedMul(
|
||||
8,
|
||||
max(min(FRACUNIT,
|
||||
FRACUNIT - (player->distancefromcluster /
|
||||
(INVINDIST >> 2))),
|
||||
0));
|
||||
}
|
||||
else
|
||||
{
|
||||
player->invincibilitybottleneck =
|
||||
max(0, (INT32)(player->invincibilitybottleneck) - 2);
|
||||
}
|
||||
|
||||
invin_subtrahend =
|
||||
max(1,
|
||||
FixedMul((UINT16)invinfac,
|
||||
max(0, player->invincibilitybottleneck) << 8));
|
||||
}
|
||||
|
||||
player->invincibilitytimer = (UINT16)(max(
|
||||
2, (INT32)(player->invincibilitytimer) - invin_subtrahend));
|
||||
|
||||
const boolean warning_cond_standard =
|
||||
((K_InvincibilityGradient(player->invincibilitytimer) <
|
||||
(FRACHALF * invin_subtrahend)) &&
|
||||
(player->maxinvincibilitytime >= (BASEINVINTIME - TICRATE)));
|
||||
|
||||
const boolean warning_cond_nobottleneck =
|
||||
((K_InvincibilityGradient(player->invincibilitytimer) <
|
||||
SecsToFixedTens(MININVINTIME / 2)) &&
|
||||
(player->maxinvincibilitytime >= (MININVINTIME - TICRATE)));
|
||||
|
||||
const boolean warning_cond =
|
||||
((INT16)(player->invincibilitybottleneck) == -2)
|
||||
? warning_cond_nobottleneck
|
||||
: warning_cond_standard;
|
||||
|
||||
if (warning_cond)
|
||||
{
|
||||
if (!player->invincibilitywarning)
|
||||
{
|
||||
S_StartSound(player->mo, sfx_cdfm71);
|
||||
player->invincibilitywarning = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (((INT16)(player->invincibilitybottleneck) > 127) &&
|
||||
(!S_SoundPlaying(player->mo, sfx_s3kbes)))
|
||||
{
|
||||
S_StartSound(player->mo, sfx_s3kbes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player->invincibilitytimer--;
|
||||
|
||||
if (S_SoundPlaying(player->mo, sfx_s3kbes) &&
|
||||
K_IsKartItemAlternate(KITEM_INVINCIBILITY))
|
||||
{
|
||||
// Shut off the bottlenecker sound.
|
||||
S_StopSoundByID(player->mo, sfx_s3kbes);
|
||||
}
|
||||
|
||||
player->invincibilitybottleneck = 0;
|
||||
player->invincibilitywarning = 0;
|
||||
}
|
||||
|
||||
if (!player->invincibilitytimer)
|
||||
K_KartResetPlayerColor(player,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->invincibilitybottleneck = 0; // No need for bottlenecking.
|
||||
player->maxinvincibilitytime = 0;
|
||||
player->invincibilitywarning = 0;
|
||||
player->invincibilitycancel = -1;
|
||||
}
|
||||
|
||||
if (player->checkskip)
|
||||
player->checkskip--;
|
||||
|
|
@ -7432,16 +7659,26 @@ void K_KartResetPlayerColor(player_t *player, boolean disablecolor)
|
|||
|
||||
if (player->invincibilitytimer || player->powers[pw_invulnerability]) // You're gonna kiiiiill
|
||||
{
|
||||
fullbright = true;
|
||||
boolean skip = false;
|
||||
|
||||
player->mo->color = K_RainbowColor(leveltime / 2);
|
||||
|
||||
if (player->invincibilitytimer)
|
||||
if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))
|
||||
{
|
||||
player->mo->colorized = true;
|
||||
}
|
||||
fullbright = true;
|
||||
|
||||
goto finalise;
|
||||
player->mo->color = K_RainbowColor(leveltime / 2);
|
||||
|
||||
if (player->invincibilitytimer)
|
||||
{
|
||||
player->mo->colorized = true;
|
||||
}
|
||||
|
||||
skip = true;
|
||||
}
|
||||
|
||||
if (skip)
|
||||
{
|
||||
goto finalise;
|
||||
}
|
||||
}
|
||||
|
||||
if (player->growshrinktimer) // Ditto, for grow/shrink
|
||||
|
|
@ -8759,9 +8996,9 @@ 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 || player->sneakertimer ||
|
||||
player->bubbleboost || player->growshrinktimer > 0
|
||||
|| K_IsAltShrunk(player))
|
||||
if ((player->invincibilitytimer && (!K_IsKartItemAlternate(KITEM_INVINCIBILITY)))
|
||||
|| player->sneakertimer || player->bubbleboost ||
|
||||
player->growshrinktimer > 0 || K_IsAltShrunk(player))
|
||||
{
|
||||
turnvalue = FixedMul(turnvalue, FixedDiv(5 * FRACUNIT, 4 * FRACUNIT));
|
||||
}
|
||||
|
|
@ -8843,6 +9080,19 @@ static void K_SpawnDriftEFX(player_t *player,SINT8 level)
|
|||
}
|
||||
}
|
||||
|
||||
// Sliptide conditions for Alternative Invincibility.
|
||||
static boolean K_AltInvinSliptideCondition(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));
|
||||
}
|
||||
|
||||
fixed_t K_GetSpeedPercentage(const player_t *player)
|
||||
{
|
||||
if (!player)
|
||||
|
|
@ -8888,7 +9138,7 @@ boolean K_InterceptArrowBullet(player_t *player)
|
|||
if (!player)
|
||||
return false;
|
||||
|
||||
return ((player->invincibilitytimer) || (player->growshrinktimer > 0) || (player->flamestore));
|
||||
return ((player->invincibilitytimer && !K_IsKartItemAlternate(KITEM_INVINCIBILITY)) || (player->growshrinktimer > 0) || (player->flamestore));
|
||||
}
|
||||
|
||||
// 0.25 fracunits
|
||||
|
|
@ -8902,7 +9152,7 @@ static boolean K_OtherSliptideCondition(player_t* player)
|
|||
return false;
|
||||
|
||||
return (
|
||||
K_AltShrinkSliptideCondition(player) ||
|
||||
K_AltInvinSliptideCondition(player) || K_AltShrinkSliptideCondition(player) ||
|
||||
(cv_handleboostslip.value && (player->handleboost >= HANDLEBOOSTTHRESHOLD)));
|
||||
}
|
||||
|
||||
|
|
@ -9405,6 +9655,7 @@ static UINT32 K_UpdateDistanceFromCluster(player_t* player)
|
|||
if (pingame <= 1)
|
||||
{
|
||||
// There's only us around.
|
||||
player->invincibilitybottleneck = (UINT16)(-1); // No bottlenecking!
|
||||
return 0;
|
||||
}
|
||||
else if ((pingame == 3))
|
||||
|
|
@ -10140,6 +10391,8 @@ void K_StripOther(player_t *player)
|
|||
player->roulettetype = KROULETTETYPE_NORMAL;
|
||||
|
||||
player->invincibilitytimer = 0;
|
||||
player->invincibilitywarning = 0;
|
||||
player->invincibilitycancel = -1;
|
||||
|
||||
if (player->growshrinktimer)
|
||||
{
|
||||
|
|
@ -10360,6 +10613,14 @@ INT32 K_GetShieldFromItem(INT32 item)
|
|||
}
|
||||
}
|
||||
|
||||
static boolean K_InvincibilitySlotHogging(player_t *player)
|
||||
{
|
||||
if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))
|
||||
return false;
|
||||
|
||||
return ((player->invincibilitytimer) != 0);
|
||||
}
|
||||
|
||||
//
|
||||
// K_MoveKartPlayer
|
||||
//
|
||||
|
|
@ -10396,6 +10657,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
|| player->itemroulette
|
||||
|| player->rocketsneakertimer
|
||||
|| player->eggmanexplode
|
||||
|| ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && player->invincibilitytimer)
|
||||
|| (player->growshrinktimer > 0)
|
||||
|| player->flametimer
|
||||
|| (leveltime < starttime)
|
||||
|
|
@ -10606,6 +10868,32 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->growcancel = 0;
|
||||
}
|
||||
}
|
||||
// Invincibility
|
||||
else if (K_InvincibilitySlotHogging(player))
|
||||
{
|
||||
// (Alternate) Cancel Invincibility
|
||||
if (player->invincibilitycancel >= 0)
|
||||
{
|
||||
if (buttons & BT_ATTACK)
|
||||
{
|
||||
player->invincibilitycancel++;
|
||||
if (player->invincibilitycancel > 25)
|
||||
{
|
||||
// Don't fully cancel due to how the music handling works.
|
||||
player->invincibilitytimer = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
player->invincibilitycancel = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((buttons & BT_ATTACK) || (player->oldcmd.buttons & BT_ATTACK))
|
||||
player->invincibilitycancel = -1;
|
||||
else
|
||||
player->invincibilitycancel = 0;
|
||||
}
|
||||
}
|
||||
else if (player->itemamount == 0)
|
||||
{
|
||||
K_UnsetItemOut(player);
|
||||
|
|
|
|||
17
src/k_kart.h
17
src/k_kart.h
|
|
@ -29,6 +29,7 @@ Make sure this matches the actual number of states
|
|||
*/
|
||||
#define KART_NUMINVSPARKLESANIM 12
|
||||
#define BASEINVINTIME (10 * TICRATE)
|
||||
#define MININVINTIME (7 * TICRATE)
|
||||
|
||||
#define GROW_SCALE ((3*FRACUNIT)/2)
|
||||
#define SHRINK_SCALE ((6*FRACUNIT)/8)
|
||||
|
|
@ -84,6 +85,12 @@ 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)
|
||||
|
||||
|
|
@ -107,9 +114,12 @@ extern vector3_t clusterpoint, clusterdtf;
|
|||
#define SEPARATEPANELS CV_Get(&cv_kartstacking_panel_separate)
|
||||
#define MAXPANELSTACK CV_Get(&cv_kartstacking_panel_maxgrade)
|
||||
|
||||
#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 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 INVINSTACKABLE CV_Get(&cv_kartstacking_invincibility_stackable)
|
||||
|
||||
#define GROWSPEEDBOOST CV_Get(&cv_kartstacking_grow_speedboost)
|
||||
|
|
@ -271,6 +281,7 @@ void K_ResetPogoSpring(player_t *player);
|
|||
extern boolean forcefullinvintheme;
|
||||
boolean K_PlayFullInvinTheme(void);
|
||||
void K_DoInvincibility(player_t *player, tic_t time);
|
||||
fixed_t K_InvincibilityGradient(UINT16 time);
|
||||
UINT16 K_GetInvincibilityTime(player_t *player);
|
||||
fixed_t K_GetInvincibilitySpeed(UINT16 time);
|
||||
fixed_t K_GetInvincibilityAccel(UINT16 time);
|
||||
|
|
|
|||
|
|
@ -4483,6 +4483,15 @@ static int lib_kGetNewSpeed(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int lib_kInvincibilityGradient(lua_State *L)
|
||||
{
|
||||
UINT16 time = (UINT16)luaL_checkinteger(L, 1);
|
||||
// HUDSAFE
|
||||
|
||||
lua_pushinteger(L, K_InvincibilityGradient(time));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_kGetInvincibilitySpeed(lua_State *L)
|
||||
{
|
||||
UINT16 time = (UINT16)luaL_checkinteger(L, 1);
|
||||
|
|
@ -5727,6 +5736,7 @@ 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_3dKartMovement", lib_k3dKartMovement},
|
||||
|
|
|
|||
|
|
@ -413,6 +413,10 @@ static int lib_lenLocalplayers(lua_State *L)
|
|||
X(arrowbullet) \
|
||||
X(rocketsneakertimer) \
|
||||
X(invincibilitytimer) \
|
||||
X(maxinvincibilitytime) \
|
||||
X(invincibilitybottleneck) \
|
||||
X(invincibilitycancel) \
|
||||
X(invincibilitywarning) \
|
||||
X(eggmanexplode) \
|
||||
X(eggmanblame) \
|
||||
X(bananadrag) \
|
||||
|
|
@ -892,6 +896,19 @@ static int player_get(lua_State *L)
|
|||
case player_invincibilitytimer:
|
||||
lua_pushinteger(L, plr->invincibilitytimer);
|
||||
break;
|
||||
case player_maxinvincibilitytime:
|
||||
lua_pushinteger(L, plr->maxinvincibilitytime);
|
||||
break;
|
||||
case player_invincibilitybottleneck:
|
||||
// Push as an INT16 due to the negative value signal systems.
|
||||
lua_pushinteger(L, (INT16)plr->invincibilitybottleneck);
|
||||
break;
|
||||
case player_invincibilitycancel:
|
||||
lua_pushinteger(L, plr->invincibilitycancel);
|
||||
break;
|
||||
case player_invincibilitywarning:
|
||||
lua_pushboolean(L, (boolean)plr->invincibilitywarning);
|
||||
break;
|
||||
case player_eggmanexplode:
|
||||
lua_pushinteger(L, plr->eggmanexplode);
|
||||
break;
|
||||
|
|
@ -1673,6 +1690,21 @@ static int player_set(lua_State *L)
|
|||
case player_invincibilitytimer:
|
||||
plr->invincibilitytimer = luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case player_maxinvincibilitytime:
|
||||
{
|
||||
UINT16 maxinv = max(1, (UINT16)luaL_checkinteger(L, 3)); // Prevent zero-divides
|
||||
plr->maxinvincibilitytime = maxinv;
|
||||
break;
|
||||
}
|
||||
case player_invincibilitybottleneck:
|
||||
plr->invincibilitybottleneck = (UINT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case player_invincibilitycancel:
|
||||
plr->invincibilitycancel = (INT16)luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case player_invincibilitywarning:
|
||||
plr->invincibilitywarning = (UINT8)luaL_checkboolean(L, 3);
|
||||
break;
|
||||
case player_eggmanexplode:
|
||||
plr->eggmanexplode = luaL_checkinteger(L, 3);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -155,6 +155,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->growshrinktimer > 0)
|
||||
|| player->flametimer)
|
||||
return false;
|
||||
|
|
|
|||
70
src/p_mobj.c
70
src/p_mobj.c
|
|
@ -6860,6 +6860,71 @@ static void P_RemoveOverlay(mobj_t *thing)
|
|||
}
|
||||
}
|
||||
|
||||
static UINT32 P_GetTranslucencyForInvincibility(mobj_t *mo)
|
||||
{
|
||||
if (!mo->player)
|
||||
{
|
||||
// Get out.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return max(0, min(9, 10 - FixedMul(10, K_InvincibilityGradient(mo->player->invincibilitytimer))))<<RF_TRANSSHIFT;
|
||||
}
|
||||
|
||||
// Called only when MT_OVERLAY thinks.
|
||||
static void P_PlayerInvincibilityOverlay(mobj_t *thing)
|
||||
{
|
||||
I_Assert(thing->target != NULL);
|
||||
I_Assert(thing->target->player != NULL);
|
||||
|
||||
if (!thing->target->player->invincibilitytimer)
|
||||
{
|
||||
P_SetTarget(&thing->target, NULL);
|
||||
|
||||
I_Assert(thing->target == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
thing->destscale = thing->target->scale;
|
||||
|
||||
if (thing->target->eflags & MFE_VERTICALFLIP)
|
||||
{
|
||||
thing->eflags |= MFE_VERTICALFLIP;
|
||||
thing->z += thing->target->height - thing->height;
|
||||
}
|
||||
|
||||
thing->color = K_AltInvincibilityColor(leveltime / 2);
|
||||
thing->colorized = true;
|
||||
thing->dispoffset = min(2, thing->target->dispoffset + 1);
|
||||
|
||||
thing->angle = (thing->target->player ? thing->target->player->drawangle : thing->target->angle);
|
||||
|
||||
// Rotation is handled in r_patchrotation
|
||||
|
||||
thing->sprite = thing->target->sprite;
|
||||
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->skin = thing->target->skin;
|
||||
thing->standingslope = thing->target->standingslope;
|
||||
|
||||
thing->sprxoff = thing->target->sprxoff;
|
||||
thing->spryoff = thing->target->spryoff;
|
||||
thing->sprzoff = thing->target->sprzoff;
|
||||
|
||||
thing->spritexscale = thing->target->spritexscale;
|
||||
thing->spriteyscale = thing->target->spriteyscale;
|
||||
thing->spritexoffset = thing->target->spritexoffset;
|
||||
thing->spriteyoffset = thing->target->spriteyoffset;
|
||||
|
||||
if (thing->target->flags2 & MF2_OBJECTFLIP)
|
||||
thing->flags2 |= MF2_OBJECTFLIP;
|
||||
|
||||
if (!(thing->target->flags & MF_DONTENCOREMAP))
|
||||
thing->flags &= ~MF_DONTENCOREMAP;
|
||||
}
|
||||
|
||||
static void P_MobjScaleThink(mobj_t *mobj)
|
||||
{
|
||||
fixed_t oldheight = mobj->height;
|
||||
|
|
@ -7205,6 +7270,11 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
else
|
||||
{
|
||||
P_AddOverlay(mobj);
|
||||
if ((mobj->extravalue2) && (mobj->target->player))
|
||||
{
|
||||
// Could be overlaying an invincible player.
|
||||
P_PlayerInvincibilityOverlay(mobj);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MT_WATERDROP:
|
||||
|
|
|
|||
|
|
@ -711,6 +711,10 @@ 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].eggmanexplode);
|
||||
SYNC(players[i].eggmanblame);
|
||||
|
|
|
|||
|
|
@ -2309,7 +2309,10 @@ void P_MovePlayer(player_t *player)
|
|||
&& onground && (leveltime & 1))
|
||||
K_SpawnBoostTrail(player);
|
||||
|
||||
if (player->invincibilitytimer > 0)
|
||||
if ((player->invincibilitytimer > 0) &&
|
||||
(((leveltime %
|
||||
max(1, 10 - FixedMul(9, K_InvincibilityGradient(player->invincibilitytimer)))) == 0) ||
|
||||
(!K_IsKartItemAlternate(KITEM_INVINCIBILITY))))
|
||||
{
|
||||
K_SpawnSparkleTrail(player->mo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ patch_t *Patch_GetRotatedSprite(
|
|||
void *info, INT32 rotationangle);
|
||||
|
||||
INT32 R_GetRollAngle(angle_t rollangle);
|
||||
boolean R_IsOverlayingInvinciblePlayer(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);
|
||||
|
|
|
|||
|
|
@ -82,6 +82,14 @@ 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)
|
||||
{
|
||||
return ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && (mobj->type == MT_OVERLAY) &&
|
||||
(mobj->target) && (mobj->extravalue2) && (mobj->target->player) &&
|
||||
(mobj->target->player->invincibilitytimer));
|
||||
}
|
||||
|
||||
angle_t R_ModelRotationAngle(mobj_t *mobj, player_t *viewPlayer)
|
||||
{
|
||||
angle_t rollAngle = mobj->rollangle;
|
||||
|
|
@ -90,13 +98,26 @@ angle_t R_ModelRotationAngle(mobj_t *mobj, player_t *viewPlayer)
|
|||
{
|
||||
rollAngle += R_PlayerSpriteRotation(mobj->player, viewPlayer);
|
||||
}
|
||||
else if (R_IsOverlayingInvinciblePlayer(mobj))
|
||||
{
|
||||
rollAngle += R_PlayerSpriteRotation(mobj->target->player, viewPlayer);
|
||||
}
|
||||
|
||||
return rollAngle;
|
||||
}
|
||||
|
||||
angle_t R_SpriteRotationAngle(mobj_t *mobj, player_t *viewPlayer, interpmobjstate_t *interp)
|
||||
{
|
||||
angle_t rollOrPitch = R_GetPitchRollAngle(mobj, viewPlayer, interp);
|
||||
angle_t rollOrPitch;
|
||||
|
||||
if (R_IsOverlayingInvinciblePlayer(mobj))
|
||||
{
|
||||
rollOrPitch = R_GetPitchRollAngle(mobj->target, viewPlayer, interp);
|
||||
}
|
||||
else
|
||||
{
|
||||
rollOrPitch = R_GetPitchRollAngle(mobj, viewPlayer, interp);
|
||||
}
|
||||
return (rollOrPitch + R_ModelRotationAngle(mobj, viewPlayer));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -922,7 +922,7 @@ UINT8 *R_GetSpriteTranslation(vissprite_t *vis)
|
|||
|
||||
if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized)
|
||||
{
|
||||
return R_GetTranslationColormap(TC_RAINBOW,
|
||||
return R_GetTranslationColormap(R_IsOverlayingInvinciblePlayer(vis->mobj) ? TC_BLINK : TC_RAINBOW,
|
||||
static_cast<skincolornum_t>(vis->mobj->color),
|
||||
GTC_CACHE);
|
||||
}
|
||||
|
|
@ -1832,6 +1832,12 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
interpmobjstate_t interp = {0};
|
||||
mobj_t *interptarg = thing;
|
||||
|
||||
if (R_IsOverlayingInvinciblePlayer(thing))
|
||||
{
|
||||
// Kill overlay misalignment
|
||||
interptarg = thing->target;
|
||||
}
|
||||
|
||||
// do interpolation
|
||||
R_InterpolateMobjState(interptarg, R_GetTimeFrac(RTF_LEVEL), &interp);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue