Set a sidedef's midtexture to "TRIPWIRE" to turn that line
into a tripwire.

Players can't drive through a tripwire and will bounce
back at high speed if they're in one of the following
states:

1. Invincibility / Grow
2. Sneakers
3. Flame Shield dash
4. >200% on the speedometer

Hitting a tripwire plays a sound, sends you into hitlag,
then plays another sound when the hitlag is over. The
sounds used depend on whether you can drive through the
tripwire.
This commit is contained in:
James R 2021-11-28 02:57:45 -08:00
parent 17b3cd205e
commit 8e20ca4c04
9 changed files with 90 additions and 6 deletions

View file

@ -198,6 +198,13 @@ typedef enum
#undef KSPIN_TYPE
} kartspinoutflags_t;
typedef enum
{
TRIP_NONE,
TRIP_PASSED,
TRIP_BLOCKED,
} tripwirestate_t;
typedef enum
{
// Unsynced, HUD or clientsided effects
@ -470,6 +477,8 @@ typedef struct player_s
SINT8 glanceDir; // Direction the player is trying to look backwards in
UINT8 tripWireState; // see tripwirestate_t
//
SINT8 lives;

View file

@ -2287,6 +2287,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->karthud[khud_fault] = khudfault;
p->nocontrol = nocontrol;
p->kickstartaccel = kickstartaccel;
p->tripWireState = TRIP_NONE;
memcpy(&p->respawn, &respawn, sizeof (p->respawn));

View file

@ -2673,6 +2673,19 @@ boolean K_SlopeResistance(player_t *player)
return false;
}
boolean K_TripwirePass(player_t *player)
{
if (
player->invincibilitytimer ||
player->sneakertimer ||
player->growshrinktimer > 0 ||
player->flamedash ||
player->speed > 2 * K_GetKartSpeed(player, false)
)
return true;
return false;
}
static fixed_t K_FlameShieldDashVar(INT32 val)
{
// 1 second = 75% + 50% top speed
@ -3300,6 +3313,17 @@ static void K_HandleTumbleSound(player_t *player)
}
}
void K_ApplyTripWire(player_t *player, tripwirestate_t state)
{
if (state == TRIP_PASSED)
S_StartSound(player->mo, sfx_ssa015);
else if (state == TRIP_BLOCKED)
S_StartSound(player->mo, sfx_kc40);
player->tripWireState = state;
K_AddHitLag(player->mo, 10, false);
}
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;
@ -6983,6 +7007,16 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
// Handle invincibility sfx
K_UpdateInvincibilitySounds(player); // Also thanks, VAda!
if (player->tripWireState != TRIP_NONE)
{
if (player->tripWireState == TRIP_PASSED)
S_StartSound(player->mo, sfx_cdfm63);
else if (player->tripWireState == TRIP_BLOCKED)
S_StartSound(player->mo, sfx_kc4c);
player->tripWireState = TRIP_NONE;
}
}
void K_KartPlayerAfterThink(player_t *player)

View file

@ -105,6 +105,8 @@ void K_StripOther(player_t *player);
void K_MomentumToFacing(player_t *player);
boolean K_ApplyOffroad(player_t *player);
boolean K_SlopeResistance(player_t *player);
boolean K_TripwirePass(player_t *player);
void K_ApplyTripWire(player_t *player, tripwirestate_t state);
INT16 K_GetSpindashChargeTime(player_t *player);
fixed_t K_GetSpindashChargeSpeed(player_t *player);
fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed);

View file

@ -398,6 +398,7 @@ void P_SetThingPosition(mobj_t *thing);
void P_SetUnderlayPosition(mobj_t *thing);
boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing);
boolean P_IsLineTripWire(const line_t *ld);
boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y);
boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam);
boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);

View file

@ -1552,6 +1552,12 @@ boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing)
}
}
boolean P_IsLineTripWire(const line_t *ld)
{
return (sides[ld->sidenum[0]].midtexture ==
R_TextureNumForName("TRIPWIRE"));
}
//
// PIT_CheckLine
// Adjusts tmfloorz and tmceilingz as lines are contacted
@ -1666,7 +1672,8 @@ static boolean PIT_CheckLine(line_t *ld)
tmdropoffz = lowfloor;
// we've crossed the line
if (P_SpecialIsLinedefCrossType(ld->special))
if (P_SpecialIsLinedefCrossType(ld->special) ||
P_IsLineTripWire(ld))
{
add_spechit(ld);
}
@ -3022,6 +3029,7 @@ static void P_PlayerHitBounceLine(line_t *ld)
INT32 side;
angle_t lineangle;
fixed_t movelen;
fixed_t x, y;
side = P_PointOnLineSide(slidemo->x, slidemo->y, ld);
lineangle = R_PointToAngle2(0, 0, ld->dx, ld->dy)-ANGLE_90;
@ -3036,8 +3044,19 @@ static void P_PlayerHitBounceLine(line_t *ld)
if (slidemo->player && movelen < (15*mapobjectscale))
movelen = (15*mapobjectscale);
tmxmove += FixedMul(movelen, FINECOSINE(lineangle));
tmymove += FixedMul(movelen, FINESINE(lineangle));
x = FixedMul(movelen, FINECOSINE(lineangle));
y = FixedMul(movelen, FINESINE(lineangle));
if (P_IsLineTripWire(ld))
{
tmxmove = x * 4;
tmymove = y * 4;
}
else
{
tmxmove += x;
tmymove += y;
}
}
//
@ -3675,6 +3694,11 @@ void P_BouncePlayerMove(mobj_t *mo)
tmymove = FixedMul(mmomy, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3)));
}
if (P_IsLineTripWire(bestslideline))
{
K_ApplyTripWire(mo->player, TRIP_BLOCKED);
}
else
{
mobj_t *fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP);
if (mo->eflags & MFE_VERTICALFLIP)
@ -3694,8 +3718,11 @@ void P_BouncePlayerMove(mobj_t *mo)
mo->player->cmomx = tmxmove;
mo->player->cmomy = tmymove;
if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true)) {
P_TryMove(mo, mo->x - oldmomx, mo->y - oldmomy, true);
if (!P_IsLineTripWire(bestslideline))
{
if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true)) {
P_TryMove(mo, mo->x - oldmomx, mo->y - oldmomy, true);
}
}
}

View file

@ -15,6 +15,7 @@
#include "doomdef.h"
#include "doomstat.h"
#include "k_kart.h"
#include "p_local.h"
#include "r_main.h"
#include "r_data.h"
@ -588,7 +589,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
if (mobj)
{
// Check for collision with front side's midtexture if Effect 4 is set
if (linedef->flags & ML_EFFECT4
if ((linedef->flags & ML_EFFECT4 || (mobj->player && P_IsLineTripWire(linedef) && !K_TripwirePass(mobj->player)))
&& !linedef->polyobj // don't do anything for polyobjects! ...for now
) {
side_t *side = &sides[linedef->sidenum[0]];

View file

@ -318,6 +318,7 @@ static void P_NetArchivePlayers(void)
WRITEINT16(save_p, players[i].spheres);
WRITESINT8(save_p, players[i].glanceDir);
WRITEUINT8(save_p, players[i].tripWireState);
WRITEUINT8(save_p, players[i].typing_timer);
WRITEUINT8(save_p, players[i].typing_duration);
@ -573,6 +574,7 @@ static void P_NetUnArchivePlayers(void)
players[i].spheres = READINT16(save_p);
players[i].glanceDir = READSINT8(save_p);
players[i].tripWireState = READUINT8(save_p);
players[i].typing_timer = READUINT8(save_p);
players[i].typing_duration = READUINT8(save_p);

View file

@ -2018,6 +2018,13 @@ void P_CrossSpecialLine(line_t *line, INT32 side, mobj_t *thing)
return;
{
player_t *player = thing->player;
if (P_IsLineTripWire(line))
{
K_ApplyTripWire(player, TRIP_PASSED);
return;
}
switch (line->special)
{
case 2001: // Finish Line