mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-01-26 08:26:31 +00:00
The little SPB tweaks
- Explosion strength scales with how long you've been outrunning it. 0 seconds is even more punishing than it was before, while surviving 60+ seconds converts the damage into minimal stumble. - When it starts properly chasing a new target, it will be intangible for 1 second - Hot potato takes 2 seconds instead of 7 - Too much hot potato will make it run ahead & explode (untested)
This commit is contained in:
parent
0e7d9ba84e
commit
a790ffee79
5 changed files with 213 additions and 80 deletions
93
src/k_kart.c
93
src/k_kart.c
|
|
@ -3820,10 +3820,38 @@ angle_t K_StumbleSlope(angle_t angle, angle_t pitch, angle_t roll)
|
|||
return slope;
|
||||
}
|
||||
|
||||
static void K_StumblePlayer(player_t *player)
|
||||
{
|
||||
P_ResetPlayer(player);
|
||||
|
||||
#if 0
|
||||
// Single, medium bounce
|
||||
player->tumbleBounces = TUMBLEBOUNCES;
|
||||
player->tumbleHeight = 30;
|
||||
#else
|
||||
// Two small bounces
|
||||
player->tumbleBounces = TUMBLEBOUNCES-1;
|
||||
player->tumbleHeight = 20;
|
||||
#endif
|
||||
|
||||
player->pflags &= ~PF_TUMBLESOUND;
|
||||
S_StartSound(player->mo, sfx_s3k9b);
|
||||
|
||||
// and then modulate momz like that...
|
||||
player->mo->momz = K_TumbleZ(player->mo, player->tumbleHeight * FRACUNIT);
|
||||
|
||||
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
|
||||
|
||||
if (P_IsDisplayPlayer(player))
|
||||
P_StartQuake(64<<FRACBITS, 10);
|
||||
|
||||
// Reset slope.
|
||||
player->mo->pitch = player->mo->roll = 0;
|
||||
}
|
||||
|
||||
boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir)
|
||||
{
|
||||
angle_t steepVal = ANGLE_MAX;
|
||||
fixed_t gravityadjust;
|
||||
angle_t oldSlope, newSlope;
|
||||
angle_t slopeDelta;
|
||||
|
||||
|
|
@ -3873,36 +3901,7 @@ boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, bool
|
|||
// Oh jeez, you landed on your side.
|
||||
// You get to tumble.
|
||||
|
||||
P_ResetPlayer(player);
|
||||
|
||||
#if 0
|
||||
// Single, medium bounce
|
||||
player->tumbleBounces = TUMBLEBOUNCES;
|
||||
player->tumbleHeight = 30;
|
||||
#else
|
||||
// Two small bounces
|
||||
player->tumbleBounces = TUMBLEBOUNCES-1;
|
||||
player->tumbleHeight = 20;
|
||||
#endif
|
||||
|
||||
player->pflags &= ~PF_TUMBLESOUND;
|
||||
S_StartSound(player->mo, sfx_s3k9b);
|
||||
|
||||
gravityadjust = P_GetMobjGravity(player->mo)/2; // so we'll halve it for our calculations.
|
||||
|
||||
if (player->mo->eflags & MFE_UNDERWATER)
|
||||
gravityadjust /= 2; // halve "gravity" underwater
|
||||
|
||||
// and then modulate momz like that...
|
||||
player->mo->momz = -gravityadjust * player->tumbleHeight;
|
||||
|
||||
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
|
||||
|
||||
if (P_IsDisplayPlayer(player))
|
||||
P_StartQuake(64<<FRACBITS, 10);
|
||||
|
||||
// Reset slope.
|
||||
player->mo->pitch = player->mo->roll = 0;
|
||||
K_StumblePlayer(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -4136,23 +4135,45 @@ void K_ApplyTripWire(player_t *player, tripwirestate_t state)
|
|||
INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A bit of a hack, we just throw the player up higher here and extend their spinout timer
|
||||
{
|
||||
INT32 ringburst = 10;
|
||||
fixed_t spbMultiplier = FRACUNIT;
|
||||
|
||||
(void)source;
|
||||
|
||||
K_DirectorFollowAttack(player, inflictor, source);
|
||||
|
||||
player->mo->momz = 18*mapobjectscale*P_MobjFlip(player->mo); // please stop forgetting mobjflip checks!!!!
|
||||
if (inflictor != NULL && P_MobjWasRemoved(inflictor) == false)
|
||||
{
|
||||
if (inflictor->type == MT_SPBEXPLOSION && inflictor->movefactor)
|
||||
{
|
||||
spbMultiplier = inflictor->movefactor;
|
||||
|
||||
if (spbMultiplier <= 0)
|
||||
{
|
||||
// Convert into stumble.
|
||||
K_StumblePlayer(player);
|
||||
return 0;
|
||||
}
|
||||
else if (spbMultiplier < FRACUNIT)
|
||||
{
|
||||
spbMultiplier = FRACUNIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player->mo->momz = 18 * mapobjectscale * P_MobjFlip(player->mo); // please stop forgetting mobjflip checks!!!!
|
||||
player->mo->momx = player->mo->momy = 0;
|
||||
|
||||
player->spinouttype = KSPIN_EXPLOSION;
|
||||
player->spinouttimer = (3*TICRATE/2)+2;
|
||||
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor))
|
||||
if (spbMultiplier != FRACUNIT)
|
||||
{
|
||||
if (inflictor->type == MT_SPBEXPLOSION && inflictor->extravalue1)
|
||||
player->mo->momz = FixedMul(player->mo->momz, spbMultiplier);
|
||||
player->spinouttimer = FixedMul(player->spinouttimer, spbMultiplier + ((spbMultiplier - FRACUNIT) / 2));
|
||||
|
||||
ringburst = FixedMul(ringburst * FRACUNIT, spbMultiplier) / FRACUNIT;
|
||||
if (ringburst > 20)
|
||||
{
|
||||
player->spinouttimer = ((5*player->spinouttimer)/2)+1;
|
||||
player->mo->momz *= 2;
|
||||
ringburst = 20;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ fixed_t Obj_ItemDebrisBounce(mobj_t *debris, fixed_t momz);
|
|||
|
||||
/* SPB */
|
||||
void Obj_SPBThink(mobj_t *spb);
|
||||
void Obj_SPBExplode(mobj_t *spb);
|
||||
void Obj_SPBTouch(mobj_t *spb, mobj_t *toucher);
|
||||
|
||||
/* SPB Juicebox Rings */
|
||||
void Obj_MantaRingThink(mobj_t *manta);
|
||||
|
|
|
|||
|
|
@ -24,13 +24,20 @@
|
|||
#include "../k_waypoint.h"
|
||||
#include "../k_respawn.h"
|
||||
|
||||
//#define SPB_SEEKTEST
|
||||
#define SPB_SEEKTEST
|
||||
|
||||
#define SPB_SLIPTIDEDELTA (ANG1 * 3)
|
||||
#define SPB_STEERDELTA (ANGLE_90 - ANG10)
|
||||
#define SPB_DEFAULTSPEED (FixedMul(mapobjectscale, K_GetKartSpeedFromStat(9) * 2))
|
||||
#define SPB_ACTIVEDIST (1024 * FRACUNIT)
|
||||
|
||||
#define SPB_HOTPOTATO (2*TICRATE)
|
||||
#define SPB_MAXSWAPS (2)
|
||||
#define SPB_FLASHING (TICRATE)
|
||||
|
||||
#define SPB_CHASETIMESCALE (60*TICRATE)
|
||||
#define SPB_CHASETIMEMUL (3*FRACUNIT)
|
||||
|
||||
#define SPB_MANTA_SPACING (2750 * FRACUNIT)
|
||||
|
||||
#define SPB_MANTA_VSTART (150)
|
||||
|
|
@ -48,10 +55,15 @@ enum
|
|||
#define spb_modetimer(o) ((o)->extravalue2)
|
||||
|
||||
#define spb_nothink(o) ((o)->threshold)
|
||||
#define spb_intangible(o) ((o)->cvmem)
|
||||
|
||||
#define spb_lastplayer(o) ((o)->lastlook)
|
||||
#define spb_speed(o) ((o)->movefactor)
|
||||
#define spb_pitch(o) ((o)->movedir)
|
||||
|
||||
#define spb_chasetime(o) ((o)->watertop) // running out of variables here...
|
||||
#define spb_swapcount(o) ((o)->health)
|
||||
|
||||
#define spb_curwaypoint(o) ((o)->cusval)
|
||||
|
||||
#define spb_manta_vscale(o) ((o)->movecount)
|
||||
|
|
@ -318,14 +330,31 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer)
|
|||
(void)dist;
|
||||
(void)activeDist;
|
||||
#else
|
||||
if (dist <= activeDist)
|
||||
if (spb_swapcount(spb) > SPB_MAXSWAPS + 1)
|
||||
{
|
||||
S_StopSound(spb);
|
||||
S_StartSound(spb, spb->info->attacksound);
|
||||
spb_mode(spb) = SPB_MODE_CHASE; // TARGET ACQUIRED
|
||||
spb_modetimer(spb) = 7*TICRATE;
|
||||
spb_speed(spb) = desiredSpeed;
|
||||
return;
|
||||
// Too much hot potato.
|
||||
// Go past our target and explode instead.
|
||||
if (spb->fuse == 0)
|
||||
{
|
||||
spb->fuse = 2*TICRATE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dist <= activeDist)
|
||||
{
|
||||
S_StopSound(spb);
|
||||
S_StartSound(spb, spb->info->attacksound);
|
||||
|
||||
spb_mode(spb) = SPB_MODE_CHASE; // TARGET ACQUIRED
|
||||
spb_swapcount(spb)++;
|
||||
|
||||
spb_modetimer(spb) = SPB_HOTPOTATO;
|
||||
spb_intangible(spb) = SPB_FLASHING;
|
||||
|
||||
spb_speed(spb) = desiredSpeed;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -379,10 +408,12 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer)
|
|||
{
|
||||
curWaypoint = (waypoint_t *)pathtoplayer.array[1].nodedata;
|
||||
}
|
||||
else if (destWaypoint->numnextwaypoints > 0)
|
||||
#if 0
|
||||
else if (spb->fuse > 0 && destWaypoint->numnextwaypoints > 0)
|
||||
{
|
||||
curWaypoint = destWaypoint->nextwaypoints[0];
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
curWaypoint = destWaypoint;
|
||||
|
|
@ -522,6 +553,9 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer)
|
|||
return;
|
||||
}
|
||||
|
||||
// Increment chase time
|
||||
spb_chasetime(spb)++;
|
||||
|
||||
baseSpeed = SPB_DEFAULTSPEED;
|
||||
range = (160 * chase->scale);
|
||||
|
||||
|
|
@ -570,7 +604,7 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer)
|
|||
// Switch targets if you're no longer 1st for long enough
|
||||
if (bestPlayer != NULL && chasePlayer->position <= bestPlayer->position)
|
||||
{
|
||||
spb_modetimer(spb) = 7*TICRATE;
|
||||
spb_modetimer(spb) = SPB_HOTPOTATO;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -582,6 +616,7 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer)
|
|||
if (spb_modetimer(spb) <= 0)
|
||||
{
|
||||
spb_mode(spb) = SPB_MODE_SEEK; // back to SEEKING
|
||||
spb_intangible(spb) = SPB_FLASHING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -677,7 +712,8 @@ static void SPBWait(mobj_t *spb)
|
|||
{
|
||||
P_SetTarget(&spb_chase(spb), oldPlayer->mo);
|
||||
spb_mode(spb) = SPB_MODE_CHASE;
|
||||
spb_modetimer(spb) = 7*TICRATE;
|
||||
spb_modetimer(spb) = SPB_HOTPOTATO;
|
||||
spb_intangible(spb) = SPB_FLASHING;
|
||||
spb_speed(spb) = SPB_DEFAULTSPEED;
|
||||
}
|
||||
}
|
||||
|
|
@ -685,6 +721,7 @@ static void SPBWait(mobj_t *spb)
|
|||
{
|
||||
spb_mode(spb) = SPB_MODE_SEEK;
|
||||
spb_modetimer(spb) = 0;
|
||||
spb_intangible(spb) = SPB_FLASHING;
|
||||
spbplace = -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -718,6 +755,7 @@ void Obj_SPBThink(mobj_t *spb)
|
|||
// Init values, don't think yet.
|
||||
spb_lastplayer(spb) = -1;
|
||||
spb_curwaypoint(spb) = -1;
|
||||
spb_chasetime(spb) = 0;
|
||||
spbplace = -1;
|
||||
|
||||
spb_manta_totaldist(spb) = 0; // 30000?
|
||||
|
|
@ -792,6 +830,36 @@ void Obj_SPBThink(mobj_t *spb)
|
|||
}
|
||||
}
|
||||
|
||||
// Flash on/off when intangible.
|
||||
if (spb_intangible(spb) > 0)
|
||||
{
|
||||
spb_intangible(spb)--;
|
||||
|
||||
if (spb_intangible(spb) & 1)
|
||||
{
|
||||
spb->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
spb->renderflags &= ~RF_DONTDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
// Flash white when about to explode!
|
||||
if (spb->fuse > 0)
|
||||
{
|
||||
if (spb->fuse & 1)
|
||||
{
|
||||
spb->color = SKINCOLOR_INVINCFLASH;
|
||||
spb->colorized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
spb->color = SKINCOLOR_NONE;
|
||||
spb->colorized = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Clamp within level boundaries.
|
||||
if (spb->z < spb->floorz)
|
||||
{
|
||||
|
|
@ -802,3 +870,71 @@ void Obj_SPBThink(mobj_t *spb)
|
|||
spb->z = spb->ceilingz - spb->height;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_SPBExplode(mobj_t *spb)
|
||||
{
|
||||
mobj_t *spbExplode = NULL;
|
||||
|
||||
// Don't continue playing the gurgle or the siren
|
||||
S_StopSound(spb);
|
||||
|
||||
spbExplode = P_SpawnMobjFromMobj(spb, 0, 0, 0, MT_SPBEXPLOSION);
|
||||
|
||||
if (spb_owner(spb) != NULL && P_MobjWasRemoved(spb_owner(spb)) == false)
|
||||
{
|
||||
P_SetTarget(&spbExplode->target, spb_owner(spb));
|
||||
}
|
||||
|
||||
// Tell the explosion to use alternate knockback.
|
||||
spbExplode->movefactor = ((SPB_CHASETIMESCALE - spb_chasetime(spb)) * SPB_CHASETIMEMUL) / SPB_CHASETIMESCALE;
|
||||
|
||||
P_RemoveMobj(spb);
|
||||
}
|
||||
|
||||
void Obj_SPBTouch(mobj_t *spb, mobj_t *toucher)
|
||||
{
|
||||
player_t *player = toucher->player;
|
||||
|
||||
if (spb_intangible(spb) > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((spb_owner(spb) == toucher || spb_owner(spb) == toucher->target)
|
||||
&& (spb_nothink(spb) > 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (spb->health <= 0 || toucher->health <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->spectator == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->bubbleblowup > 0)
|
||||
{
|
||||
// Stun the SPB, and remove the shield.
|
||||
K_DropHnextList(player, false);
|
||||
spb_mode(spb) = SPB_MODE_WAIT;
|
||||
spb_modetimer(spb) = 55; // Slightly over the respawn timer length
|
||||
return;
|
||||
}
|
||||
|
||||
if (spb_chase(spb) != NULL && P_MobjWasRemoved(spb_chase(spb)) == false
|
||||
&& toucher == spb_chase(spb))
|
||||
{
|
||||
// Cause the explosion.
|
||||
Obj_SPBExplode(spb);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Regular spinout, please.
|
||||
P_DamageMobj(toucher, spb, spb_owner(spb), 1, DMG_NORMAL);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,41 +352,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
}
|
||||
return;
|
||||
case MT_SPB:
|
||||
if ((special->target == toucher || special->target == toucher->target) && (special->threshold > 0))
|
||||
return;
|
||||
|
||||
if (special->health <= 0 || toucher->health <= 0)
|
||||
return;
|
||||
|
||||
if (player->spectator)
|
||||
return;
|
||||
|
||||
if (special->tracer && !P_MobjWasRemoved(special->tracer) && toucher == special->tracer)
|
||||
{
|
||||
mobj_t *spbexplode;
|
||||
|
||||
if (player->bubbleblowup > 0)
|
||||
{
|
||||
K_DropHnextList(player, false);
|
||||
special->extravalue1 = 2; // WAIT...
|
||||
special->extravalue2 = 52; // Slightly over the respawn timer length
|
||||
return;
|
||||
}
|
||||
|
||||
S_StopSound(special); // Don't continue playing the gurgle or the siren
|
||||
|
||||
spbexplode = P_SpawnMobj(toucher->x, toucher->y, toucher->z, MT_SPBEXPLOSION);
|
||||
spbexplode->extravalue1 = 1; // Tell K_ExplodePlayer to use extra knockback
|
||||
if (special->target && !P_MobjWasRemoved(special->target))
|
||||
P_SetTarget(&spbexplode->target, special->target);
|
||||
|
||||
P_RemoveMobj(special);
|
||||
Obj_SPBTouch(special, toucher);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_DamageMobj(player->mo, special, special->target, 1, DMG_NORMAL);
|
||||
}
|
||||
return;
|
||||
case MT_EMERALD:
|
||||
if (!P_CanPickupItem(player, 0))
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -6269,6 +6269,11 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
case MT_DRIFTELECTRICSPARK:
|
||||
mobj->renderflags ^= RF_DONTDRAW;
|
||||
break;
|
||||
case MT_SPB:
|
||||
{
|
||||
Obj_SPBExplode(mobj);
|
||||
return;
|
||||
}
|
||||
case MT_VWREF:
|
||||
case MT_VWREB:
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue