Add guarding while ebraking with spheres

This commit is contained in:
AJ Martinez 2023-05-19 01:53:14 -07:00
parent 1b16b3f777
commit dadaab1817
12 changed files with 251 additions and 27 deletions

View file

@ -3288,6 +3288,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_SLIPTIDEZIP",
"S_INSTAWHIP",
"S_BLOCKRING",
"S_BLOCKBODY",
// Signpost sparkles
"S_SIGNSPARK1",
@ -5321,6 +5323,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_SLIPTIDEZIP",
"MT_INSTAWHIP",
"MT_BLOCKRING",
"MT_BLOCKBODY",
"MT_SIGNSPARKLE",

View file

@ -556,6 +556,8 @@ char sprnames[NUMSPRITES + 1][5] =
"SLPT", // Sliptide zip indicator
"IWHP", // Instawhip
"GRNG", // Guard ring
"GBDY", // Guard body
"WIPD", // Wipeout dust trail
"DRIF", // Drift Sparks
@ -3949,6 +3951,8 @@ state_t states[NUMSTATES] =
{SPR_SLPT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SLIPTIDEZIP
{SPR_IWHP, FF_FLOORSPRITE|FF_ANIMATE|0, -1, {NULL}, 6, 2, S_NULL}, // S_INSTAWHIP
{SPR_GRNG, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_BLOCKRING
{SPR_GBDY, FF_ANIMATE|0, -1, {NULL}, 4, 2, S_NULL}, // S_BLOCKBODY
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2
@ -22663,6 +22667,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_BLOCKRING
-1, // doomednum
S_BLOCKRING, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // 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
0, // speed
67*FRACUNIT, // radius
67*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate
},
{ // MT_BLOCKBODY
-1, // doomednum
S_BLOCKBODY, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // 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
0, // speed
67*FRACUNIT, // radius
67*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate
},
{ // MT_SIGNSPARKLE
-1, // doomednum

View file

@ -1109,6 +1109,8 @@ typedef enum sprite
SPR_SLPT, // Sliptide zip indicator
SPR_IWHP, // Instawhip
SPR_GRNG, // Guard ring
SPR_GBDY, // Guard body
SPR_WIPD, // Wipeout dust trail
SPR_DRIF, // Drift Sparks
@ -4360,6 +4362,8 @@ typedef enum state
S_SLIPTIDEZIP,
S_INSTAWHIP,
S_BLOCKRING,
S_BLOCKBODY,
// Signpost sparkles
S_SIGNSPARK1,
@ -6428,6 +6432,8 @@ typedef enum mobj_type
MT_SLIPTIDEZIP,
MT_INSTAWHIP,
MT_BLOCKRING,
MT_BLOCKBODY,
MT_SIGNSPARKLE,

View file

@ -787,48 +787,96 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
return true;
}
boolean K_InstaWhipCollide(mobj_t *t1, mobj_t *t2)
boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
{
const int defenderHitlag = 10;
const int victimHitlag = 10;
const int attackerHitlag = 4;
if (t2->player)
// EV1 is used to indicate that we should no longer hit monitors.
// EV2 indicates we should no longer hit anything.
if (shield->extravalue2)
return false;
mobj_t *attacker = shield->target;
if (!attacker || P_MobjWasRemoved(attacker) || !attacker->player)
return false; // How did we even get here?
player_t *attackerPlayer = attacker->player;
if (victim->player)
{
if (t2 != t1->target && !P_PlayerInPain(t2->player) && t2->player->flashing == 0)
player_t *victimPlayer = victim->player;
if (victim != attacker && !P_PlayerInPain(victimPlayer) && victimPlayer->flashing == 0)
{
if (K_PlayerEBrake(victimPlayer) && victimPlayer->spheres > 0)
{
if (P_PlayerInPain(attackerPlayer))
return false; // never punish shield more than once
angle_t thrangle = R_PointToAngle2(victim->x, victim->y, shield->x, shield->y);
attacker->momx = attacker->momy = 0;
P_Thrust(attacker, thrangle, FRACUNIT*7);
victimPlayer->spheres = std::min(victimPlayer->spheres + 10, 40);
shield->renderflags &= ~RF_DONTDRAW;
shield->flags |= MF_NOCLIPTHING;
attacker->renderflags &= ~RF_DONTDRAW;
attackerPlayer->instaShieldCooldown = TICRATE*2;
attackerPlayer->flashing = 0;
P_DamageMobj(attacker, victim, victim, 1, DMG_STING);
S_StartSound(victim, sfx_mbv92);
K_AddHitLag(attacker, 2*victimHitlag, true);
K_AddHitLag(victim, attackerHitlag, false);
attacker->hitlag = std::min(attacker->hitlag, 2*victimHitlag);
shield->hitlag = attacker->hitlag;
shield->extravalue2 = 1;
return true;
}
// Damage is a bit hacky, we want only a small loss-of-control
// while still behaving as if it's a "real" hit.
P_PlayRinglossSound(t2);
P_PlayerRingBurst(t2->player, 5);
P_DamageMobj(t2, t1, t1->target, 1, DMG_STUMBLE);
P_PlayRinglossSound(victim);
P_PlayerRingBurst(victimPlayer, 5);
P_DamageMobj(victim, shield, attacker, 1, DMG_STUMBLE); // There's a pecial exception in P_DamageMobj for type==MT_INSTAWHIP
K_AddHitLag(t2, defenderHitlag, true);
K_AddHitLag(t1->target, attackerHitlag, false);
t1->hitlag = t1->target->hitlag;
angle_t thrangle = ANGLE_180 + R_PointToAngle2(victim->x, victim->y, shield->x, shield->y);
P_Thrust(victim, thrangle, FRACUNIT*10);
K_AddHitLag(victim, victimHitlag, true);
K_AddHitLag(attacker, attackerHitlag, false);
shield->hitlag = attacker->hitlag;
return true;
}
return false;
}
else
{
if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_GACHABOM
|| 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_GARDENTOP || t2->type == MT_DROPTARGET || t2->type == MT_BATTLECAPSULE
|| t2->type == MT_MONITOR)
if (victim->type == MT_ORBINAUT || victim->type == MT_JAWZ || victim->type == MT_GACHABOM
|| victim->type == MT_BANANA || victim->type == MT_EGGMANITEM || victim->type == MT_BALLHOG
|| victim->type == MT_SSMINE || victim->type == MT_LANDMINE || victim->type == MT_SINK
|| victim->type == MT_GARDENTOP || victim->type == MT_DROPTARGET || victim->type == MT_BATTLECAPSULE
|| victim->type == MT_MONITOR)
{
// Monitor hack. We can hit monitors once per instawhip, no multihit shredding!
// Damage values in Obj_MonitorGetDamage.
if (t2->type == MT_MONITOR)
if (victim->type == MT_MONITOR)
{
if (t1->extravalue1 == 1)
if (shield->extravalue1 == 1)
return false;
t1->extravalue1 = 1;
shield->extravalue1 = 1;
}
P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL);
K_AddHitLag(t1->target, attackerHitlag, false);
t1->hitlag = t1->target->hitlag;
P_DamageMobj(victim, shield, attacker, 1, DMG_NORMAL);
K_AddHitLag(attacker, attackerHitlag, false);
shield = attacker;
}
return false;
}
@ -1022,7 +1070,7 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
bool stung = false;
if (t2->player->rings <= 0)
if (t2->player->rings <= 0 && t2->player->spheres <= 0)
{
P_DamageMobj(t2, t1, t1, 1, DMG_STING|DMG_WOMBO);
stung = true;

View file

@ -24,7 +24,7 @@ boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2);
void K_LightningShieldAttack(mobj_t *actor, fixed_t size);
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2);
boolean K_InstaWhipCollide(mobj_t *t1, mobj_t *t2);
boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim);
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2);

View file

@ -7777,7 +7777,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
// where's the < 0 check? see below the following block!
{
tic_t spheredigestion = TICRATE; // Base rate of 1 every second when playing.
tic_t spheredigestion = TICRATE*2; // Base rate of 1 every second when playing.
tic_t digestionpower = ((10 - player->kartspeed) + (10 - player->kartweight))-1; // 1 to 17
// currently 0-34
@ -7789,7 +7789,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
}
else
{
spheredigestion -= digestionpower;
spheredigestion -= digestionpower/2;
}
if ((player->spheres > 0) && (player->spheredigestion > 0))
@ -7807,6 +7807,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->spheres--;
player->spheredigestion = spheredigestion;
}
if (K_PlayerEBrake(player) && (player->ebrakefor%6 == 0))
player->spheres--;
}
else
{
@ -9833,6 +9836,23 @@ void K_KartEbrakeVisuals(player_t *p)
if (!S_SoundPlaying(p->mo, sfx_s3kd9s))
S_ReducedVFXSound(p->mo, sfx_s3kd9s, p);
// Block visuals
// (These objects track whether a player is block-eligible on their own, no worries)
if (!p->ebrakefor)
{
mobj_t *ring = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKRING);
P_SetTarget(&ring->target, p->mo);
P_SetScale(ring, p->mo->scale);
K_MatchGenericExtraFlags(ring, p->mo);
ring->renderflags &= ~RF_DONTDRAW;
mobj_t *body = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKBODY);
P_SetTarget(&body->target, p->mo);
P_SetScale(body, p->mo->scale);
K_MatchGenericExtraFlags(body, p->mo);
body->renderflags |= RF_DONTDRAW;
}
// HOLD! bubble.
if (!p->ebrakefor)
{

View file

@ -110,6 +110,10 @@ boolean Obj_DropTargetMorphThink(mobj_t *morph);
/* Instawhip */
void Obj_InstaWhipThink(mobj_t *whip);
/* Block VFX */
void Obj_BlockRingThink(mobj_t *ring);
void Obj_BlockBodyThink(mobj_t *body);
/* Ring Shooter */
boolean Obj_RingShooterThinker(mobj_t *mo);
boolean Obj_PlayerRingShooterFreeze(player_t *const player);

View file

@ -18,4 +18,5 @@ target_sources(SRB2SDL2 PRIVATE
audience.c
random-item.c
instawhip.c
block.c
)

68
src/objects/block.c Normal file
View file

@ -0,0 +1,68 @@
#include "../doomdef.h"
#include "../info.h"
#include "../k_objects.h"
#include "../p_local.h"
void Obj_BlockRingThink (mobj_t *ring)
{
if (P_MobjWasRemoved(ring->target) || !ring->target->player || !ring->target->player->ebrakefor)
{
P_RemoveMobj(ring);
}
else
{
mobj_t *mo = ring->target;
player_t *player = mo->player;
// Follow player
ring->flags &= ~(MF_NOCLIPTHING);
P_SetScale(ring, mo->scale);
P_MoveOrigin(ring, mo->x, mo->y, mo->z + mo->height/2);
ring->flags |= MF_NOCLIPTHING;
ring->color = mo->color;
// Twirl
ring->angle = ring->target->angle + (ANG15 * leveltime);
// Visuals
ring->renderflags |= RF_ADD|RF_PAPERSPRITE;
if (leveltime%2)
ring->renderflags &= ~RF_DONTDRAW;
else
ring->renderflags |= RF_DONTDRAW;
if (player->spheres == 0)
ring->renderflags |= RF_DONTDRAW;
}
}
void Obj_BlockBodyThink (mobj_t *body)
{
if (P_MobjWasRemoved(body->target) || !body->target->player || !body->target->player->ebrakefor)
{
P_RemoveMobj(body);
}
else
{
mobj_t *mo = body->target;
player_t *player = mo->player;
// Follow player
body->flags &= ~(MF_NOCLIPTHING);
P_SetScale(body, mo->scale);
P_MoveOrigin(body, mo->x, mo->y, mo->z + mo->height/2);
body->flags |= MF_NOCLIPTHING;
body->color = mo->color;
// Visuals
body->renderflags |= RF_ADD;
if (leveltime%2 == 0)
body->renderflags &= ~RF_DONTDRAW;
else
body->renderflags |= RF_DONTDRAW;
if (player->spheres == 0)
body->renderflags |= RF_DONTDRAW;
}
}

View file

@ -2208,6 +2208,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
{
sfx = sfx_grownd;
}
else if (player->spheres > 0 && K_PlayerEBrake(player))
{
sfx = sfx_s3k3a;
player->spheres = max(player->spheres - 10, 0);
}
else if (player->hyudorotimer > 0)
;
else
@ -2308,7 +2313,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
// Instawhip breaks the rules and does "damaging stumble",
// but sting and stumble shouldn't be rewarding Battle hits otherwise.
if ((type == DMG_STING || type == DMG_STUMBLE) && inflictor->type != MT_INSTAWHIP )
if ((type == DMG_STING || type == DMG_STUMBLE) && (inflictor && inflictor->type != MT_INSTAWHIP))
{
damage = 0;
}

View file

@ -8361,6 +8361,16 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
Obj_InstaWhipThink(mobj);
break;
}
case MT_BLOCKRING:
{
Obj_BlockRingThink(mobj);
break;
}
case MT_BLOCKBODY:
{
Obj_BlockBodyThink(mobj);
break;
}
case MT_GARDENTOPSPARK:
{
Obj_GardenTopSparkThink(mobj);

View file

@ -901,7 +901,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"mbv8f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"mbv90", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"mbv91", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"mbv92", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"mbv92", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Changed falloff for use in instashield parry.
{"mbv93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"mbv94", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"mbv95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},