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.
This commit is contained in:
toaster 2019-06-26 23:26:05 +01:00
parent d5988c4f8c
commit 8f6973cb51
9 changed files with 126 additions and 49 deletions

View File

@ -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]);

View File

@ -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);

View File

@ -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);

View File

@ -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<<FRACBITS)) > 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.
{

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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"},

View File

@ -263,6 +263,7 @@ typedef enum
sfx_corkh,
sfx_bowl,
sfx_chuchu,
sfx_sprong,
// Menu, interface
sfx_chchng,