diff --git a/src/d_player.h b/src/d_player.h index e37a563e1..e6e306537 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -740,6 +740,12 @@ struct player_t mobj_t *stumbleIndicator; mobj_t *sliptideZipIndicator; + mobj_t *whip; + + UINT8 instaShieldCooldown; + UINT8 guardCooldown; + + INT16 incontrol; // -1 to -175 when spinning out or tumbling, 1 to 175 when not. Use to check for combo hits or emergency inputs. uint8_t public_key[PUBKEYLENGTH]; diff --git a/src/deh_tables.c b/src/deh_tables.c index 63458676b..d348b3a4a 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3287,6 +3287,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_SLIPTIDEZIP", + "S_INSTAWHIP", + "S_BLOCKRING", + "S_BLOCKBODY", + // Signpost sparkles "S_SIGNSPARK1", "S_SIGNSPARK2", @@ -4011,6 +4015,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_INSTASHIELDB7", "S_POWERCLASH", // Invinc/Grow no damage collide VFX + "S_GUARDBREAK", // Guard break "S_PLAYERARROW", // Above player arrow "S_PLAYERARROW_BOX", @@ -5318,6 +5323,10 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_SLIPTIDEZIP", + "MT_INSTAWHIP", + "MT_BLOCKRING", + "MT_BLOCKBODY", + "MT_SIGNSPARKLE", "MT_FASTLINE", @@ -5487,7 +5496,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_INSTASHIELDB", "MT_POWERCLASH", // Invinc/Grow no damage clash VFX - + "MT_GUARDBREAK", // Guard break + "MT_PLAYERARROW", "MT_PLAYERWANTED", diff --git a/src/g_game.c b/src/g_game.c index 37399c561..9f75d137a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2675,6 +2675,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) P_SetTarget(&players[player].follower, NULL); P_SetTarget(&players[player].awayview.mobj, NULL); P_SetTarget(&players[player].stumbleIndicator, NULL); + P_SetTarget(&players[player].whip, NULL); P_SetTarget(&players[player].ringShooter, NULL); P_SetTarget(&players[player].followmobj, NULL); diff --git a/src/info.c b/src/info.c index bb3f3f8e4..6e01d67b1 100644 --- a/src/info.c +++ b/src/info.c @@ -555,6 +555,10 @@ char sprnames[NUMSPRITES + 1][5] = "SLPT", // Sliptide zip indicator + "IWHP", // Instawhip + "GRNG", // Guard ring + "GBDY", // Guard body + "WIPD", // Wipeout dust trail "DRIF", // Drift Sparks "BDRF", // Brake drift sparks @@ -634,6 +638,7 @@ char sprnames[NUMSPRITES + 1][5] = "ISTB", // instashield layer B "PWCL", // Invinc/grow clash VFX + "GBRK", // Guard break "ARRO", // player arrows "ITEM", @@ -3946,6 +3951,10 @@ state_t states[NUMSTATES] = {SPR_SLPT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SLIPTIDEZIP + {SPR_IWHP, FF_FULLBRIGHT|FF_FLOORSPRITE|FF_ANIMATE|0, -1, {NULL}, 6, 2, S_NULL}, // S_INSTAWHIP + {SPR_GRNG, FF_FULLBRIGHT|FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_BLOCKRING + {SPR_GBDY, FF_FULLBRIGHT|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 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3 @@ -4627,6 +4636,7 @@ state_t states[NUMSTATES] = {SPR_ISTB, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_NULL}, // S_INSTASHIELDB7 {SPR_PWCL, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE, 10, {NULL}, 9, 1, S_NULL}, // S_POWERCLASH + {SPR_GBRK, FF_ADD|FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE, 24, {NULL}, 5, 4, S_NULL}, // S_GUARDBREAK // Above player arrow {SPR_ARRO, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_PLAYERARROW @@ -22632,6 +22642,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, + + { // MT_INSTAWHIP + -1, // doomednum + S_INSTAWHIP, // 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 + 90*FRACUNIT, // radius + 90*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + 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 @@ -26089,6 +26180,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_GUARDBREAK + -1, // doomednum + S_GUARDBREAK, // 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 + 8*FRACUNIT, // radius + 8*FRACUNIT, // height + 2, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_PLAYERARROW -1, // doomednum S_PLAYERARROW, // spawnstate diff --git a/src/info.h b/src/info.h index cdb577e1b..c2d7a0356 100644 --- a/src/info.h +++ b/src/info.h @@ -1108,6 +1108,10 @@ 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 SPR_BDRF, // Brake drift sparks @@ -1187,6 +1191,7 @@ typedef enum sprite SPR_ISTB, // instashield layer B SPR_PWCL, // Invinc/grow clash VFX + SPR_GBRK, // Guard break SPR_ARRO, // player arrows SPR_ITEM, @@ -4357,6 +4362,10 @@ typedef enum state S_SLIPTIDEZIP, + S_INSTAWHIP, + S_BLOCKRING, + S_BLOCKBODY, + // Signpost sparkles S_SIGNSPARK1, S_SIGNSPARK2, @@ -5080,6 +5089,7 @@ typedef enum state S_INSTASHIELDB7, S_POWERCLASH, // Grow/Invinc clash VFX + S_GUARDBREAK, S_PLAYERARROW, // Above player arrow S_PLAYERARROW_BOX, @@ -6423,6 +6433,10 @@ typedef enum mobj_type MT_MAGICIANBOX, MT_SLIPTIDEZIP, + MT_INSTAWHIP, + MT_BLOCKRING, + MT_BLOCKBODY, + MT_SIGNSPARKLE, MT_FASTLINE, @@ -6592,6 +6606,7 @@ typedef enum mobj_type MT_INSTASHIELDB, MT_POWERCLASH, // Grow/Invinc clash VFX + MT_GUARDBREAK, MT_PLAYERARROW, MT_PLAYERWANTED, diff --git a/src/k_battle.c b/src/k_battle.c index 7d2ad8039..7c6dd7d09 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -197,9 +197,9 @@ mobj_t *K_SpawnChaosEmerald(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT P_Thrust(emerald, FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle, - 24 * mapobjectscale); + 36 * mapobjectscale); - emerald->momz = flip * 24 * mapobjectscale; + emerald->momz = flip * 36 * mapobjectscale; if (emerald->eflags & MFE_UNDERWATER) emerald->momz = (117 * emerald->momz) / 200; @@ -265,6 +265,9 @@ void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType) UINT8 i; SINT8 flip = P_MobjFlip(player->mo); + if (player->incontrol < TICRATE) + return; + for (i = 0; i < 14; i++) { UINT32 emeraldFlag = (1 << i); @@ -275,6 +278,7 @@ void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType) P_SetTarget(&emerald->target, player->mo); player->emeralds &= ~emeraldFlag; + break; // Drop only one emerald. Emerald wins are hard enough! } } } diff --git a/src/k_botitem.c b/src/k_botitem.c index dc69cc058..55dc3f0eb 100644 --- a/src/k_botitem.c +++ b/src/k_botitem.c @@ -1362,6 +1362,18 @@ static void K_BotItemRings(player_t *player, ticcmd_t *cmd) { INT32 saferingsval = 16 - K_GetKartRingPower(player, false); + if (leveltime < starttime) + { + // Don't use rings during POSITION!! + return; + } + + if ((cmd->buttons & BT_ACCELERATE) == 0) + { + // Don't use rings if you're not trying to accelerate. + return; + } + if (P_IsObjectOnGround(player->mo) == false) { // Don't use while mid-air. @@ -1380,6 +1392,70 @@ static void K_BotItemRings(player_t *player, ticcmd_t *cmd) } } +/*-------------------------------------------------- + static void K_BotItemInstashield(player_t *player, ticcmd_t *cmd) + + Item usage for instashield. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemInstashield(player_t *player, ticcmd_t *cmd) +{ + const fixed_t radius = FixedMul(mobjinfo[MT_INSTAWHIP].radius, player->mo->scale); + size_t i = SIZE_MAX; + + if (K_ItemButtonWasDown(player) == true) + { + // Release the button, dude. + return; + } + + if (player->instaShieldCooldown || leveltime < starttime || player->spindash) + { + // Instashield is on cooldown. + return; + } + + // Find players within the instashield's range. + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *target = NULL; + fixed_t dist = INT32_MAX; + + if (!playeringame[i]) + { + continue; + } + + target = &players[i]; + if (P_MobjWasRemoved(target->mo) == true + || player == target + || target->spectator == true + || target->flashing != 0) + { + continue; + } + + dist = P_AproxDistance(P_AproxDistance( + player->mo->x - target->mo->x, + player->mo->y - target->mo->y), + (player->mo->z - target->mo->z) / 4 + ); + + if (dist <= radius) + { + // Use it!! + cmd->buttons |= BT_ATTACK; + break; + } + } +} + /*-------------------------------------------------- static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd) @@ -1453,12 +1529,16 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt) { if (player->pflags & PF_USERINGS) { - // Use rings! - - if (leveltime > starttime) + if (player->rings > 0) { + // Use rings! K_BotItemRings(player, cmd); } + else + { + // Use the instashield! + K_BotItemInstashield(player, cmd); + } } else { diff --git a/src/k_collide.cpp b/src/k_collide.cpp index 9bb2283be..a129d6c44 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -787,6 +787,140 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2) return true; } +boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim) +{ + int victimHitlag = 10; + int attackerHitlag = 4; + + // 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) + { + player_t *victimPlayer = victim->player; + + //if (victim != attacker && !P_PlayerInPain(victimPlayer) && victimPlayer->flashing == 0) + if (victim != attacker && victim->hitlag == 0) + { + // If both players have a whip, hits are order-of-execution dependent and that sucks. + // Player expectation is a clash here. + if (victimPlayer->whip && !P_MobjWasRemoved(victimPlayer->whip)) + { + victimPlayer->whip->extravalue2 = 1; + shield->extravalue2 = 1; + + K_DoPowerClash(victim, attacker); + + victim->renderflags &= ~RF_DONTDRAW; + attacker->renderflags &= ~RF_DONTDRAW; + + angle_t thrangle = R_PointToAngle2(attacker->x, attacker->y, victim->x, victim->y); + P_Thrust(victim, thrangle, FRACUNIT*7); + P_Thrust(attacker, ANGLE_180 + thrangle, FRACUNIT*7); + + return false; + } + + // Instawhip _always_ loses to guard. + if (K_PlayerGuard(victimPlayer)) + //if (true) + { + victimHitlag = 3*victimHitlag; + + 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); + + // A little extra juice, so successful reads are usually positive or zero on spheres. + victimPlayer->spheres = std::min(victimPlayer->spheres + 10, 40); + + shield->renderflags &= ~RF_DONTDRAW; + shield->flags |= MF_NOCLIPTHING; + + // Attacker should be free to all reasonable followups. + attacker->renderflags &= ~RF_DONTDRAW; + attackerPlayer->spindashboost = 0; + attackerPlayer->sneakertimer = 0; + attackerPlayer->instaShieldCooldown = TICRATE*2; + attackerPlayer->guardCooldown = TICRATE*2; + attackerPlayer->flashing = 0; + + // Localized broly for a local event. + mobj_t *broly = Obj_SpawnBrolyKi(victim, victimHitlag); + broly->extravalue2 = 16*mapobjectscale; + + P_PlayVictorySound(victim); + + P_DamageMobj(attacker, victim, victim, 1, DMG_STING); + + S_StartSound(victim, sfx_mbv92); + K_AddHitLag(attacker, victimHitlag, true); + K_AddHitLag(victim, attackerHitlag, false); + + K_DoPowerClash(shield, victim); // REJECTED + + attacker->hitlag = victimHitlag; // No, seriously, we do not care about K_AddHitLag's idea of a normal maximum + shield->hitlag = attacker->hitlag; + + shield->extravalue2 = 1; + + return true; + } + + // if you're here, you're getting hit + // 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(victim); + P_PlayerRingBurst(victimPlayer, 5); + P_DamageMobj(victim, shield, attacker, 1, DMG_STUMBLE); // There's a special exception in P_DamageMobj for type==MT_INSTAWHIP + + 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 (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 || victim->type == MT_SPECIAL_UFO) + { + // Monitor hack. We can hit monitors once per instawhip, no multihit shredding! + // Damage values in Obj_MonitorGetDamage. + if (victim->type == MT_MONITOR) + { + if (shield->extravalue1 == 1) + return false; + shield->extravalue1 = 1; + } + + P_DamageMobj(victim, shield, attacker, 1, DMG_NORMAL); + K_AddHitLag(attacker, attackerHitlag, false); + shield->hitlag = attacker->hitlag; + } + return false; + } +} + boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2) { if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0))) @@ -872,12 +1006,13 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2) || (t1->player->invincibilitytimer > 0) || (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD) || (t1->player->curshield == KSHIELD_TOP && !K_IsHoldingDownTop(t1->player)) - || (t1->player->bubbleblowup > 0); + || (t1->player->bubbleblowup > 0) + || (t1->player->spheres > 0 && K_PlayerEBrake(t1->player)); }; if (canClash(t1, t2) && canClash(t2, t1)) { - K_DoPowerClash(t1->player, t2->player); + K_DoPowerClash(t1, t2); return false; } @@ -975,7 +1110,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 c93c72ed2..84d9a324e 100644 --- a/src/k_collide.h +++ b/src/k_collide.h @@ -24,6 +24,8 @@ 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 *shield, mobj_t *victim); + boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2); boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2); diff --git a/src/k_kart.c b/src/k_kart.c index 539b8e3f2..bbec10990 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -933,6 +933,14 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2) K_SpawnBumpForObjs(mobj1, mobj2); + if (mobj1->type == MT_PLAYER && mobj2->type == MT_PLAYER) + { + if (K_PlayerGuard(mobj1->player)) + K_DoGuardBreak(mobj1, mobj2); + if (K_PlayerGuard(mobj2->player)) + K_DoGuardBreak(mobj2, mobj1); + } + K_PlayerJustBumped(mobj1->player); K_PlayerJustBumped(mobj2->player); @@ -1979,6 +1987,7 @@ void K_SpawnMagicianParticles(mobj_t *mo, int spread) dust->frame |= FF_SUBTRACT|FF_TRANS90; dust->color = color; dust->colorized = true; + dust->hitlag = 0; } } @@ -3606,28 +3615,54 @@ void K_DoInstashield(player_t *player) P_SetTarget(&layerb->target, player->mo); } -void K_DoPowerClash(player_t *t1, player_t *t2) { +void K_DoPowerClash(mobj_t *t1, mobj_t *t2) { mobj_t *clash; // short-circuit instashield for vfx visibility - t1->instashield = 1; - t2->instashield = 1; + if (t1->player) + t1->player->instashield = 1; + if (t2->player) + t2->player->instashield = 1; - S_StartSound(t1->mo, sfx_parry); - K_AddHitLag(t1->mo, 6, false); - K_AddHitLag(t2->mo, 6, false); + S_StartSound(t1, sfx_parry); + K_AddHitLag(t1, 6, false); + K_AddHitLag(t2, 6, false); - clash = P_SpawnMobj((t1->mo->x/2) + (t2->mo->x/2), (t1->mo->y/2) + (t2->mo->y/2), (t1->mo->z/2) + (t2->mo->z/2), MT_POWERCLASH); + clash = P_SpawnMobj((t1->x/2) + (t2->x/2), (t1->y/2) + (t2->y/2), (t1->z/2) + (t2->z/2), MT_POWERCLASH); // needs to handle mixed scale collisions (t1 grow t2 invinc)... - clash->z = clash->z + (t1->mo->height/4) + (t2->mo->height/4); - clash->angle = R_PointToAngle2(clash->x, clash->y, t1->mo->x, t1->mo->y) + ANGLE_90; + clash->z = clash->z + (t1->height/4) + (t2->height/4); + clash->angle = R_PointToAngle2(clash->x, clash->y, t1->x, t1->y) + ANGLE_90; // Shrink over time (accidental behavior that looked good) - clash->destscale = (t1->mo->scale/2) + (t2->mo->scale/2); + clash->destscale = (t1->scale) + (t2->scale); P_SetScale(clash, 3*clash->destscale/2); } +void K_DoGuardBreak(mobj_t *t1, mobj_t *t2) { + mobj_t *clash; + + if (!(t1->player && t2->player)) + return; + + // short-circuit instashield for vfx visibility + t1->player->instaShieldCooldown = 2*TICRATE; + t1->player->guardCooldown = 2*TICRATE; + + S_StartSound(t1, sfx_gbrk); + K_AddHitLag(t1, 24, true); + P_DamageMobj(t1, t2, t2, 1, DMG_STING); + + clash = P_SpawnMobj((t1->x/2) + (t2->x/2), (t1->y/2) + (t2->y/2), (t1->z/2) + (t2->z/2), MT_GUARDBREAK); + + // needs to handle mixed scale collisions + clash->z = clash->z + (t1->height/4) + (t2->height/4); + clash->angle = R_PointToAngle2(clash->x, clash->y, t1->x, t1->y) + ANGLE_90; + clash->color = t1->color; + + clash->destscale = 3*((t1->scale) + (t2->scale))/2; +} + void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 damage) { UINT8 points = 1; @@ -7777,7 +7812,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 2 seconds when playing. tic_t digestionpower = ((10 - player->kartspeed) + (10 - player->kartweight))-1; // 1 to 17 // currently 0-34 @@ -7789,7 +7824,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 +7842,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->spheres--; player->spheredigestion = spheredigestion; } + + if (K_PlayerGuard(player) && (player->ebrakefor%6 == 0)) + player->spheres--; } else { @@ -7877,6 +7915,19 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->gateBoost) player->gateBoost--; + if (player->instaShieldCooldown) + { + player->instaShieldCooldown--; + if (!P_IsObjectOnGround(player->mo)) + player->instaShieldCooldown = max(player->instaShieldCooldown, 1); + } + + if (player->guardCooldown) + player->guardCooldown--; + + if (player->whip && P_MobjWasRemoved(player->whip)) + P_SetTarget(&player->whip, NULL); + if (player->startboost > 0 && onground == true) { player->startboost--; @@ -7980,6 +8031,22 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->tiregrease) player->tiregrease--; + if (player->spinouttimer || player->tumbleBounces) + { + if (player->incontrol > 0) + player->incontrol = 0; + player->incontrol--; + } + else + { + if (player->incontrol < 0) + player->incontrol = 0; + player->incontrol++; + } + + player->incontrol = min(player->incontrol, 5*TICRATE); + player->incontrol = max(player->incontrol, -5*TICRATE); + if (player->tumbleBounces > 0) { K_HandleTumbleSound(player); @@ -8097,6 +8164,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->pflags &= ~PF_DRIFTINPUT; } + if (K_PlayerGuard(player)) + player->instaShieldCooldown = max(player->instaShieldCooldown, 12); + // Roulette Code K_KartItemRoulette(player, cmd); @@ -9784,6 +9854,11 @@ boolean K_PlayerEBrake(player_t *player) return false; } +boolean K_PlayerGuard(player_t *player) +{ + return (K_PlayerEBrake(player) && player->spheres > 0 && player->guardCooldown == 0); +} + SINT8 K_Sliptiding(player_t *player) { if (player->mo->eflags & MFE_UNDERWATER) @@ -9825,6 +9900,26 @@ 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; + + if (K_PlayerGuard(p)) + S_StartSound(body, sfx_s1af); + } + // HOLD! bubble. if (!p->ebrakefor) { @@ -10538,6 +10633,28 @@ void K_MoveKartPlayer(player_t *player, boolean onground) // Ring boosting if (player->pflags & PF_USERINGS) { + if (ATTACK_IS_DOWN && player->rings <= 0) + { + if (player->instaShieldCooldown || leveltime < starttime || player->spindash) + { + S_StartSound(player->mo, sfx_kc50); + } + else + { + player->instaShieldCooldown = 50; + player->guardCooldown = 50; + S_StartSound(player->mo, sfx_iwhp); + mobj_t *whip = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INSTAWHIP); + P_SetTarget(&player->whip, whip); + P_SetScale(whip, player->mo->scale); + P_SetTarget(&whip->target, player->mo); + K_MatchGenericExtraFlags(whip, player->mo); + whip->fuse = 12; // Changing instawhip animation duration? Look here + player->flashing = max(player->flashing, 12); + player->mo->momz += 4*mapobjectscale; + } + } + if ((cmd->buttons & BT_ATTACK) && !player->ringdelay && player->rings > 0) { mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING); @@ -11841,7 +11958,7 @@ UINT32 K_PointLimitForGametype(void) { if (D_IsPlayerHumanAndGaming(i)) { - ptsCap += 3; + ptsCap += 5; } } } diff --git a/src/k_kart.h b/src/k_kart.h index 839cadc6c..a12388af8 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -90,7 +90,8 @@ void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage); void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics, boolean fromDamage); void K_AwardPlayerRings(player_t *player, INT32 rings, boolean overload); void K_DoInstashield(player_t *player); -void K_DoPowerClash(player_t *t1, player_t *t2); +void K_DoPowerClash(mobj_t *t1, mobj_t *t2); +void K_DoGuardBreak(mobj_t *t1, mobj_t *t2); void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved); void K_RemoveGrowShrink(player_t *player); boolean K_IsBigger(mobj_t *compare, mobj_t *other); @@ -178,6 +179,7 @@ SINT8 K_GetForwardMove(player_t *player); fixed_t K_GetNewSpeed(player_t *player); fixed_t K_3dKartMovement(player_t *player); boolean K_PlayerEBrake(player_t *player); +boolean K_PlayerGuard(player_t *player); SINT8 K_Sliptiding(player_t *player); boolean K_FastFallBounce(player_t *player); fixed_t K_PlayerBaseFriction(player_t *player, fixed_t original); diff --git a/src/k_objects.h b/src/k_objects.h index 605206ec7..07a906a84 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -107,6 +107,14 @@ void Obj_LoopEndpointCollide(mobj_t *special, mobj_t *toucher); void Obj_BeginDropTargetMorph(mobj_t *target, skincolornum_t color); 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); +void Obj_GuardBreakThink(mobj_t *fx); + /* Ring Shooter */ boolean Obj_RingShooterThinker(mobj_t *mo); boolean Obj_PlayerRingShooterFreeze(player_t *const player); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 4dc28ac18..60f7959b5 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -319,6 +319,10 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->sliptideZipDelay); else if (fastcmp(field,"sliptideZipBoost")) lua_pushinteger(L, plr->sliptideZipBoost); + else if (fastcmp(field,"instaShieldCooldown")) + lua_pushinteger(L, plr->instaShieldCooldown); + else if (fastcmp(field,"guardCooldown")) + lua_pushinteger(L, plr->guardCooldown); /* else if (fastcmp(field,"itemroulette")) lua_pushinteger(L, plr->itemroulette); @@ -713,6 +717,10 @@ static int player_set(lua_State *L) plr->sliptideZipDelay = luaL_checkinteger(L, 3); else if (fastcmp(field,"sliptideZipBoost")) plr->sliptideZipBoost = luaL_checkinteger(L, 3); + else if (fastcmp(field,"instaShieldCooldown")) + plr->instaShieldCooldown = luaL_checkinteger(L, 3); + else if (fastcmp(field,"guardCooldown")) + plr->guardCooldown = luaL_checkinteger(L, 3); /* else if (fastcmp(field,"itemroulette")) plr->itemroulette = luaL_checkinteger(L, 3); diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index df047fb5d..2fe1f0937 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -17,4 +17,6 @@ target_sources(SRB2SDL2 PRIVATE ring-shooter.c 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..b2d70ed49 --- /dev/null +++ b/src/objects/block.c @@ -0,0 +1,84 @@ +#include "../doomdef.h" +#include "../info.h" +#include "../k_objects.h" +#include "../p_local.h" +#include "../k_kart.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_MoveOrigin(ring, mo->x, mo->y, mo->z + mo->height/2); + ring->flags |= MF_NOCLIPTHING; + ring->color = mo->color; + + fixed_t baseScale = mo->scale / 2; + baseScale += (mo->scale / 30) * player->spheres; + P_SetScale(ring, baseScale); + + // 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 (!K_PlayerGuard(player)) + 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); + + fixed_t baseScale = mo->scale / 2; + baseScale += (mo->scale / 30) * player->spheres; + P_SetScale(body, baseScale); + + 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 (!K_PlayerGuard(player)) + body->renderflags |= RF_DONTDRAW; + } +} + +void Obj_GuardBreakThink (mobj_t *fx) +{ + if (leveltime%2) + fx->renderflags &= ~RF_DONTDRAW; + else + fx->renderflags |= RF_DONTDRAW; +} diff --git a/src/objects/instawhip.c b/src/objects/instawhip.c new file mode 100644 index 000000000..f7abb9640 --- /dev/null +++ b/src/objects/instawhip.c @@ -0,0 +1,42 @@ +#include "../doomdef.h" +#include "../info.h" +#include "../k_objects.h" +#include "../p_local.h" + +void Obj_InstaWhipThink (mobj_t *whip) +{ + if (P_MobjWasRemoved(whip->target)) + { + P_RemoveMobj(whip); + } + else + { + mobj_t *mo = whip->target; + player_t *player = mo->player; + + // Follow player + whip->flags &= ~(MF_NOCLIPTHING); + P_SetScale(whip, whip->target->scale); + P_MoveOrigin(whip, mo->x, mo->y, mo->z + mo->height/2); + whip->flags |= MF_NOCLIPTHING; + + // Twirl + whip->angle = whip->target->angle + (ANG30 * 2 * whip->fuse); + whip->target->player->drawangle = whip->angle; + if (player->follower) + player->follower->angle = whip->angle; + player->pflags |= PF_GAINAX; + player->glanceDir = -2; + + // Visuals + whip->renderflags |= RF_NOSPLATBILLBOARD; + + if (whip->renderflags & RF_DONTDRAW) + whip->renderflags &= ~RF_DONTDRAW; + else + whip->renderflags |= RF_DONTDRAW; + + if (whip->extravalue2) // Whip has no hitbox but removing it is a pain in the ass + whip->renderflags |= RF_DONTDRAW; + } +} diff --git a/src/objects/monitor.c b/src/objects/monitor.c index 8f5be65eb..072cfbe84 100644 --- a/src/objects/monitor.c +++ b/src/objects/monitor.c @@ -440,9 +440,15 @@ adjust_monitor_drop ( mobj_t * monitor, mobj_t * drop) { - P_InstaThrust(drop, drop->angle, 4*mapobjectscale); - - drop->momz *= 8; + if (drop->type == MT_EMERALD) + { + drop->momx = drop->momy = drop->momz = 0; + } + else + { + P_InstaThrust(drop, drop->angle, 8*mapobjectscale); + drop->momz *= 8; + } K_FlipFromObject(drop, monitor); @@ -615,7 +621,16 @@ Obj_MonitorGetDamage } else { - damage = FRACUNIT; // kill instantly + if (inflictor->type == MT_INSTAWHIP) + { + damage = FRACUNIT/3; + if (K_IsPlayerWanted(inflictor->target->player)) + damage = FRACUNIT; // Emerald hunting time! + } + else + { + damage = FRACUNIT; // kill instantly + } } return damage; diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 7d8b2ea8e..7a4cf56c0 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -670,6 +670,7 @@ static UINT8 GetUFODamage(mobj_t *inflictor, UINT8 damageType) { case MT_JAWZ_SHIELD: case MT_ORBINAUT_SHIELD: + case MT_INSTAWHIP: { // Shields deal chip damage. return 10; diff --git a/src/p_inter.c b/src/p_inter.c index 620076dd3..cf8333dfb 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2188,6 +2188,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (!force) { boolean invincible = true; + boolean clash = false; sfxenum_t sfx = sfx_None; if (!(gametyperules & GTR_BUMPERS)) @@ -2208,6 +2209,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da { sfx = sfx_grownd; } + else if (K_PlayerGuard(player)) + { + sfx = sfx_s3k3a; + clash = true; + } else if (player->hyudorotimer > 0) ; else @@ -2249,6 +2255,15 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da S_StartSound(target, sfx); } + if (clash) + { + player->spheres = max(player->spheres - 10, 0); + if (inflictor) + K_DoPowerClash(target, inflictor); + else if (source) + K_DoPowerClash(target, source); + } + // Full invulnerability K_DoInstashield(player); return false; @@ -2306,7 +2321,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da damage = 0; } - if (type == DMG_STING || type == DMG_STUMBLE) + // 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 && inflictor->type != MT_INSTAWHIP)) { damage = 0; } @@ -2426,6 +2443,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da K_PlayPainSound(target, source); } + if (gametyperules & GTR_BUMPERS) + player->spheres = min(player->spheres + 5, 40); + if ((hardhit == true) || cv_kartdebughuddrop.value) { K_DropItems(player); diff --git a/src/p_map.c b/src/p_map.c index 5b539ad28..b72ce2145 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -741,7 +741,17 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_ABORT; // stop moving } - // SRB2kart 011617 - Colission[sic] code for kart items //{ + // SRB2kart 011617 - Colission[sic] code for kart items // + + if (tm.thing->type == MT_INSTAWHIP) + { + if (tm.thing->z > thing->z + thing->height) + return BMIT_CONTINUE; // overhead + if (tm.thing->z + tm.thing->height < thing->z) + return BMIT_CONTINUE; // underneath + K_InstaWhipCollide(tm.thing, thing); + return BMIT_CONTINUE; + } if (thing->type == MT_SPB) { diff --git a/src/p_mobj.c b/src/p_mobj.c index fbe4d90c2..dcedd4105 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8356,6 +8356,26 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_GardenTopThink(mobj); break; } + case MT_INSTAWHIP: + { + Obj_InstaWhipThink(mobj); + break; + } + case MT_BLOCKRING: + { + Obj_BlockRingThink(mobj); + break; + } + case MT_BLOCKBODY: + { + Obj_BlockBodyThink(mobj); + break; + } + case MT_GUARDBREAK: + { + Obj_GuardBreakThink(mobj); + break; + } case MT_GARDENTOPSPARK: { Obj_GardenTopSparkThink(mobj); diff --git a/src/p_saveg.c b/src/p_saveg.c index 16073ac06..ca03c667f 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -74,7 +74,8 @@ typedef enum HOVERHYUDORO = 0x0020, STUMBLE = 0x0040, SLIPTIDEZIP = 0x0080, - RINGSHOOTER = 0x0100 + RINGSHOOTER = 0x0100, + WHIP = 0x0200, } player_saveflags; static inline void P_ArchivePlayer(savebuffer_t *save) @@ -225,6 +226,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) if (players[i].sliptideZipIndicator) flags |= SLIPTIDEZIP; + if (players[i].whip) + flags |= WHIP; + if (players[i].ringShooter) flags |= RINGSHOOTER; @@ -251,6 +255,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) if (flags & SLIPTIDEZIP) WRITEUINT32(save->p, players[i].sliptideZipIndicator->mobjnum); + if (flags & WHIP) + WRITEUINT32(save->p, players[i].whip->mobjnum); + if (flags & RINGSHOOTER) WRITEUINT32(save->p, players[i].ringShooter->mobjnum); @@ -419,6 +426,10 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEMEM(save->p, players[i].public_key, PUBKEYLENGTH); + WRITEUINT8(save->p, players[i].instaShieldCooldown); + WRITEUINT8(save->p, players[i].guardCooldown); + WRITEINT16(save->p, players[i].incontrol); + // respawnvars_t WRITEUINT8(save->p, players[i].respawn.state); WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].respawn.wp)); @@ -635,6 +646,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) if (flags & SLIPTIDEZIP) players[i].sliptideZipIndicator = (mobj_t *)(size_t)READUINT32(save->p); + if (flags & WHIP) + players[i].whip = (mobj_t *)(size_t)READUINT32(save->p); + if (flags & RINGSHOOTER) players[i].ringShooter = (mobj_t *)(size_t)READUINT32(save->p); @@ -804,6 +818,10 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) READMEM(save->p, players[i].public_key, PUBKEYLENGTH); + players[i].instaShieldCooldown = READUINT8(save->p); + players[i].guardCooldown = READUINT8(save->p); + players[i].incontrol = READINT16(save->p); + // respawnvars_t players[i].respawn.state = READUINT8(save->p); players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save->p); @@ -4982,6 +5000,13 @@ static void P_RelinkPointers(void) if (!P_SetTarget(&players[i].sliptideZipIndicator, P_FindNewPosition(temp))) CONS_Debug(DBG_GAMELOGIC, "sliptideZipIndicator not found on player %d\n", i); } + if (players[i].whip) + { + temp = (UINT32)(size_t)players[i].whip; + players[i].whip = NULL; + if (!P_SetTarget(&players[i].whip, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "whip not found on player %d\n", i); + } if (players[i].ringShooter) { temp = (UINT32)(size_t)players[i].ringShooter; diff --git a/src/r_things.c b/src/r_things.c index 337b9c8cf..bc73df96e 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -49,7 +49,7 @@ #include "k_kart.h" // HITLAGJITTERS #include "r_fps.h" -#define MINZ (FRACUNIT*16) +#define MINZ (FRACUNIT*4) #define BASEYCENTER (BASEVIDHEIGHT/2) typedef struct diff --git a/src/sounds.c b/src/sounds.c index ebf43289a..d8852928b 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, ""}, @@ -1184,6 +1184,9 @@ sfxinfo_t S_sfx[NUMSFX] = {"monch", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"etexpl", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Game crash"}, + {"iwhp", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Instawhip attack + {"gbrk", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Guard break! + // SRB2Kart - Engine sounds // Engine class A {"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""}, diff --git a/src/sounds.h b/src/sounds.h index 427731ec5..422138d65 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1253,6 +1253,9 @@ typedef enum sfx_monch, sfx_etexpl, + sfx_iwhp, + sfx_gbrk, + // Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy... // Engine class A - Low Speed, Low Weight sfx_krta00,