From 8f6973cb519d252ff15856cc2c421173c27d5df8 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 26 Jun 2019 23:26:05 +0100 Subject: [PATCH] Now it's CA_TWINSPIN's turn to get the improvements! * Remove PF_THOKKED every time a successful damage bounce occours. * When this happens, spawn a number of particles based on thokitem at half scale! (Optimised, again, for MT_LHRT.) * Also spawn these particles when a successful spring boost occours, as well as playing a twisted spring sound. Also, some other related tweaks: * Optimisations to A_VultureBlast, which was used as a base for the particle creation. * Make the Metal Sonic boss use P_PlayerCanDamage instead of a custom, somewhat broken player damage detection mechanism. * P_SpawnGhostMobj takes colorized into account. * Fold Tails propeller damage into P_PlayerCanDamage. * When performing an Attraction Blast, place the player in roll frames. * Update all conditions preventing SH_PINK to incorporate thokitem and spinitem as well. * Buff MT_LHRT travel distance at slow speeds. --- src/p_enemy.c | 15 ++++++++---- src/p_inter.c | 22 ++++++----------- src/p_local.h | 1 + src/p_map.c | 27 ++++++++++++++++++--- src/p_mobj.c | 40 ++++++++++++++---------------- src/p_user.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++--- src/r_things.c | 2 +- src/sounds.c | 1 + src/sounds.h | 1 + 9 files changed, 126 insertions(+), 49 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 95138a3fa..23c9b88fc 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2411,6 +2411,8 @@ void A_VultureBlast(mobj_t *actor) { mobj_t *dust; UINT8 i; + angle_t faa; + fixed_t faacos, faasin; #ifdef HAVE_BLUA if (LUA_CallAction("A_VultureBlast", actor)) @@ -2419,18 +2421,21 @@ void A_VultureBlast(mobj_t *actor) S_StartSound(actor, actor->info->attacksound); + faa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK; + faacos = FINECOSINE(faa); + faasin = FINESINE(faa); + for (i = 0; i <= 7; i++) { angle_t fa = ((i*(angle_t)ANGLE_45) >> ANGLETOFINESHIFT) & FINEMASK; - angle_t faa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK; - dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -FINESINE(faa)), actor->y + 48*FixedMul(FINECOSINE(fa), FINECOSINE(faa)), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE); + dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -faasin), actor->y + 48*FixedMul(FINECOSINE(fa), faacos), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE); P_SetScale(dust, 4*FRACUNIT); dust->destscale = FRACUNIT; dust->scalespeed = 4*FRACUNIT/TICRATE; dust->fuse = TICRATE; - dust->momx = FixedMul(FINECOSINE(fa), -FINESINE(faa))*3; - dust->momy = FixedMul(FINECOSINE(fa), FINECOSINE(faa))*3; + dust->momx = FixedMul(FINECOSINE(fa), -faasin)*3; + dust->momy = FixedMul(FINECOSINE(fa), faacos)*3; dust->momz = FINESINE(fa)*6; } } @@ -6631,7 +6636,7 @@ void A_RecyclePowers(mobj_t *actor) players[recv_pl].ringweapons = weapons[send_pl]; players[recv_pl].currentweapon = weaponheld[send_pl]; - if (((players[recv_pl].powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (players[recv_pl].revitem == MT_LHRT)) // Healers can't keep their buff. + if (((players[recv_pl].powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (players[recv_pl].revitem == MT_LHRT || players[recv_pl].spinitem == MT_LHRT || players[recv_pl].thokitem == MT_LHRT)) // Healers can't keep their buff. players[recv_pl].powers[pw_shield] &= SH_STACK; P_SpawnShieldOrb(&players[recv_pl]); diff --git a/src/p_inter.c b/src/p_inter.c index 42809c66b..3348696c0 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -468,18 +468,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { toucher->momx = -toucher->momx; toucher->momy = -toucher->momy; + if (player->charability == CA_FLY && player->panim == PA_ABILITY) + toucher->momz = -toucher->momz/2; } P_DamageMobj(special, toucher, toucher, 1, 0); - } - else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP)) - || (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP))) - && player->charability == CA_FLY - && (player->powers[pw_tailsfly] - || toucher->state-states == S_PLAY_FLY_TIRED)) // Tails can shred stuff with her propeller. - { - toucher->momz = -toucher->momz/2; - - P_DamageMobj(special, toucher, toucher, 1, 0); + if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) + P_TwinSpinRejuvenate(player, player->thokitem); } else P_DamageMobj(toucher, special, special, 1, 0); @@ -2898,7 +2892,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { - if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); @@ -2913,7 +2907,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { - if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); @@ -2998,7 +2992,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj { if (gametype == GT_COOP && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only { - if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); @@ -3021,7 +3015,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { - if (player->revitem != MT_LHRT) // Healers do not get to heal other healers. + if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. { P_SwitchShield(player, SH_PINK); S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound); diff --git a/src/p_local.h b/src/p_local.h index d6f9d7648..8aeddf162 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -159,6 +159,7 @@ boolean P_AutoPause(void); void P_DoJumpShield(player_t *player); void P_DoBubbleBounce(player_t *player); void P_DoAbilityBounce(player_t *player, boolean changemomz); +void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type); void P_BlackOw(player_t *player); void P_ElementalFire(player_t *player, boolean cropcircle); diff --git a/src/p_map.c b/src/p_map.c index 4d4d30356..76b6535b5 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -135,6 +135,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) fixed_t vertispeed = spring->info->mass; fixed_t horizspeed = spring->info->damage; boolean final = false; + UINT8 strong = 0; // Object was already sprung this tic if (object->eflags & MFE_SPRUNG) @@ -148,6 +149,14 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (!spring->health || !object->health) return false; + if (object->player) + { + if (object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY) + strong = 1; + else if (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2) + strong = 2; + } + if (spring->info->painchance == -1) // Pinball bumper mode. { // The first of the entirely different spring modes! @@ -188,6 +197,9 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) { fixed_t playervelocity; + if (strong) + vertispeed <<= 1; + if (!(object->player->pflags & PF_THOKKED) && !(object->player->homing) && ((playervelocity = FixedDiv(9*FixedHypot(object->player->speed, object->momz), 10< vertispeed)) vertispeed = playervelocity; @@ -260,11 +272,8 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) return false; } - if (object->player - && ((object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY) - || (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2))) + if (strong) { - S_StartSound(object, sfx_s3k8b); if (horizspeed) horizspeed = FixedMul(horizspeed, (4*FRACUNIT)/3); if (vertispeed) @@ -399,6 +408,12 @@ springstate: P_AddPlayerScore(object->player, 10); spring->reactiontime--; } + + if (strong) + { + P_TwinSpinRejuvenate(object->player, (strong == 1 ? object->player->thokitem : object->player->revitem)); + S_StartSound(object, sfx_sprong); // strong spring. sprong. + } } return final; @@ -1504,7 +1519,11 @@ static boolean PIT_CheckThing(mobj_t *thing) if (elementalpierce == 2) P_DoBubbleBounce(player); else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + { *momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. + if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) + P_TwinSpinRejuvenate(player, player->thokitem); + } } if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough. { diff --git a/src/p_mobj.c b/src/p_mobj.c index a78a83da1..70017546c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -281,6 +281,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) player->panim = PA_FALL; break; case S_PLAY_FLY: + case S_PLAY_FLY_TIRED: case S_PLAY_SWIM: case S_PLAY_GLIDE: case S_PLAY_BOUNCE: @@ -1509,8 +1510,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) if (mo->player) { if ((mo->player->pflags & PF_GLIDING) - || (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly] - || mo->state-states == S_PLAY_FLY_TIRED))) + || (mo->player->charability == CA_FLY && mo->player->panim == PA_ABILITY)) gravityadd = gravityadd/3; // less gravity while flying/gliding if (mo->player->climbing || (mo->player->powers[pw_carry] == CR_NIGHTSMODE)) gravityadd = 0; @@ -5484,7 +5484,6 @@ static void P_Boss9Thinker(mobj_t *mobj) // AI goes here. { - boolean danger = true; angle_t angle; if (mobj->threshold) mobj->momz = (mobj->watertop-mobj->z)/16; // Float to your desired position FASTER @@ -5837,29 +5836,26 @@ static void P_Boss9Thinker(mobj_t *mobj) //A_FaceTarget(mobj); // Check if we're being attacked - if (!(mobj->target->player->pflags & (PF_JUMPED|PF_SPINNING) - || mobj->target->player->powers[pw_tailsfly] - || mobj->target->player->powers[pw_invulnerability] - || mobj->target->player->powers[pw_super])) - danger = false; + if (!mobj->target || !mobj->target->player || !P_PlayerCanDamage(mobj->target->player, mobj)) + goto nodanger; if (mobj->target->x+mobj->target->radius+abs(mobj->target->momx*2) < mobj->x-mobj->radius) - danger = false; + goto nodanger; if (mobj->target->x-mobj->target->radius-abs(mobj->target->momx*2) > mobj->x+mobj->radius) - danger = false; + goto nodanger; if (mobj->target->y+mobj->target->radius+abs(mobj->target->momy*2) < mobj->y-mobj->radius) - danger = false; + goto nodanger; if (mobj->target->y-mobj->target->radius-abs(mobj->target->momy*2) > mobj->y+mobj->radius) - danger = false; + goto nodanger; if (mobj->target->z+mobj->target->height+mobj->target->momz*2 < mobj->z) - danger = false; + goto nodanger; if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height) - danger = false; - if (danger) { - // An incoming attack is detected! What should we do?! - // Go into vector form! - vectorise; - return; - } + goto nodanger; + + // An incoming attack is detected! What should we do?! + // Go into vector form! + vectorise; + return; +nodanger: // Move normally: Approach the player using normal thrust and simulated friction. dist = P_AproxDistance(mobj->x-mobj->target->x, mobj->y-mobj->target->y); @@ -7920,8 +7916,8 @@ void P_MobjThinker(mobj_t *mobj) } break; case MT_LHRT: - mobj->momx = FixedMul(mobj->momx, (49*FRACUNIT)/50); - mobj->momy = FixedMul(mobj->momy, (49*FRACUNIT)/50); + mobj->momx = FixedMul(mobj->momx, mobj->extravalue2); + mobj->momy = FixedMul(mobj->momy, mobj->extravalue2); break; case MT_EGGCAPSULE: if (!mobj->reactiontime) diff --git a/src/p_user.c b/src/p_user.c index 9961d55dc..ac951a8fa 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1021,9 +1021,13 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) && (player->drawangle - R_PointToAngle2(player->mo->x - player->mo->momx, player->mo->y - player->mo->momy, thing->x, thing->y) + + ANGLE_90) < ANGLE_180) return true; - // From the top. - if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) - && (P_MobjFlip(player->mo)*(player->mo->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(player->mo)*player->mo->momz < 0)) + // From the top/bottom. + if (P_MobjFlip(player->mo)*(player->mo->z - (thing->z + thing->height/2)) > 0) + { + if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*player->mo->momz < 0)) + return true; + } + else if (player->charability == CA_FLY && player->panim == PA_ABILITY) return true; // Shield stomp. @@ -1752,6 +1756,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) } ghost->color = mobj->color; + ghost->colorized = mobj->colorized; // alternatively, "true" for sonic advance style colourisation ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle); ghost->sprite = mobj->sprite; @@ -2031,9 +2036,11 @@ boolean P_PlayerHitFloor(player_t *player) fixed_t zo = 6*player->mo->scale; fixed_t mu = FixedMul(player->maxdash, player->mo->scale); fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); + fixed_t ev; mobj_t *missile; if (mu2 < mu) mu2 = mu; + ev = (50*FRACUNIT - (mu/25))/50; while (i < 5) { missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); @@ -2044,6 +2051,7 @@ boolean P_PlayerHitFloor(player_t *player) P_Thrust(missile, player->drawangle, mu2); // forward component P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); missile->fuse = TICRATE/2; + missile->extravalue2 = ev; i++; throwang += ANG30; @@ -4529,6 +4537,57 @@ void P_DoAbilityBounce(player_t *player, boolean changemomz) player->pflags |= PF_BOUNCING|PF_THOKKED; } +// +// P_TwinSpinRejuvenate +// +// CA_TWINSPIN landing handling +// +void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type) +{ + fixed_t actionspd; + angle_t movang, ang, fa; + fixed_t v, h; + UINT8 i; + + if (!player->mo || !type) + return; + + actionspd = FixedMul(player->actionspd, player->mo->scale); + + fa = (R_PointToAngle2(0, 0, player->mo->momz, FixedHypot(player->mo->momx, player->mo->momy))>>ANGLETOFINESHIFT) & FINEMASK; + movang = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + ang = 0; + + v = FixedMul(actionspd, FINESINE(fa)); + h = actionspd - FixedMul(actionspd, FINECOSINE(fa)); + + // hearticles + for (i = 0; i <= 7; i++) + { + fixed_t side = actionspd - FixedMul(h, abs(FINESINE((ang>>ANGLETOFINESHIFT) & FINEMASK))); + fixed_t xo = P_ReturnThrustX(NULL, ang + movang, side); + fixed_t yo = P_ReturnThrustY(NULL, ang + movang, side); + fixed_t zo = -FixedMul(FINECOSINE(((ang>>ANGLETOFINESHIFT) & FINEMASK)), v); + mobj_t *missile = P_SpawnMobjFromMobj(player->mo, + xo, + yo, + player->mo->height/2 + zo, + type); + P_SetTarget(&missile->target, player->mo); + P_SetScale(missile, (missile->destscale >>= 1)); + missile->angle = ang + movang; + missile->fuse = TICRATE/2; + missile->extravalue2 = (99*FRACUNIT)/100; + missile->momx = xo; + missile->momy = yo; + missile->momz = zo; + + ang += ANGLE_45; + } + + player->pflags &= ~PF_THOKKED; +} + // // P_Telekinesis // @@ -7899,6 +7958,7 @@ static void P_MovePlayer(player_t *player) { player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y); player->pflags &= ~PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); S_StartSound(player->mo, sfx_s3k40); player->homing = 3*TICRATE; } diff --git a/src/r_things.c b/src/r_things.c index 22c3d96c9..9fe1e96e4 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2704,7 +2704,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; player->followitem = skin->followitem; - if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT)) // Healers can't keep their buff. + if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT || player->spinitem == MT_LHRT || player->thokitem == MT_LHRT)) // Healers can't keep their buff. player->powers[pw_shield] &= SH_STACK; player->actionspd = skin->actionspd; diff --git a/src/sounds.c b/src/sounds.c index 56de4a9c5..52dbee341 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -197,6 +197,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"corkh", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork hit"}, {"bowl", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bowling"}, {"chuchu", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Train horn"}, + {"sprong", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power spring"}, // Menu, interface {"chchng", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Score"}, diff --git a/src/sounds.h b/src/sounds.h index 475309121..742febbba 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -263,6 +263,7 @@ typedef enum sfx_corkh, sfx_bowl, sfx_chuchu, + sfx_sprong, // Menu, interface sfx_chchng,