From dadaab1817789dcfe32fab85dc766b01f73112ea Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Fri, 19 May 2023 01:53:14 -0700 Subject: [PATCH] Add guarding while ebraking with spheres --- src/deh_tables.c | 4 ++ src/info.c | 58 ++++++++++++++++++++++++ src/info.h | 6 +++ src/k_collide.cpp | 92 +++++++++++++++++++++++++++++--------- src/k_collide.h | 2 +- src/k_kart.c | 24 +++++++++- src/k_objects.h | 4 ++ src/objects/CMakeLists.txt | 1 + src/objects/block.c | 68 ++++++++++++++++++++++++++++ src/p_inter.c | 7 ++- src/p_mobj.c | 10 +++++ src/sounds.c | 2 +- 12 files changed, 251 insertions(+), 27 deletions(-) create mode 100644 src/objects/block.c diff --git a/src/deh_tables.c b/src/deh_tables.c index f9ad7fdad..8844cb7b3 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -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", diff --git a/src/info.c b/src/info.c index 57713644e..7b3f3c177 100644 --- a/src/info.c +++ b/src/info.c @@ -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 diff --git a/src/info.h b/src/info.h index 10d35a0a8..af8297eff 100644 --- a/src/info.h +++ b/src/info.h @@ -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, diff --git a/src/k_collide.cpp b/src/k_collide.cpp index 9911895ff..dc34a204d 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -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; diff --git a/src/k_collide.h b/src/k_collide.h index 0f29ebf6b..84d9a324e 100644 --- a/src/k_collide.h +++ b/src/k_collide.h @@ -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); diff --git a/src/k_kart.c b/src/k_kart.c index a8d7c207e..4499ca04f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -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) { diff --git a/src/k_objects.h b/src/k_objects.h index a7788d303..f9f488036 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -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); diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index cb2f61519..2fe1f0937 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -18,4 +18,5 @@ target_sources(SRB2SDL2 PRIVATE audience.c random-item.c instawhip.c + block.c ) diff --git a/src/objects/block.c b/src/objects/block.c new file mode 100644 index 000000000..e567473a3 --- /dev/null +++ b/src/objects/block.c @@ -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; + } +} \ No newline at end of file diff --git a/src/p_inter.c b/src/p_inter.c index 6ca9acf66..1196bd836 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -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; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 98b9470a8..5f6f6f599 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -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); diff --git a/src/sounds.c b/src/sounds.c index 2f5edb9c6..09d9e437d 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -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, ""},