From b69d105af3d446e1a537c5beac2aeff650c61153 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 24 Oct 2019 16:35:39 -0400 Subject: [PATCH 1/3] Add respawn animation This commit also fixes MF_NOCLIP not working properly on players. Sink now spawns an SPB explosion on successful hit, since dying is no longer a harsh punishment. --- src/d_netcmd.c | 14 ++-- src/dehacked.c | 5 ++ src/g_game.c | 5 +- src/info.c | 7 +- src/info.h | 5 ++ src/k_kart.c | 185 +++++++++++++++++++++++++++++++++++++++++-------- src/k_kart.h | 1 + src/m_cheat.c | 9 +++ src/p_enemy.c | 4 +- src/p_map.c | 26 +++++-- src/p_mobj.c | 8 ++- src/p_spec.c | 12 ++-- src/p_user.c | 6 -- 13 files changed, 227 insertions(+), 60 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c19f8e391..39434928b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2842,13 +2842,15 @@ static void Got_Respawn(UINT8 **cp, INT32 playernum) return; } - // incase the above checks were modified to allow sending a respawn on these occasions: - if (players[respawnplayer].mo && !P_IsObjectOnGround(players[respawnplayer].mo)) - return; - if (players[respawnplayer].mo) - P_DamageMobj(players[respawnplayer].mo, NULL, NULL, 10000); - demo_extradata[playernum] |= DXD_RESPAWN; + { + // incase the above checks were modified to allow sending a respawn on these occasions: + if (!P_IsObjectOnGround(players[respawnplayer].mo)) + return; + + K_DoIngameRespawn(&players[respawnplayer]); + demo_extradata[playernum] |= DXD_RESPAWN; + } } /** Deals with an ::XD_RANDOMSEED message in a netgame. diff --git a/src/dehacked.c b/src/dehacked.c index fb6e7ff4f..6b99eeb7c 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6661,6 +6661,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // DEZ respawn laser "S_DEZLASER", + "S_DEZLASER_TRAIL1", + "S_DEZLASER_TRAIL2", + "S_DEZLASER_TRAIL3", + "S_DEZLASER_TRAIL4", + "S_DEZLASER_TRAIL5", // Audience Members "S_RANDOMAUDIENCE", diff --git a/src/g_game.c b/src/g_game.c index 0b58855a0..ad41f13af 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4915,7 +4915,10 @@ void G_ReadDemoExtraData(void) if (extradata & DXD_RESPAWN) { if (players[p].mo) - P_DamageMobj(players[p].mo, NULL, NULL, 10000); // Is this how this should work..? + { + // Is this how this should work..? + K_DoIngameRespawn(&players[p]); + } } if (extradata & DXD_SKIN) { diff --git a/src/info.c b/src/info.c index 60ffbc626..943c0bbb9 100644 --- a/src/info.c +++ b/src/info.c @@ -2875,7 +2875,12 @@ state_t states[NUMSTATES] = {SPR_KBLN, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_BATTLEBUMPER2}, // S_BATTLEBUMPER2 {SPR_KBLN, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_BATTLEBUMPER3}, // S_BATTLEBUMPER3 - {SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE, 8, {NULL}, 0, 0, S_NULL}, // S_DEZLASER + {SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE, 8, {NULL}, 0, 0, S_NULL}, // S_DEZLASER + {SPR_DEZL, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL2}, // S_DEZLASER_TRAIL1 + {SPR_DEZL, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL3}, // S_DEZLASER_TRAIL2 + {SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE|3, 4, {NULL}, 0, 0, S_DEZLASER_TRAIL4}, // S_DEZLASER_TRAIL3 + {SPR_DEZL, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL5}, // S_DEZLASER_TRAIL4 + {SPR_DEZL, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_NULL}, // S_DEZLASER_TRAIL5 {SPR_NULL, 0, 1, {A_RandomStateRange}, S_AUDIENCE_CHAO_CHEER1, S_AUDIENCE_CHAO_CHEER2, S_RANDOMAUDIENCE}, // S_RANDOMAUDIENCE diff --git a/src/info.h b/src/info.h index 27488d916..f47a4a151 100644 --- a/src/info.h +++ b/src/info.h @@ -3550,6 +3550,11 @@ typedef enum state // DEZ Laser respawn S_DEZLASER, + S_DEZLASER_TRAIL1, + S_DEZLASER_TRAIL2, + S_DEZLASER_TRAIL3, + S_DEZLASER_TRAIL4, + S_DEZLASER_TRAIL5, // Audience Members S_RANDOMAUDIENCE, diff --git a/src/k_kart.c b/src/k_kart.c index eb6d68a59..936259d8f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1919,6 +1919,29 @@ static void K_SpawnBrakeDriftSparks(player_t *player) // Be sure to update the m sparks->flags2 |= MF2_DONTDRAW; } +/** \brief Preps a player to respawn + + \param player player to respawn + + \return void +*/ +void K_DoIngameRespawn(player_t *player) +{ + if (!player->mo || P_MobjWasRemoved(player->mo)) + return; + + if (player->kartstuff[k_respawn]) + return; + + if (leveltime <= starttime) + return; + + player->mo->flags &= ~(MF_SOLID|MF_SHOOTABLE); + player->mo->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY; + player->mo->flags2 &= ~MF2_DONTDRAW; + player->kartstuff[k_respawn] = 48; +} + /** \brief Calculates the respawn timer and drop-boosting \param player player object passed from K_KartPlayerThink @@ -1934,39 +1957,136 @@ void K_RespawnChecker(player_t *player) if (player->kartstuff[k_respawn] > 1) { - player->kartstuff[k_respawn]--; - player->mo->momz = 0; + fixed_t destx = 0, desty = 0, destz = 0; + + player->mo->momx = player->mo->momy = player->mo->momz = 0; player->powers[pw_flashing] = 2; player->powers[pw_nocontrol] = 2; - if (leveltime % 8 == 0) + + if (leveltime % 8 == 0 && !mapreset) + S_StartSound(player->mo, sfx_s3kcas); + + destx = (player->starpostx << FRACBITS); + desty = (player->starposty << FRACBITS); + destz = (player->starpostz << FRACBITS); + + if (player->kartstuff[k_starpostflip]) + destz -= (128 * mapobjectscale) + (player->mo->height); + else + destz += (128 * mapobjectscale); + + if (player->mo->x != destx || player->mo->y != desty || player->mo->z != destz) { - INT32 i; - if (!mapreset) - S_StartSound(player->mo, sfx_s3kcas); + fixed_t step = 64*mapobjectscale; + fixed_t dist = P_AproxDistance(P_AproxDistance(player->mo->x - destx, player->mo->y - desty), player->mo->z - destz); - for (i = 0; i < 8; i++) + if (dist <= step) // You're ready to respawn { - mobj_t *mo; - angle_t newangle; - fixed_t newx, newy, newz; + P_TryMove(player->mo, destx, desty, true); + player->mo->z = destz; + } + else + { + fixed_t stepx = 0, stepy = 0, stepz = 0; + angle_t stepha = R_PointToAngle2(player->mo->x, player->mo->y, destx, desty); + angle_t stepva = R_PointToAngle2(0, player->mo->z, P_AproxDistance(player->mo->x - destx, player->mo->y - desty), destz); + fixed_t laserx = 0, lasery = 0, laserz = 0; + UINT8 lasersteps = 4; - newangle = FixedAngle(((360/8)*i)*FRACUNIT); - newx = player->mo->x + P_ReturnThrustX(player->mo, newangle, 31<mo->y + P_ReturnThrustY(player->mo, newangle, 31<mo->eflags & MFE_VERTICALFLIP) - newz = player->mo->z + player->mo->height; - else - newz = player->mo->z; + // Move toward the respawn point + stepx = FixedMul(FixedMul(FINECOSINE(stepha >> ANGLETOFINESHIFT), step), FINECOSINE(stepva >> ANGLETOFINESHIFT)); + stepy = FixedMul(FixedMul(FINESINE(stepha >> ANGLETOFINESHIFT), step), FINECOSINE(stepva >> ANGLETOFINESHIFT)); + stepz = FixedMul(FINESINE(stepva >> ANGLETOFINESHIFT), 2*step); - mo = P_SpawnMobj(newx, newy, newz, MT_DEZLASER); - if (mo) + P_TryMove(player->mo, player->mo->x + stepx, player->mo->y + stepy, true); + player->mo->z += stepz; + + // Spawn lasers along the path + laserx = player->mo->x + (stepx / 2); + lasery = player->mo->y + (stepy / 2); + laserz = player->mo->z + (stepz / 2); + dist = P_AproxDistance(P_AproxDistance(laserx - destx, lasery - desty), laserz - destz); + + if (dist > step/2) { + while (lasersteps) + { + + stepha = R_PointToAngle2(laserx, lasery, destx, desty); + stepva = R_PointToAngle2(0, laserz, P_AproxDistance(laserx - destx, lasery - desty), destz); + + stepx = FixedMul(FixedMul(FINECOSINE(stepha >> ANGLETOFINESHIFT), step), FINECOSINE(stepva >> ANGLETOFINESHIFT)); + stepy = FixedMul(FixedMul(FINESINE(stepha >> ANGLETOFINESHIFT), step), FINECOSINE(stepva >> ANGLETOFINESHIFT)); + stepz = FixedMul(FINESINE(stepva >> ANGLETOFINESHIFT), 2*step); + + laserx += stepx; + lasery += stepy; + laserz += stepz; + dist = P_AproxDistance(P_AproxDistance(laserx - destx, lasery - desty), laserz - destz); + + if (dist <= step/2) + break; + + lasersteps--; + } + } + + if (lasersteps == 0) // Don't spawn them beyond the respawn point. + { + mobj_t *laser; + + laser = P_SpawnMobj(laserx, lasery, laserz + (player->mo->height / 2), MT_DEZLASER); + + if (laser && !P_MobjWasRemoved(laser)) + { + P_SetMobjState(laser, S_DEZLASER_TRAIL1); + if (player->mo->eflags & MFE_VERTICALFLIP) + laser->eflags |= MFE_VERTICALFLIP; + P_SetTarget(&laser->target, player->mo); + laser->angle = stepha + ANGLE_90; + P_SetScale(laser, (laser->destscale = FRACUNIT)); + } + } + } + } + else + { + player->kartstuff[k_respawn]--; + + player->mo->flags |= MF_SOLID|MF_SHOOTABLE; + player->mo->flags &= ~(MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY); + if (!(player->pflags & PF_NOCLIP)) + player->mo->flags &= ~MF_NOCLIP; + + if (leveltime % 8 == 0) + { + INT32 i; + + for (i = 0; i < 8; i++) + { + mobj_t *laser; + angle_t newangle; + fixed_t newx, newy, newz; + + newangle = FixedAngle(((360/8)*i)*FRACUNIT); + newx = player->mo->x + P_ReturnThrustX(player->mo, newangle, 31<mo->y + P_ReturnThrustY(player->mo, newangle, 31<mo->eflags & MFE_VERTICALFLIP) - mo->eflags |= MFE_VERTICALFLIP; - P_SetTarget(&mo->target, player->mo); - mo->angle = newangle+ANGLE_90; - mo->momz = (8<mo); - P_SetScale(mo, (mo->destscale = FRACUNIT)); + newz = player->mo->z + player->mo->height; + else + newz = player->mo->z; + + laser = P_SpawnMobj(newx, newy, newz, MT_DEZLASER); + + if (laser && !P_MobjWasRemoved(laser)) + { + if (player->mo->eflags & MFE_VERTICALFLIP) + laser->eflags |= MFE_VERTICALFLIP; + P_SetTarget(&laser->target, player->mo); + laser->angle = newangle+ANGLE_90; + laser->momz = (8<mo); + P_SetScale(laser, (laser->destscale = FRACUNIT)); + } } } } @@ -5313,8 +5433,15 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->kartstuff[k_stolentimer]--; if (player->kartstuff[k_squishedtimer]) + { player->kartstuff[k_squishedtimer]--; + if ((player->kartstuff[k_squishedtimer] == 0) && !(player->pflags & PF_NOCLIP)) + { + player->mo->flags &= ~MF_NOCLIP; + } + } + if (player->kartstuff[k_justbumped]) player->kartstuff[k_justbumped]--; @@ -5698,10 +5825,12 @@ static void K_UpdateDistanceFromFinishLine(player_t *const player) if ((nextwaypoint != NULL) && (nextwaypoint != player->nextwaypoint) && + (player->kartstuff[k_respawn] == 0) && (K_GetWaypointIsShortcut(nextwaypoint) == false) && (K_GetWaypointIsEnabled(nextwaypoint) == true)) { size_t i = 0U; waypoint_t *aimwaypoint = NULL; + player->starpostx = nextwaypoint->mobj->x >> FRACBITS; player->starposty = nextwaypoint->mobj->y >> FRACBITS; player->starpostz = nextwaypoint->mobj->z >> FRACBITS; @@ -6895,13 +7024,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground) // Squishing // If a Grow player or a sector crushes you, get flattened instead of being killed. - if (player->kartstuff[k_squishedtimer] <= 0) + if (player->kartstuff[k_squishedtimer] > 0) { - player->mo->flags &= ~MF_NOCLIP; - } - else - { - player->mo->flags |= MF_NOCLIP; + //player->mo->flags |= MF_NOCLIP; player->mo->momx = 0; player->mo->momy = 0; } diff --git a/src/k_kart.h b/src/k_kart.h index b91e8c8a1..ff6f6fafc 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -27,6 +27,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) void K_KartPainEnergyFling(player_t *player); void K_FlipFromObject(mobj_t *mo, mobj_t *master); void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master); +void K_DoIngameRespawn(player_t *player); void K_RespawnChecker(player_t *player); void K_KartMoveAnimation(player_t *player); void K_KartPlayerHUDUpdate(player_t *player); diff --git a/src/m_cheat.c b/src/m_cheat.c index c24a8014b..d61d22cd0 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -292,9 +292,18 @@ void Command_CheatNoClip_f(void) REQUIRE_NOULTIMATE; plyr = &players[consoleplayer]; + + if (!plyr->mo || P_MobjWasRemoved(plyr->mo)) + return; + plyr->pflags ^= PF_NOCLIP; CONS_Printf(M_GetText("No Clipping %s\n"), plyr->pflags & PF_NOCLIP ? M_GetText("On") : M_GetText("Off")); + if (plyr->pflags & PF_NOCLIP) + plyr->mo->flags |= MF_NOCLIP; + else + plyr->mo->flags &= ~MF_NOCLIP; + G_SetGameModified(multiplayer, true); } diff --git a/src/p_enemy.c b/src/p_enemy.c index a4684b40b..86e615ee8 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -10673,8 +10673,8 @@ void A_RemoteDamage(mobj_t *actor) if (locvar2 == 1) // Kill mobj! { - if (target->player) // players die using P_DamageMobj instead for some reason - P_DamageMobj(target, source, source, 10000); + if (target->player) + K_DoIngameRespawn(target->player); else P_KillMobj(target, source, source); } diff --git a/src/p_map.c b/src/p_map.c index 9585849f7..52a19e1c0 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1005,12 +1005,20 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_PLAYER) { - S_StartSound(NULL, sfx_bsnipe); //let all players hear it. + mobj_t *explosion; + + S_StartSound(NULL, sfx_bsnipe); // let all players hear it. + HU_SetCEchoFlags(0); HU_SetCEchoDuration(5); HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[thing->player-players])); I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[thing->player-players]); - P_DamageMobj(thing, tmthing, tmthing->target, 10000); + + explosion = P_SpawnMobj(thing->x, thing->y, thing->z, MT_SPBEXPLOSION); + explosion->extravalue1 = 1; // Tell K_ExplodePlayer to use extra knockback + if (tmthing->target && !P_MobjWasRemoved(tmthing->target)) + P_SetTarget(&explosion->target, tmthing->target); + P_KillMobj(tmthing, thing, thing); } @@ -1269,15 +1277,23 @@ static boolean PIT_CheckThing(mobj_t *thing) } else if (thing->type == MT_SINK) { + mobj_t *explosion; + if ((thing->target == tmthing) && (thing->threshold > 0)) return true; - S_StartSound(NULL, sfx_cgot); //let all players hear it. + S_StartSound(NULL, sfx_bsnipe); // let all players hear it. + HU_SetCEchoFlags(0); HU_SetCEchoDuration(5); HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[tmthing->player-players])); I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[tmthing->player-players]); - P_DamageMobj(tmthing, thing, thing->target, 10000); + + explosion = P_SpawnMobj(tmthing->x, tmthing->y, tmthing->z, MT_SPBEXPLOSION); + explosion->extravalue1 = 1; // Tell K_ExplodePlayer to use extra knockback + if (thing->target && !P_MobjWasRemoved(thing->target)) + P_SetTarget(&explosion->target, thing->target); + P_KillMobj(thing, tmthing, tmthing); } @@ -1662,7 +1678,7 @@ static boolean PIT_CheckThing(mobj_t *thing) { // Objects kill you if it falls from above. if (thing != tmthing->target) - P_DamageMobj(thing, tmthing, tmthing->target, 10000); + K_DoIngameRespawn(thing->player); tmthing->momz = -tmthing->momz/2; // Bounce, just for fun! // The tmthing->target allows the pusher of the object diff --git a/src/p_mobj.c b/src/p_mobj.c index b0e378649..b04bf717a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11475,6 +11475,9 @@ void P_SpawnPlayer(INT32 playernum) // Spawn with a pity shield if necessary. //P_DoPityCheck(p); + if (p->kartstuff[k_respawn] != 0) + p->mo->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY; + if (G_BattleGametype()) // SRB2kart { mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + P_GetPlayerHeight(p)+16*FRACUNIT, MT_PLAYERARROW); @@ -11691,11 +11694,10 @@ void P_MovePlayerToStarpost(INT32 playernum) sector->ceilingheight; if (mobj->player->kartstuff[k_starpostflip]) - z = (p->starpostz<height; + z = (p->starpostz<height; else - z = (p->starpostz<starpostz<starpostz + 128) << FRACBITS; // reverse gravity exists, pls mobj->player->kartstuff[k_starpostflip] = 0; if (z < floor) diff --git a/src/p_spec.c b/src/p_spec.c index b71d7508c..f83ca79a7 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3777,10 +3777,10 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers case 6: // Death Pit (Camera Mod) case 7: // Death Pit (No Camera Mod) if (roversector || P_MobjReadyToTrigger(player->mo, sector)) - P_DamageMobj(player->mo, NULL, NULL, 10000); + K_DoIngameRespawn(player); break; case 8: // Instant Kill - P_DamageMobj(player->mo, NULL, NULL, 10000); + K_DoIngameRespawn(player); break; case 9: // Ring Drainer (Floor Touch) case 10: // Ring Drainer (No Floor Touch) @@ -6954,8 +6954,8 @@ void T_Scroll(scroll_t *s) height = P_GetSpecialBottomZ(thing, sec, psec); - if (!(thing->flags & MF_NOCLIP)) // Thing must be clipped - if (!(thing->flags & MF_NOGRAVITY || thing->z+thing->height != height)) // Thing must a) be non-floating and have z+height == height + if (!(thing->flags & MF_NOCLIP) && // Thing must be clipped + (!(thing->flags & MF_NOGRAVITY || thing->z+thing->height != height))) // Thing must a) be non-floating and have z+height == height { // Move objects only if on floor // non-floating, and clipped. @@ -7030,8 +7030,8 @@ void T_Scroll(scroll_t *s) height = P_GetSpecialTopZ(thing, sec, psec); - if (!(thing->flags & MF_NOCLIP)) // Thing must be clipped - if (!(thing->flags & MF_NOGRAVITY || thing->z != height))// Thing must a) be non-floating and have z == height + if (!(thing->flags & MF_NOCLIP) && // Thing must be clipped + (!(thing->flags & MF_NOGRAVITY || thing->z != height))) // Thing must a) be non-floating and have z == height { // Move objects only if on floor or underwater, // non-floating, and clipped. diff --git a/src/p_user.c b/src/p_user.c index 16aeeb054..6267559e0 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8047,12 +8047,6 @@ void P_PlayerThink(player_t *player) // The timer might've reached zero, but we'll run the remote view camera anyway by setting it to -1. } - /// \note do this in the cheat code - if (player->pflags & PF_NOCLIP) - player->mo->flags |= MF_NOCLIP; - else - player->mo->flags &= ~MF_NOCLIP; - cmd = &player->cmd; // SRB2kart From ed007f34ccb183559e44752b1c2b51e567f0750f Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 24 Oct 2019 16:55:13 -0400 Subject: [PATCH 2/3] change colors, since orange & yellow are pretty indistinguishable --- src/k_waypoint.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_waypoint.c b/src/k_waypoint.c index 695d47201..ab3bd8be9 100644 --- a/src/k_waypoint.c +++ b/src/k_waypoint.c @@ -421,11 +421,11 @@ void K_DebugWaypointsVisualise(void) } else if (waypoint->numnextwaypoints == 0 || waypoint->numprevwaypoints == 0) { - debugmobj->color = SKINCOLOR_ORANGE; + debugmobj->color = SKINCOLOR_YELLOW; } else if (waypoint == players[displayplayers[0]].nextwaypoint) { - debugmobj->color = SKINCOLOR_YELLOW; + debugmobj->color = SKINCOLOR_GREEN; } else { From 3686445f2f378be529acd43eecbe360a5ba7c9f1 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 24 Oct 2019 17:11:27 -0400 Subject: [PATCH 3/3] Snap to bottom on WRONG WAY --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 936259d8f..ccc9ff447 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10426,7 +10426,7 @@ void K_drawKartHUD(void) } if (stplyr->kartstuff[k_wrongway] && ((leveltime / 8) & 1)) - V_DrawCenteredString(BASEVIDWIDTH>>1, 176, V_REDMAP, "WRONG WAY"); + V_DrawCenteredString(BASEVIDWIDTH>>1, 176, V_REDMAP|V_SNAPTOBOTTOM, "WRONG WAY"); if (cv_kartdebugdistribution.value) K_drawDistributionDebugger();