diff --git a/src/deh_tables.c b/src/deh_tables.c index 8844cb7b3..d348b3a4a 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4015,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", @@ -5495,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/info.c b/src/info.c index b75f8cae0..74b9c70db 100644 --- a/src/info.c +++ b/src/info.c @@ -638,6 +638,7 @@ char sprnames[NUMSPRITES + 1][5] = "ISTB", // instashield layer B "PWCL", // Invinc/grow clash VFX + "GBRK", // Guard break "ARRO", // player arrows "ITEM", @@ -4635,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 @@ -26178,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 af8297eff..c2d7a0356 100644 --- a/src/info.h +++ b/src/info.h @@ -1191,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, @@ -5088,6 +5089,7 @@ typedef enum state S_INSTASHIELDB7, S_POWERCLASH, // Grow/Invinc clash VFX + S_GUARDBREAK, S_PLAYERARROW, // Above player arrow S_PLAYERARROW_BOX, @@ -6604,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_kart.c b/src/k_kart.c index d04b71171..a1fba70ab 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -718,7 +718,7 @@ static void K_SpawnBumpForObjs(mobj_t *mobj1, mobj_t *mobj2) } } -static void K_PlayerJustBumped(player_t *player, boolean guardbreak) +static void K_PlayerJustBumped(player_t *player) { mobj_t *playerMobj = NULL; @@ -742,13 +742,6 @@ static void K_PlayerJustBumped(player_t *player, boolean guardbreak) player->rmomy = playerMobj->momy - player->cmomy; } - if (guardbreak && K_PlayerGuard(player)) - { - S_StartSound(player->mo, sfx_gbrk); - K_AddHitLag(player->mo, TICRATE, true); - player->instaShieldCooldown = 2*TICRATE; - } - player->justbumped = bumptime; player->spindash = 0; @@ -940,8 +933,16 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2) K_SpawnBumpForObjs(mobj1, mobj2); - K_PlayerJustBumped(mobj1->player, true); - K_PlayerJustBumped(mobj2->player, true); + 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); return true; } @@ -1010,7 +1011,7 @@ boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj) bounceMobj->momz = -bounceMobj->momz; K_SpawnBumpForObjs(bounceMobj, solidMobj); - K_PlayerJustBumped(bounceMobj->player, false); + K_PlayerJustBumped(bounceMobj->player); return true; } @@ -1986,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; } } @@ -3637,6 +3639,29 @@ void K_DoPowerClash(mobj_t *t1, mobj_t *t2) { 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; + + 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; diff --git a/src/k_kart.h b/src/k_kart.h index 46f530900..a12388af8 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -91,6 +91,7 @@ void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics, boolean fromDam void K_AwardPlayerRings(player_t *player, INT32 rings, boolean overload); void K_DoInstashield(player_t *player); 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); diff --git a/src/k_objects.h b/src/k_objects.h index f9f488036..07a906a84 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -113,6 +113,7 @@ 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); diff --git a/src/objects/block.c b/src/objects/block.c index bf54f908a..1d715ecbe 100644 --- a/src/objects/block.c +++ b/src/objects/block.c @@ -73,4 +73,12 @@ void Obj_BlockBodyThink (mobj_t *body) 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; } \ No newline at end of file diff --git a/src/p_mobj.c b/src/p_mobj.c index 5f6f6f599..dcedd4105 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8371,6 +8371,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_BlockBodyThink(mobj); break; } + case MT_GUARDBREAK: + { + Obj_GuardBreakThink(mobj); + break; + } case MT_GARDENTOPSPARK: { Obj_GardenTopSparkThink(mobj);