Bubble Shield adjustments
- Players with inflated Bubble Shields now ignore collisions with anything the shield itself is supposed to reflect - If a player happens to still collide with a reflectable in this state, they noclip through and a ``bubblegraze`` value increments - ``bubblegraze``, like ``justbumped``, prevents K_KartBouncing collisions for some time - Falling rocks can now be reflected by Bubble Shields - 1.5 seconds of flashtics applied to players whose (inflated) Bubble Shields are shattered
This commit is contained in:
parent
9a39b24d28
commit
b46a51607f
7 changed files with 175 additions and 5 deletions
|
|
@ -465,6 +465,17 @@ typedef enum
|
|||
// Delay-drift: Time the game is given to predict a "wanted" drift
|
||||
#define DRIFT_DELAY_TIME (7)
|
||||
|
||||
#define BUBBLEGRAZE_INCREMENT (2)
|
||||
|
||||
#if ((BUBBLEGRAZE_INCREMENT / 2) < 1)
|
||||
#define BUBBLEGRAZE_SOFTINCREMENT (1)
|
||||
#else
|
||||
#define BUBBLEGRAZE_SOFTINCREMENT (BUBBLEGRAZE_INCREMENT / 2)
|
||||
#endif
|
||||
|
||||
#define BUBBLEGRAZE_DECREMENT (1)
|
||||
#define BUBBLEGRAZE_MAX (0x3FFFFFFF)
|
||||
|
||||
// enum for saved lap times
|
||||
typedef enum
|
||||
{
|
||||
|
|
@ -702,6 +713,11 @@ struct player_t
|
|||
UINT8 bubbleblowup; // Bubble Shield usage blowup
|
||||
UINT8 bubblehealth; // Bubble Shield health
|
||||
UINT16 bubbleboost; // Bubble shield boost timer
|
||||
|
||||
// Specific variant of justbumped where skimming a player with an inflated
|
||||
// Bubble Shield increments this.
|
||||
UINT32 bubblegraze;
|
||||
|
||||
tic_t bubblebuffer; // Prevents Bubble Shield from taking damage
|
||||
|
||||
UINT16 flamedash; // Flame Shield dash power
|
||||
|
|
|
|||
|
|
@ -713,6 +713,14 @@ static void K_BubbleShieldCollideDrain(player_t *player, mobj_t *bubble, INT16 d
|
|||
player->bubbleblowup /= 2;
|
||||
}
|
||||
|
||||
boolean K_BubbleShieldReflectSpecialCase(mobj_t *t)
|
||||
{
|
||||
if ((!t) || (P_MobjWasRemoved(t)))
|
||||
return false; // Object doesn't even exist
|
||||
|
||||
return t->type == MT_FALLINGROCK; // TODO: Maybe an object flag (MF_BUBBLEREFLECT)?
|
||||
}
|
||||
|
||||
static boolean K_BubbleReflectingTrapItem(const mobj_t *t)
|
||||
{
|
||||
// slow orbis are traps
|
||||
|
|
@ -721,7 +729,7 @@ static boolean K_BubbleReflectingTrapItem(const mobj_t *t)
|
|||
|
||||
return t->type == MT_BANANA || (t->type == MT_ORBINAUT && t->flags2 & MF2_AMBUSH) || t->type == MT_JAWZ_DUD ||
|
||||
t->type == MT_EGGMANITEM || t->type == MT_SSMINE || t->type == MT_SSMINE_SHIELD || t->type == MT_LANDMINE ||
|
||||
t->type == MT_EGGMINE;
|
||||
t->type == MT_EGGMINE || K_BubbleShieldReflectSpecialCase(t);
|
||||
}
|
||||
|
||||
static boolean K_StrongPlayerBump(const player_t *player)
|
||||
|
|
@ -782,7 +790,7 @@ boolean K_BubbleShieldCanReflect(mobj_t *t)
|
|||
return (t->type == MT_ORBINAUT || t->type == MT_JAWZ || t->type == MT_JAWZ_DUD
|
||||
|| t->type == MT_BANANA || t->type == MT_EGGMANITEM || t->type == MT_BALLHOG
|
||||
|| t->type == MT_SSMINE || t->type == MT_LANDMINE || t->type == MT_SINK || t->type == MT_EGGMINE
|
||||
|| t->type == MT_KART_LEFTOVER
|
||||
|| t->type == MT_KART_LEFTOVER || K_BubbleShieldReflectSpecialCase(t)
|
||||
|| t->type == MT_PLAYER);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ void K_ThunderShieldAttack(mobj_t *actor, fixed_t size);
|
|||
|
||||
boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2);
|
||||
boolean K_BubbleShieldCanReflect(mobj_t *t);
|
||||
boolean K_BubbleShieldReflectSpecialCase(mobj_t *t);
|
||||
|
||||
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2);
|
||||
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2);
|
||||
|
|
|
|||
28
src/k_kart.c
28
src/k_kart.c
|
|
@ -846,6 +846,23 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean sol
|
|||
return false;
|
||||
}
|
||||
|
||||
// Don't bump if you've bubble-grazed
|
||||
if (mobj1->player && mobj1->player->bubblegraze)
|
||||
{
|
||||
mobj1->player->bubblegraze = ApproachOneWayUINT32(
|
||||
mobj1->player->bubblegraze, BUBBLEGRAZE_MAX, BUBBLEGRAZE_SOFTINCREMENT);
|
||||
mobj1->player->justbumped = bumptime;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mobj2->player && mobj2->player->bubblegraze)
|
||||
{
|
||||
mobj2->player->bubblegraze = ApproachOneWayUINT32(
|
||||
mobj2->player->bubblegraze, BUBBLEGRAZE_MAX, BUBBLEGRAZE_SOFTINCREMENT);
|
||||
mobj2->player->justbumped = bumptime;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't bump if you're flipping over
|
||||
if (mobj1->player && mobj1->player->flipovertimer)
|
||||
{
|
||||
|
|
@ -5478,6 +5495,12 @@ void K_RemoveBubbleHealth(player_t *player, INT16 sub)
|
|||
|
||||
if (player->bubblehealth <= 0)
|
||||
{
|
||||
if (player->bubbleblowup)
|
||||
{
|
||||
// 1.5 seconds of i-frames for better gamefeel on shatters
|
||||
player->flashing = (UINT32)((float)(TICRATE) * 1.5f);
|
||||
}
|
||||
|
||||
K_PopPlayerShield(player);
|
||||
}
|
||||
else
|
||||
|
|
@ -7673,6 +7696,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
if (player->justbumped > 0)
|
||||
player->justbumped--;
|
||||
|
||||
if (player->bubblegraze > 0)
|
||||
{
|
||||
player->bubblegraze = ApproachOneWayUINT32(player->bubblegraze, 0, BUBBLEGRAZE_DECREMENT);
|
||||
}
|
||||
|
||||
if (player->outruntime > 0)
|
||||
player->outruntime--;
|
||||
|
||||
|
|
|
|||
|
|
@ -399,6 +399,7 @@ static int lib_lenLocalplayers(lua_State *L)
|
|||
X(bubbleblowup) \
|
||||
X(bubblehealth) \
|
||||
X(bubbleboost) \
|
||||
X(bubblegraze) \
|
||||
X(flamedash) \
|
||||
X(flametimer) \
|
||||
X(flamestore) \
|
||||
|
|
@ -861,6 +862,9 @@ static int player_get(lua_State *L)
|
|||
case player_bubbleboost:
|
||||
lua_pushinteger(L, plr->bubbleboost);
|
||||
break;
|
||||
case player_bubblegraze:
|
||||
lua_pushinteger(L, plr->bubblegraze);
|
||||
break;
|
||||
case player_flamedash:
|
||||
lua_pushinteger(L, plr->flamedash);
|
||||
break;
|
||||
|
|
@ -1656,6 +1660,9 @@ static int player_set(lua_State *L)
|
|||
case player_bubbleboost:
|
||||
plr->bubbleboost = luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case player_bubblegraze:
|
||||
plr->bubblegraze = luaL_checkinteger(L, 3);
|
||||
break;
|
||||
case player_flamedash:
|
||||
plr->flamedash = luaL_checkinteger(L, 3);
|
||||
break;
|
||||
|
|
|
|||
115
src/p_map.c
115
src/p_map.c
|
|
@ -548,6 +548,11 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
{
|
||||
fixed_t blockdist;
|
||||
boolean shrinkleeway = false;
|
||||
boolean bubbleleeway = false, movingbubble = false, movedbubble = false;
|
||||
|
||||
// Bubble Shield special case: unconditionally process collision for this object so the
|
||||
// Bubble Shield can reflect it.
|
||||
boolean bubblewantsreflect = false;
|
||||
|
||||
if (g_tm.thing == NULL || P_MobjWasRemoved(g_tm.thing) == true)
|
||||
return BMIT_STOP; // func just popped our g_tm.thing, cannot continue.
|
||||
|
|
@ -565,8 +570,54 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
|| (thing->player && thing->player->spectator))
|
||||
return BMIT_CONTINUE;
|
||||
|
||||
if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE/*|MF_SPRING*/))) // we still use MF_SOLID for springs
|
||||
return BMIT_CONTINUE;
|
||||
// Check for players with inflated Bubble Shields
|
||||
if (g_tm.thing->player && K_IsBubbleDefending(g_tm.thing->player))
|
||||
movingbubble = true;
|
||||
|
||||
if (thing->player && K_IsBubbleDefending(thing->player))
|
||||
movedbubble = true;
|
||||
|
||||
if (movingbubble || movedbubble)
|
||||
bubbleleeway = true;
|
||||
|
||||
/*
|
||||
* "Why does this exist?" Well...
|
||||
* Falling rocks don't have the needed flags to process collisions further, when the Bubble
|
||||
* Shield is the one checking for collisions (and thus things to reflect). At the same time,
|
||||
* when falling rocks are checking for collision, the Bubble Shield has its noclip flags
|
||||
* enabled, meaning it's ALSO never checked.
|
||||
* So, how do we solve the problem? This shitty special-case bandaid.
|
||||
*/
|
||||
|
||||
boolean _playerinflate = false;
|
||||
|
||||
if (g_tm.thing->type == MT_BUBBLESHIELD)
|
||||
{
|
||||
_playerinflate =
|
||||
(g_tm.thing->target && (!P_MobjWasRemoved(g_tm.thing->target)) &&
|
||||
(g_tm.thing->target->player) && (g_tm.thing->target->player->bubbleblowup));
|
||||
|
||||
bubblewantsreflect =
|
||||
((_playerinflate) && (!(g_tm.thing->flags & (MF_NOCLIP | MF_NOCLIPTHING))) &&
|
||||
(K_BubbleShieldReflectSpecialCase(thing)));
|
||||
}
|
||||
else if (thing->type == MT_BUBBLESHIELD)
|
||||
{
|
||||
_playerinflate =
|
||||
(g_tm.thing->target && (!P_MobjWasRemoved(g_tm.thing->target)) &&
|
||||
(g_tm.thing->target->player) && (g_tm.thing->target->player->bubbleblowup));
|
||||
|
||||
bubblewantsreflect =
|
||||
((_playerinflate) && (!(thing->flags & (MF_NOCLIP | MF_NOCLIPTHING))) &&
|
||||
(K_BubbleShieldReflectSpecialCase(g_tm.thing)));
|
||||
}
|
||||
|
||||
if ((thing->flags & MF_NOCLIPTHING) ||
|
||||
!((thing->flags & (MF_SOLID | MF_SPECIAL | MF_PAIN | MF_SHOOTABLE /*|MF_SPRING*/)) ||
|
||||
bubblewantsreflect)) // we still use MF_SOLID for springs
|
||||
{
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
// Get rid of the "just flipped" flag.
|
||||
// We only use that to confirm flipover hits.
|
||||
|
|
@ -745,6 +796,38 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
if (thing->type == MT_BUBBLESHIELD || g_tm.thing->type == MT_BUBBLESHIELD)
|
||||
return BMIT_CONTINUE;
|
||||
|
||||
// Triple-check: anything the Bubble Shield reflects should phase through players inflating their shield.
|
||||
if (bubbleleeway)
|
||||
{
|
||||
// see if it went over / under
|
||||
if (g_tm.thing->z > thing->z + thing->height)
|
||||
return BMIT_CONTINUE; // overhead
|
||||
if (g_tm.thing->z + g_tm.thing->height < thing->z)
|
||||
return BMIT_CONTINUE; // underneath
|
||||
|
||||
if (movingbubble && K_BubbleShieldCanReflect(thing))
|
||||
{
|
||||
g_tm.thing->player->bubblegraze =
|
||||
ApproachOneWayUINT32(g_tm.thing->player->bubblegraze,
|
||||
BUBBLEGRAZE_MAX,
|
||||
BUBBLEGRAZE_INCREMENT);
|
||||
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (movedbubble && K_BubbleShieldCanReflect(g_tm.thing))
|
||||
{
|
||||
thing->player->bubblegraze =
|
||||
ApproachOneWayUINT32(thing->player->bubblegraze,
|
||||
BUBBLEGRAZE_MAX,
|
||||
BUBBLEGRAZE_INCREMENT);
|
||||
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
// Anything else falls through as a possible false positive.
|
||||
}
|
||||
|
||||
if (thing->flags & MF_PAIN)
|
||||
{ // Player touches painful thing sitting on the floor
|
||||
// see if it went over / under
|
||||
|
|
@ -1330,10 +1413,33 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
// If we're inflating, don't do PvP bumps.
|
||||
// I do not doubt the previous bubbleleeway check'll fall through, so, yeah.
|
||||
if (bubbleleeway)
|
||||
{
|
||||
if (movingbubble)
|
||||
{
|
||||
g_tm.thing->player->bubblegraze =
|
||||
ApproachOneWayUINT32(g_tm.thing->player->bubblegraze,
|
||||
BUBBLEGRAZE_MAX,
|
||||
BUBBLEGRAZE_INCREMENT);
|
||||
}
|
||||
|
||||
if (movedbubble)
|
||||
{
|
||||
thing->player->bubblegraze =
|
||||
ApproachOneWayUINT32(thing->player->bubblegraze,
|
||||
BUBBLEGRAZE_MAX,
|
||||
BUBBLEGRAZE_INCREMENT);
|
||||
}
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (thing->player->squishedtimer || thing->player->hyudorotimer
|
||||
|| thing->player->justbumped || thing->scale > g_tm.thing->scale + (mapobjectscale/8)
|
||||
|| g_tm.thing->player->squishedtimer || g_tm.thing->player->hyudorotimer
|
||||
|| g_tm.thing->player->justbumped || g_tm.thing->scale > thing->scale + (mapobjectscale/8))
|
||||
|| g_tm.thing->player->justbumped || g_tm.thing->scale > thing->scale + (mapobjectscale/8)
|
||||
|| thing->player->bubblegraze || g_tm.thing->player->bubblegraze)
|
||||
{
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
|
@ -1453,6 +1559,9 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
}
|
||||
else if (thing->type == MT_KART_LEFTOVER)
|
||||
{
|
||||
if (bubbleleeway)
|
||||
return BMIT_CONTINUE; // If we're inflating, don't do PvP bumps.
|
||||
|
||||
// see if it went over / under
|
||||
if (g_tm.thing->z > thing->z + thing->height)
|
||||
return BMIT_CONTINUE; // overhead
|
||||
|
|
|
|||
|
|
@ -725,6 +725,7 @@ static void P_NetSyncPlayers(savebuffer_t *save)
|
|||
SYNC(players[i].bubbleblowup);
|
||||
SYNC(players[i].bubblehealth);
|
||||
SYNC(players[i].bubbleboost);
|
||||
SYNC(players[i].bubblegraze);
|
||||
SYNC(players[i].bubblebuffer);
|
||||
|
||||
SYNC(players[i].flamedash);
|
||||
|
|
|
|||
Loading…
Reference in a new issue