Ring Shooter: countdown animation & experimental stretchy spawn

This commit is contained in:
lachablock 2022-05-22 23:48:03 +10:00 committed by Sally Coolatta
parent c98ff9616b
commit a458490639
3 changed files with 177 additions and 16 deletions

View file

@ -4472,8 +4472,8 @@ state_t states[NUMSTATES] =
{SPR_RSHT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_SIDE
{SPR_RSHT, FF_SEMIBRIGHT|FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_NIPPLES
{SPR_RSHT, FF_PAPERSPRITE|4, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_SCREEN
{SPR_RSHT, FF_FULLBRIGHT|FF_PAPERSPRITE|8, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_NUMBERBACK
{SPR_RSHT, FF_FULLBRIGHT|FF_PAPERSPRITE|12, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_NUMBERFRONT
{SPR_RSHT, FF_FULLBRIGHT|FF_PAPERSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_NUMBERBACK
{SPR_RSHT, FF_FULLBRIGHT|FF_PAPERSPRITE|9, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_NUMBERFRONT
{SPR_PLAY, FF_FULLBRIGHT|FF_PAPERSPRITE|SPR2_XTRA, -1, {A_RingShooterFace}, 0, 0, S_NULL}, // S_RINGSHOOTER_FACE
{SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE, 8, {NULL}, 0, 0, S_NULL}, // S_DEZLASER
@ -24672,12 +24672,12 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
sfx_s3ka7, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
sfx_s3kad, // deathsound
0, // speed
16*FRACUNIT, // radius
16*FRACUNIT, // height

View file

@ -11775,13 +11775,15 @@ boolean K_Cooperative(void)
//}
// I've tried to reduce redundancy as much as I can,
// but check P_UpdateRingShooterParts if you edit this
void K_SpawnRingShooter(player_t *player)
{
const fixed_t scale = 2*FRACUNIT;
mobjinfo_t *info = &mobjinfo[MT_RINGSHOOTER_PART];
mobj_t *mo = player->mo;
mobj_t *base = P_SpawnMobj(mo->x, mo->y, mo->z, MT_RINGSHOOTER);
mobj_t *part;
mobj_t *part, *refNipple;
UINT32 frameNum;
angle_t angle;
vector2_t offset;
@ -11791,6 +11793,15 @@ void K_SpawnRingShooter(player_t *player)
P_SetTarget(&base->target, mo);
P_SetScale(base, base->destscale = FixedMul(base->destscale, scale));
P_InitAngle(base, mo->angle);
base->scalespeed = FRACUNIT/2;
base->extravalue1 = FRACUNIT; // horizontal scale
base->extravalue2 = 0; // vertical scale
// the ring shooter object itself is invisible and acts as the thinker
// each ring shooter uses three linked lists to keep track of its parts
// the hprev chain stores the two NIPPLE BARS
// the hnext chain stores the four sides of the box
// the tracer chain stores the screen and the screen layers
// spawn the RING NIPPLES
part = base;
@ -11810,8 +11821,11 @@ void K_SpawnRingShooter(player_t *player)
P_InitAngle(part, base->angle - i * ANGLE_45);
P_SetMobjState(part, S_RINGSHOOTER_NIPPLES);
part->frame += frameNum;
part->flags |= MF_NOTHINK;
part->old_spriteyscale = part->spriteyscale = 0;
frameNum++;
}
refNipple = part; // keep the second ring nipple; its position will be referenced by the box
// spawn the box
part = base;
@ -11835,15 +11849,23 @@ void K_SpawnRingShooter(player_t *player)
frameNum++;
frameNum ^= FF_HORIZONTALFLIP;
angle -= ANGLE_90;
part->frame += frameNum;
P_InitAngle(part, angle);
part->frame += frameNum;
part->extravalue1 = part->x - refNipple->x;
part->extravalue2 = part->y - refNipple->y;
part->flags |= MF_NOTHINK;
part->old_spriteyscale = part->spriteyscale = 0;
}
// spawn the screen
part = P_SpawnMobjFromMobj(base, offset.x, offset.y, info->height, MT_RINGSHOOTER_SCREEN);
part = P_SpawnMobjFromMobj(base, offset.x, offset.y, 0, MT_RINGSHOOTER_SCREEN);
P_SetTarget(&base->tracer, part);
P_SetTarget(&part->target, base);
P_InitAngle(part, base->angle - ANGLE_45);
part->extravalue1 = part->x - refNipple->x;
part->extravalue2 = part->y - refNipple->y;
part->flags |= MF_NOTHINK;
part->old_spriteyscale = part->spriteyscale = 0;
// spawn the screen numbers
for (i = 0; i < 2; i++)
@ -11853,9 +11875,6 @@ void K_SpawnRingShooter(player_t *player)
part = part->tracer;
P_InitAngle(part, part->target->angle);
P_SetMobjState(part, S_RINGSHOOTER_NUMBERBACK + i);
part->renderflags |= RF_DONTDRAW;
}
// test face feature (to be moved into thinker later)
part->skin = mo->skin;
P_SetMobjState(part, S_RINGSHOOTER_FACE);
}

View file

@ -4550,17 +4550,150 @@ static void P_SpawnItemCapsuleParts(mobj_t *mobj)
#undef ANG_CAPSULE
#undef ROTATIONSPEED
static void P_RingShooterThinker(mobj_t *mo)
// ------------
// RING SHOOTER
// ------------
static void P_ActivateRingShooter(mobj_t *mo)
{
mobj_t *part = mo->tracer;
while (!P_MobjWasRemoved(part->tracer))
{
part = part->tracer;
part->renderflags &= ~RF_DONTDRAW;
part->frame += 4;
}
}
#define scaleSpeed mo->scalespeed
#define scaleState mo->threshold
#define xScale mo->extravalue1
#define yScale mo->extravalue2
#define xOffset part->extravalue1
#define yOffset part->extravalue2
#define SCALEPART part->spritexscale = xScale; part->spriteyscale = yScale;
#define MOVEPART P_MoveOrigin(part, refNipple->x + FixedMul(xOffset, xScale), refNipple->y + FixedMul(yOffset, xScale), part->z);
// I've tried to reduce redundancy as much as I can,
// but check K_SpawnRingShooter if you edit this
static void P_UpdateRingShooterParts(mobj_t *mo)
{
mobj_t *part, *refNipple;
part = mo;
while (!P_MobjWasRemoved(part->hprev))
{
part = part->hprev;
SCALEPART
}
refNipple = part;
part = mo;
while (!P_MobjWasRemoved(part->hnext))
{
part = part->hnext;
MOVEPART
SCALEPART
}
part = mo->tracer;
part->z = mo->z + FixedMul(refNipple->height, yScale);
MOVEPART
SCALEPART
}
static boolean P_RingShooterInit(mobj_t *mo)
{
if (scaleState == -1)
return false;
switch (scaleState) {
case 0:
yScale += scaleSpeed;
if (yScale >= FRACUNIT)
{
//xScale -= scaleSpeed;
scaleState++;
}
break;
case 1:
scaleSpeed -= FRACUNIT/5;
yScale += scaleSpeed;
xScale -= scaleSpeed;
if (yScale < 3*FRACUNIT/4)
{
scaleState ++;
scaleSpeed = FRACUNIT >> 2;
}
break;
case 2:
yScale += scaleSpeed;
xScale -= scaleSpeed;
if (yScale >= FRACUNIT)
{
scaleState = -1;
xScale = yScale = FRACUNIT;
P_ActivateRingShooter(mo);
}
}
P_UpdateRingShooterParts(mo);
return scaleState != -1;
}
#undef scaleSpeed
#undef scaleState
#undef xScale
#undef yScale
#undef xOffset
#undef yOffset
#undef MOVEPART
#undef SCALEPART
static void P_RingShooterCountdown(mobj_t *mo)
{
mobj_t *part = mo->tracer;
if (mo->reactiontime == -1)
return;
if (mo->reactiontime > 0)
{
mo->reactiontime--;
return;
}
while (!P_MobjWasRemoved(part->tracer))
{
part = part->tracer;
part->frame--;
}
switch ((part->frame & FF_FRAMEMASK) - (part->state->frame & FF_FRAMEMASK)) {
case -1:
mo->reactiontime = -1;
part->skin = mo->skin;
P_SetMobjState(part, S_RINGSHOOTER_FACE);
break;
case 0:
mo->reactiontime = TICRATE;
S_StartSound(mo, mo->info->deathsound);
break;
default:
mo->reactiontime = TICRATE;
S_StartSound(mo, mo->info->painsound);
break;
}
}
static void P_RingShooterFlicker(mobj_t *mo)
{
UINT32 trans;
mobj_t *part = mo;
mobj_t *part = mo->tracer;
while (!P_MobjWasRemoved(part->tracer))
part = part->tracer;
if (part == mo) // ??? where did you go
return;
part->renderflags ^= RF_DONTDRAW;
if (part->renderflags & RF_DONTDRAW)
trans = FF_TRANS50;
@ -4569,6 +4702,15 @@ static void P_RingShooterThinker(mobj_t *mo)
part->target->frame = (part->target->frame & ~FF_TRANSMASK) | trans;
}
static void P_RingShooterThinker(mobj_t *mo)
{
if (P_MobjWasRemoved(mo->tracer) || P_RingShooterInit(mo))
return;
P_RingShooterCountdown(mo);
P_RingShooterFlicker(mo);
}
//
// P_BossTargetPlayer
// If closest is true, find the closest player.