Metal Sonic battle improvements.

* Tweaked to use new sprites.
* Jet fume behaves much closer to Lach's wonderful work.
* Instead of clobbering tracer to spawn powerup overlay, use hprev.
* Change timings. One second less to charge up, but two seconds less to spin them out.
* Remove terrible pinch overlay in favour of new dashmode-mimic flashing.
This commit is contained in:
toaster 2019-10-29 23:11:12 +00:00
parent 56d095e39f
commit 4d55a9f4a9
4 changed files with 83 additions and 49 deletions

View file

@ -1803,21 +1803,21 @@ state_t states[NUMSTATES] =
{SPR_PLAY, SPR2_STND, -1, {NULL}, 0, 0, S_METALSONIC_RACE}, // S_METALSONIC_RACE
{SPR_METL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_FLOAT
{SPR_METL, 12|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR
{SPR_METL, 11, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN
{SPR_METL, 13, 20, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE
{SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_GATHER
{SPR_METL, 15, -1, {NULL}, 0, 0, S_METALSONIC_BOUNCE},// S_METALSONIC_DASH
{SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BOUNCE
{SPR_METL, 16, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BADBOUNCE
{SPR_METL, 13, -1, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT
{SPR_METL, 11, 40, {A_Pain}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN
{SPR_METL, 13, 2, {A_Fall}, 0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1
{SPR_METL, 13, 4, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2
{SPR_METL, 13, 0, {A_Repeat}, 17, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3
{SPR_METL, 13, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH4
{SPR_METL, 11, 1, {A_BossScream}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1
{SPR_METL, 11, 7, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE2
{SPR_METL, 16|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR
{SPR_METL, 15, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN
{SPR_METL, 17, 20, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE
{SPR_METL, 18, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_GATHER
{SPR_METL, 6|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_METALSONIC_BOUNCE},// S_METALSONIC_DASH
{SPR_METL, 18|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 1, 2, S_NULL}, // S_METALSONIC_BOUNCE
{SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BADBOUNCE
{SPR_METL, 17, -1, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT
{SPR_METL, 15, 40, {A_Pain}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN
{SPR_METL, 17, 2, {A_Fall}, 0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1
{SPR_METL, 17, 4, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2
{SPR_METL, 17, 0, {A_Repeat}, 17, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3
{SPR_METL, 17, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH4
{SPR_METL, 15, 1, {A_BossScream}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1
{SPR_METL, 15, 7, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE2
{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30|FF_ANIMATE, -1, {NULL}, 11, 1, S_NULL}, // S_MSSHIELD_F1
{SPR_MSCF, FF_FULLBRIGHT|FF_ANIMATE|12, -1, {NULL}, 8, 2, S_NULL}, // S_MSSHIELD_F2
@ -6734,7 +6734,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // speed
32*FRACUNIT, // radius
52*FRACUNIT, // height
0, // display offset
1, // display offset
0, // mass
0, // damage
sfx_None, // activesound

View file

@ -8966,10 +8966,11 @@ void A_BossJetFume(mobj_t *actor)
P_SetTarget(&filler->target, actor);
filler->fuse = 59;
P_SetTarget(&actor->tracer, filler);
filler->destscale = actor->scale/3;
P_SetScale(filler, filler->destscale);
P_SetScale(filler, (filler->destscale = actor->scale/3));
if (actor->eflags & MFE_VERTICALFLIP)
filler->flags2 |= MF2_OBJECTFLIP;
filler->color = SKINCOLOR_ICY;
filler->colorized = true;
}
else if (locvar1 == 3) // Boss 4 jet flame
{

View file

@ -5595,16 +5595,22 @@ static void P_Boss9Thinker(mobj_t *mobj)
if ((!mobj->target || !(mobj->target->flags & MF_SHOOTABLE)))
{
if (mobj->tracer)
P_RemoveMobj(mobj->tracer);
if (mobj->hprev)
{
P_RemoveMobj(mobj->hprev);
P_SetTarget(&mobj->hprev, NULL);
}
P_BossTargetPlayer(mobj, false);
if (mobj->target && (!P_IsObjectOnGround(mobj->target) || mobj->target->player->pflags & PF_SPINNING))
P_SetTarget(&mobj->target, NULL); // Wait for them to hit the ground first
if (!mobj->target) // Still no target, aww.
{
// Reset the boss.
if (mobj->tracer)
P_RemoveMobj(mobj->tracer);
if (mobj->hprev)
{
P_RemoveMobj(mobj->hprev);
P_SetTarget(&mobj->hprev, NULL);
}
P_SetMobjState(mobj, mobj->info->spawnstate);
mobj->fuse = 0;
mobj->momx = FixedDiv(mobj->momx, FRACUNIT + (FRACUNIT>>2));
@ -5618,7 +5624,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
return;
}
else if (!mobj->fuse)
mobj->fuse = 10*TICRATE;
mobj->fuse = 8*TICRATE;
}
// AI goes here.
@ -5645,16 +5651,18 @@ static void P_Boss9Thinker(mobj_t *mobj)
mobj->angle -= InvAngle(angle)/8;
// Alter your energy bubble's size/position
if (mobj->health > 3)
if (mobj->health > mobj->info->damage)
{
mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2);
P_SetScale(mobj->tracer, mobj->tracer->destscale);
}
if (mobj->hprev)
{
mobj->hprev->destscale = FRACUNIT + (2*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2);
P_SetScale(mobj->hprev, mobj->hprev->destscale);
P_TeleportMove(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2);
mobj->tracer->momx = mobj->momx;
mobj->tracer->momy = mobj->momy;
mobj->tracer->momz = mobj->momz;
P_TeleportMove(mobj->hprev, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->hprev->height/2);
mobj->hprev->momx = mobj->momx;
mobj->hprev->momy = mobj->momy;
mobj->hprev->momz = mobj->momz;
}
// Firin' mah lazors - INDICATOR
if (mobj->fuse > TICRATE/2)
@ -5742,6 +5750,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
S_StartSound(mobj, sfx_s3kb3);
}
}
}
// up...
mobj->z += mobj->height/2;
@ -5768,12 +5777,12 @@ static void P_Boss9Thinker(mobj_t *mobj)
if (mobj->health > mobj->info->damage)
{
P_SetScale(missile, FRACUNIT/3);
missile->color = SKINCOLOR_GOLD; // sonic cd electric power
missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power
}
else
{
P_SetScale(missile, FRACUNIT/5);
missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power
missile->color = SKINCOLOR_SUNSET; // sonic cd electric power
}
missile->destscale = missile->scale*2;
missile->scalespeed = abs(missile->scale - missile->destscale)/missile->fuse;
@ -5885,8 +5894,6 @@ static void P_Boss9Thinker(mobj_t *mobj)
return;
}
P_SpawnGhostMobj(mobj);
// Pinball attack!
if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2))
{
@ -5901,20 +5908,20 @@ static void P_Boss9Thinker(mobj_t *mobj)
if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true))
{ // Hit a wall? Find a direction to bounce
mobj->threshold--;
P_SetMobjState(mobj, mobj->state->nextstate);
if (!mobj->threshold) { // failed bounce!
S_StartSound(mobj, sfx_mspogo);
P_BounceMove(mobj);
mobj->angle = R_PointToAngle2(mobj->momx, mobj->momy,0,0);
mobj->momz = 4*FRACUNIT;
mobj->flags &= ~MF_PAIN;
mobj->fuse = 10*TICRATE;
mobj->fuse = 8*TICRATE;
mobj->movecount = 0;
P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_CYBRAKDEMON_VILE_EXPLOSION);
P_SetMobjState(mobj, mobj->info->meleestate);
}
else if (!(mobj->threshold%4))
{ // We've decided to lock onto the player this bounce.
P_SetMobjState(mobj, mobj->state->nextstate);
S_StartSound(mobj, sfx_s3k5a);
mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x + mobj->target->momx*4, mobj->target->y + mobj->target->momy*4);
mobj->reactiontime = TICRATE - 5*(mobj->info->damage - mobj->health); // targetting time
@ -5931,6 +5938,8 @@ static void P_Boss9Thinker(mobj_t *mobj)
return;
}
P_SpawnGhostMobj(mobj);
// Vector form dodge!
mobj->angle += mobj->movedir;
P_InstaThrust(mobj, mobj->angle, -speed);
@ -6027,7 +6036,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
if (mobj->health > mobj->info->damage)
{ // No more bubble if we're broken (pinch phase)
mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT);
P_SetTarget(&mobj->tracer, shield);
P_SetTarget(&mobj->hprev, shield);
P_SetTarget(&shield->target, mobj);
// Attack 2: Energy shot!
@ -6058,14 +6067,15 @@ static void P_Boss9Thinker(mobj_t *mobj)
}
else
{
mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT);
/*mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT);
P_SetTarget(&mobj->tracer, shield);
P_SetTarget(&shield->target, mobj);
shield->height -= 20*FRACUNIT; // different offset...
P_SetMobjState(shield, S_MSSHIELD_F2);
P_SetMobjState(shield, S_MSSHIELD_F2);*/
P_SetMobjState(mobj, S_METALSONIC_BOUNCE);
//P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); -- why does this happen twice? see case 2...
}
mobj->fuse = 4*TICRATE;
mobj->fuse = 3*TICRATE;
mobj->flags |= MF_PAIN;
if (mobj->info->attacksound)
S_StartSound(mobj, mobj->info->attacksound);
@ -6076,14 +6086,14 @@ static void P_Boss9Thinker(mobj_t *mobj)
case 2:
{
// We're all charged and ready now! Unleash the fury!!
mobj_t *removemobj = mobj->tracer;
S_StopSound(mobj);
P_SetTarget(&mobj->tracer, mobj->hnext);
P_RemoveMobj(removemobj);
if (mobj->hprev)
{
P_RemoveMobj(mobj->hprev);
P_SetTarget(&mobj->hprev, NULL);
}
if (mobj->health <= mobj->info->damage)
{
mobj_t *whoosh;
// Attack 1: Pinball dash!
if (mobj->health == 1)
mobj->movedir = 0;
@ -6099,6 +6109,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
mobj->watertop = mobj->target->floorz + 16*FRACUNIT;
P_LinedefExecute(LE_PINCHPHASE, mobj, NULL);
#if 0
whoosh = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_GHOST); // done here so the offset is correct
whoosh->frame = FF_FULLBRIGHT;
whoosh->sprite = SPR_ARMA;
@ -6106,9 +6117,13 @@ static void P_Boss9Thinker(mobj_t *mobj)
whoosh->scalespeed = FixedMul(whoosh->scalespeed, whoosh->scale);
whoosh->height = 38*whoosh->scale;
whoosh->fuse = 10;
whoosh->color = SKINCOLOR_MAGENTA;
whoosh->color = SKINCOLOR_SUNSET;
whoosh->colorized = true;
whoosh->flags |= MF_NOCLIPHEIGHT;
#endif
P_SetMobjState(mobj->tracer, S_JETFUMEFLASH);
P_SetScale(mobj->tracer, mobj->scale << 1);
}
else
{
@ -6123,7 +6138,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
mobj->watertop = mobj->target->floorz + 32*FRACUNIT;
P_SetMobjState(mobj, mobj->info->spawnstate);
mobj->flags &= ~MF_PAIN;
mobj->fuse = 10*TICRATE;
mobj->fuse = 8*TICRATE;
break;
}
mobj->movecount++;
@ -8738,11 +8753,17 @@ void P_MobjThinker(mobj_t *mobj)
}
else if (mobj->fuse == 59)
{
boolean dashmod = ((mobj->target->flags & MF_PAIN) && (mobj->target->health <= mobj->target->info->damage));
jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, -mobj->target->radius);
jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, -mobj->target->radius);
P_UnsetThingPosition(mobj);
mobj->x = jetx;
mobj->y = jety;
mobj->destscale = mobj->target->scale;
if (!(dashmod && mobj->target->state == states+S_METALSONIC_BOUNCE))
{
mobj->destscale = (mobj->destscale + FixedDiv(R_PointToDist2(0, 0, mobj->target->momx, mobj->target->momy), 36*mobj->target->scale))/3;
}
if (mobj->target->eflags & MFE_VERTICALFLIP)
mobj->z = mobj->target->z + mobj->target->height/2 + mobj->height/2;
else
@ -8750,6 +8771,14 @@ void P_MobjThinker(mobj_t *mobj)
mobj->floorz = mobj->z;
mobj->ceilingz = mobj->z+mobj->height;
P_SetThingPosition(mobj);
if (dashmod)
{
mobj->color = SKINCOLOR_SUNSET;
if (mobj->target->movecount == 3 && !mobj->target->reactiontime && (mobj->target->movedir == 0 || mobj->target->movedir == 2))
P_SpawnGhostMobj(mobj);
}
else
mobj->color = SKINCOLOR_ICY;
}
mobj->fuse++;
}
@ -10426,9 +10455,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
break;
case MT_METALSONIC_RACE:
mobj->skin = &skins[5];
mobj->color = skins[5].prefcolor;
/* FALLTHRU */
case MT_METALSONIC_BATTLE:
mobj->color = skins[5].prefcolor;
sc = 5;
break;
case MT_FANG:

View file

@ -567,8 +567,12 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
else if (skinnum == TC_METALSONIC)
{
for (i = 0; i < 6; i++)
{
dest_colormap[Color_Index[SKINCOLOR_BLUE-1][12-i]] = Color_Index[SKINCOLOR_BLUE-1][i];
}
dest_colormap[159] = dest_colormap[253] = dest_colormap[254] = 0;
for (i = 0; i < 16; i++)
dest_colormap[96+i] = dest_colormap[Color_Index[SKINCOLOR_COBALT-1][i]];
}
else if (skinnum == TC_DASHMODE) // This is a long one, because MotorRoach basically hand-picked the indices
{