Merge branch 'spindash-dust' into 'master'

Spindash dust

Charging a spindash kicks up dust, we all know this feature was dying to get in at some point. Bubble and flame forms of spin dust are included from FSonic, for underwater and elemental respectively.

Oh, and as a bonus I reorganised the spindash/spinning/other ability2 stuff code to look a bit neater and more organised.

New resources:
* MT_SPINDUST - the object
* S_SPINDUST1 to 4 - the normal form's states
* S_SPINDUST_BUBBLE1 to 4 - the bubble form's states
* S_SPINDUST_FIRE1 to 4 - the bubble form's states
* SPR_DUST - the normal form's sprite set (uses frames A to D, just pinch FSonic's sprites really)
* SPR_FPRT - the flame form's sprite set (frame A only)

SF_NOSPINDASHDUST disables spindash dust for a character

See merge request !52
This commit is contained in:
Monster Iestyn 2016-12-13 15:15:33 -05:00
commit 6f8969aec0
7 changed files with 201 additions and 74 deletions

View file

@ -44,6 +44,7 @@ typedef enum
SF_STOMPDAMAGE = 1<<9, // Always damage enemies, etc by landing on them, no matter your vunerability?
SF_MARIODAMAGE = SF_NOJUMPDAMAGE|SF_STOMPDAMAGE, // The Mario method of being able to damage enemies, etc.
SF_MACHINE = 1<<10, // Beep boop. Are you a robot?
SF_NOSPINDASHDUST = 1<<11, // Don't spawn dust particles when charging a spindash
// free up to and including 1<<31
} skinflags_t;

View file

@ -5566,6 +5566,20 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_WATERZAP",
// Spindash dust
"S_SPINDUST1",
"S_SPINDUST2",
"S_SPINDUST3",
"S_SPINDUST4",
"S_SPINDUST_BUBBLE1",
"S_SPINDUST_BUBBLE2",
"S_SPINDUST_BUBBLE3",
"S_SPINDUST_BUBBLE4",
"S_SPINDUST_FIRE1",
"S_SPINDUST_FIRE2",
"S_SPINDUST_FIRE3",
"S_SPINDUST_FIRE4",
"S_FOG1",
"S_FOG2",
"S_FOG3",
@ -6376,6 +6390,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_MEDIUMBUBBLE", // medium bubble
"MT_EXTRALARGEBUBBLE", // extra large bubble
"MT_WATERZAP",
"MT_SPINDUST", // Spindash dust
"MT_TFOG",
"MT_SEED",
"MT_PARTICLE",
@ -7045,6 +7060,7 @@ struct {
{"SF_STOMPDAMAGE",SF_STOMPDAMAGE},
{"SF_MARIODAMAGE",SF_MARIODAMAGE},
{"SF_MACHINE",SF_MACHINE},
{"SF_NOSPINDASHDUST",SF_NOSPINDASHDUST},
// Character abilities!
// Primary

View file

@ -274,6 +274,8 @@ char sprnames[NUMSPRITES + 1][5] =
"SMOK",
"BUBL", // Bubble
"WZAP",
"DUST", // Spindash dust
"FPRT", // Spindash dust (flame)
"TFOG", // Teleport Fog
"SEED", // Sonic CD flower seed
"PRTL", // Particle (for fans, etc.)
@ -2279,6 +2281,21 @@ state_t states[NUMSTATES] =
{SPR_WZAP, FF_TRANS10|FF_ANIMATE|FF_RANDOMANIM, 4, {NULL}, 3, 2, S_NULL}, // S_WATERZAP
// Spindash dust
{SPR_DUST, 0, 7, {NULL}, 0, 0, S_SPINDUST2}, // S_SPINDUST1
{SPR_DUST, 1, 6, {NULL}, 0, 0, S_SPINDUST3}, // S_SPINDUST2
{SPR_DUST, FF_TRANS30|2, 4, {NULL}, 0, 0, S_SPINDUST4}, // S_SPINDUST3
{SPR_DUST, FF_TRANS60|3, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST4
{SPR_BUBL, 0, 7, {NULL}, 0, 0, S_SPINDUST_BUBBLE2}, // S_SPINDUST_BUBBLE1
{SPR_BUBL, 0, 6, {NULL}, 0, 0, S_SPINDUST_BUBBLE3}, // S_SPINDUST_BUBBLE2
{SPR_BUBL, FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_BUBBLE4}, // S_SPINDUST_BUBBLE3
{SPR_BUBL, FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_BUBBLE4
{SPR_FPRT, 0, 7, {NULL}, 0, 0, S_SPINDUST_FIRE2}, // S_SPINDUST_FIRE1
{SPR_FPRT, 0, 6, {NULL}, 0, 0, S_SPINDUST_FIRE3}, // S_SPINDUST_FIRE2
{SPR_FPRT, FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_FIRE4}, // S_SPINDUST_FIRE3
{SPR_FPRT, FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_FIRE4
{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50, 2, {NULL}, 0, 0, S_FOG2}, // S_FOG1
{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|1, 2, {NULL}, 0, 0, S_FOG3}, // S_FOG2
{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|2, 2, {NULL}, 0, 0, S_FOG4}, // S_FOG3
@ -10940,6 +10957,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_SPINDUST
-1, // doomednum
S_SPINDUST1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
4*FRACUNIT, // speed
4*FRACUNIT, // radius
4*FRACUNIT, // height
0, // display offset
4, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags
S_NULL // raisestate
},
{ // MT_TFOG
-1, // doomednum
S_FOG1, // spawnstate

View file

@ -466,6 +466,8 @@ typedef enum sprite
SPR_SMOK,
SPR_BUBL, // Bubble
SPR_WZAP,
SPR_DUST, // Spindash dust
SPR_FPRT, // Spindash dust (flame)
SPR_TFOG, // Teleport Fog
SPR_SEED, // Sonic CD flower seed
SPR_PRTL, // Particle (for fans, etc.)
@ -2457,6 +2459,20 @@ typedef enum state
S_WATERZAP,
// Spindash dust
S_SPINDUST1,
S_SPINDUST2,
S_SPINDUST3,
S_SPINDUST4,
S_SPINDUST_BUBBLE1,
S_SPINDUST_BUBBLE2,
S_SPINDUST_BUBBLE3,
S_SPINDUST_BUBBLE4,
S_SPINDUST_FIRE1,
S_SPINDUST_FIRE2,
S_SPINDUST_FIRE3,
S_SPINDUST_FIRE4,
S_FOG1,
S_FOG2,
S_FOG3,
@ -3286,6 +3302,7 @@ typedef enum mobj_type
MT_MEDIUMBUBBLE, // medium bubble
MT_EXTRALARGEBUBBLE, // extra large bubble
MT_WATERZAP,
MT_SPINDUST, // Spindash dust
MT_TFOG,
MT_SEED,
MT_PARTICLE,

View file

@ -7563,6 +7563,18 @@ void P_MobjThinker(mobj_t *mobj)
mobj->tracer->y, mobj->tracer->floorz, SPLATDRAWMODE_SHADE);
#endif
break;
case MT_SPINDUST: // Spindash dust
mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000
mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same
//mobj->momz = mobj->momz+P_MobjFlip(mobj)/3; // no meaningful change in value to be frank
if (mobj->state >= &states[S_SPINDUST_BUBBLE1] && mobj->state <= &states[S_SPINDUST_BUBBLE4]) // bubble dust!
{
P_MobjCheckWater(mobj);
if (mobj->watertop != mobj->subsector->sector->floorheight - 1000*FRACUNIT
&& mobj->z+mobj->height >= mobj->watertop - 5*FRACUNIT)
mobj->flags2 |= MF2_DONTDRAW;
}
break;
case MT_SPINFIRE:
if (mobj->eflags & MFE_VERTICALFLIP)
mobj->z = mobj->ceilingz - mobj->height;

View file

@ -3666,6 +3666,35 @@ void P_DoJump(player_t *player, boolean soundandstate)
}
}
static void P_DoSpinDashDust(player_t *player)
{
UINT32 i;
mobj_t *particle;
INT32 prandom[3];
for (i = 0; i <= (leveltime%7)/2; i++) { // 1, 2, 3 or 4 particles
particle = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_SPINDUST);
if (player->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) // overrides fire version
P_SetMobjState(particle, S_SPINDUST_BUBBLE1);
else if (player->powers[pw_shield] == SH_ELEMENTAL)
P_SetMobjState(particle, S_SPINDUST_FIRE1);
P_SetTarget(&particle->target, player->mo);
particle->destscale = (2*player->mo->scale)/3;
P_SetScale(particle, particle->destscale);
if (player->mo->eflags & MFE_VERTICALFLIP) // readjust z position if needed
particle->z = player->mo->z + player->mo->height - particle->height;
prandom[0] = P_RandomFixed()<<2; // P_RandomByte()<<10
prandom[1] = P_RandomRange(-30, 30); // P_RandomRange(-ANG30/FRACUNIT, ANG30/FRACUNIT)*FRACUNIT
prandom[2] = P_RandomFixed()<<3; // P_RandomByte()<<11
P_SetObjectMomZ(particle, player->dashspeed/50 + prandom[0], false);
P_InstaThrust(particle,
player->mo->angle + (prandom[1]*ANG1),
-FixedMul(player->dashspeed/12 + FRACUNIT + prandom[2], player->mo->scale));
P_TryMove(particle, particle->x+particle->momx, particle->y+particle->momy, true);
}
}
//
// P_DoSpinAbility
//
@ -3673,6 +3702,7 @@ void P_DoJump(player_t *player, boolean soundandstate)
//
static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
{
boolean canstand = true; // can we stand on the ground? (mostly relevant for slopes)
if (player->pflags & PF_STASIS)
return;
@ -3684,69 +3714,92 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
}
#endif
// Spinning and Spindashing
if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_SLIDING) && !player->exiting
&& !P_PlayerInPain(player)) // subsequent revs
{
if ((cmd->buttons & BT_USE) && player->speed < FixedMul(5<<FRACBITS, player->mo->scale) && !player->mo->momz && onground && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING)
#ifdef ESLOPE
&& (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
canstand = (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2);
#endif
)
{
player->mo->momx = player->cmomx;
player->mo->momy = player->cmomy;
player->pflags |= PF_STARTDASH|PF_SPINNING;
player->dashspeed = player->mindash;
P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
player->pflags |= PF_USEDOWN;
if (!player->spectator)
S_StartSound(player->mo, sfx_s3kab); // Make the rev sound! Previously sfx_spndsh.
}
else if ((cmd->buttons & BT_USE) && (player->pflags & PF_STARTDASH))
{
if (player->dashspeed < player->maxdash)
{
#define chargecalculation (6*(player->dashspeed - player->mindash))/(player->maxdash - player->mindash)
fixed_t soundcalculation = chargecalculation;
player->dashspeed += FRACUNIT;
if (!player->spectator && soundcalculation != chargecalculation)
S_StartSound(player->mo, sfx_s3kab); // Make the rev sound! Previously sfx_spndsh.
#undef chargecalculation
}
if (player->revitem && !(leveltime % 5)) // Now spawn the color thok circle.
{
P_SpawnSpinMobj(player, player->revitem);
if (demorecording)
G_GhostAddRev();
}
}
// If not moving up or down, and travelling faster than a speed of four while not holding
// down the spin button and not spinning.
// AKA Just go into a spin on the ground, you idiot. ;)
else if ((cmd->buttons & BT_USE || ((twodlevel || (player->mo->flags2 & MF2_TWOD)) && cmd->forwardmove < -20))
&& !player->climbing && !player->mo->momz && onground && (player->speed > FixedMul(5<<FRACBITS, player->mo->scale)
#ifdef ESLOPE
|| (player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
#endif
) && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING))
///////////////////////////////
// ability-specific behavior //
///////////////////////////////
if (!(player->pflags & PF_SLIDING) && !player->exiting && !P_PlayerInPain(player))
{
switch (player->charability2)
{
player->pflags |= PF_SPINNING;
P_SetPlayerMobjState(player->mo, S_PLAY_SPIN);
if (!player->spectator)
S_StartSound(player->mo, sfx_spin);
player->pflags |= PF_USEDOWN;
case CA2_SPINDASH: // Spinning and Spindashing
// Start revving
if ((cmd->buttons & BT_USE) && player->speed < FixedMul(5<<FRACBITS, player->mo->scale)
&& !player->mo->momz && onground && !(player->pflags & (PF_USEDOWN|PF_SPINNING))
&& canstand)
{
player->mo->momx = player->cmomx;
player->mo->momy = player->cmomy;
player->pflags |= PF_STARTDASH|PF_SPINNING;
player->dashspeed = player->mindash;
P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
player->pflags |= PF_USEDOWN;
if (!player->spectator)
S_StartSound(player->mo, sfx_s3kab); // Make the rev sound! Previously sfx_spndsh.
}
// Revving
else if ((cmd->buttons & BT_USE) && (player->pflags & PF_STARTDASH))
{
if (player->dashspeed < player->maxdash)
{
#define chargecalculation (6*(player->dashspeed - player->mindash))/(player->maxdash - player->mindash)
fixed_t soundcalculation = chargecalculation;
player->dashspeed += FRACUNIT;
if (!player->spectator && soundcalculation != chargecalculation)
S_StartSound(player->mo, sfx_s3kab); // Make the rev sound! Previously sfx_spndsh.
#undef chargecalculation
}
if (player->revitem && !(leveltime % 5)) // Now spawn the color thok circle.
{
P_SpawnSpinMobj(player, player->revitem);
if (demorecording)
G_GhostAddRev();
}
}
// If not moving up or down, and travelling faster than a speed of four while not holding
// down the spin button and not spinning.
// AKA Just go into a spin on the ground, you idiot. ;)
else if ((cmd->buttons & BT_USE || ((twodlevel || (player->mo->flags2 & MF2_TWOD)) && cmd->forwardmove < -20))
&& !player->climbing && !player->mo->momz && onground && (player->speed > FixedMul(5<<FRACBITS, player->mo->scale)
|| !canstand) && !(player->pflags & (PF_USEDOWN|PF_SPINNING)))
{
player->pflags |= PF_SPINNING;
P_SetPlayerMobjState(player->mo, S_PLAY_SPIN);
if (!player->spectator)
S_StartSound(player->mo, sfx_spin);
player->pflags |= PF_USEDOWN;
}
break;
case CA2_MELEE: // Melee attack
if (!(player->panim == PA_ABILITY2) && (cmd->buttons & BT_USE) && player->speed < FixedMul(10<<FRACBITS, player->mo->scale)
&& !player->mo->momz && onground && !(player->pflags & PF_USEDOWN)
&& canstand)
{
P_ResetPlayer(player);
player->mo->z += P_MobjFlip(player->mo);
player->mo->momx = player->cmomx = 0;
player->mo->momy = player->cmomy = 0;
P_SetObjectMomZ(player->mo, player->mindash, false);
P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale));
P_SetPlayerMobjState(player->mo, S_PLAY_MELEE);
player->pflags |= PF_USEDOWN;
S_StartSound(player->mo, sfx_s3k8b);
}
break;
}
}
///////////////////////////////
// general spinning behavior //
///////////////////////////////
// Rolling normally
if (onground && player->pflags & PF_SPINNING && !(player->pflags & PF_STARTDASH)
&& player->speed < FixedMul(5*FRACUNIT,player->mo->scale)
#ifdef ESLOPE
&& (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
#endif
)
&& player->speed < FixedMul(5*FRACUNIT,player->mo->scale) && canstand)
{
if (GETSECSPECIAL(player->mo->subsector->sector->special, 4) == 7 || (player->mo->ceilingz - player->mo->floorz < P_GetPlayerHeight(player)))
P_InstaThrust(player->mo, player->mo->angle, FixedMul(10*FRACUNIT, player->mo->scale));
@ -3791,29 +3844,12 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
{
if (player->mo->state-states != S_PLAY_DASH)
P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
// Spawn spin dash dust
if (!(player->charflags & SF_NOSPINDASHDUST) && !(player->mo->eflags & MFE_GOOWATER))
P_DoSpinDashDust(player);
}
else if (onground && player->pflags & PF_SPINNING && !(player->panim == PA_ROLL))
P_SetPlayerMobjState(player->mo, S_PLAY_SPIN);
// Melee attack
if ((player->charability2 == CA2_MELEE) && !(player->panim == PA_ABILITY2) && !player->exiting
&& !P_PlayerInPain(player) && (cmd->buttons & BT_USE) && player->speed < FixedMul(10<<FRACBITS, player->mo->scale)
&& !player->mo->momz && onground && !(player->pflags & PF_USEDOWN)
#ifdef ESLOPE
&& (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
#endif
)
{
P_ResetPlayer(player);
player->mo->z += P_MobjFlip(player->mo);
player->mo->momx = player->cmomx = 0;
player->mo->momy = player->cmomy = 0;
P_SetObjectMomZ(player->mo, player->mindash, false);
P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale));
P_SetPlayerMobjState(player->mo, S_PLAY_MELEE);
player->pflags |= PF_USEDOWN;
S_StartSound(player->mo, sfx_s3k8b);
}
}
//

View file

@ -2880,6 +2880,7 @@ void R_AddSkins(UINT16 wadnum)
GETFLAG(STOMPDAMAGE)
GETFLAG(MARIODAMAGE)
GETFLAG(MACHINE)
GETFLAG(NOSPINDASHDUST)
#undef GETFLAG
else // let's check if it's a sound, otherwise error out