Merge branch 'lightning-attack' into 'master'

Lightning attack

See merge request kart-krew-dev/ring-racers-internal!2691
This commit is contained in:
Oni VelocitOni 2025-07-19 05:03:26 +00:00
commit f8c5764276
11 changed files with 188 additions and 15 deletions

View file

@ -833,6 +833,7 @@ struct player_t
UINT16 flamedash; // Flame Shield dash power
UINT16 flamemeter; // Flame Shield dash meter left
UINT8 flamelength; // Flame Shield dash meter, number of segments
UINT8 lightningcharge; // Lightning Shield attack timer
UINT16 counterdash; // Flame Shield boost without the flame, largely. Used in places where awarding thrust would affect player control.

View file

@ -2011,6 +2011,12 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_THNC2",
"S_THNB1",
"S_THND",
"S_THNE",
"S_THNH",
"S_THNF",
"S_THNG",
// Bubble Shield
"S_BUBBLESHIELD1",
"S_BUBBLESHIELD2",
@ -3664,6 +3670,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_LIGHTNINGSHIELD", // Shields
"MT_LIGHTNINGSHIELD_VISUAL",
"MT_LIGHTNINGATTACK_VISUAL",
"MT_BUBBLESHIELD",
"MT_BUBBLESHIELD_VISUAL",
"MT_FLAMESHIELD",

View file

@ -388,6 +388,11 @@ char sprnames[NUMSPRITES + 1][5] =
"THNC", // Lightning Shield Top Flash
"THNA", // Lightning Shield Top Swoosh
"THNB", // Lightning Shield Bottom Swoosh
"THND", // Lightning attack
"THNE", // Lightning attack
"THNH", // Lightning attack
"THNF", // Lightning attack
"THNG", // Lightning attack
"BUBS", // Bubble Shield (not Bubs)
"BUBT", // Bubble Shield trap
"BUBA", // Bubble Shield Outline
@ -2580,6 +2585,12 @@ state_t states[NUMSTATES] =
{SPR_THNC, FF_ADD|FF_FULLBRIGHT|FF_ANIMATE, 11, {NULL}, 10, 1, S_THNB1}, // S_THNC2
{SPR_THNB, FF_ADD|FF_FULLBRIGHT|FF_ANIMATE, 43, {NULL}, 42, 1, S_THNC1}, // S_THNB1
{SPR_THND, FF_ADD|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 10, 1, S_THND}, // S_THND
{SPR_THNE, FF_FULLBRIGHT|FF_ANIMATE, 34, {NULL}, 33, 1, S_THNH}, // S_THNE
{SPR_NULL, FF_FULLBRIGHT, 34, {NULL}, 33, 1, S_THNE}, // S_THNH
{SPR_THNF, FF_FULLBRIGHT|FF_ANIMATE, 4, {NULL}, 3, 1, S_THNG}, // S_THNF
{SPR_THNG, FF_FULLBRIGHT|FF_ANIMATE, 64, {NULL}, 63, 1, S_THNF}, // S_THNG
{SPR_BUBS, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BUBBLESHIELD2}, // S_BUBBLESHIELD1
{SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD3}, // S_BUBBLESHIELD2
{SPR_BUBS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_BUBBLESHIELD4}, // S_BUBBLESHIELD3
@ -15603,6 +15614,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_LIGHTNINGATTACK_VISUAL
-1, // doomednum
S_THND, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
8, // speed
28*FRACUNIT, // radius
56*FRACUNIT, // height
1, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_BUBBLESHIELD
-1, // doomednum
S_BUBBLESHIELD1, // spawnstate

View file

@ -929,6 +929,11 @@ typedef enum sprite
SPR_THNC, // Lightning Shield Top Flash
SPR_THNA, // Lightning Shield Top Swoosh
SPR_THNB, // Lightning Shield Bottom Swoosh
SPR_THND, // Lightning Attack
SPR_THNE, // Lightning Attack
SPR_THNH, // Lightning Attack
SPR_THNF, // Lightning Attack
SPR_THNG, // Lightning Attack
SPR_BUBS, // Bubble Shield (not Bubs)
SPR_BUBT, // Bubble Shield trap
SPR_BUBA, // Bubble Shield Outline
@ -3073,6 +3078,12 @@ typedef enum state
S_THNC2,
S_THNB1,
S_THND,
S_THNE,
S_THNH,
S_THNF,
S_THNG,
// Bubble Shield
S_BUBBLESHIELD1,
S_BUBBLESHIELD2,
@ -4753,6 +4764,7 @@ typedef enum mobj_type
MT_LIGHTNINGSHIELD, // Shields
MT_LIGHTNINGSHIELD_VISUAL,
MT_LIGHTNINGATTACK_VISUAL,
MT_BUBBLESHIELD,
MT_BUBBLESHIELD_VISUAL,
MT_FLAMESHIELD,

View file

@ -1488,6 +1488,9 @@ static boolean K_HasInfiniteTether(player_t *player)
return true;
}
if (player->lightningcharge)
return true;
if (player->eggmanexplode > 0)
return true;
@ -1618,7 +1621,7 @@ static boolean K_TryDraft(player_t *player, mobj_t *dest, fixed_t minDist, fixed
player->draftpower -= 3*add/4;
}
if (gametyperules & GTR_CLOSERPLAYERS)
if (gametyperules & GTR_CLOSERPLAYERS || player->curshield == KSHIELD_LIGHTNING || player->lightningcharge)
{
// Double speed in smaller environments
player->draftpower += add;
@ -10713,6 +10716,45 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
K_FlameDashLeftoverSmoke(player->mo);
}
if (player->curshield != KSHIELD_LIGHTNING)
{
player->lightningcharge = 0;
}
if (player->lightningcharge)
{
player->lightningcharge++;
/*
if (onground)
P_Thrust(player->mo, player->mo->angle, player->mo->scale);
*/
if (player->lightningcharge == LIGHTNING_CHARGE)
{
K_DoLightningShield(player);
P_Thrust(player->mo, onground ? player->mo->angle : K_MomentumAngle(player->mo), 100*player->mo->scale);
// player->tiregrease = TICRATE/4;
player->lightningcharge = 0;
if (player->itemamount > 0)
{
// Why is this a conditional?
// Lightning shield: the only item that allows you to
// activate a mine while you're out of its radius,
// the SAME tic it sets your itemamount to 0
// ...:dumbestass:
player->itemamount--;
K_PlayAttackTaunt(player->mo);
player->botvars.itemconfirm = 0;
}
}
}
else
{
S_StopSoundByID(player->mo, LIGHTNING_SOUND);
}
if (P_IsObjectOnGround(player->mo) && player->trickpanel != TRICKSTATE_NONE)
{
if (P_MobjFlip(player->mo) * player->mo->momz <= 0)
@ -14745,20 +14787,27 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
Obj_SpawnLightningShieldVisuals(shield);
}
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO && !player->lightningcharge)
{
K_DoLightningShield(player);
if (player->itemamount > 0)
{
// Why is this a conditional?
// Lightning shield: the only item that allows you to
// activate a mine while you're out of its radius,
// the SAME tic it sets your itemamount to 0
// ...:dumbestass:
player->itemamount--;
K_PlayAttackTaunt(player->mo);
player->botvars.itemconfirm = 0;
}
// K_DoLightningShield(player);
player->lightningcharge = 1;
mobj_t *at1 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
mobj_t *at2 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
mobj_t *at3 = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_LIGHTNINGATTACK_VISUAL);
P_SetMobjState(at1, S_THNG);
P_SetMobjState(at2, S_THND);
P_SetMobjState(at3, S_THNH);
at2->dispoffset = 2;
at3->dispoffset = -1;
P_SetTarget(&at1->target, player->mo);
P_SetTarget(&at2->target, player->mo);
P_SetTarget(&at3->target, player->mo);
S_StartSound(player->mo, LIGHTNING_SOUND);
}
break;
case KITEM_GARDENTOP:

View file

@ -59,6 +59,9 @@ Make sure this matches the actual number of states
#define TIMEATTACK_START (TICRATE*10)
#define LIGHTNING_CHARGE (TICRATE*2)
#define LIGHTNING_SOUND (sfx_s3k84)
#define OVERDRIVE_STARTUP (0)
#define AMPLEVEL (15)

View file

@ -464,6 +464,10 @@ boolean Obj_TickBubbleShieldVisual(mobj_t *mobj);
void Obj_SpawnLightningShieldVisuals(mobj_t *source);
boolean Obj_TickLightningShieldVisual(mobj_t *mobj);
/* Lightning Attack */
void Obj_SpawnLightningAttackVisuals(mobj_t *source);
boolean Obj_TickLightningAttackVisual(mobj_t *mobj);
/* Flame Shield */
void Obj_SpawnFlameShieldVisuals(mobj_t *source);
boolean Obj_TickFlameShieldVisual(mobj_t *mobj);

View file

@ -494,6 +494,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->flamemeter);
else if (fastcmp(field,"flamelength"))
lua_pushinteger(L, plr->flamelength);
else if (fastcmp(field,"lightningcharge"))
lua_pushinteger(L, plr->lightningcharge);
else if (fastcmp(field,"ballhogcharge"))
lua_pushinteger(L, plr->ballhogcharge);
else if (fastcmp(field,"ballhogtap"))
@ -1133,6 +1135,8 @@ static int player_set(lua_State *L)
plr->flamemeter = luaL_checkinteger(L, 3);
else if (fastcmp(field,"flamelength"))
plr->flamelength = luaL_checkinteger(L, 3);
else if (fastcmp(field,"lightningcharge"))
plr->lightningcharge = luaL_checkinteger(L, 3);
else if (fastcmp(field,"ballhogcharge"))
plr->ballhogcharge = luaL_checkinteger(L, 3);
else if (fastcmp(field,"ballhogtap"))

View file

@ -6721,6 +6721,59 @@ static void P_MobjSceneryThink(mobj_t *mobj)
}
break;
}
case MT_LIGHTNINGATTACK_VISUAL:
{
if (!(mobj->target && !P_MobjWasRemoved(mobj->target)))
{
P_RemoveMobj(mobj);
return;
}
if (!mobj->target->player || !mobj->target->player->lightningcharge)
{
P_RemoveMobj(mobj);
return;
}
UINT8 SHRINK = 5;
UINT8 timer = (LIGHTNING_CHARGE - mobj->target->player->lightningcharge);
UINT8 target = timer/10 + 1;
fixed_t myscale = (5*mobj->target->scale)>>2;
if (timer <= SHRINK)
{
myscale = Easing_InSine(FRACUNIT*(SHRINK - timer)/SHRINK, myscale, 0);
}
else
{
UINT8 pretimer = LIGHTNING_CHARGE - SHRINK;
fixed_t scalefactor = FRACUNIT * (timer - SHRINK) / pretimer;
myscale = Easing_Linear(scalefactor, 5*myscale/4, myscale);
}
P_SetScale(mobj, (mobj->destscale = myscale));
P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z + mobj->target->height/2);
// Taken from K_FlipFromObject. We just want to flip the visual according to its target, but that's it.
mobj->eflags = (mobj->eflags & ~MFE_VERTICALFLIP)|(mobj->target->eflags & MFE_VERTICALFLIP);
mobj->extravalue1++;
if (mobj->extravalue1 > target)
{
mobj->color = SKINCOLOR_WHITE;
mobj->colorized = true;
mobj->extravalue1 = 0;
}
else
{
mobj->colorized = false;
mobj->renderflags &= ~RF_DONTDRAW;
}
break;
}
case MT_FLAMESHIELD_VISUAL:
{
if (!Obj_TickFlameShieldVisual(mobj))

View file

@ -560,6 +560,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEUINT16(save->p, players[i].counterdash);
WRITEUINT16(save->p, players[i].flamemeter);
WRITEUINT8(save->p, players[i].flamelength);
WRITEUINT8(save->p, players[i].lightningcharge);
WRITEUINT16(save->p, players[i].ballhogcharge);
WRITEUINT8(save->p, players[i].ballhogtap);
@ -1225,6 +1226,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].counterdash = READUINT16(save->p);
players[i].flamemeter = READUINT16(save->p);
players[i].flamelength = READUINT8(save->p);
players[i].lightningcharge = READUINT8(save->p);
players[i].ballhogcharge = READUINT16(save->p);
players[i].ballhogtap = READUINT8(save->p);

View file

@ -534,7 +534,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3k81", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"},
{"s3k82", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"},
{"s3k83", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Collapsing"},
{"s3k84", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"},
{"s3k84", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"}, // Lightning Shield Charge
{"s3k85", false, 64, 24, -1, NULL, 0, -1, -1, LUMPERROR, "Powering down"},
{"s3k86", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Alarm"},
{"s3k87", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"},