diff --git a/src/k_hud.c b/src/k_hud.c index 49d55d595..5e5546b2d 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -88,6 +88,7 @@ static CV_PossibleValue_t speedo_cons_t[]= { {0, "Default"}, {1, "Small"}, {2, "P-Meter"}, + {3, "Dial"}, {0, NULL} }; @@ -242,6 +243,13 @@ patch_t *kp_itemtarget_far[2][2]; patch_t *kp_itemtarget_far_text[2]; patch_t *kp_itemtarget_near[2][8]; +// dial speedometer +static patch_t *kp_dial = NULL; +static patch_t *kp_dialfinish = NULL; +static patch_t *kp_dialbase[4] = {NULL}; +static patch_t *kp_speedpatchesdial[8] = {NULL}; +static patch_t *kp_dialnum[20] = {NULL}; + void K_RegisterKartHUDStuff(void) { K_ReloadHUDColorCvar(); @@ -436,6 +444,41 @@ void K_LoadKartHUDGraphics(void) // Speedometer Sticker Color HU_UpdatePatch(&kp_speedometersticker[1], "SC_SMSTC"); + // Dial speedometer + HU_UpdatePatch(&kp_dial, "K_DSDIAL"); + + kp_dial->pivot.x = kp_dial->width / 2; + kp_dial->pivot.y = kp_dial->height / 2; + kp_dial->alignflags |= PATCHALIGN_USEPIVOTS; + + HU_UpdatePatch(&kp_dialfinish, "K_DILFIN"); + HU_UpdatePatch(&kp_dialbase[0], "K_DSPBS1"); + HU_UpdatePatch(&kp_dialbase[1], "K_DSPBS2"); + HU_UpdatePatch(&kp_dialbase[2], "K_DSPBC1"); + HU_UpdatePatch(&kp_dialbase[3], "K_DSPBC2"); + HU_UpdatePatch(&kp_speedpatchesdial[0], "SP_DKMH"); + HU_UpdatePatch(&kp_speedpatchesdial[1], "SP_DMPH"); + HU_UpdatePatch(&kp_speedpatchesdial[2], "SP_DFRAC"); + HU_UpdatePatch(&kp_speedpatchesdial[3], "SP_DPERC"); + HU_UpdatePatch(&kp_speedpatchesdial[4], "SC_DKMH"); + HU_UpdatePatch(&kp_speedpatchesdial[5], "SC_DMPH"); + HU_UpdatePatch(&kp_speedpatchesdial[6], "SC_DFRAC"); + HU_UpdatePatch(&kp_speedpatchesdial[7], "SC_DPERC"); + + sprintf(buffer, "K_DSPNMx"); + for (i = 0; i < 10; i++) + { + buffer[7] = '0'+(i%10); + HU_UpdatePatch(&kp_dialnum[i], "%s", buffer); + } + + sprintf(buffer, "K_DSPNCx"); + for (i = 0; i < 10; i++) + { + buffer[7] = '0'+(i%10); + HU_UpdatePatch(&kp_dialnum[i+10], "%s", buffer); + } + // Driftgauge Stickers HU_UpdatePatch(&kp_driftgauge[0], "K_DGAU0"); // Spee HU_UpdatePatch(&kp_driftgauge[1], "K_DGAU1"); // Achii @@ -3047,7 +3090,7 @@ static void K_drawKartStatsnLives(void) if ((cv_lives_xoffset.value == 0 && cv_lives_yoffset.value == 0) || split) { - if ((cv_newspeedometer.value == 0 || cv_newspeedometer.value == 2) && !K_RingsActive() && !split) + if ((cv_newspeedometer.value == 0 || cv_newspeedometer.value == 2 || cv_newspeedometer.value == 3) && !K_RingsActive() && !split) { offsetx = 25; offsety = 15; @@ -3161,33 +3204,188 @@ static void K_drawKartAccessibilityIcons(INT32 fx) } } +#ifdef ROTSPRITE + +#define DIALSPDDIV 97090 // 1.48148; converts 200 to 135 +#define MPHDIV 68283 // 1.04192; converts 141 to 135 + +static void K_DrawDialNum(INT32 x, INT32 y, boolean colorized, INT32 flags, INT32 num, INT32 digits, const UINT8 *colormap) +{ + INT32 w = 0; + w = kp_dialnum[0]->width; + + if (flags & V_NOSCALESTART) + w *= vid.dup; + + if (num < 0) + num = -num; + + // draw the number + do + { + x -= (w); + + if (colorized) + V_DrawFixedPatch(x << FRACBITS, y << FRACBITS, FRACUNIT, flags, kp_dialnum[(num % 10) + 10], colormap); + else + V_DrawFixedPatch(x << FRACBITS, y << FRACBITS, FRACUNIT, flags, kp_dialnum[num % 10], colormap); + + num /= 10; + } while (--digits); +} + +static void K_DrawDialLaps(INT32 x, INT32 y, INT32 num, INT32 total, INT32 flags) +{ + INT32 fx; + fx = x + ((num < 10) ? 0 : 6); + V_DrawRankNum(fx, y, flags, num, (num < 10) ? 1 : 2, NULL); + V_DrawScaledPatch(fx + 2, y, flags, frameslash); + V_DrawRankNum(fx + 13 + ((total < 10) ? 0 : 6), y, flags, total, (total < 10) ? 1 : 2, NULL); +} + +static void K_DrawDialSpeedometer(fixed_t speed, + fixed_t divisor, + UINT16 labeln, + INT32 splitflags, + boolean battlemode, + boolean infoactive, + boolean colorized) +{ + const UINT8* colormap = R_GetTranslationColormap(TC_DEFAULT, K_GetHudColor(), GTC_CACHE); + + INT32 ringoffset = 0; + const UINT8 infoidx = (infoactive) ? 1 : 0; + + const fixed_t spd = FixedDiv(speed, divisor); + const angle_t speedangle = + FixedAngle(((min(135 * FRACUNIT, spd) - (45 * FRACUNIT)))); + + if (K_RingsActive() == true) + { + ringoffset = -16; + } + + if (colorized) // Colourized hud + { + V_DrawMappedPatch( + SPDM_X, SPDM_Y - 25 + ringoffset, (V_HUDTRANS | splitflags), kp_dialbase[infoidx + 2], colormap); + V_DrawMappedPatch(SPDM_X, + SPDM_Y + 14 + ringoffset, + V_HUDTRANS | splitflags, + kp_speedpatchesdial[labeln + 4], + colormap); + } + else + { + V_DrawScaledPatch(SPDM_X, SPDM_Y - 25 + ringoffset, (V_HUDTRANS | splitflags), kp_dialbase[infoidx]); + V_DrawScaledPatch(SPDM_X, + SPDM_Y + 14 + ringoffset, + V_HUDTRANS | splitflags, + kp_speedpatchesdial[labeln]); + } + + K_DrawDialNum(SPDM_X + 10, + SPDM_Y + 9 + ringoffset, + colorized, + V_HUDTRANS | splitflags, + speed / FRACUNIT, + 3, + colormap); + + // gotta center the dial manually + V_DrawRotatedPatch((SPDM_X - 19) << FRACBITS, + (SPDM_Y - 1 + ringoffset) << FRACBITS, + speedangle, + FRACUNIT, + FRACUNIT, + (V_HUDTRANS | splitflags), + kp_dial, + colormap); + + if (!infoactive) + { + // no need to draw info if we're not supposed to + return; + } + + // draw the info + if (battlemode) + { + if (stplyr->kartstuff[k_bumper] <= 0) + { + V_DrawMappedPatch( + SPDM_X + 28, SPDM_Y + 12 + ringoffset, V_HUDTRANS | splitflags, kp_splitkarmabomb, colormap); + K_DrawDialLaps(SPDM_X + 46, + SPDM_Y + ringoffset + 13, + stplyr->kartstuff[k_comebackpoints], + 2, + V_HUDTRANS | splitflags); + } + else // the above doesn't need to account for weird stuff since the max amount of karma + // necessary is always 2 ^^^^ + { + V_DrawMappedPatch( + SPDM_X + 28, SPDM_Y + 12, V_HUDTRANS | splitflags, kp_rankbumper, colormap); + K_DrawDialLaps(SPDM_X + 46, + SPDM_Y + ringoffset + 13, + stplyr->kartstuff[k_bumper], + cv_kartbumpers.value, + V_HUDTRANS | splitflags); + } + } + else + { + V_DrawScaledPatch(SPDM_X + 28, SPDM_Y + 12 + ringoffset, V_HUDTRANS | splitflags, kp_splitlapflag); + + if (stplyr->exiting) + V_DrawScaledPatch(SPDM_X + 39, SPDM_Y + 29 + ringoffset, V_HUDTRANS | splitflags, kp_dialfinish); + else + K_DrawDialLaps(SPDM_X + 46, + SPDM_Y + ringoffset + 13, + stplyr->laps, + numlaps, + V_HUDTRANS | splitflags); + } +} + +#endif + static void K_drawKartSpeedometer(void) { - static fixed_t convSpeed; + static fixed_t convSpeed[2] = {0}; UINT8 labeln = 0; UINT8 numbers[3]; INT32 splitflags = V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN; INT32 battleoffset = 0; INT32 ringoffset = 0; INT32 oldringoffset = 0; +#ifdef ROTSPRITE + fixed_t dial_divisor = DIALSPDDIV; +#endif switch (cv_kartspeedometer.value) { case 1: // Kilometers - convSpeed = FixedDiv(FixedMul(stplyr->speed, 142371), mapobjectscale) / FRACUNIT; // 2.172409058 + convSpeed[0] = FixedDiv(FixedMul(stplyr->speed, 142371), mapobjectscale); // 2.172409058 + convSpeed[1] = convSpeed[0] / FRACUNIT; labeln = 0; break; case 2: // Miles - convSpeed = FixedDiv(FixedMul(stplyr->speed, 88465), mapobjectscale) / FRACUNIT; // 1.349868774 + convSpeed[0] = FixedDiv(FixedMul(stplyr->speed, 88465), mapobjectscale); // 1.349868774 + convSpeed[1] = convSpeed[0] / FRACUNIT; labeln = 1; break; case 3: // Fracunits - convSpeed = FixedDiv(stplyr->speed, mapobjectscale) / FRACUNIT; // 1.0. duh. + convSpeed[0] = FixedDiv(stplyr->speed, mapobjectscale); // 1.0. duh. + convSpeed[1] = convSpeed[0] / FRACUNIT; labeln = 2; break; case 4: // Sonic Drift 2 style percentage if (stplyr->mo) - convSpeed = (FixedDiv(stplyr->speed, FixedMul(K_GetKartSpeed(stplyr, false, false), K_PlayerBaseFriction(stplyr, ORIG_FRICTION)))*100)>>FRACBITS; + { + convSpeed[0] = (FixedDiv(stplyr->speed, FixedMul(K_GetKartSpeed(stplyr, false, false), K_PlayerBaseFriction(stplyr, ORIG_FRICTION)))*100); + convSpeed[1] = convSpeed[0] >> FRACBITS; + } labeln = 3; break; default: @@ -3196,8 +3394,11 @@ static void K_drawKartSpeedometer(void) // Don't overflow // (negative speed IS really high speed :V) - if (convSpeed > 999 || convSpeed < 0) - convSpeed = 999; + if (convSpeed[1] > 999 || convSpeed[1] < 0) + { + convSpeed[1] = 999; + convSpeed[0] = convSpeed[1] * FRACUNIT; + } if (cv_speed_xoffset.value == 0 && cv_speed_yoffset.value == 0) { @@ -3215,16 +3416,16 @@ static void K_drawKartSpeedometer(void) { switch (cv_kartspeedometer.value) { case 1: - V_DrawKartString(SPDM_X + oldringoffset, SPDM_Y-18 + battleoffset + ringoffset, V_HUDTRANS|splitflags, va("%3d km/h", convSpeed)); + V_DrawKartString(SPDM_X + oldringoffset, SPDM_Y-18 + battleoffset + ringoffset, V_HUDTRANS|splitflags, va("%3d km/h", convSpeed[1])); break; case 2: - V_DrawKartString(SPDM_X + oldringoffset, SPDM_Y-18 + battleoffset + ringoffset, V_HUDTRANS|splitflags, va("%3d mph", convSpeed)); + V_DrawKartString(SPDM_X + oldringoffset, SPDM_Y-18 + battleoffset + ringoffset, V_HUDTRANS|splitflags, va("%3d mph", convSpeed[1])); break; case 3: - V_DrawKartString(SPDM_X + oldringoffset, SPDM_Y-18 + battleoffset + ringoffset, V_HUDTRANS|splitflags, va("%3d fu/t", convSpeed)); + V_DrawKartString(SPDM_X + oldringoffset, SPDM_Y-18 + battleoffset + ringoffset, V_HUDTRANS|splitflags, va("%3d fu/t", convSpeed[1])); break; case 4: - V_DrawKartString(SPDM_X + oldringoffset, SPDM_Y-18 + battleoffset + ringoffset, V_HUDTRANS|splitflags, va("%4d %%", convSpeed)); + V_DrawKartString(SPDM_X + oldringoffset, SPDM_Y-18 + battleoffset + ringoffset, V_HUDTRANS|splitflags, va("%4d %%", convSpeed[1])); break; default: break; @@ -3232,9 +3433,9 @@ static void K_drawKartSpeedometer(void) } else if (cv_newspeedometer.value == 1) { - numbers[0] = ((convSpeed / 100) % 10); - numbers[1] = ((convSpeed / 10) % 10); - numbers[2] = (convSpeed % 10); + numbers[0] = ((convSpeed[1] / 100) % 10); + numbers[1] = ((convSpeed[1] / 10) % 10); + numbers[2] = (convSpeed[1] % 10); if (!K_UseColorHud()) { @@ -3278,10 +3479,27 @@ static void K_drawKartSpeedometer(void) V_DrawScaledPatch(SPDM_X, SPDM_Y-yoffset + battleoffset + ringoffset, V_HUDTRANS|splitflags, (!K_RingsActive() ? kp_kartzspeedo : kp_kartzspeedo_smol)[spdpatch]); } +#ifdef ROTSPRITE + else if (cv_newspeedometer.value == 3) + { + K_DrawDialSpeedometer(convSpeed[0], + dial_divisor, + labeln, + splitflags, + (boolean)((gametypes[gametype]->rules & GTR_BUMPERS) == GTR_BUMPERS), + (LUA_HudEnabled(hud_gametypeinfo)), + (K_UseColorHud())); + } +#endif K_drawKartAccessibilityIcons((cv_newspeedometer.value == 0 || cv_newspeedometer.value == 2) ? 50 : 56); } +#ifdef ROTSPRITE +#undef DIALSPDDIV +#undef MPHDIV +#endif + static void K_drawRingMeter(void) { UINT8 rn[2]; @@ -6265,10 +6483,33 @@ static void K_SlipstreamIndicator(boolean tiny) V_DrawThinString(fx - V_StringWidth(str, flags)/2, fy, flags, str); } +// determines if gametype info (laps/bumpers) should be hidden +static boolean K_DisableGametypeInfo(void) +{ + if (!LUA_HudEnabled(hud_gametypeinfo)) + { + return true; + } + +#ifdef ROTSPRITE + if (r_splitscreen || (!cv_kartspeedometer.value)) + { + // don't need to run checks if we're in splitscreen, or not using the speedometer + return false; + } + + if (cv_newspeedometer.value == 3) + return true; +#endif + + return false; +} + void K_drawKartHUD(void) { boolean islonesome = false; boolean battlefullscreen = false; + boolean gameinfovisible = false; UINT8 viewnum = R_GetViewNumber(); boolean freecam = camera[viewnum].freecam; //disable some hud elements w/ freecam UINT8 i; @@ -6376,6 +6617,9 @@ void K_drawKartHUD(void) if (!stplyr->spectator && !freecam) // Bottom of the screen elements, don't need in spectate mode { + // get gametype info visibility ahead of time + gameinfovisible = (!K_DisableGametypeInfo()); + if (demo.title) // Draw title logo instead in demo.titles { INT32 x = (BASEVIDWIDTH - 32), y = 128, snapflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT; @@ -6412,12 +6656,15 @@ void K_drawKartHUD(void) { if (gametypes[gametype]->rules & GTR_CIRCUIT) { - K_drawKartLaps(); + if (gameinfovisible) + K_drawKartLaps(); + K_drawKartStatsnLives(); } else if (gametypes[gametype]->rules & GTR_BUMPERS) { - K_drawKartBumpersOrKarma(); + if (gameinfovisible) + K_drawKartBumpersOrKarma(); } }