Merge branch 'mania-time-trial' into 'master'

Mania-style time trials (resolves #747 mostly by accident)

Closes #747

See merge request KartKrew/Kart!1592
This commit is contained in:
Oni 2023-11-03 03:12:03 +00:00
commit 4e5e0835b5
10 changed files with 56 additions and 29 deletions

View file

@ -821,6 +821,7 @@ extern boolean thwompsactive;
extern UINT8 lastLowestLap; extern UINT8 lastLowestLap;
extern SINT8 spbplace; extern SINT8 spbplace;
extern boolean rainbowstartavailable; extern boolean rainbowstartavailable;
extern tic_t linecrossed;
extern boolean inDuel; extern boolean inDuel;
extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :) extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :)

View file

@ -1171,9 +1171,18 @@ void G_GhostTicker(void)
demoghost *g,*p; demoghost *g,*p;
for(g = ghosts, p = NULL; g; g = g->next) for(g = ghosts, p = NULL; g; g = g->next)
{ {
UINT16 ziptic;
UINT8 xziptic;
// Pause jhosts that cross until we cross ourself.
if (g->linecrossed && !linecrossed)
continue;
readghosttic:
// Skip normal demo data. // Skip normal demo data.
UINT16 ziptic = READUINT8(g->p); ziptic = READUINT8(g->p);
UINT8 xziptic = 0; xziptic = 0;
while (ziptic != DW_END) // Get rid of extradata stuff while (ziptic != DW_END) // Get rid of extradata stuff
{ {
@ -1198,6 +1207,8 @@ void G_GhostTicker(void)
g->p += 32; // ok (32 because there's both the skin and the colour) g->p += 32; // ok (32 because there's both the skin and the colour)
if (ziptic & DXD_WEAPONPREF) if (ziptic & DXD_WEAPONPREF)
g->p++; // ditto g->p++; // ditto
if (ziptic & DXD_START)
g->linecrossed = true;
} }
else if (ziptic == DW_RNG) else if (ziptic == DW_RNG)
{ {
@ -1463,6 +1474,9 @@ skippedghosttic:
continue; continue;
} }
if (linecrossed && !g->linecrossed)
goto readghosttic;
p = g; p = g;
#undef follow #undef follow
} }

View file

@ -126,6 +126,7 @@ extern UINT8 demo_writerng;
#define DXD_NAME 0x08 // name changed #define DXD_NAME 0x08 // name changed
#define DXD_COLOR 0x10 // color changed #define DXD_COLOR 0x10 // color changed
#define DXD_FOLLOWER 0x20 // follower was changed #define DXD_FOLLOWER 0x20 // follower was changed
#define DXD_START 0x40 // Crossed the line in TA
#define DXD_ADDPLAYER (DXD_JOINDATA|DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN|DXD_FOLLOWER) #define DXD_ADDPLAYER (DXD_JOINDATA|DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN|DXD_FOLLOWER)
@ -168,6 +169,7 @@ struct demoghost {
UINT8 fadein; UINT8 fadein;
UINT16 version; UINT16 version;
UINT8 numskins; UINT8 numskins;
boolean linecrossed;
democharlist_t *skinlist; democharlist_t *skinlist;
mobj_t oldmo, *mo; mobj_t oldmo, *mo;
struct demoghost *next; struct demoghost *next;

View file

@ -310,6 +310,7 @@ boolean thwompsactive; // Thwomps activate on lap 2
UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors
SINT8 spbplace; // SPB exists, give the person behind better items SINT8 spbplace; // SPB exists, give the person behind better items
boolean rainbowstartavailable; // Boolean, keeps track of if the rainbow start was gotten boolean rainbowstartavailable; // Boolean, keeps track of if the rainbow start was gotten
tic_t linecrossed; // For Time Attack
boolean inDuel; // Boolean, keeps track of if it is a 1v1 boolean inDuel; // Boolean, keeps track of if it is a 1v1
// Client-sided, unsynched variables (NEVER use in anything that needs to be synced with other players) // Client-sided, unsynched variables (NEVER use in anything that needs to be synced with other players)
@ -328,6 +329,11 @@ UINT16 prevmap, nextmap;
char player_names[MAXPLAYERS][MAXPLAYERNAME+1]; char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
INT32 player_name_changes[MAXPLAYERS]; INT32 player_name_changes[MAXPLAYERS];
boolean G_TimeAttackStart(void)
{
return (modeattacking && (gametyperules & (GTR_CIRCUIT|GTR_CATCHER)) == GTR_CIRCUIT);
}
// MAKE SURE YOU SAVE DATA BEFORE CALLING THIS // MAKE SURE YOU SAVE DATA BEFORE CALLING THIS
void G_ClearRecords(void) void G_ClearRecords(void)
{ {

View file

@ -263,6 +263,8 @@ void G_LoadGameSettings(void);
void G_SetGameModified(boolean silent, boolean major); void G_SetGameModified(boolean silent, boolean major);
void G_SetUsedCheats(void); void G_SetUsedCheats(void);
boolean G_TimeAttackStart(void);
// Gamedata record shit // Gamedata record shit
void G_ClearRecords(void); void G_ClearRecords(void);

View file

@ -118,6 +118,7 @@ void K_TimerReset(void)
darkness = darktimer = 0; darkness = darktimer = 0;
numbulbs = 1; numbulbs = 1;
inDuel = rainbowstartavailable = false; inDuel = rainbowstartavailable = false;
linecrossed = 0;
timelimitintics = extratimeintics = secretextratime = 0; timelimitintics = extratimeintics = secretextratime = 0;
g_pointlimit = 0; g_pointlimit = 0;
} }
@ -262,6 +263,12 @@ void K_TimerInit(void)
introtime = 0; introtime = 0;
} }
if (G_TimeAttackStart())
{
starttime = 15*TICRATE; // Longest permitted start. No half-laps in reverse.
// (Changed on finish line cross later, don't worry.)
}
K_SpawnItemCapsules(); K_SpawnItemCapsules();
K_BattleInit(domodeattack); K_BattleInit(domodeattack);
@ -8332,7 +8339,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
// If the button stays held, delay charge a bit. // If the button stays held, delay charge a bit.
if (player->instaWhipChargeLockout) if (player->instaWhipChargeLockout)
player->instaWhipChargeLockout--; player->instaWhipChargeLockout--;
if (player->rings > 0 || player->itemamount || player->ringdelay || player->rocketsneakertimer) if (player->rings > 0 || player->itemamount || player->ringdelay || player->rocketsneakertimer || player->ringboxdelay)
player->instaWhipChargeLockout = INSTAWHIP_HOLD_DELAY; player->instaWhipChargeLockout = INSTAWHIP_HOLD_DELAY;
else if (!(player->cmd.buttons & BT_ATTACK)) // Deliberate Item button release, no need to protect you from lockout else if (!(player->cmd.buttons & BT_ATTACK)) // Deliberate Item button release, no need to protect you from lockout
player->instaWhipChargeLockout = 0; player->instaWhipChargeLockout = 0;
@ -8357,7 +8364,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
S_StopSoundByID(player->mo, sfx_wchrg2); S_StopSoundByID(player->mo, sfx_wchrg2);
} }
if (player->itemamount || player->respawn.state != RESPAWNST_NONE || player->pflags & (PF_ITEMOUT|PF_EGGMANOUT) || player->rocketsneakertimer) if (player->itemamount || player->respawn.state != RESPAWNST_NONE || player->pflags & (PF_ITEMOUT|PF_EGGMANOUT) || player->rocketsneakertimer || player->ringboxdelay)
player->instaWhipCharge = 0; player->instaWhipCharge = 0;
if (player->tiregrease) if (player->tiregrease)

View file

@ -319,6 +319,13 @@ boolean M_Responder(event_t *ev)
} }
#endif #endif
// Attack modes quick-restart
if (CON_Ready() == false && modeattacking && G_PlayerInputDown(0, gc_y, splitscreen + 1) == true)
{
M_TryAgain(0);
return true;
}
if (CON_Ready() == false && G_PlayerInputDown(0, gc_start, splitscreen + 1) == true) if (CON_Ready() == false && G_PlayerInputDown(0, gc_start, splitscreen + 1) == true)
{ {
if (!chat_on) if (!chat_on)

View file

@ -283,7 +283,7 @@ static void K_DrawFinishLineBeamForLine(fixed_t offset, angle_t aiming, line_t *
y = liney + FixedMul(FixedMul(FINISHLINEBEAM_SPACING, FINESINE(lineangle >> ANGLETOFINESHIFT)), FINECOSINE(aiming >> ANGLETOFINESHIFT)); y = liney + FixedMul(FixedMul(FINISHLINEBEAM_SPACING, FINESINE(lineangle >> ANGLETOFINESHIFT)), FINECOSINE(aiming >> ANGLETOFINESHIFT));
z = FINISHLINEBEAM_SPACING + FixedMul(FINISHLINEBEAM_SPACING, FINESINE(aiming >> ANGLETOFINESHIFT)); z = FINISHLINEBEAM_SPACING + FixedMul(FINISHLINEBEAM_SPACING, FINESINE(aiming >> ANGLETOFINESHIFT));
if (leveltime >= starttime) if (leveltime >= starttime || G_TimeAttackStart())
{ {
spriteframe = 4; // Weakest sprite when passable spriteframe = 4; // Weakest sprite when passable
} }

View file

@ -49,6 +49,7 @@
#include "k_objects.h" #include "k_objects.h"
#include "acs/interface.h" #include "acs/interface.h"
#include "m_easing.h" #include "m_easing.h"
#include "music.h"
// Not sure if this is necessary, but it was in w_wad.c, so I'm putting it here too -Shadow Hog // Not sure if this is necessary, but it was in w_wad.c, so I'm putting it here too -Shadow Hog
#include <errno.h> #include <errno.h>
@ -1909,7 +1910,7 @@ static void K_HandleLapIncrement(player_t *player)
{ {
if (player) if (player)
{ {
if (leveltime < starttime && !(gametyperules & GTR_ROLLINGSTART)) if (!G_TimeAttackStart() && leveltime < starttime && !(gametyperules & GTR_ROLLINGSTART))
{ {
// freeze 'em until fault penalty is over // freeze 'em until fault penalty is over
player->mo->hitlag = starttime - leveltime + TICRATE*3; player->mo->hitlag = starttime - leveltime + TICRATE*3;
@ -1964,6 +1965,15 @@ static void K_HandleLapIncrement(player_t *player)
player->karthud[khud_lapanimation] = 80; player->karthud[khud_lapanimation] = 80;
} }
if (G_TimeAttackStart() && !linecrossed)
{
linecrossed = leveltime;
if (starttime > leveltime) // Overlong starts shouldn't reset time on cross
starttime = leveltime;
demo_extradata[player-players] |= DXD_START;
Music_Stop("position");
}
if (rainbowstartavailable == true && player->mo->hitlag == 0) if (rainbowstartavailable == true && player->mo->hitlag == 0)
{ {
S_StartSound(player->mo, sfx_s23c); S_StartSound(player->mo, sfx_s23c);

View file

@ -1330,7 +1330,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
if (demo.playback == false) if (demo.playback == false)
{ {
if (modeattacking == true) if (modeattacking)
{ {
G_UpdateRecords(); G_UpdateRecords();
} }
@ -2834,28 +2834,6 @@ static void P_DeathThink(player_t *player)
K_ToggleDirector(G_PartyPosition(player - players), true); K_ToggleDirector(G_PartyPosition(player - players), true);
} }
// Keep time rolling
if (!(player->exiting || mapreset) && !(player->pflags & PF_NOCONTEST) && !stoppedclock)
{
if (leveltime >= starttime)
{
player->realtime = leveltime - starttime;
if (player == &players[consoleplayer])
{
if (player->spectator)
curlap = 0;
else if (curlap != UINT32_MAX)
curlap++; // This is too complicated to sync to realtime, just sorta hope for the best :V
}
}
else
{
player->realtime = 0;
if (player == &players[consoleplayer])
curlap = 0;
}
}
if (!player->mo) if (!player->mo)
return; return;