From 4d55a9f4a9f7db942aa8b04bfdc36a29e2db0594 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 29 Oct 2019 23:11:12 +0000 Subject: [PATCH] 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. --- src/info.c | 32 +++++++++--------- src/p_enemy.c | 5 +-- src/p_mobj.c | 91 +++++++++++++++++++++++++++++++++------------------ src/r_draw.c | 4 +++ 4 files changed, 83 insertions(+), 49 deletions(-) diff --git a/src/info.c b/src/info.c index a418b1c51..1064eaf42 100644 --- a/src/info.c +++ b/src/info.c @@ -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 diff --git a/src/p_enemy.c b/src/p_enemy.c index cc2d64e8b..9d2a8e95a 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -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 { diff --git a/src/p_mobj.c b/src/p_mobj.c index 64c8d61d3..b7103ce65 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -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: diff --git a/src/r_draw.c b/src/r_draw.c index bb70a319f..6fc8d6599 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -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 {