Merge pull request 'Redapple the Bubble Shield' (#177) from itemstuff into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/177
This commit is contained in:
commit
601c0999b4
9 changed files with 255 additions and 339 deletions
13
src/g_game.c
13
src/g_game.c
|
|
@ -255,7 +255,7 @@ INT32 stealtime = TICRATE/2;
|
|||
INT32 sneakertime = TICRATE + (TICRATE/3);
|
||||
INT32 waterpaneltime = TICRATE*2;
|
||||
INT32 itemtime = 8*TICRATE;
|
||||
INT32 bubbletime = TICRATE/4;
|
||||
INT32 bubbletime = TICRATE/2;
|
||||
INT32 comebacktime = 10*TICRATE;
|
||||
INT32 bumptime = 6;
|
||||
INT32 greasetics = 3*TICRATE;
|
||||
|
|
@ -2744,6 +2744,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
INT32 previtemroulette;
|
||||
INT32 roulettetype;
|
||||
INT32 growshrinktimer;
|
||||
UINT8 bubblehealth;
|
||||
INT32 bumper;
|
||||
INT32 karmapoints;
|
||||
INT32 wanted;
|
||||
|
|
@ -2812,6 +2813,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
itemtype = 0;
|
||||
itemamount = 0;
|
||||
growshrinktimer = 0;
|
||||
bubblehealth = 0;
|
||||
bumper = ((gametyperules & GTR_BUMPERS) ? K_StartingBumperCount() : 0);
|
||||
karmapoints = 0;
|
||||
wanted = 0;
|
||||
|
|
@ -2867,6 +2869,14 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
else
|
||||
growshrinktimer = 0;
|
||||
|
||||
// deplete your item stack if you died with zero bubble health
|
||||
bubblehealth = players[player].bubblehealth;
|
||||
if (bubblehealth == 0 && itemtype == KITEM_BUBBLESHIELD && itemamount > 0)
|
||||
{
|
||||
if (--itemamount == 0)
|
||||
itemtype = 0;
|
||||
}
|
||||
|
||||
bumper = players[player].bumper;
|
||||
karmapoints = players[player].karmapoints;
|
||||
wanted = players[player].wanted;
|
||||
|
|
@ -3001,6 +3011,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
p->itemtype = itemtype;
|
||||
p->itemamount = itemamount;
|
||||
p->growshrinktimer = growshrinktimer;
|
||||
p->bubblehealth = bubblehealth;
|
||||
p->bumper = bumper;
|
||||
p->karmadelay = comebacktime;
|
||||
p->karmapoints = karmapoints;
|
||||
|
|
|
|||
|
|
@ -922,7 +922,7 @@ static void K_BotItemBubble(botdata_t *bd, const player_t *player)
|
|||
boolean hold = false;
|
||||
|
||||
// We are holding this thing too long, lets get rid of it.
|
||||
if (bd->itemconfirm > 20*TICRATE)
|
||||
if (bd->itemconfirm > 15*TICRATE)
|
||||
{
|
||||
bd->itemconfirm++;
|
||||
|
||||
|
|
@ -934,17 +934,13 @@ static void K_BotItemBubble(botdata_t *bd, const player_t *player)
|
|||
return;
|
||||
}
|
||||
|
||||
if (player->bubbleblowup <= 0)
|
||||
if (player->bubblecool <= 0)
|
||||
{
|
||||
if (player->bubblecool <= 0)
|
||||
{
|
||||
fixed_t radius = 192 * player->mo->scale;
|
||||
radius = Easing_Linear(FRACUNIT * player->botvars.difficulty / MAXBOTDIFFICULTY, 2*radius, radius);
|
||||
|
||||
hold = K_GetBlockedBubbleItem(player, radius);
|
||||
}
|
||||
fixed_t radius = 192 * player->mo->scale;
|
||||
radius = Easing_Linear(FRACUNIT * player->botvars.difficulty / MAXBOTDIFFICULTY, 2*radius, radius);
|
||||
hold = K_GetBlockedBubbleItem(player, radius);
|
||||
}
|
||||
else if (player->bubbleblowup < bubbletime)
|
||||
else if (player->bubblecool < bubbletime)
|
||||
{
|
||||
hold = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -343,7 +343,8 @@ boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2)
|
|||
{
|
||||
if (t2->player)
|
||||
{
|
||||
if (t2->player->flashing > 0)
|
||||
// don't sideswipe anyone boosting with a bubble shield!
|
||||
if (t2->player->flashing > 0 || t2->player->bubbleboost > 0)
|
||||
return true;
|
||||
|
||||
if (t1->state == &states[S_MINEEXPLOSION1])
|
||||
|
|
@ -547,12 +548,7 @@ static void K_BubbleShieldCollideDrain(player_t *player, mobj_t *bubble, INT16 d
|
|||
|
||||
// Apply a cooldown if the Bubble Shield took damage without shattering.
|
||||
if ((player->bubblehealth > 0) && (dmg > 0))
|
||||
{
|
||||
player->bubblecool = 15*4;
|
||||
player->itemflags &= ~IF_HOLDREADY;
|
||||
bubble->extravalue1 = 4;
|
||||
bubble->cvmem = 1;
|
||||
}
|
||||
player->bubbleblowup /= 2;
|
||||
}
|
||||
|
||||
static boolean K_BubbleReflectingTrapItem(const mobj_t *t)
|
||||
|
|
@ -561,6 +557,12 @@ static boolean K_BubbleReflectingTrapItem(const mobj_t *t)
|
|||
t->type == MT_EGGMANITEM || t->type == MT_SSMINE || t->type == MT_SSMINE_SHIELD || t->type == MT_LANDMINE;
|
||||
}
|
||||
|
||||
static boolean K_StrongPlayerBump(const player_t *player)
|
||||
{
|
||||
return (((K_GetKartInvinType() == KARTINVIN_LEGACY) && (player->invincibilitytimer))
|
||||
|| (player->growshrinktimer > 0));
|
||||
}
|
||||
|
||||
boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
if (t2->threshold && !t2->player)
|
||||
|
|
@ -572,9 +574,16 @@ boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2)
|
|||
fixed_t momentum = max(FixedHypot(owner->momx, owner->momy), FixedHypot(t2->momx, t2->momy));
|
||||
momentum = max(3*momentum/4, 16*mapobjectscale); // do SOMETHING!
|
||||
|
||||
P_InstaThrust(t2, angle, momentum);
|
||||
if (!t2->player)
|
||||
t2->angle = angle;
|
||||
if (t2->player && !K_StrongPlayerBump(t2->player))
|
||||
{
|
||||
P_Thrust(t2, angle, momentum/2);
|
||||
}
|
||||
else
|
||||
{
|
||||
P_InstaThrust(t2, angle, momentum);
|
||||
if (!t2->player)
|
||||
t2->angle = angle;
|
||||
}
|
||||
|
||||
if (K_BubbleReflectingTrapItem(t2))
|
||||
{
|
||||
|
|
@ -598,19 +607,13 @@ boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2)
|
|||
return true;
|
||||
}
|
||||
|
||||
boolean K_BubbleShieldCanReflect(mobj_t *t1, mobj_t *t2)
|
||||
boolean K_BubbleShieldCanReflect(mobj_t *t)
|
||||
{
|
||||
return (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD
|
||||
|| t2->type == MT_BANANA || t2->type == MT_EGGMANITEM || t2->type == MT_BALLHOG
|
||||
|| t2->type == MT_SSMINE || t2->type == MT_LANDMINE || t2->type == MT_SINK
|
||||
|| t2->type == MT_KART_LEFTOVER
|
||||
|| (t2->type == MT_PLAYER && t1->target != t2));
|
||||
}
|
||||
|
||||
static boolean K_PlayerCanBeBubbleBumped(player_t *player)
|
||||
{
|
||||
return (((K_GetKartInvinType() == KARTINVIN_LEGACY) && (player->invincibilitytimer))
|
||||
|| (player->growshrinktimer > 0));
|
||||
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_KART_LEFTOVER
|
||||
|| t->type == MT_PLAYER);
|
||||
}
|
||||
|
||||
static INT16 K_GetBubbleDamage(mobj_t* itm)
|
||||
|
|
@ -665,19 +668,11 @@ static INT16 K_GetBubbleDamage(mobj_t* itm)
|
|||
|
||||
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
if (t2->type == MT_PLAYER)
|
||||
{
|
||||
// don't bump yourself
|
||||
if (t1->target == t2)
|
||||
return true;
|
||||
|
||||
boolean bumpme = ((t2->player) && (K_PlayerCanBeBubbleBumped(t2->player)));
|
||||
|
||||
if (!bumpme)
|
||||
{
|
||||
// Ignore non-bumpable players.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (K_BubbleShieldCanReflect(t1, t2))
|
||||
if (K_BubbleShieldCanReflect(t2))
|
||||
{
|
||||
boolean reflected = K_BubbleShieldReflect(t1, t2);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2);
|
|||
void K_ThunderShieldAttack(mobj_t *actor, fixed_t size);
|
||||
|
||||
boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2);
|
||||
boolean K_BubbleShieldCanReflect(mobj_t *t1, mobj_t *t2);
|
||||
boolean K_BubbleShieldCanReflect(mobj_t *t);
|
||||
|
||||
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2);
|
||||
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2);
|
||||
|
|
|
|||
92
src/k_hud.c
92
src/k_hud.c
|
|
@ -1306,6 +1306,22 @@ void K_getMinimapDrawinfo(drawinfo_t *out)
|
|||
out->flags = fflags;
|
||||
}
|
||||
|
||||
static void K_DrawItemBar(INT32 fx, INT32 fy, INT32 fflags, fixed_t itembar, UINT8 colors[static 3])
|
||||
{
|
||||
const boolean fourp = r_splitscreen > 1;
|
||||
const INT32 barlength = (fourp ? 12 : 26)*FRACUNIT;
|
||||
const INT32 length = min(barlength, FixedMul(itembar, barlength));
|
||||
const INT32 height = (fourp ? 1 : 2)*FRACUNIT;
|
||||
const INT32 x = (fx + (fourp ? 17 : 11)) * FRACUNIT, y = (fy + (fourp ? 27 : 35)) * FRACUNIT;
|
||||
|
||||
V_DrawSciencePatch(x, y, V_HUDTRANS|fflags, kp_itemtimer[fourp ? 1 : 0], FRACUNIT);
|
||||
V_DrawFixedFill(x+FRACUNIT, y+FRACUNIT, min(FRACUNIT, length), height, colors[2]|fflags); // the left edge
|
||||
V_DrawFixedFill(x+max(FRACUNIT, length), y+FRACUNIT, min(FRACUNIT, length), height, colors[2]|fflags); // the right edge
|
||||
if (!fourp)
|
||||
V_DrawFixedFill(x+2*FRACUNIT, y+2*FRACUNIT, max(0, length - 2*FRACUNIT), FRACUNIT, colors[1]|fflags); // the dulled underside
|
||||
V_DrawFixedFill(x+2*FRACUNIT, y+FRACUNIT, max(0, length - 2*FRACUNIT), FRACUNIT, colors[0]|fflags); // the shine
|
||||
}
|
||||
|
||||
// see also MT_PLAYERARROW mobjthinker in p_mobj.c
|
||||
static void K_drawKartItem(void)
|
||||
{
|
||||
|
|
@ -1321,11 +1337,7 @@ static void K_drawKartItem(void)
|
|||
boolean dark = false;
|
||||
INT32 fx = 0, fy = 0, fflags = 0; // final coords for hud and flags...
|
||||
INT32 numberdisplaymin = 2;
|
||||
INT32 itembar = 0;
|
||||
INT32 maxl = 0; // itembar's normal highest value
|
||||
INT32 flamebar = 0;
|
||||
INT32 flamemaxl = 0; // flamebar's normal highest value
|
||||
const INT32 barlength = (r_splitscreen > 1 ? 12 : 26);
|
||||
fixed_t itembar = -1, flamebar = -1;
|
||||
UINT16 localcolor = SKINCOLOR_NONE;
|
||||
SINT8 colormode = TC_RAINBOW;
|
||||
UINT8 *colmap = NULL;
|
||||
|
|
@ -1386,8 +1398,7 @@ static void K_drawKartItem(void)
|
|||
}
|
||||
else if (stplyr->rocketsneakertimer > 1)
|
||||
{
|
||||
itembar = stplyr->rocketsneakertimer;
|
||||
maxl = (itemtime*3) - barlength;
|
||||
itembar = FixedDiv(stplyr->rocketsneakertimer, itemtime*3);
|
||||
|
||||
if (leveltime & 1)
|
||||
localpatch = kp_rocketsneaker[offset];
|
||||
|
|
@ -1396,10 +1407,8 @@ static void K_drawKartItem(void)
|
|||
}
|
||||
else if (stplyr->flametimer > 1)
|
||||
{
|
||||
itembar = stplyr->flametimer;
|
||||
maxl = (itemtime*3) - barlength;
|
||||
flamebar = stplyr->flamestore;
|
||||
flamemaxl = FLAMESTOREMAX;
|
||||
itembar = FixedDiv(stplyr->flametimer, itemtime*3);
|
||||
flamebar = FixedDiv(stplyr->flamestore, FLAMESTOREMAX);
|
||||
localbg = kp_itembg[offset+1];
|
||||
dark = true;
|
||||
|
||||
|
|
@ -1417,10 +1426,7 @@ static void K_drawKartItem(void)
|
|||
else if (stplyr->growshrinktimer > 0)
|
||||
{
|
||||
if (stplyr->growcancel > 0)
|
||||
{
|
||||
itembar = stplyr->growcancel;
|
||||
maxl = 26;
|
||||
}
|
||||
itembar = FixedDiv(stplyr->growcancel, 26);
|
||||
|
||||
if (leveltime & 1)
|
||||
localpatch = kp_grow[offset];
|
||||
|
|
@ -1429,14 +1435,10 @@ static void K_drawKartItem(void)
|
|||
}
|
||||
else if ((stplyr->invincibilitytimer) && (K_GetKartInvinType() == KARTINVIN_ALTERN))
|
||||
{
|
||||
itembar = stplyr->invincibilitytimer;
|
||||
maxl = max(1, stplyr->maxinvincibilitytime);
|
||||
itembar = FixedDiv(stplyr->invincibilitytimer, max(1, stplyr->maxinvincibilitytime));
|
||||
|
||||
if (stplyr->invincibilitycancel > 0)
|
||||
{
|
||||
flamebar = stplyr->invincibilitycancel;
|
||||
flamemaxl = 26;
|
||||
}
|
||||
flamebar = FixedDiv(stplyr->invincibilitycancel, 26);
|
||||
|
||||
if (leveltime & 1)
|
||||
localpatch = localinv;
|
||||
|
|
@ -1448,14 +1450,13 @@ static void K_drawKartItem(void)
|
|||
localpatch = kp_bubbleshield[offset];
|
||||
dark = true;
|
||||
|
||||
if ((stplyr->bubbleblowup > bubbletime) && (leveltime & 1))
|
||||
if (stplyr->bubbleblowup > 0 && leveltime & 1)
|
||||
{
|
||||
colormode = TC_BLINK;
|
||||
localcolor = SKINCOLOR_WHITE;
|
||||
}
|
||||
|
||||
itembar = stplyr->bubblehealth;
|
||||
maxl = MAXBUBBLEHEALTH;
|
||||
itembar = FixedDiv(stplyr->bubblehealth, MAXBUBBLEHEALTH);
|
||||
}
|
||||
else if (stplyr->sadtimer > 0)
|
||||
{
|
||||
|
|
@ -1588,45 +1589,12 @@ static void K_drawKartItem(void)
|
|||
//V_ClearClipRect();
|
||||
|
||||
// Extensible meter, currently used by Invincibilty, Grow, Rocket Sneakers and Flame Shield
|
||||
if (itembar)
|
||||
{
|
||||
const INT32 fill = ((itembar*barlength)/maxl);
|
||||
const INT32 length = min(barlength, fill);
|
||||
const INT32 height = (offset ? 1 : 2);
|
||||
const INT32 x = (offset ? 17 : 11), y = (offset ? 27 : 35);
|
||||
// ...aren't you forgetting something?
|
||||
if (itembar != -1)
|
||||
K_DrawItemBar(fx, fy, fflags|V_HUDTRANS, itembar, (UINT8 []){0, 8, 12});
|
||||
|
||||
V_DrawScaledPatch(fx+x, fy+y, V_HUDTRANS|fflags, kp_itemtimer[offset]);
|
||||
// The left dark "AA" edge
|
||||
V_DrawFill(fx+x+1, fy+y+1, (length == 2 ? 2 : 1), height, 12|fflags|V_HUDTRANS);
|
||||
// The bar itself
|
||||
if (length > 2)
|
||||
{
|
||||
V_DrawFill(fx+x+length, fy+y+1, 1, height, 12|fflags|V_HUDTRANS); // the right one
|
||||
if (height == 2)
|
||||
V_DrawFill(fx+x+2, fy+y+2, length-2, 1, 8|fflags|V_HUDTRANS); // the dulled underside
|
||||
V_DrawFill(fx+x+2, fy+y+1, length-2, 1, 0|fflags|V_HUDTRANS); // the shine
|
||||
}
|
||||
}
|
||||
|
||||
if (flamebar)
|
||||
{
|
||||
const INT32 fill = ((flamebar*barlength)/flamemaxl);
|
||||
const INT32 length = min(barlength, fill);
|
||||
const INT32 height = (offset ? 1 : 2);
|
||||
const INT32 x = (offset ? 17 : 11), y = (offset ? 27 : 35);
|
||||
|
||||
V_DrawScaledPatch(fx+x, fy+y-8, V_HUDTRANS|fflags, kp_itemtimer[offset]);
|
||||
// The left dark "AA" edge
|
||||
V_DrawFill(fx+x+1, fy+y+1-8, (length == 2 ? 2 : 1), height, 55|fflags|V_HUDTRANS);
|
||||
// The bar itself
|
||||
if (length > 2)
|
||||
{
|
||||
V_DrawFill(fx+x+length, fy+y+1-8, 1, height, 55|fflags|V_HUDTRANS); // the right one
|
||||
if (height == 2)
|
||||
V_DrawFill(fx+x+2, fy+y+2-8, length-2, 1, 36|fflags|V_HUDTRANS); // the dulled underside
|
||||
V_DrawFill(fx+x+2, fy+y+1-8, length-2, 1, 51|fflags|V_HUDTRANS); // the shine
|
||||
}
|
||||
}
|
||||
if (flamebar != -1)
|
||||
K_DrawItemBar(fx, fy - 8, fflags|V_HUDTRANS, flamebar, (UINT8 []){51, 36, 55});
|
||||
|
||||
// Quick Eggman numbers
|
||||
if (stplyr->eggmanexplode > 1)
|
||||
|
|
|
|||
190
src/k_kart.c
190
src/k_kart.c
|
|
@ -82,6 +82,12 @@ consvar_t cv_driftsparkpulse = CVAR_INIT ("driftsparkpulse", "1.4", CV_SAVE|CV_F
|
|||
consvar_t cv_saltyhop = CVAR_INIT ("hardcodehop", "Off", CV_SAVE, CV_OnOff, NULL);
|
||||
consvar_t cv_karthitemdialog = CVAR_INIT ("karthitemdialog", "On", CV_SAVE, CV_OnOff, NULL);
|
||||
|
||||
// opinionated stuff for testing
|
||||
consvar_t cv_kartbubble_defense_canidle = CVAR_INIT ("kartbubble_defense_canidle", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
static CV_PossibleValue_t bubble_defense_damagerate_cons_t[] = {{0, "MIN"}, {FRACUNIT, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_kartbubble_defense_damagerate = CVAR_INIT ("kartbubble_defense_damagerate", "1.0", CV_NETVAR|CV_FLOAT, bubble_defense_damagerate_cons_t, NULL);
|
||||
consvar_t cv_kartbubble_boost_allow = CVAR_INIT ("kartbubble_boost_allow", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
|
||||
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
|
||||
// franticitems is Frantic Mode items, bool
|
||||
|
|
@ -303,6 +309,11 @@ void K_RegisterKartStuff(void)
|
|||
CV_RegisterVar(&cv_kartdebugcolorize);
|
||||
CV_RegisterVar(&cv_kartdebugdirector);
|
||||
|
||||
// experimental stuff
|
||||
CV_RegisterVar(&cv_kartbubble_defense_canidle);
|
||||
CV_RegisterVar(&cv_kartbubble_defense_damagerate);
|
||||
CV_RegisterVar(&cv_kartbubble_boost_allow);
|
||||
|
||||
// HUD cvars
|
||||
K_RegisterKartHUDStuff();
|
||||
|
||||
|
|
@ -485,7 +496,8 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against)
|
|||
|
||||
if (against && !P_MobjWasRemoved(against) && against->player
|
||||
&& ((!P_PlayerInPain(against->player) && P_PlayerInPain(mobj->player)) // You're hurt
|
||||
|| (against->player->itemtype == KITEM_BUBBLESHIELD && mobj->player->itemtype != KITEM_BUBBLESHIELD))) // They have a Bubble Shield
|
||||
|| (K_GetShieldFromPlayer(against->player) == KSHIELD_BUBBLE // They have a Bubble Shield
|
||||
&& K_GetShieldFromPlayer(mobj->player) != KSHIELD_BUBBLE))) // and you don't
|
||||
{
|
||||
weight = 0; // This player does not cause any bump action
|
||||
}
|
||||
|
|
@ -497,7 +509,7 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against)
|
|||
|
||||
weight = (mobj->player->kartweight) * FRACUNIT;
|
||||
|
||||
if (mobj->player->itemtype == KITEM_BUBBLESHIELD)
|
||||
if (K_GetShieldFromPlayer(mobj->player) == KSHIELD_BUBBLE && mobj->player->bubblecool == 0)
|
||||
{
|
||||
weight = max(BUBBLEMINWEIGHT, weight);
|
||||
weight = FixedMul(weight, FRACUNIT/16);
|
||||
|
|
@ -766,7 +778,7 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean sol
|
|||
p1shield = K_GetShieldFromPlayer(mobj1->player);
|
||||
|
||||
// Moved here so it only fires once on bump.
|
||||
if (p1shield == KSHIELD_BUBBLE)
|
||||
if (p1shield == KSHIELD_BUBBLE && mobj1->player->bubblecool == 0)
|
||||
{
|
||||
// Each bump does chip damage to the shield.
|
||||
K_RemoveBubbleHealth(mobj1->player, BUBBLEBUMPCHIP);
|
||||
|
|
@ -802,7 +814,7 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean sol
|
|||
p2shield = K_GetShieldFromPlayer(mobj2->player);
|
||||
|
||||
// Moved here so it only fires once on bump.
|
||||
if (p2shield == KSHIELD_BUBBLE)
|
||||
if (p2shield == KSHIELD_BUBBLE && mobj2->player->bubblecool == 0)
|
||||
{
|
||||
// Each bump does chip damage to the shield.
|
||||
K_RemoveBubbleHealth(mobj2->player, BUBBLEBUMPCHIP);
|
||||
|
|
@ -5308,59 +5320,49 @@ static void K_BreakBubbleShield(player_t* player)
|
|||
if (K_GetShieldFromPlayer(player) != KSHIELD_BUBBLE)
|
||||
return;
|
||||
|
||||
// TODO: Some more dramatic SFX and VFX (DSS3K59, bubble shield shards fly all over)
|
||||
mobj_t* shard;
|
||||
const INT32 flip = P_MobjFlip(player->mo);
|
||||
const fixed_t scalediff = player->shieldtracer->scale - mapobjectscale;
|
||||
const fixed_t shieldrad = player->shieldtracer->radius;
|
||||
|
||||
fixed_t move_magnitude, shieldrad, shieldscale, scalediff;
|
||||
vector2_t mul_vec;
|
||||
vector3_t mom;
|
||||
fixed_t randang, randzang;
|
||||
INT32 flip = P_MobjFlip(player->mo);
|
||||
|
||||
shieldscale = player->shieldtracer->scale;
|
||||
|
||||
scalediff = shieldscale - mapobjectscale;
|
||||
shieldrad = FixedMul(player->shieldtracer->radius, shieldscale);
|
||||
|
||||
mul_vec.x = FRACUNIT;
|
||||
mul_vec.y = 0;
|
||||
|
||||
INT32 i;
|
||||
for (i = 0; i < MAXSHARDCOUNT; i++)
|
||||
for (INT32 i = 0; i < MAXSHARDCOUNT; i++)
|
||||
{
|
||||
mul_vec.x = FRACUNIT;
|
||||
mul_vec.y = 0;
|
||||
vector2_t mul_vec = { FRACUNIT, 0 };
|
||||
|
||||
randang = (SHARDROT * (i + 1));
|
||||
randzang = (P_RandomRange(23, 157) * FRACUNIT);
|
||||
move_magnitude =
|
||||
fixed_t randang = SHARDROT * (i + 1);
|
||||
fixed_t randzang = P_RandomRange(10, 120) * FRACUNIT;
|
||||
fixed_t move_magnitude =
|
||||
FixedMul((P_RandomRange(4, 16) * FRACUNIT), mapobjectscale + (scalediff / 4));
|
||||
|
||||
|
||||
FV2_Rotate(&mul_vec, randzang);
|
||||
|
||||
// Do shitty initial 3D rotations around the shield's radius.
|
||||
shard = P_SpawnMobj(
|
||||
mobj_t *shard = P_SpawnMobj(
|
||||
player->shieldtracer->x +
|
||||
FixedMul(FixedMul(mul_vec.x, shieldrad), FCOS(FixedAngle(randang))),
|
||||
FixedMul(FixedMul(mul_vec.x, shieldrad), FCOS(FixedAngle(randang))),
|
||||
player->shieldtracer->y +
|
||||
FixedMul(FixedMul(mul_vec.x, shieldrad), FSIN(FixedAngle(randang))),
|
||||
player->shieldtracer->z + FixedMul(mul_vec.y * flip, shieldrad),
|
||||
FixedMul(FixedMul(mul_vec.x, shieldrad), FSIN(FixedAngle(randang))),
|
||||
player->shieldtracer->z + ((player->shieldtracer->height + scalediff) / 4)
|
||||
+ FixedMul(mul_vec.y * flip, shieldrad),
|
||||
MT_BUBBLESHLD_DEBRIS);
|
||||
|
||||
if (shard)
|
||||
if (!P_MobjWasRemoved(shard))
|
||||
{
|
||||
//CONS_Printf(M_GetText("randzang: %d, randang: %d\n"), randzang / FRACUNIT, randang / FRACUNIT);
|
||||
|
||||
mul_vec.x = FixedMul(move_magnitude, mul_vec.x);
|
||||
mul_vec.y = FixedMul(move_magnitude, mul_vec.y * flip);
|
||||
|
||||
mom.x = FixedMul(mul_vec.x, FCOS(FixedAngle(randang)));
|
||||
mom.y = FixedMul(mul_vec.x, FSIN(FixedAngle(randang)));
|
||||
mom.z = mul_vec.y;
|
||||
vector3_t mom = {
|
||||
.x = FixedMul(mul_vec.x, FCOS(FixedAngle(randang))),
|
||||
.y = FixedMul(mul_vec.x, FSIN(FixedAngle(randang))),
|
||||
.z = mul_vec.y,
|
||||
};
|
||||
|
||||
shard->momx = mom.x + player->mo->momx;
|
||||
shard->momy = mom.y + player->mo->momy;
|
||||
shard->momz = mom.z + player->mo->momz;
|
||||
|
||||
shard->extravalue1 = i % 5; // 20% chance to play the shard sound
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5388,9 +5390,7 @@ void K_PopPlayerShield(player_t *player)
|
|||
player->itemamount = 0;
|
||||
break;
|
||||
case KSHIELD_BUBBLE:
|
||||
if (player->bubblehealth > 0)
|
||||
K_BreakBubbleShield(player); // Nice whiff; see ya!
|
||||
|
||||
K_BreakBubbleShield(player);
|
||||
player->bubbleblowup = 0;
|
||||
player->bubblecool = 0;
|
||||
player->bubblehealth = 0;
|
||||
|
|
@ -5411,16 +5411,25 @@ void K_PopPlayerShield(player_t *player)
|
|||
K_UnsetItemOut(player);
|
||||
}
|
||||
|
||||
// Returns true is the bubble is actively in defense mode (inflating or inflated)
|
||||
boolean K_IsBubbleDefending(player_t *player)
|
||||
{
|
||||
if (K_GetShieldFromPlayer(player) != KSHIELD_BUBBLE) return false;
|
||||
return (player->bubbleblowup);
|
||||
}
|
||||
|
||||
// Depletes a bubble shield's health, and pops the shield at 0 health.
|
||||
void K_RemoveBubbleHealth(player_t *player, INT16 sub)
|
||||
{
|
||||
// experiment: inflated bubble shield applies a direct reduction to all incoming damage
|
||||
if (K_IsBubbleDefending(player))
|
||||
{
|
||||
sub = FixedMul(sub<<FRACBITS, cv_kartbubble_defense_damagerate.value)>>FRACBITS;
|
||||
}
|
||||
player->bubblehealth = (UINT8)(max(0, (INT16)(player->bubblehealth) - sub));
|
||||
|
||||
if (player->bubblehealth <= 0)
|
||||
{
|
||||
K_BreakBubbleShield(player);
|
||||
K_PopPlayerShield(player);
|
||||
}
|
||||
}
|
||||
|
||||
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount)
|
||||
|
|
@ -7463,12 +7472,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
if (player->itemtype == KITEM_BUBBLESHIELD)
|
||||
{
|
||||
if (player->bubblecool)
|
||||
player->bubblecool--;
|
||||
}
|
||||
else
|
||||
if (player->itemtype != KITEM_BUBBLESHIELD)
|
||||
{
|
||||
player->bubbleblowup = 0;
|
||||
player->bubblecool = 0;
|
||||
|
|
@ -10220,8 +10224,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->itemflags &= ~IF_USERINGS;
|
||||
}
|
||||
|
||||
if (player->exiting && player->bubbleblowup > 0)
|
||||
player->bubbleblowup--;
|
||||
if (player->exiting)
|
||||
{
|
||||
player->bubbleblowup = 0;
|
||||
if (player->bubblecool > 0)
|
||||
player->bubblecool--;
|
||||
}
|
||||
|
||||
if (player && player->mo && player->mo->health > 0 && !player->spectator && !P_PlayerInPain(player) && player->respawn == 0 && !(player->exiting || mapreset))
|
||||
{
|
||||
|
|
@ -10780,27 +10788,30 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
P_SetTarget(&shield->target, player->mo);
|
||||
P_SetTarget(&player->shieldtracer, shield);
|
||||
S_StartSound(player->mo, sfx_s3k3f);
|
||||
player->bubblehealth = MAXBUBBLEHEALTH;
|
||||
if (player->bubblehealth <= 0 || player->bubblehealth > MAXBUBBLEHEALTH)
|
||||
player->bubblehealth = MAXBUBBLEHEALTH;
|
||||
}
|
||||
|
||||
if (!HOLDING_ITEM && NO_HYUDORO)
|
||||
{
|
||||
if ((buttons & BT_ATTACK) && (player->itemflags & IF_HOLDREADY))
|
||||
if ((buttons & BT_ATTACK && player->itemflags & IF_HOLDREADY)
|
||||
|| (player->bubbleblowup > 0 && player->bubblecool <= bubbletime/2)) // auto
|
||||
{
|
||||
if (player->bubbleblowup == 0)
|
||||
if (player->bubblecool == 0)
|
||||
S_StartSound(player->mo, sfx_s3k75);
|
||||
|
||||
player->bubbleblowup++;
|
||||
if (player->bubblecool < bubbletime && player->bubblehealth > 0)
|
||||
{
|
||||
player->bubbleblowup += 3;
|
||||
player->bubblehealth--;
|
||||
}
|
||||
else if (player->bubblecool >= bubbletime)
|
||||
player->bubbleblowup++; // overcharge bonus
|
||||
|
||||
// Reduce cooldown for easier itemset chaining.
|
||||
// (was blowup x4 before)
|
||||
player->bubblecool = player->bubbleblowup*2;
|
||||
|
||||
if (player->bubbleblowup > bubbletime*4)
|
||||
if (++player->bubblecool >= bubbletime + TICRATE/2)
|
||||
{
|
||||
// If you overcharge the Bubble Shield at
|
||||
// any point, it pops and gives you a boost.
|
||||
K_BreakBubbleShield(player);
|
||||
K_PopPlayerShield(player);
|
||||
|
||||
if (onground)
|
||||
|
|
@ -10812,44 +10823,43 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
K_PlayBoostTaunt(player->mo);
|
||||
}
|
||||
|
||||
player->bubbleboost = 7 * sneakertime / 10;
|
||||
// experiment: don't boost, just give invulnerability
|
||||
if (cv_kartbubble_boost_allow.value)
|
||||
{
|
||||
player->bubbleboost = 7 * sneakertime / 10;
|
||||
}
|
||||
player->flashing = 4*TICRATE/7;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->bubblecool > bubbletime)
|
||||
player->bubblecool = bubbletime;
|
||||
|
||||
if (player->bubbleblowup > 0)
|
||||
{
|
||||
boolean popped = false;
|
||||
if (player->bubbleblowup > bubbletime)
|
||||
player->bubbleblowup = bubbletime;
|
||||
player->bubbleblowup--;
|
||||
if (player->bubbleblowup == 0)
|
||||
K_BotResetItemConfirm(player, false);
|
||||
if (player->bubblecool < bubbletime)
|
||||
player->bubblecool++;
|
||||
}
|
||||
|
||||
if (player->bubbleblowup)
|
||||
{
|
||||
player->bubbleblowup--;
|
||||
if (player->bubbleblowup == 0 && player->bubblecool > 0)
|
||||
{
|
||||
player->bubblecool--;
|
||||
|
||||
if (!player->bubbleblowup)
|
||||
{
|
||||
// Each use costs some points of health.
|
||||
K_RemoveBubbleHealth(player, BUBBLEUSECOST);
|
||||
if (player->bubblecool == 0 && player->bubblehealth <= 0)
|
||||
K_PopPlayerShield(player);
|
||||
}
|
||||
|
||||
if (player->bubblehealth <= 0)
|
||||
{
|
||||
// Bubble popped!
|
||||
popped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!popped)
|
||||
{
|
||||
if (buttons & BT_ATTACK || player->bubblecool)
|
||||
{
|
||||
player->itemflags &= ~IF_HOLDREADY;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->itemflags |= IF_HOLDREADY;
|
||||
}
|
||||
}
|
||||
if (buttons & BT_ATTACK || player->bubblecool > 0)
|
||||
{
|
||||
player->itemflags &= ~IF_HOLDREADY;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->itemflags |= IF_HOLDREADY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
21
src/k_kart.h
21
src/k_kart.h
|
|
@ -20,6 +20,11 @@ extern consvar_t cv_kartchainingsound;
|
|||
extern consvar_t cv_kartdriftsounds;
|
||||
extern consvar_t cv_kartdriftefx;
|
||||
|
||||
// opinionated stuff for testing
|
||||
extern consvar_t cv_kartbubble_defense_canidle;
|
||||
extern consvar_t cv_kartbubble_defense_damagerate;
|
||||
extern consvar_t cv_kartbubble_boost_allow;
|
||||
|
||||
#define KART_FULLTURN 800
|
||||
|
||||
/*
|
||||
|
|
@ -68,17 +73,14 @@ extern boolean clusterplayer[MAXPLAYERS];
|
|||
extern UINT32 clusterid; // ID of the "cluster player", the one closest to the cluster point.
|
||||
extern vector3_t clusterpoint, clusterdtf;
|
||||
|
||||
// Bubble Shield's maximum health
|
||||
#define MAXBUBBLEHEALTH 12
|
||||
// Bubble Shield's maximum health (determines how many times it can be fully inflated)
|
||||
#define MAXBUBBLEHEALTH (bubbletime * 3)
|
||||
|
||||
// Chip damage done to a Bubble Shield upon bumping a player
|
||||
#define BUBBLEBUMPCHIP (MAXBUBBLEHEALTH / 4)
|
||||
// Chip damage done to a Bubble Shield upon bumping a player when not inflated (rounded up)
|
||||
#define BUBBLEBUMPCHIP ((MAXBUBBLEHEALTH + 1) / 2)
|
||||
|
||||
// HP cost for a Bubble Shield to inflate
|
||||
#define BUBBLEUSECOST (MAXBUBBLEHEALTH / 3)
|
||||
|
||||
// Damage done to an inflated Bubble Shield by items.
|
||||
#define BUBBLEITMDAMAGE (MAXBUBBLEHEALTH / 6)
|
||||
// Damage done to an inflated Bubble Shield (rounded up)
|
||||
#define BUBBLEITMDAMAGE ((MAXBUBBLEHEALTH + 8) / 9)
|
||||
|
||||
// Bump weight for a Bubble Shield
|
||||
#define BUBBLEMINWEIGHT (5 * FRACUNIT)
|
||||
|
|
@ -257,6 +259,7 @@ void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source);
|
|||
void K_UpdateHnextList(player_t *player, boolean clean);
|
||||
void K_DropHnextList(player_t *player);
|
||||
void K_PopPlayerShield(player_t *player);
|
||||
boolean K_IsBubbleDefending(player_t *player);
|
||||
void K_RemoveBubbleHealth(player_t *player, INT16 sub);
|
||||
void K_RepairOrbitChain(mobj_t *orbit);
|
||||
void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player);
|
||||
|
|
|
|||
|
|
@ -2133,8 +2133,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
boolean force = false;
|
||||
boolean spbpop = false;
|
||||
boolean painsound = false;
|
||||
boolean bubbleinvuln = false;
|
||||
INT32 myShield = KSHIELD_NONE;
|
||||
|
||||
if (objectplacing)
|
||||
return false;
|
||||
|
|
@ -2232,8 +2230,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
else
|
||||
{
|
||||
const UINT8 type = (damagetype & DMG_TYPEMASK);
|
||||
const boolean explosioncombo = (type == DMG_EXPLODE); // This damage type can do evil stuff like ALWAYS combo
|
||||
myShield = K_GetShieldFromPlayer(player);
|
||||
|
||||
const boolean explosioncombo = type == DMG_EXPLODE // This damage type can do evil stuff like ALWAYS combo
|
||||
&& player->bubbleboost == 0; // ...but popping a Bubble Shield protects you!
|
||||
|
||||
// Check if the player is allowed to be damaged!
|
||||
// If not, then spawn the instashield effect instead.
|
||||
|
|
@ -2265,32 +2264,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((myShield == KSHIELD_BUBBLE) && (player->bubbleblowup))
|
||||
{
|
||||
// This player is on the defensive; protect them from certain attacks.
|
||||
switch (type)
|
||||
{
|
||||
case DMG_WIPEOUT:
|
||||
bubbleinvuln = true;
|
||||
break;
|
||||
case DMG_VOLTAGE:
|
||||
case DMG_NORMAL:
|
||||
bubbleinvuln = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (bubbleinvuln)
|
||||
{
|
||||
// This attack likely penetrated. Defense!
|
||||
player->flashing = K_GetKartFlashing(player);
|
||||
player->bubblecool = player->bubbleblowup*2;
|
||||
K_DoInstashield(player);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we should allow explosion combos.
|
||||
if ((explosioncombo == false) && (player->flashing > 0 || player->squishedtimer > 0))
|
||||
{
|
||||
|
|
@ -2298,6 +2271,17 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
K_DoInstashield(player);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bubble Shield protects you from spinout, but not knockback
|
||||
if (K_GetShieldFromPlayer(player) == KSHIELD_BUBBLE
|
||||
&& explosioncombo == false && source != NULL && type != DMG_VOLTAGE
|
||||
// experiment: disable this since defense can be prepared in advance instead of requiring reaction
|
||||
&& cv_kartbubble_defense_canidle.value)
|
||||
{
|
||||
K_PopPlayerShield(player);
|
||||
K_DoInstashield(player);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We successfully damaged them! Give 'em some bumpers!
|
||||
|
|
@ -2454,7 +2438,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
}
|
||||
|
||||
// Have a shield? You get hit, but don't lose your rings!
|
||||
if (myShield != KSHIELD_NONE)
|
||||
if (K_GetShieldFromPlayer(player) != KSHIELD_NONE)
|
||||
{
|
||||
ringburst = 0;
|
||||
K_PopPlayerShield(player);
|
||||
|
|
|
|||
151
src/p_mobj.c
151
src/p_mobj.c
|
|
@ -69,18 +69,6 @@ mobj_t *boss3cap = NULL;
|
|||
|
||||
mobj_t *mobjcache = NULL;
|
||||
|
||||
// Bubble Shield overlay spritescales.
|
||||
static fixed_t bubbleoverlayscales[4][2] = {
|
||||
// All scales are raw 16.16 fixed-point numbers based on FRACUNIT.
|
||||
{65536, 65536}, // 1.0, 1.0
|
||||
{65536, 59667}, // 1.0, 0.9104477
|
||||
{90593, 61623}, // 1.382352, 0.940298
|
||||
{100231, 53798} // 1.529411, 0.820895
|
||||
};
|
||||
static statenum_t bubbledamagestates[5] = { S_INVISIBLE, S_BUBLSHLD_DMG_1, S_BUBLSHLD_DMG_2, S_BUBLSHLD_DMG_3, S_BUBLSHLD_DMG_4 };
|
||||
|
||||
|
||||
|
||||
void P_InitCachedActions(void)
|
||||
{
|
||||
actioncachehead.prev = actioncachehead.next = &actioncachehead;
|
||||
|
|
@ -9176,79 +9164,65 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
case MT_BUBBLESHIELD:
|
||||
{
|
||||
fixed_t scale;
|
||||
statenum_t curstate, overlaystate;
|
||||
const player_t *player = P_MobjWasRemoved(mobj->target) ? NULL : mobj->target->player;
|
||||
|
||||
if (!mobj->target || !mobj->target->health || !mobj->target->player
|
||||
|| K_GetShieldFromPlayer(mobj->target->player) != KSHIELD_BUBBLE)
|
||||
if (player == NULL || player->mo->health == 0 || K_GetShieldFromPlayer(player) != KSHIELD_BUBBLE)
|
||||
{
|
||||
P_RemoveMobj(mobj);
|
||||
return false;
|
||||
}
|
||||
|
||||
scale = (5*mobj->target->scale)>>2;
|
||||
curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states)));
|
||||
fixed_t scale = 5*player->mo->scale/4;
|
||||
if (cv_kartbubble_defense_canidle.value && player->bubbleblowup == 0 && player->bubblecool > 0)
|
||||
mobj->renderflags |= RF_GHOSTLY;
|
||||
else if ((!cv_kartbubble_defense_canidle.value) && !K_IsBubbleDefending(player))
|
||||
mobj->renderflags |= (RF_TRANS40 | RF_FULLBRIGHT);
|
||||
else
|
||||
mobj->renderflags &= ~RF_GHOSTLYMASK;
|
||||
|
||||
// Lookup for rescaling the "bubble damage" overlay
|
||||
UINT8 frame, scale_idx;
|
||||
|
||||
frame = scale_idx = 0;
|
||||
|
||||
if (mobj->target->player->bubbleblowup)
|
||||
if (player->bubblecool)
|
||||
{
|
||||
INT32 blow = mobj->target->player->bubbleblowup;
|
||||
if (blow > bubbletime)
|
||||
blow = bubbletime;
|
||||
INT32 blow = player->bubbleblowup + min(player->bubblecool, bubbletime)*10;
|
||||
scale += (blow * scale) / (bubbletime * 10);
|
||||
|
||||
if (curstate != S_BUBBLESHIELDBLOWUP)
|
||||
if (mobj->state - states != S_BUBBLESHIELDBLOWUP)
|
||||
P_SetMobjState(mobj, S_BUBBLESHIELDBLOWUP);
|
||||
|
||||
mobj->angle += ANGLE_22h;
|
||||
mobj->renderflags &= ~RF_GHOSTLYMASK;
|
||||
scale += (blow * ((3*scale)>>1)) / bubbletime;
|
||||
|
||||
mobj->frame = CLAMP(states[S_BUBBLESHIELDBLOWUP].frame + mobj->extravalue1, states[S_BUBBLESHIELDBLOWUP].frame, states[S_BUBBLESHIELDBLOWUP].frame + 3);
|
||||
fixed_t stretch = 0;
|
||||
if (player->bubblecool >= bubbletime) // overcharge
|
||||
stretch = ((player->bubblecool - bubbletime) % 4) * FRACUNIT/4;
|
||||
else if (player->bubbleblowup > 0 && player->bubblecool <= 4) // inflate 1
|
||||
stretch = player->bubblecool*FRACUNIT/5;
|
||||
else if (player->bubbleblowup >= 5 && player->bubblecool < 8) // inflate 2
|
||||
stretch = (8 - player->bubblecool)*FRACUNIT/5;
|
||||
else if (player->bubblehealth == 0 && player->bubbleblowup == 0) // decaying
|
||||
stretch = (player->bubblecool - bubbletime)*FRACUNIT/bubbletime;
|
||||
|
||||
frame = mobj->frame & FF_FRAMEMASK;
|
||||
scale_idx = CLAMP(frame - 9, 0, 3);
|
||||
mobj->spritexscale = FRACUNIT + FTAN(FixedAngle(stretch*30) + ANGLE_90);
|
||||
mobj->spriteyscale = FRACUNIT - stretch/5;
|
||||
|
||||
if ((mobj->target->player->bubbleblowup > bubbletime) && (leveltime & 1))
|
||||
{
|
||||
mobj->colorized = true;
|
||||
if (player->bubbleblowup > 0 && leveltime & 1)
|
||||
mobj->color = SKINCOLOR_WHITE;
|
||||
mobj->colorized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mobj->color = SKINCOLOR_BLUE;
|
||||
mobj->colorized = false;
|
||||
}
|
||||
|
||||
if (mobj->extravalue1 < 4 && mobj->extravalue2 < blow && !mobj->cvmem && (leveltime & 1)) // Growing
|
||||
{
|
||||
mobj->extravalue1++;
|
||||
if (mobj->extravalue1 >= 4)
|
||||
mobj->cvmem = 1; // shrink back down
|
||||
}
|
||||
else if ((mobj->extravalue1 > -4 && mobj->extravalue2 > blow)
|
||||
|| (mobj->cvmem && mobj->extravalue1 > 0)) // Shrinking
|
||||
mobj->extravalue1--;
|
||||
|
||||
if (P_IsObjectOnGround(mobj->target))
|
||||
if (P_IsObjectOnGround(player->mo) && player->bubbleblowup > 0)
|
||||
{
|
||||
UINT8 i;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
angle_t a = mobj->angle + ((i & 1) ? ANGLE_180 : 0);
|
||||
fixed_t ws = (mobj->target->scale>>1);
|
||||
fixed_t ws = player->mo->scale/4 + scale/4;
|
||||
mobj_t *wave;
|
||||
|
||||
ws += (blow * ws) / bubbletime;
|
||||
|
||||
wave = P_SpawnMobj(
|
||||
(mobj->target->x - mobj->target->momx) + P_ReturnThrustX(NULL, a, mobj->radius - (21*ws)),
|
||||
(mobj->target->y - mobj->target->momy) + P_ReturnThrustY(NULL, a, mobj->radius - (21*ws)),
|
||||
(mobj->target->z - mobj->target->momz), MT_THOK);
|
||||
(player->mo->x - player->mo->momx) + P_ReturnThrustX(NULL, a, mobj->radius - (21*ws)),
|
||||
(player->mo->y - player->mo->momy) + P_ReturnThrustY(NULL, a, mobj->radius - (21*ws)),
|
||||
(player->mo->z - player->mo->momz), MT_THOK);
|
||||
|
||||
wave->colorized = true;
|
||||
wave->color = SKINCOLOR_BLUE;
|
||||
|
|
@ -9257,47 +9231,23 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
|
||||
P_SetMobjState(wave, S_SPLISH1);
|
||||
|
||||
wave->momx = mobj->target->momx;
|
||||
wave->momy = mobj->target->momy;
|
||||
wave->momz = mobj->target->momz;
|
||||
wave->momx = player->mo->momx;
|
||||
wave->momy = player->mo->momy;
|
||||
wave->momz = player->mo->momz;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mobj->cvmem = 0;
|
||||
mobj->angle = mobj->target->angle;
|
||||
mobj->angle = player->mo->angle;
|
||||
// mobj->renderflags &= ~RF_GHOSTLYMASK;
|
||||
mobj->colorized = false;
|
||||
mobj->color = SKINCOLOR_BLUE;
|
||||
|
||||
if (curstate == S_BUBBLESHIELDBLOWUP)
|
||||
{
|
||||
if (mobj->extravalue1 != 0)
|
||||
{
|
||||
mobj->frame = (states[S_BUBBLESHIELDBLOWUP].frame + mobj->extravalue1);
|
||||
|
||||
frame = mobj->frame & FF_FRAMEMASK;
|
||||
scale_idx = CLAMP(frame - 9, 0, 3);
|
||||
|
||||
if (mobj->extravalue1 < 0 && (leveltime & 1))
|
||||
mobj->extravalue1++;
|
||||
else if (mobj->extravalue1 > 0)
|
||||
mobj->extravalue1--;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_SetMobjState(mobj, S_BUBBLESHIELD1);
|
||||
mobj->extravalue1 = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mobj->target->player->bubblecool && ((curstate-S_BUBBLESHIELD1) & 1))
|
||||
mobj->renderflags |= RF_GHOSTLY;
|
||||
else
|
||||
mobj->renderflags &= ~RF_GHOSTLYMASK;
|
||||
}
|
||||
if (mobj->state - states == S_BUBBLESHIELDBLOWUP)
|
||||
P_SetMobjState(mobj, S_BUBBLESHIELD1);
|
||||
}
|
||||
|
||||
mobj->extravalue2 = mobj->target->player->bubbleblowup;
|
||||
P_SetScale(mobj, (mobj->destscale = scale));
|
||||
|
||||
if (mobj->tracer && (!P_MobjWasRemoved(mobj->tracer)))
|
||||
|
|
@ -9305,24 +9255,22 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
if (mobj->tracer->type == MT_OVERLAY)
|
||||
{
|
||||
fixed_t health_scalar;
|
||||
|
||||
|
||||
P_SetScale(mobj->tracer, mobj->destscale);
|
||||
|
||||
mobj->tracer->threshold |= OV_DONTXYSCALE;
|
||||
|
||||
mobj->tracer->spritexscale = FixedMul(mobj->spritexscale, bubbleoverlayscales[scale_idx][0]);
|
||||
mobj->tracer->spriteyscale = FixedMul(mobj->spriteyscale, bubbleoverlayscales[scale_idx][1]);
|
||||
mobj->tracer->spritexscale = mobj->spritexscale;
|
||||
mobj->tracer->spriteyscale = mobj->spriteyscale;
|
||||
|
||||
health_scalar = mobj->target->player->bubblehealth * FRACUNIT / MAXBUBBLEHEALTH;
|
||||
health_scalar = player->bubblehealth * FRACUNIT / MAXBUBBLEHEALTH;
|
||||
health_scalar = 5 - CLAMP(health_scalar / (FRACUNIT / 5), 1, 5);
|
||||
|
||||
overlaystate = ((mobj->tracer->tics == 1) ? (mobj->tracer->state->nextstate) : ((statenum_t)(mobj->tracer->state-states)));
|
||||
statenum_t damagestate = health_scalar == 0 ? S_INVISIBLE : S_BUBLSHLD_DMG_1 - 1 + health_scalar;
|
||||
|
||||
// Depending on the level of damage done to the shield, show some cracks.
|
||||
if (overlaystate != bubbledamagestates[health_scalar])
|
||||
{
|
||||
P_SetMobjState(mobj->tracer, bubbledamagestates[health_scalar]);
|
||||
}
|
||||
if (mobj->tracer->state - states != damagestate)
|
||||
P_SetMobjState(mobj->tracer, damagestate);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -9346,7 +9294,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
mobj->sloperoll = 0;
|
||||
|
||||
mobj->flags &= ~(MF_NOCLIP|MF_NOCLIPTHING);
|
||||
P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z);
|
||||
P_MoveOrigin(mobj, player->mo->x, player->mo->y, player->mo->z);
|
||||
mobj->flags |= MF_NOCLIP|MF_NOCLIPTHING;
|
||||
break;
|
||||
}
|
||||
|
|
@ -9371,7 +9319,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
if (curstate != S_INVISIBLE)
|
||||
{
|
||||
// "Despawn" and play the glass landing sound.
|
||||
S_StartSoundAtVolume(mobj, mobj->info->activesound, 40);
|
||||
if (mobj->extravalue1 == 0)
|
||||
S_StartSoundAtVolume(mobj, mobj->info->activesound, 128);
|
||||
P_SetMobjState(mobj, S_INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue