mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-10-19 19:52:39 +00:00
358 lines
9.9 KiB
C
358 lines
9.9 KiB
C
|
#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"
|
||
|
|
||
|
/* Originally hud_print.c
|
||
|
* This file seems to draw the in-game HUD
|
||
|
**/
|
||
|
|
||
|
enum PowerMeterAnimation {
|
||
|
POWER_METER_HIDDEN,
|
||
|
POWER_METER_EMPHASIZED,
|
||
|
POWER_METER_DEEMPHASIZING,
|
||
|
POWER_METER_HIDING,
|
||
|
POWER_METER_VISIBLE
|
||
|
};
|
||
|
|
||
|
struct PowerMeterHUD {
|
||
|
s8 animation;
|
||
|
s16 x;
|
||
|
s16 y;
|
||
|
f32 u_E8;
|
||
|
s32 d_EC;
|
||
|
};
|
||
|
|
||
|
struct UnknownStruct803314F0 {
|
||
|
u32 u_F0;
|
||
|
u16 u_F4;
|
||
|
u16 u_F6;
|
||
|
};
|
||
|
|
||
|
struct CameraHUD {
|
||
|
s16 d_F8;
|
||
|
};
|
||
|
|
||
|
// some sort of store for shown health wedges (0-8); maybe from previous frame/update?
|
||
|
static s16 D_803600D0;
|
||
|
|
||
|
static struct PowerMeterHUD sPowerMeterHUD = {
|
||
|
POWER_METER_HIDDEN, 140, 166, 1.0, 0x00000000,
|
||
|
};
|
||
|
|
||
|
static struct UnknownStruct803314F0 D_803314F0 = { 0x00000000, 0x000A, 0x0000 };
|
||
|
|
||
|
static struct CameraHUD sCameraHUD = { 0x0000 };
|
||
|
|
||
|
void render_hud_camera(s32 x, s32 y, u8 texture[]) {
|
||
|
gDPPipeSync(gDisplayListHead++);
|
||
|
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, (u32) texture);
|
||
|
gSPDisplayList(gDisplayListHead++, &dl_hud_img_load_tex_block);
|
||
|
gSPTextureRectangle(gDisplayListHead++, x << 2, y << 2, (x + 15) << 2, (y + 15) << 2,
|
||
|
G_TX_RENDERTILE, 0, 0, 0x1000, 0x400);
|
||
|
}
|
||
|
|
||
|
void render_hud_c_buttons(s32 x, s32 y, u8 texture[]) {
|
||
|
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++);
|
||
|
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, (u32) texture);
|
||
|
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,
|
||
|
0, 0, 0x1000, 0x400);
|
||
|
}
|
||
|
|
||
|
void func_802E21A4(s16 numHealthWedges) {
|
||
|
u8 *(*sp34)[];
|
||
|
|
||
|
sp34 = segmented_to_virtual(&power_meter_seg3_health_icons_030293E0);
|
||
|
|
||
|
gDPPipeSync(gDisplayListHead++);
|
||
|
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1,
|
||
|
(*sp34)[numHealthWedges - 1]);
|
||
|
gDPLoadSync(gDisplayListHead++);
|
||
|
gDPLoadBlock(gDisplayListHead++, G_TX_LOADTILE, 0, 0, 1023, 256);
|
||
|
gSP1Triangle(gDisplayListHead++, 0, 1, 2, 0);
|
||
|
gSP1Triangle(gDisplayListHead++, 0, 2, 3, 0);
|
||
|
}
|
||
|
|
||
|
void func_802E2304(s16 numHealthWedges) {
|
||
|
Mtx *sp2C;
|
||
|
|
||
|
sp2C = alloc_display_list(0x40);
|
||
|
|
||
|
if (sp2C == NULL)
|
||
|
return;
|
||
|
|
||
|
guTranslate(sp2C, (f32) sPowerMeterHUD.x, (f32) sPowerMeterHUD.y, 0);
|
||
|
|
||
|
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(sp2C++),
|
||
|
(G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH));
|
||
|
gSPDisplayList(gDisplayListHead++, &power_meter_seg3_dl_03029480);
|
||
|
|
||
|
if (numHealthWedges != 0) {
|
||
|
gSPDisplayList(gDisplayListHead++, &power_meter_seg3_dl_03029570);
|
||
|
func_802E21A4(numHealthWedges);
|
||
|
gSPDisplayList(gDisplayListHead++, &power_meter_seg3_dl_030295A0);
|
||
|
}
|
||
|
|
||
|
gSPPopMatrix(gDisplayListHead++, 0);
|
||
|
}
|
||
|
|
||
|
static void animate_power_meter_emphasized(void) {
|
||
|
s16 hudDisplayFlags;
|
||
|
hudDisplayFlags = gHudDisplay.flags;
|
||
|
|
||
|
if (!(hudDisplayFlags & HUD_DISPLAY_FLAG_EMPHASIZE_POWER)) {
|
||
|
if (sPowerMeterHUD.d_EC == 45.0)
|
||
|
sPowerMeterHUD.animation = POWER_METER_DEEMPHASIZING;
|
||
|
} else {
|
||
|
sPowerMeterHUD.d_EC = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void animate_power_meter_deemphasizing(void) {
|
||
|
s16 speed = 5;
|
||
|
|
||
|
if (sPowerMeterHUD.y >= 181)
|
||
|
speed = 3;
|
||
|
|
||
|
if (sPowerMeterHUD.y >= 191)
|
||
|
speed = 2;
|
||
|
|
||
|
if (sPowerMeterHUD.y >= 196)
|
||
|
speed = 1;
|
||
|
|
||
|
sPowerMeterHUD.y += speed;
|
||
|
|
||
|
if (sPowerMeterHUD.y >= 201) {
|
||
|
sPowerMeterHUD.y = 200;
|
||
|
sPowerMeterHUD.animation = POWER_METER_VISIBLE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void animate_power_meter_hiding(void) {
|
||
|
sPowerMeterHUD.y += 20;
|
||
|
if (sPowerMeterHUD.y >= 301) {
|
||
|
sPowerMeterHUD.animation = POWER_METER_HIDDEN;
|
||
|
sPowerMeterHUD.d_EC = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void func_802E261C(s16 numHealthWedges) {
|
||
|
if (numHealthWedges < 8 && D_803600D0 == 8 && sPowerMeterHUD.animation == POWER_METER_HIDDEN) {
|
||
|
sPowerMeterHUD.animation = POWER_METER_EMPHASIZED;
|
||
|
sPowerMeterHUD.y = 166;
|
||
|
}
|
||
|
|
||
|
if (numHealthWedges == 8 && D_803600D0 == 7)
|
||
|
sPowerMeterHUD.d_EC = 0;
|
||
|
|
||
|
if (numHealthWedges == 8 && sPowerMeterHUD.d_EC > 45.0)
|
||
|
sPowerMeterHUD.animation = POWER_METER_HIDING;
|
||
|
|
||
|
D_803600D0 = numHealthWedges;
|
||
|
|
||
|
if (gPlayerStatusForCamera->action & 0x2000) {
|
||
|
if (sPowerMeterHUD.animation == POWER_METER_HIDDEN
|
||
|
|| sPowerMeterHUD.animation == POWER_METER_EMPHASIZED) {
|
||
|
sPowerMeterHUD.animation = POWER_METER_DEEMPHASIZING;
|
||
|
sPowerMeterHUD.y = 166;
|
||
|
}
|
||
|
sPowerMeterHUD.d_EC = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void render_hud_hp(void) {
|
||
|
s16 shownHealthWedges = gHudDisplay.wedges;
|
||
|
|
||
|
if (sPowerMeterHUD.animation != POWER_METER_HIDING)
|
||
|
func_802E261C(shownHealthWedges);
|
||
|
|
||
|
if (sPowerMeterHUD.animation == POWER_METER_HIDDEN)
|
||
|
return;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
func_802E2304(shownHealthWedges);
|
||
|
|
||
|
sPowerMeterHUD.d_EC += 1;
|
||
|
}
|
||
|
|
||
|
#ifdef VERSION_JP
|
||
|
#define HUD_TOP_Y 210
|
||
|
#else
|
||
|
#define HUD_TOP_Y 209
|
||
|
#endif
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
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
|
||
|
|
||
|
void render_hud_stars(void) {
|
||
|
s8 showX = 0;
|
||
|
|
||
|
if (D_803305CC == 1 && gGlobalTimer & 0x00000008)
|
||
|
return;
|
||
|
|
||
|
if (gHudDisplay.stars < 100)
|
||
|
showX = 1;
|
||
|
|
||
|
print_text(HUD_STARS_X, HUD_TOP_Y, "-"); // 'Star' glyph
|
||
|
if (showX == 1)
|
||
|
print_text((HUD_STARS_X + 16), HUD_TOP_Y, "*"); // 'X' glyph
|
||
|
print_text_fmt_int(((showX * 14) + (HUD_STARS_X + 16)), HUD_TOP_Y, "%d", gHudDisplay.stars);
|
||
|
}
|
||
|
|
||
|
void func_802E29D4() {
|
||
|
s16 i;
|
||
|
|
||
|
for (i = 0; i < gHudDisplay.keys; i++)
|
||
|
print_text((i * 16) + 220, 142, "/"); // unused glyph (originally for a key?)
|
||
|
}
|
||
|
|
||
|
void render_hud_timer(void) {
|
||
|
u8 *(*hudPrintLUT)[58];
|
||
|
u16 timerValFrames;
|
||
|
u16 timerMins;
|
||
|
u16 timerSecs;
|
||
|
u16 timerFracSecs;
|
||
|
|
||
|
hudPrintLUT = segmented_to_virtual(&seg2_hud_lut);
|
||
|
timerValFrames = gHudDisplay.timer;
|
||
|
timerMins = timerValFrames / (30 * 60);
|
||
|
timerSecs = (timerValFrames - (timerMins * 1800)) / 30;
|
||
|
|
||
|
timerFracSecs = ((timerValFrames - (timerMins * 1800) - (timerSecs * 30)) & 0xFFFF) / 3;
|
||
|
|
||
|
print_text(170, 185, "TIME");
|
||
|
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);
|
||
|
render_hud_camera(239, 32, (*hudPrintLUT)[56]);
|
||
|
render_hud_camera(274, 32, (*hudPrintLUT)[57]);
|
||
|
gSPDisplayList(gDisplayListHead++, dl_hud_img_end);
|
||
|
}
|
||
|
|
||
|
void set_camera_status(s16 a0) {
|
||
|
sCameraHUD.d_F8 = a0;
|
||
|
}
|
||
|
|
||
|
void show_camera_status(void) {
|
||
|
u8 *(*cameraLUT)[6];
|
||
|
s32 x;
|
||
|
s32 y;
|
||
|
|
||
|
cameraLUT = segmented_to_virtual(&seg2_hud_camera_lut);
|
||
|
x = 266;
|
||
|
y = 205;
|
||
|
|
||
|
if (sCameraHUD.d_F8 == 0)
|
||
|
return;
|
||
|
|
||
|
gSPDisplayList(gDisplayListHead++, dl_hud_img_begin);
|
||
|
render_hud_camera(x, y, (*cameraLUT)[0]);
|
||
|
|
||
|
switch (sCameraHUD.d_F8 & 0x07) {
|
||
|
case 1 << 0: // 1
|
||
|
render_hud_camera(x + 16, y, (*cameraLUT)[1]);
|
||
|
break;
|
||
|
case 1 << 1: // 2
|
||
|
render_hud_camera(x + 16, y, (*cameraLUT)[2]);
|
||
|
break;
|
||
|
case 1 << 2: // 4
|
||
|
render_hud_camera(x + 16, y, (*cameraLUT)[3]);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (sCameraHUD.d_F8 & 0x18) {
|
||
|
case 1 << 3: // 8
|
||
|
render_hud_c_buttons(x + 4, y + 16, (*cameraLUT)[5]);
|
||
|
break;
|
||
|
case 1 << 4: // 16
|
||
|
render_hud_c_buttons(x + 4, y - 8, (*cameraLUT)[4]);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
gSPDisplayList(gDisplayListHead++, dl_hud_img_end);
|
||
|
}
|
||
|
|
||
|
void render_hud(void) {
|
||
|
s16 hudDisplayFlags;
|
||
|
|
||
|
hudDisplayFlags = gHudDisplay.flags;
|
||
|
|
||
|
if (hudDisplayFlags == HUD_DISPLAY_NONE) {
|
||
|
sPowerMeterHUD.animation = POWER_METER_HIDDEN;
|
||
|
D_803600D0 = 8;
|
||
|
sPowerMeterHUD.d_EC = 0;
|
||
|
} else {
|
||
|
dl_add_new_ortho_matrix();
|
||
|
|
||
|
if (gCurrentArea != NULL && gCurrentArea->camera->currPreset == CAMERA_PRESET_INSIDE_CANNON)
|
||
|
RenderHudCannonReticle();
|
||
|
|
||
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_LIVES)
|
||
|
render_hud_mario_lives();
|
||
|
|
||
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_COIN_COUNT)
|
||
|
render_hud_coins();
|
||
|
|
||
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_STAR_COUNT)
|
||
|
render_hud_stars();
|
||
|
|
||
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_UNKNOWN_0010)
|
||
|
func_802E29D4();
|
||
|
|
||
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_CAMERA_AND_POWER) {
|
||
|
render_hud_hp();
|
||
|
show_camera_status();
|
||
|
}
|
||
|
|
||
|
if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER)
|
||
|
render_hud_timer();
|
||
|
}
|
||
|
}
|