diff --git a/src/d_player.h b/src/d_player.h index e73ff2e12..d9bc6d6b3 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -350,6 +350,13 @@ typedef enum khud_exp, khud_exptimer, + // Splits + khud_splittime, + khud_splitwin, + khud_splittimer, + khud_splitskin, + khud_splitcolor, + NUMKARTHUD } karthudtype_t; diff --git a/src/g_demo.cpp b/src/g_demo.cpp index 7a3d91004..71ef9ca38 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -118,7 +118,7 @@ size_t copy_fixed_buf(void* p, const void* s, size_t n) static char demoname[MAX_WADPATH]; static savebuffer_t demobuf = {0}; -static UINT8 *demotime_p, *demoinfo_p, *demoattack_p; +static UINT8 *demotime_p, *demoinfo_p, *demoattack_p, *demosplits_p; static UINT16 demoflags; boolean demosynced = true; // console warning message @@ -2068,6 +2068,13 @@ void G_BeginRecording(void) demoattack_p = demobuf.p; WRITEUINT32(demobuf.p, INT32_MAX); + demosplits_p = demobuf.p; + for (i = 0; i < MAXSPLITS; i++) + { + WRITEUINT32(demobuf.p, INT32_MAX); + } + + // Save netvar data CV_SaveDemoVars(&demobuf.p); @@ -2235,8 +2242,57 @@ void srb2::write_current_demo_end_marker() void G_SetDemoAttackTiming(tic_t time) { - if (!demo.playback) - *(UINT32 *)demoattack_p = time; + if (demo.playback) + return; + + *(UINT32 *)demoattack_p = time; +} + +void G_SetDemoCheckpointTiming(player_t *player, tic_t time, UINT8 checkpoint) +{ + if (demo.playback) + return; + if (checkpoint >= MAXSPLITS || checkpoint < 0) + return; + + UINT32 *splits = (UINT32 *)demosplits_p; + splits[checkpoint] = time; + + CONS_Printf("%d / %d\n", checkpoint, time); + + demoghost *g; + tic_t lowest = INT32_MAX; + UINT32 lowestskin = ((skin_t*)player->mo->skin) - skins; + UINT32 lowestcolor = player->skincolor; + for (g = ghosts; g; g = g->next) + { + if (lowest > g->splits[checkpoint]) + { + lowest = g->splits[checkpoint]; + lowestskin = ((skin_t*)g->mo->skin)-skins; + lowestcolor = g->mo->color; + + } + CONS_Printf("->%d\n", g->splits[checkpoint]); + } + + if (lowest != INT32_MAX) + { + player->karthud[khud_splittimer] = 1; + player->karthud[khud_splitskin] = lowestskin; + player->karthud[khud_splitcolor] = lowestcolor; + + if (lowest < time) + { + player->karthud[khud_splittime] = time - lowest; + player->karthud[khud_splitwin] = false; + } + else + { + player->karthud[khud_splittime] = lowest - time; + player->karthud[khud_splitwin] = true; + } + } } void G_SetDemoTime(UINT32 ptime, UINT32 plap) @@ -2594,6 +2650,8 @@ void G_LoadDemoInfo(menudemo_t *pdemo, boolean allownonmultiplayer) extrainfo_p = info.buffer + READUINT32(info.p); // The extra UINT32 read is for a blank 4 bytes? info.p += 4; // attack start + for (i = 0; i < MAXSPLITS; i++) + info.p += 4; // splits // Pared down version of CV_LoadNetVars to find the kart speed pdemo->kartspeed = KARTSPEED_NORMAL; // Default to normal speed @@ -3509,7 +3567,13 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname) } p += 4; // Extra data location reference - UINT32 attackstart = READUINT32(p); + tic_t attackstart = READUINT32(p); + + UINT8 *splits = p; + for (i = 0; i < MAXSPLITS; i++) + { + p += 4; + } // net var data count = READUINT16(p); @@ -3602,6 +3666,7 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname) gh->skinlist = skinlist; gh->attackstart = attackstart; + std::memcpy(gh->splits, splits, sizeof(tic_t) * MAXSPLITS); ghosts = gh; @@ -3755,6 +3820,8 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer) p += 4; // Extrainfo location marker p += 4; // Attack start info + for (i = 0; i < MAXSPLITS; i++) + p += 4; // splits // Ehhhh don't need ghostversion here (?) so I'll reuse the var here ghostversion = READUINT16(p); diff --git a/src/g_demo.h b/src/g_demo.h index 39292d54e..ab0bc4e68 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -168,6 +168,8 @@ extern UINT8 demo_writerng; #define DXD_PST_SPECTATING 0x02 #define DXD_PST_LEFT 0x03 +#define MAXSPLITS (200) + boolean G_CompatLevel(UINT16 level); // Record/playback tics @@ -203,6 +205,7 @@ struct demoghost { UINT16 version; UINT8 numskins; tic_t attackstart; + tic_t splits[MAXSPLITS]; boolean done; democharlist_t *skinlist; mobj_t oldmo, *mo; @@ -238,6 +241,7 @@ void G_SaveDemo(void); void G_ResetDemoRecording(void); void G_SetDemoAttackTiming(tic_t time); +void G_SetDemoCheckpointTiming(player_t *player, tic_t time, UINT8 checkpoint); boolean G_CheckDemoTitleEntry(void); diff --git a/src/k_hud.cpp b/src/k_hud.cpp index c3e444930..688b266bf 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -525,7 +525,7 @@ void K_LoadKartHUDGraphics(void) buffer[7] = '0'+((i) % 10); HU_UpdatePatch(&kp_overdrive[0][i], "%s", buffer); } - + sprintf(buffer, "bsOVRDxx"); for (i = 0; i < 32; i++) { @@ -2000,7 +2000,7 @@ static void K_drawKartItem(void) static void K_drawBackupItem(void) { bool tiny = r_splitscreen > 1; - patch_t *localpatch[3] = { kp_nodraw, kp_nodraw, kp_nodraw }; + patch_t *localpatch[3] = { kp_nodraw, kp_nodraw, kp_nodraw }; patch_t *localbg = (kp_itembg[2]); patch_t *localinv = kp_invincibility[((leveltime % (6*3)) / 3) + 7 + tiny]; INT32 fx = 0, fy = 0, fflags = 0, tx = 0, ty = 0; // final coords for hud and flags... @@ -3406,7 +3406,7 @@ static void K_drawKartDuelScores(void) { flags |= V_SNAPTOBOTTOM; flags &= ~V_SNAPTOTOP; - basey = BASEVIDHEIGHT - 40; + basey = BASEVIDHEIGHT - 40; } basex = BASEVIDWIDTH - 80; } @@ -3493,7 +3493,7 @@ static void K_drawKartDuelScores(void) V_DrawScaledPatch(basex-barheight+foeheight, basey, flags, kp_duel_4over); else V_DrawScaledPatch(basex, basey-barheight+foeheight, flags, kp_duel_over); - + if (!use4p) { V_DrawScaledPatch(basex, basey, flags, kp_duel_foe); @@ -3512,7 +3512,7 @@ static void K_drawKartDuelScores(void) } foenum.text("{}", foe->duelscore); - younum.text("{}", stplyr->duelscore); + younum.text("{}", stplyr->duelscore); // minirankings shamelessly copypasted because i know that shit works already // and SURELY we will never need to use this somewhere else, right? @@ -3526,7 +3526,7 @@ static void K_drawKartDuelScores(void) UINT8 drawme = draw ? (stplyr - players) : (foe - players); UINT16 drawx = basex + (draw ? youx : foex); UINT16 drawy = basey + (draw ? youy : foey); - + if (!playeringame[drawme] || players[drawme].spectator) continue; @@ -3790,8 +3790,8 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) if (R_GetViewNumber() == 1) { flags |= V_SNAPTOBOTTOM; - flags &= ~V_SNAPTOTOP; - basey = 170; + flags &= ~V_SNAPTOTOP; + basey = 170; } } } @@ -3817,7 +3817,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) return; using srb2::Draw; - srb2::Draw::Font scorefont = Draw::Font::kTimer; + srb2::Draw::Font scorefont = Draw::Font::kTimer; if (totalscore > 99) { @@ -3834,7 +3834,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) else { scorefont = Draw::Font::kZVote; - } + } } UINT32 youscore = stplyr->teamimportance; @@ -3870,7 +3870,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) if (teams_lastleveltime[vn] != leveltime) // Timing consistency { INT32 delta = abs(easedallyscore[vn] - allyscore); // how wrong is display score? - + if (scorechangecooldown[vn] == 0 && delta) { if (allyscore > easedallyscore[vn]) @@ -3886,9 +3886,9 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) enemycolor = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_WHITE, GTC_CACHE); } scorechangecooldown[vn] = TICRATE/delta; - } + } } - + if (!fromintermission) { // replace scores with eased scores @@ -4009,7 +4009,7 @@ void K_drawKartTeamScores(boolean fromintermission, INT32 interoffset) if (totalscore > 99) { enemynum.text("{:03}", enemyscore); - allynum.text("{:03}", allyscore); + allynum.text("{:03}", allyscore); } else { @@ -5856,13 +5856,13 @@ INT32 K_GetMinimapSplitFlags(const boolean usingProgressBar) #define ICON_DOT_RADIUS (10) // modified pick from blondedradio/RadioRacers (but there are like 57 things we don't want in the commit) -// (so gogo gadget copypaste, thanks for a good feature and saving me work i was supposed to do anyway) +// (so gogo gadget copypaste, thanks for a good feature and saving me work i was supposed to do anyway) static void K_DrawKartUFOTimer(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hudy, INT32 flags) { fixed_t amnumxpos, amnumypos; INT32 amxpos, amypos; - if (exitcountdown || leveltime > g_battleufo.due || battleprisons) + if (exitcountdown || leveltime > g_battleufo.due || battleprisons) return; tic_t raw = g_battleufo.due - leveltime; @@ -5872,7 +5872,7 @@ static void K_DrawKartUFOTimer(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hud { flags |= (raw / (TICRATE/2) % 2) ? V_YELLOWMAP : 0; } - + if (countdown <= 10) { flags &= ~(V_HUDTRANS|V_HUDTRANSHALF); @@ -7758,9 +7758,48 @@ void K_drawKartHUD(void) using srb2::Draw; Draw::TextElement text = Draw::TextElement().parse(" Restart"); Draw(BASEVIDWIDTH - 19, 2) - .flags(flags | V_YELLOWMAP) + .flags(flags | V_ORANGEMAP) .align(Draw::Align::kRight) .text(text.string()); + + boolean debug_alwaysdraw = false; + + if (stplyr->karthud[khud_splittimer] || debug_alwaysdraw) + { + tic_t split = stplyr->karthud[khud_splittime]; + UINT32 skin = stplyr->karthud[khud_splitskin]; + UINT32 color = stplyr->karthud[khud_splitcolor]; + boolean ahead = stplyr->karthud[khud_splitwin]; + + // debug + if (!stplyr->karthud[khud_splittimer]) + { + ahead = !!((leveltime/17)%2); + split = leveltime; + skin = stplyr->skin; + color = stplyr->skincolor; + } + + UINT8 *skincolor = R_GetTranslationColormap(skin, static_cast(color), GTC_CACHE); + + UINT8 textcolor = ahead ? SKINCOLOR_SAPPHIRE : SKINCOLOR_KETCHUP; + + Draw row = Draw(BASEVIDWIDTH/2, BASEVIDHEIGHT/4).align(Draw::Align::kCenter) + .font(Draw::Font::kThinTimer).flags(V_30TRANS); + + // vibes offset + row.x(-32).colormap(skincolor).patch(R_CanShowSkinInDemo(skin) ? faceprefix[skin][FACE_MINIMAP] : kp_unknownminimap); + + Draw::TextElement text = Draw::TextElement( + std::string(ahead ? "-" : "+") + "{:02}'{:02}\"{:02}", + G_TicsToMinutes(split, true), + G_TicsToSeconds(split), + G_TicsToCentiseconds(split) + ); + + // vibes offset TWO + row.colormap(textcolor).colorize(textcolor).x(8).text(text); + } } else { diff --git a/src/k_kart.c b/src/k_kart.c index bbabb5051..a3996cfd2 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4422,6 +4422,11 @@ void K_CheckpointCrossAward(player_t *player) if (gametype != GT_RACE) return; + if (!demo.playback && G_TimeAttackStart()) + { + G_SetDemoCheckpointTiming(player, leveltime, player->gradingpointnum); + } + player->gradingfactor += K_GetGradingFactorAdjustment(player); player->gradingpointnum++; player->exp = K_GetEXP(player); @@ -9039,6 +9044,13 @@ void K_KartPlayerHUDUpdate(player_t *player) if (player->karthud[khud_trickcool]) player->karthud[khud_trickcool]--; + if (player->karthud[khud_splittimer]) + { + player->karthud[khud_splittimer]++; + if (player->karthud[khud_splittimer] > 2*TICRATE) + player->karthud[khud_splittimer] = 0; + } + if (player->positiondelay) player->positiondelay--;