2019-08-25 06:46:40 +02:00
|
|
|
#include <ultra64.h>
|
|
|
|
|
|
|
|
#include "sm64.h"
|
|
|
|
#include "display.h"
|
|
|
|
#include "game.h"
|
|
|
|
#include "level_update.h"
|
|
|
|
#include "camera.h"
|
|
|
|
#include "print.h"
|
|
|
|
#include "ingame_menu.h"
|
|
|
|
#include "hud.h"
|
|
|
|
#include "segment2.h"
|
|
|
|
#include "area.h"
|
2019-09-01 21:50:50 +02:00
|
|
|
#include "save_file.h"
|
2019-10-05 21:08:05 +02:00
|
|
|
#include "print.h"
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/* @file hud.c
|
|
|
|
* This file implements HUD rendering and power meter animations.
|
|
|
|
* That includes stars, lives, coins, camera status, power meter, timer
|
|
|
|
* cannon reticle, and the unused keys.
|
2019-08-25 06:46:40 +02:00
|
|
|
**/
|
|
|
|
|
|
|
|
struct PowerMeterHUD {
|
|
|
|
s8 animation;
|
|
|
|
s16 x;
|
|
|
|
s16 y;
|
2019-10-05 21:08:05 +02:00
|
|
|
f32 unused;
|
2019-08-25 06:46:40 +02:00
|
|
|
};
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
struct UnusedStruct803314F0 {
|
|
|
|
u32 unused1;
|
|
|
|
u16 unused2;
|
|
|
|
u16 unused3;
|
2019-08-25 06:46:40 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct CameraHUD {
|
2019-10-05 21:08:05 +02:00
|
|
|
s16 status;
|
2019-08-25 06:46:40 +02:00
|
|
|
};
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
// Stores health segmented value defined by numHealthWedges
|
|
|
|
// When the HUD is rendered this value is 8, full health.
|
|
|
|
static s16 sPowerMeterStoredHealth;
|
2019-08-25 06:46:40 +02:00
|
|
|
|
|
|
|
static struct PowerMeterHUD sPowerMeterHUD = {
|
2019-09-01 21:50:50 +02:00
|
|
|
POWER_METER_HIDDEN,
|
|
|
|
140,
|
|
|
|
166,
|
|
|
|
1.0,
|
2019-08-25 06:46:40 +02:00
|
|
|
};
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
// Power Meter timer that keeps counting when it's visible.
|
|
|
|
// Gets reset when the health is filled and stops counting
|
|
|
|
// when the power meter is hidden.
|
|
|
|
s32 sPowerMeterVisibleTimer = 0;
|
2019-09-01 21:50:50 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
static struct UnusedStruct803314F0 unused803314F0 = { 0x00000000, 0x000A, 0x0000 };
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
static struct CameraHUD sCameraHUD = { CAM_STATUS_NONE };
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Renders a rgba16 16x16 glyph texture from a table list.
|
|
|
|
*/
|
|
|
|
void render_hud_tex_lut(s32 x, s32 y, u8 *texture) {
|
2019-08-25 06:46:40 +02:00
|
|
|
gDPPipeSync(gDisplayListHead++);
|
2019-10-05 21:08:05 +02:00
|
|
|
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, texture);
|
2019-08-25 06:46:40 +02:00
|
|
|
gSPDisplayList(gDisplayListHead++, &dl_hud_img_load_tex_block);
|
|
|
|
gSPTextureRectangle(gDisplayListHead++, x << 2, y << 2, (x + 15) << 2, (y + 15) << 2,
|
2019-10-05 21:08:05 +02:00
|
|
|
G_TX_RENDERTILE, 0, 0, 4 << 10, 1 << 10);
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Renders a rgba16 8x8 glyph texture from a table list.
|
|
|
|
*/
|
|
|
|
void render_hud_small_tex_lut(s32 x, s32 y, u8 *texture) {
|
2019-08-25 06:46:40 +02:00
|
|
|
gDPSetTile(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0,
|
|
|
|
(G_TX_NOMIRROR | G_TX_WRAP), G_TX_NOMASK, G_TX_NOLOD, (G_TX_NOMIRROR | G_TX_WRAP),
|
|
|
|
G_TX_NOMASK, G_TX_NOLOD);
|
|
|
|
gDPTileSync(gDisplayListHead++);
|
|
|
|
gDPSetTile(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 2, 0, G_TX_RENDERTILE, 0,
|
|
|
|
(G_TX_NOMIRROR | G_TX_CLAMP), 3, G_TX_NOLOD, (G_TX_NOMIRROR | G_TX_CLAMP), 3,
|
|
|
|
G_TX_NOLOD);
|
|
|
|
gDPSetTileSize(gDisplayListHead++, G_TX_RENDERTILE, 0, 0, 28, 28);
|
|
|
|
gDPPipeSync(gDisplayListHead++);
|
2019-10-05 21:08:05 +02:00
|
|
|
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, texture);
|
2019-08-25 06:46:40 +02:00
|
|
|
gDPLoadSync(gDisplayListHead++);
|
|
|
|
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 63, 1024);
|
|
|
|
gSPTextureRectangle(gDisplayListHead++, x << 2, y << 2, (x + 7) << 2, (y + 7) << 2, G_TX_RENDERTILE,
|
2019-10-05 21:08:05 +02:00
|
|
|
0, 0, 4 << 10, 1 << 10);
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Renders power meter health segment texture using a table list.
|
|
|
|
*/
|
|
|
|
void render_power_meter_health_segment(s16 numHealthWedges) {
|
|
|
|
u8 *(*healthLUT)[];
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
healthLUT = segmented_to_virtual(&power_meter_health_segments_lut);
|
2019-08-25 06:46:40 +02:00
|
|
|
|
|
|
|
gDPPipeSync(gDisplayListHead++);
|
|
|
|
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1,
|
2019-10-05 21:08:05 +02:00
|
|
|
(*healthLUT)[numHealthWedges - 1]);
|
2019-08-25 06:46:40 +02:00
|
|
|
gDPLoadSync(gDisplayListHead++);
|
|
|
|
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 1023, 256);
|
|
|
|
gSP1Triangle(gDisplayListHead++, 0, 1, 2, 0);
|
|
|
|
gSP1Triangle(gDisplayListHead++, 0, 2, 3, 0);
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Renders power meter display lists.
|
|
|
|
* That includes the "POWER" base and the colored health segment textures.
|
|
|
|
*/
|
|
|
|
void render_dl_power_meter(s16 numHealthWedges) {
|
|
|
|
Mtx *mtx;
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
mtx = alloc_display_list(sizeof(Mtx));
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
if (mtx == NULL) {
|
2019-08-25 06:46:40 +02:00
|
|
|
return;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
guTranslate(mtx, (f32) sPowerMeterHUD.x, (f32) sPowerMeterHUD.y, 0);
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx++),
|
2019-08-25 06:46:40 +02:00
|
|
|
(G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH));
|
2019-10-05 21:08:05 +02:00
|
|
|
gSPDisplayList(gDisplayListHead++, &dl_power_meter_base);
|
2019-08-25 06:46:40 +02:00
|
|
|
|
|
|
|
if (numHealthWedges != 0) {
|
2019-10-05 21:08:05 +02:00
|
|
|
gSPDisplayList(gDisplayListHead++, &dl_power_meter_health_segments_begin);
|
|
|
|
render_power_meter_health_segment(numHealthWedges);
|
|
|
|
gSPDisplayList(gDisplayListHead++, &dl_power_meter_health_segments_end);
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
gSPPopMatrix(gDisplayListHead++, 0);
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Power meter animation called when there's less than 8 health segments
|
|
|
|
* Checks its timer to later change into deemphasizing mode.
|
|
|
|
*/
|
2019-09-01 21:50:50 +02:00
|
|
|
void animate_power_meter_emphasized(void) {
|
2019-08-25 06:46:40 +02:00
|
|
|
s16 hudDisplayFlags;
|
|
|
|
hudDisplayFlags = gHudDisplay.flags;
|
|
|
|
|
|
|
|
if (!(hudDisplayFlags & HUD_DISPLAY_FLAG_EMPHASIZE_POWER)) {
|
2019-10-05 21:08:05 +02:00
|
|
|
if (sPowerMeterVisibleTimer == 45.0) {
|
2019-08-25 06:46:40 +02:00
|
|
|
sPowerMeterHUD.animation = POWER_METER_DEEMPHASIZING;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
} else {
|
2019-10-05 21:08:05 +02:00
|
|
|
sPowerMeterVisibleTimer = 0;
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Power meter animation called after emphasized mode.
|
|
|
|
* Moves power meter y pos speed until it's at 200 to be visible.
|
|
|
|
*/
|
2019-08-25 06:46:40 +02:00
|
|
|
static void animate_power_meter_deemphasizing(void) {
|
|
|
|
s16 speed = 5;
|
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (sPowerMeterHUD.y >= 181) {
|
2019-08-25 06:46:40 +02:00
|
|
|
speed = 3;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (sPowerMeterHUD.y >= 191) {
|
2019-08-25 06:46:40 +02:00
|
|
|
speed = 2;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (sPowerMeterHUD.y >= 196) {
|
2019-08-25 06:46:40 +02:00
|
|
|
speed = 1;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
|
|
|
sPowerMeterHUD.y += speed;
|
|
|
|
|
|
|
|
if (sPowerMeterHUD.y >= 201) {
|
|
|
|
sPowerMeterHUD.y = 200;
|
|
|
|
sPowerMeterHUD.animation = POWER_METER_VISIBLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Power meter animation called when there's 8 health segments.
|
|
|
|
* Moves power meter y pos quickly until it's at 301 to be hidden.
|
|
|
|
*/
|
2019-08-25 06:46:40 +02:00
|
|
|
static void animate_power_meter_hiding(void) {
|
|
|
|
sPowerMeterHUD.y += 20;
|
|
|
|
if (sPowerMeterHUD.y >= 301) {
|
|
|
|
sPowerMeterHUD.animation = POWER_METER_HIDDEN;
|
2019-10-05 21:08:05 +02:00
|
|
|
sPowerMeterVisibleTimer = 0;
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Handles power meter actions depending of the health segments values.
|
|
|
|
*/
|
|
|
|
void handle_power_meter_actions(s16 numHealthWedges) {
|
|
|
|
// Show power meter if health is not full, less than 8
|
|
|
|
if (numHealthWedges < 8 && sPowerMeterStoredHealth == 8 && sPowerMeterHUD.animation == POWER_METER_HIDDEN) {
|
2019-08-25 06:46:40 +02:00
|
|
|
sPowerMeterHUD.animation = POWER_METER_EMPHASIZED;
|
|
|
|
sPowerMeterHUD.y = 166;
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
// Show power meter if health is full, has 8
|
|
|
|
if (numHealthWedges == 8 && sPowerMeterStoredHealth == 7) {
|
|
|
|
sPowerMeterVisibleTimer = 0;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-10-05 21:08:05 +02:00
|
|
|
|
|
|
|
// After health is full, hide power meter
|
|
|
|
if (numHealthWedges == 8 && sPowerMeterVisibleTimer > 45.0) {
|
2019-08-25 06:46:40 +02:00
|
|
|
sPowerMeterHUD.animation = POWER_METER_HIDING;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
// Update to match health value
|
|
|
|
sPowerMeterStoredHealth = numHealthWedges;
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
// If mario is swimming, keep showing power meter
|
|
|
|
if (gPlayerStatusForCamera->action & ACT_FLAG_SWIMMING) {
|
2019-08-25 06:46:40 +02:00
|
|
|
if (sPowerMeterHUD.animation == POWER_METER_HIDDEN
|
|
|
|
|| sPowerMeterHUD.animation == POWER_METER_EMPHASIZED) {
|
|
|
|
sPowerMeterHUD.animation = POWER_METER_DEEMPHASIZING;
|
|
|
|
sPowerMeterHUD.y = 166;
|
|
|
|
}
|
2019-10-05 21:08:05 +02:00
|
|
|
sPowerMeterVisibleTimer = 0;
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Renders the power meter that shows when Mario is in underwater
|
|
|
|
* or has taken damage and has less than 8 health segments.
|
|
|
|
* And calls a power meter animation function depending of the value defined.
|
|
|
|
*/
|
|
|
|
void render_hud_power_meter(void) {
|
2019-08-25 06:46:40 +02:00
|
|
|
s16 shownHealthWedges = gHudDisplay.wedges;
|
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (sPowerMeterHUD.animation != POWER_METER_HIDING) {
|
2019-10-05 21:08:05 +02:00
|
|
|
handle_power_meter_actions(shownHealthWedges);
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (sPowerMeterHUD.animation == POWER_METER_HIDDEN) {
|
2019-08-25 06:46:40 +02:00
|
|
|
return;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
|
|
|
switch (sPowerMeterHUD.animation) {
|
|
|
|
case POWER_METER_EMPHASIZED:
|
|
|
|
animate_power_meter_emphasized();
|
|
|
|
break;
|
|
|
|
case POWER_METER_DEEMPHASIZING:
|
|
|
|
animate_power_meter_deemphasizing();
|
|
|
|
break;
|
|
|
|
case POWER_METER_HIDING:
|
|
|
|
animate_power_meter_hiding();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
render_dl_power_meter(shownHealthWedges);
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
sPowerMeterVisibleTimer += 1;
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERSION_JP
|
|
|
|
#define HUD_TOP_Y 210
|
|
|
|
#else
|
|
|
|
#define HUD_TOP_Y 209
|
|
|
|
#endif
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Renders the amount of lives Mario has.
|
|
|
|
*/
|
2019-08-25 06:46:40 +02:00
|
|
|
void render_hud_mario_lives(void) {
|
|
|
|
print_text(22, HUD_TOP_Y, ","); // 'Mario Head' glyph
|
|
|
|
print_text(38, HUD_TOP_Y, "*"); // 'X' glyph
|
|
|
|
print_text_fmt_int(54, HUD_TOP_Y, "%d", gHudDisplay.lives);
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Renders the amount of coins collected.
|
|
|
|
*/
|
2019-08-25 06:46:40 +02:00
|
|
|
void render_hud_coins(void) {
|
|
|
|
print_text(168, HUD_TOP_Y, "+"); // 'Coin' glyph
|
|
|
|
print_text(184, HUD_TOP_Y, "*"); // 'X' glyph
|
|
|
|
print_text_fmt_int(198, HUD_TOP_Y, "%d", gHudDisplay.coins);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERSION_JP
|
|
|
|
#define HUD_STARS_X 247
|
|
|
|
#else
|
|
|
|
#define HUD_STARS_X 242
|
|
|
|
#endif
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Renders the amount of stars collected.
|
|
|
|
* Disables "X" glyph when Mario has 100 stars or more.
|
|
|
|
*/
|
2019-08-25 06:46:40 +02:00
|
|
|
void render_hud_stars(void) {
|
|
|
|
s8 showX = 0;
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
if (gHudFlash == 1 && gGlobalTimer & 0x08) {
|
2019-08-25 06:46:40 +02:00
|
|
|
return;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (gHudDisplay.stars < 100) {
|
2019-08-25 06:46:40 +02:00
|
|
|
showX = 1;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
|
|
|
print_text(HUD_STARS_X, HUD_TOP_Y, "-"); // 'Star' glyph
|
2019-09-01 21:50:50 +02:00
|
|
|
if (showX == 1) {
|
2019-08-25 06:46:40 +02:00
|
|
|
print_text((HUD_STARS_X + 16), HUD_TOP_Y, "*"); // 'X' glyph
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
print_text_fmt_int(((showX * 14) + (HUD_STARS_X + 16)), HUD_TOP_Y, "%d", gHudDisplay.stars);
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Unused function that renders the amount of keys collected.
|
|
|
|
* Leftover function from the beta version of the game.
|
|
|
|
*/
|
|
|
|
void render_hud_keys(void) {
|
2019-08-25 06:46:40 +02:00
|
|
|
s16 i;
|
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
for (i = 0; i < gHudDisplay.keys; i++) {
|
2019-10-05 21:08:05 +02:00
|
|
|
print_text((i * 16) + 220, 142, "/"); // unused glyph - beta key
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Renders the timer when Mario start sliding in PSS.
|
|
|
|
*/
|
2019-08-25 06:46:40 +02:00
|
|
|
void render_hud_timer(void) {
|
2019-10-05 21:08:05 +02:00
|
|
|
u8 *(*hudLUT)[58];
|
2019-08-25 06:46:40 +02:00
|
|
|
u16 timerValFrames;
|
|
|
|
u16 timerMins;
|
|
|
|
u16 timerSecs;
|
|
|
|
u16 timerFracSecs;
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
hudLUT = segmented_to_virtual(&main_hud_lut);
|
2019-08-25 06:46:40 +02:00
|
|
|
timerValFrames = gHudDisplay.timer;
|
2019-09-01 21:50:50 +02:00
|
|
|
#ifdef VERSION_EU
|
|
|
|
switch (eu_get_language()) {
|
|
|
|
case LANGUAGE_ENGLISH:
|
|
|
|
print_text(170, 185, "TIME");
|
|
|
|
break;
|
|
|
|
case LANGUAGE_FRENCH:
|
|
|
|
print_text(165, 185, "TEMPS");
|
|
|
|
break;
|
|
|
|
case LANGUAGE_GERMAN:
|
|
|
|
print_text(170, 185, "ZEIT");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2019-08-25 06:46:40 +02:00
|
|
|
timerMins = timerValFrames / (30 * 60);
|
|
|
|
timerSecs = (timerValFrames - (timerMins * 1800)) / 30;
|
|
|
|
|
|
|
|
timerFracSecs = ((timerValFrames - (timerMins * 1800) - (timerSecs * 30)) & 0xFFFF) / 3;
|
2019-09-01 21:50:50 +02:00
|
|
|
#ifndef VERSION_EU
|
2019-08-25 06:46:40 +02:00
|
|
|
print_text(170, 185, "TIME");
|
2019-09-01 21:50:50 +02:00
|
|
|
#endif
|
2019-08-25 06:46:40 +02:00
|
|
|
print_text_fmt_int(229, 185, "%0d", timerMins);
|
|
|
|
print_text_fmt_int(249, 185, "%02d", timerSecs);
|
|
|
|
print_text_fmt_int(283, 185, "%d", timerFracSecs);
|
|
|
|
gSPDisplayList(gDisplayListHead++, dl_hud_img_begin);
|
2019-10-05 21:08:05 +02:00
|
|
|
render_hud_tex_lut(239, 32, (*hudLUT)[GLYPH_APOSTROPHE]);
|
|
|
|
render_hud_tex_lut(274, 32, (*hudLUT)[GLYPH_DOUBLE_QUOTE]);
|
2019-08-25 06:46:40 +02:00
|
|
|
gSPDisplayList(gDisplayListHead++, dl_hud_img_end);
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Sets HUD status camera value depending of the actions
|
|
|
|
* defined in update_camera_status.
|
|
|
|
*/
|
|
|
|
void set_hud_camera_status(s16 status) {
|
|
|
|
sCameraHUD.status = status;
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Renders camera HUD glyphs using a table list, depending of
|
|
|
|
* the camera status called, a defined glyph is rendered.
|
|
|
|
*/
|
|
|
|
void render_hud_camera_status(void) {
|
2019-08-25 06:46:40 +02:00
|
|
|
u8 *(*cameraLUT)[6];
|
|
|
|
s32 x;
|
|
|
|
s32 y;
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
cameraLUT = segmented_to_virtual(&main_hud_camera_lut);
|
2019-08-25 06:46:40 +02:00
|
|
|
x = 266;
|
|
|
|
y = 205;
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
if (sCameraHUD.status == CAM_STATUS_NONE) {
|
2019-08-25 06:46:40 +02:00
|
|
|
return;
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
|
|
|
gSPDisplayList(gDisplayListHead++, dl_hud_img_begin);
|
2019-10-05 21:08:05 +02:00
|
|
|
render_hud_tex_lut(x, y, (*cameraLUT)[GLYPH_CAM_CAMERA]);
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
switch (sCameraHUD.status & CAM_STATUS_MODE_GROUP) {
|
|
|
|
case CAM_STATUS_MARIO:
|
|
|
|
render_hud_tex_lut(x + 16, y, (*cameraLUT)[GLYPH_CAM_MARIO_HEAD]);
|
2019-08-25 06:46:40 +02:00
|
|
|
break;
|
2019-10-05 21:08:05 +02:00
|
|
|
case CAM_STATUS_LAKITU:
|
|
|
|
render_hud_tex_lut(x + 16, y, (*cameraLUT)[GLYPH_CAM_LAKITU_HEAD]);
|
2019-08-25 06:46:40 +02:00
|
|
|
break;
|
2019-10-05 21:08:05 +02:00
|
|
|
case CAM_STATUS_FIXED:
|
|
|
|
render_hud_tex_lut(x + 16, y, (*cameraLUT)[GLYPH_CAM_FIXED]);
|
2019-08-25 06:46:40 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
switch (sCameraHUD.status & CAM_STATUS_C_MODE_GROUP) {
|
|
|
|
case CAM_STATUS_C_DOWN:
|
|
|
|
render_hud_small_tex_lut(x + 4, y + 16, (*cameraLUT)[GLYPH_CAM_ARROW_DOWN]);
|
2019-08-25 06:46:40 +02:00
|
|
|
break;
|
2019-10-05 21:08:05 +02:00
|
|
|
case CAM_STATUS_C_UP:
|
|
|
|
render_hud_small_tex_lut(x + 4, y - 8, (*cameraLUT)[GLYPH_CAM_ARROW_UP]);
|
2019-08-25 06:46:40 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gSPDisplayList(gDisplayListHead++, dl_hud_img_end);
|
|
|
|
}
|
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
/**
|
|
|
|
* Render HUD strings using hudDisplayFlags with it's render functions,
|
|
|
|
* excluding the cannon reticle which detects a camera preset for it.
|
|
|
|
*/
|
2019-08-25 06:46:40 +02:00
|
|
|
void render_hud(void) {
|
|
|
|
s16 hudDisplayFlags;
|
2019-09-01 21:50:50 +02:00
|
|
|
#ifdef VERSION_EU
|
|
|
|
Mtx *mtx;
|
|
|
|
#endif
|
2019-08-25 06:46:40 +02:00
|
|
|
|
|
|
|
hudDisplayFlags = gHudDisplay.flags;
|
|
|
|
|
|
|
|
if (hudDisplayFlags == HUD_DISPLAY_NONE) {
|
|
|
|
sPowerMeterHUD.animation = POWER_METER_HIDDEN;
|
2019-10-05 21:08:05 +02:00
|
|
|
sPowerMeterStoredHealth = 8;
|
|
|
|
sPowerMeterVisibleTimer = 0;
|
2019-08-25 06:46:40 +02:00
|
|
|
} else {
|
2019-09-01 21:50:50 +02:00
|
|
|
#ifdef VERSION_EU
|
2019-10-05 21:08:05 +02:00
|
|
|
// basically create_dl_ortho_matrix but guOrtho screen width is different
|
2019-09-01 21:50:50 +02:00
|
|
|
mtx = alloc_display_list(sizeof(*mtx));
|
|
|
|
if (mtx == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2019-10-05 21:08:05 +02:00
|
|
|
create_dl_identity_matrix();
|
2019-09-01 21:50:50 +02:00
|
|
|
guOrtho(mtx, -16.0f, 336.0f, 0, 240.0f, -10.0f, 10.0f, 1.0f);
|
|
|
|
gMoveWd(gDisplayListHead++, 0xE, 0, 0xFFFF);
|
|
|
|
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), 1);
|
|
|
|
|
|
|
|
#else
|
2019-10-05 21:08:05 +02:00
|
|
|
create_dl_ortho_matrix();
|
2019-09-01 21:50:50 +02:00
|
|
|
#endif
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (gCurrentArea != NULL && gCurrentArea->camera->currPreset == CAMERA_PRESET_INSIDE_CANNON) {
|
2019-10-05 21:08:05 +02:00
|
|
|
render_hud_cannon_reticle();
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_LIVES) {
|
2019-08-25 06:46:40 +02:00
|
|
|
render_hud_mario_lives();
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_COIN_COUNT) {
|
2019-08-25 06:46:40 +02:00
|
|
|
render_hud_coins();
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_STAR_COUNT) {
|
2019-08-25 06:46:40 +02:00
|
|
|
render_hud_stars();
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
2019-10-05 21:08:05 +02:00
|
|
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_KEYS) {
|
|
|
|
render_hud_keys();
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
|
|
|
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_CAMERA_AND_POWER) {
|
2019-10-05 21:08:05 +02:00
|
|
|
render_hud_power_meter();
|
|
|
|
render_hud_camera_status();
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
|
2019-09-01 21:50:50 +02:00
|
|
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER) {
|
2019-08-25 06:46:40 +02:00
|
|
|
render_hud_timer();
|
2019-09-01 21:50:50 +02:00
|
|
|
}
|
2019-08-25 06:46:40 +02:00
|
|
|
}
|
|
|
|
}
|