From 6a8baf89369374a4e3bbccb5b45d5de36eb7e843 Mon Sep 17 00:00:00 2001 From: coco875 <59367621+coco875@users.noreply.github.com> Date: Thu, 10 Jul 2025 23:11:36 +0000 Subject: [PATCH] port pr 730 from the decomp (#445) * port pr 730 from the decomp Co-Authored-By: Jed Grabman <7600154+jedgrabman@users.noreply.github.com> * rename file * small fix * finish fix time trial --------- Co-authored-by: Jed Grabman <7600154+jedgrabman@users.noreply.github.com> Co-authored-by: MegaMech --- include/defines.h | 37 +- src/actors/kiwano_fruit/update.inc.c | 2 +- src/buffers.h | 2 +- src/code_800029B0.c | 2 +- src/debug/all_variables.h | 2 +- src/engine/courses/BansheeBoardwalk.cpp | 2 +- src/engine/courses/BigDonut.cpp | 2 +- src/engine/courses/BlockFort.cpp | 2 +- src/engine/courses/BowsersCastle.cpp | 2 +- src/engine/courses/ChocoMountain.cpp | 2 +- src/engine/courses/Course.cpp | 4 +- src/engine/courses/DKJungle.cpp | 2 +- src/engine/courses/DoubleDeck.cpp | 2 +- src/engine/courses/FrappeSnowland.cpp | 2 +- src/engine/courses/Harbour.cpp | 2 +- src/engine/courses/KalimariDesert.cpp | 2 +- src/engine/courses/KoopaTroopaBeach.cpp | 2 +- src/engine/courses/LuigiRaceway.cpp | 6 +- src/engine/courses/MarioRaceway.cpp | 6 +- src/engine/courses/MooMooFarm.cpp | 2 +- src/engine/courses/PodiumCeremony.cpp | 2 +- src/engine/courses/RainbowRoad.cpp | 2 +- src/engine/courses/RoyalRaceway.cpp | 6 +- src/engine/courses/SherbetLand.cpp | 2 +- src/engine/courses/Skyscraper.cpp | 2 +- src/engine/courses/TestCourse.cpp | 2 +- src/engine/courses/ToadsTurnpike.cpp | 2 +- src/engine/courses/WarioStadium.cpp | 2 +- src/engine/courses/YoshiValley.cpp | 2 +- src/main.c | 4 +- src/menu_items.c | 114 ++--- src/menus.c | 4 +- src/racing/actors.c | 4 +- src/racing/actors.h | 2 +- src/racing/race_logic.c | 6 +- src/racing/race_logic.h | 2 +- src/replays.c | 575 ++++++++++++++++++++++++ src/{staff_ghosts.h => replays.h} | 32 +- src/save.c | 28 +- src/save.h | 2 +- src/spawn_players.c | 8 +- src/staff_ghosts.c | 542 ---------------------- src/update_objects.c | 2 +- src/update_objects.h | 2 +- 44 files changed, 744 insertions(+), 690 deletions(-) create mode 100644 src/replays.c rename src/{staff_ghosts.h => replays.h} (54%) delete mode 100644 src/staff_ghosts.c diff --git a/include/defines.h b/include/defines.h index 5895dc96c..594d43f46 100644 --- a/include/defines.h +++ b/include/defines.h @@ -48,6 +48,27 @@ #define HOLD_ALL_DPAD_AND_C_BUTTONS \ (U_JPAD | L_JPAD | R_JPAD | D_JPAD | U_CBUTTONS | L_CBUTTONS | R_CBUTTONS | D_CBUTTONS) +#define ALL_BUTTONS \ + (A_BUTTON | B_BUTTON | L_TRIG | R_TRIG | Z_TRIG | START_BUTTON | U_JPAD | L_JPAD | R_JPAD | D_JPAD | U_CBUTTONS | \ + L_CBUTTONS | R_CBUTTONS | D_CBUTTONS) + +/** + * Replay controller buttons + * Used for time trial replays (including staff and player ghosts) + * Each entry is converted to a u32 value + * This allows access to the button struct member + */ +#define REPLAY_A_BUTTON (1 << 31) // 0x80000000 +#define REPLAY_B_BUTTON (1 << 30) // 0x40000000 +#define REPLAY_Z_TRIG (1 << 29) // 0x20000000 +#define REPLAY_R_TRIG (1 << 28) // 0x10000000 + +#define REPLAY_FRAME_COUNTER 0xFF0000 +#define REPLAY_CLEAR_FRAME_COUNTER (0xFFFFFFFF & ~REPLAY_FRAME_COUNTER) +#define REPLAY_STICK_Y 0xFF00 +#define REPLAY_STICK_X 0xFF +#define REPLAY_FRAME_INCREMENT 0x10000 + /** * @brief Jump to demo mode from the debug menu using L and A */ @@ -382,15 +403,15 @@ enum PLACE { FIRST_PLACE, SECOND_PLACE, THIRD_PLACE, FOURTH_PLACE }; /** * @brief durations of effects */ - #define STAR_EFFECT_DURATION 0xA - #define BOO_EFFECT_DURATION 0x7 +#define STAR_EFFECT_DURATION 0xA +#define BOO_EFFECT_DURATION 0x7 - /** - * @brief alpha related values - */ - #define ALPHA_MAX 0xFF - #define ALPHA_MIN 0x0 - #define ALPHA_BOO_EFFECT 0x60 +/** + * @brief alpha related values + */ +#define ALPHA_MAX 0xFF +#define ALPHA_MIN 0x0 +#define ALPHA_BOO_EFFECT 0x60 #define ALPHA_CHANGE_LARGE 8 #define ALPHA_CHANGE_MEDIUM 4 diff --git a/src/actors/kiwano_fruit/update.inc.c b/src/actors/kiwano_fruit/update.inc.c index 7018730ee..68df96d7d 100644 --- a/src/actors/kiwano_fruit/update.inc.c +++ b/src/actors/kiwano_fruit/update.inc.c @@ -58,7 +58,7 @@ void update_actor_kiwano_fruit(struct KiwanoFruit* fruit) { player->velocity[2] -= temp_f14 * 0.7f; func_800C9060(player - gPlayerOne, SOUND_ARG_LOAD(0x19, 0x00, 0x70, 0x18)); if (gModeSelection != GRAND_PRIX) { - D_80162DF8 = 1; + gPostTimeTrialReplayCannotSave = 1; } } } diff --git a/src/buffers.h b/src/buffers.h index d8fb4f9ce..64bf2ce8d 100644 --- a/src/buffers.h +++ b/src/buffers.h @@ -22,7 +22,7 @@ typedef struct { } struct_D_802BFB80_4; // size = 0x1000 /* - * In render_player, spawn_players, and staff_ghosts D_802BFB80 is the arraySize8 entry + * In render_player, spawn_players, and replays D_802BFB80 is the arraySize8 entry * But in menu_items its the arraySize4 entry * The only way to unify those 2 things is to use a union */ diff --git a/src/code_800029B0.c b/src/code_800029B0.c index 7c406cf79..32473d14b 100644 --- a/src/code_800029B0.c +++ b/src/code_800029B0.c @@ -17,7 +17,7 @@ #include "skybox_and_splitscreen.h" #include "code_8006E9C0.h" #include "spawn_players.h" -#include "staff_ghosts.h" +#include "replays.h" #include "render_courses.h" #include "main.h" #include "courses/all_course_data.h" diff --git a/src/debug/all_variables.h b/src/debug/all_variables.h index 41afb0407..d71336b89 100644 --- a/src/debug/all_variables.h +++ b/src/debug/all_variables.h @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/engine/courses/BansheeBoardwalk.cpp b/src/engine/courses/BansheeBoardwalk.cpp index 869e6525a..205fe24c1 100644 --- a/src/engine/courses/BansheeBoardwalk.cpp +++ b/src/engine/courses/BansheeBoardwalk.cpp @@ -30,7 +30,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" -#include "staff_ghosts.h" +#include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/BigDonut.cpp b/src/engine/courses/BigDonut.cpp index f0f83cf5a..ed2d1c7fc 100644 --- a/src/engine/courses/BigDonut.cpp +++ b/src/engine/courses/BigDonut.cpp @@ -24,7 +24,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" -#include "staff_ghosts.h" +#include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/BlockFort.cpp b/src/engine/courses/BlockFort.cpp index 44ffb3423..d2f96259e 100644 --- a/src/engine/courses/BlockFort.cpp +++ b/src/engine/courses/BlockFort.cpp @@ -24,7 +24,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" -#include "staff_ghosts.h" +#include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/BowsersCastle.cpp b/src/engine/courses/BowsersCastle.cpp index d2f7d451b..e05578035 100644 --- a/src/engine/courses/BowsersCastle.cpp +++ b/src/engine/courses/BowsersCastle.cpp @@ -26,7 +26,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "code_8003DC40.h" diff --git a/src/engine/courses/ChocoMountain.cpp b/src/engine/courses/ChocoMountain.cpp index 943e5db04..6152d9911 100644 --- a/src/engine/courses/ChocoMountain.cpp +++ b/src/engine/courses/ChocoMountain.cpp @@ -25,7 +25,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "code_8003DC40.h" diff --git a/src/engine/courses/Course.cpp b/src/engine/courses/Course.cpp index 7fb775ac9..aa87ac9b3 100644 --- a/src/engine/courses/Course.cpp +++ b/src/engine/courses/Course.cpp @@ -18,7 +18,7 @@ extern "C" { #include "assets/common_data.h" #include "render_objects.h" #include "save.h" -#include "staff_ghosts.h" +#include "replays.h" #include "code_800029B0.h" #include "render_courses.h" #include "collision.h" @@ -341,7 +341,7 @@ void Course::WhatDoesThisDoAI(Player* player, int8_t playerId) { } void Course::SetStaffGhost() { - D_80162DD6 = 1; + bCourseGhostDisabled = 1; D_80162DF4 = 1; } diff --git a/src/engine/courses/DKJungle.cpp b/src/engine/courses/DKJungle.cpp index 1608a2efb..7be091ad3 100644 --- a/src/engine/courses/DKJungle.cpp +++ b/src/engine/courses/DKJungle.cpp @@ -29,7 +29,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "code_8003DC40.h" diff --git a/src/engine/courses/DoubleDeck.cpp b/src/engine/courses/DoubleDeck.cpp index 0bd2fb23e..f796c284f 100644 --- a/src/engine/courses/DoubleDeck.cpp +++ b/src/engine/courses/DoubleDeck.cpp @@ -24,7 +24,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/FrappeSnowland.cpp b/src/engine/courses/FrappeSnowland.cpp index 216dbd3d8..c4185b165 100644 --- a/src/engine/courses/FrappeSnowland.cpp +++ b/src/engine/courses/FrappeSnowland.cpp @@ -28,7 +28,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/Harbour.cpp b/src/engine/courses/Harbour.cpp index 891bfb45d..04f28dcf8 100644 --- a/src/engine/courses/Harbour.cpp +++ b/src/engine/courses/Harbour.cpp @@ -46,7 +46,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/KalimariDesert.cpp b/src/engine/courses/KalimariDesert.cpp index 283b81268..a0cdf469d 100644 --- a/src/engine/courses/KalimariDesert.cpp +++ b/src/engine/courses/KalimariDesert.cpp @@ -28,7 +28,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/KoopaTroopaBeach.cpp b/src/engine/courses/KoopaTroopaBeach.cpp index 555e4e997..0625073c7 100644 --- a/src/engine/courses/KoopaTroopaBeach.cpp +++ b/src/engine/courses/KoopaTroopaBeach.cpp @@ -27,7 +27,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "code_8003DC40.h" diff --git a/src/engine/courses/LuigiRaceway.cpp b/src/engine/courses/LuigiRaceway.cpp index 1f9bcb559..4bc59bc7f 100644 --- a/src/engine/courses/LuigiRaceway.cpp +++ b/src/engine/courses/LuigiRaceway.cpp @@ -27,7 +27,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" -#include "staff_ghosts.h" +#include "replays.h" #include "actors.h" #include "collision.h" #include "code_8003DC40.h" @@ -246,10 +246,10 @@ void LuigiRaceway::WhatDoesThisDoAI(Player* player, int8_t playerId) { void LuigiRaceway::SetStaffGhost() { u32 temp_v0 = func_800B4E24(0) & 0xfffff; if (temp_v0 <= 11200) { - D_80162DD6 = 0; + bCourseGhostDisabled = 0; D_80162DF4 = 0; } else { - D_80162DD6 = 1; + bCourseGhostDisabled = 1; D_80162DF4 = 1; } D_80162DC4 = d_luigi_raceway_staff_ghost; diff --git a/src/engine/courses/MarioRaceway.cpp b/src/engine/courses/MarioRaceway.cpp index 64dedd4df..6e6afd534 100644 --- a/src/engine/courses/MarioRaceway.cpp +++ b/src/engine/courses/MarioRaceway.cpp @@ -26,7 +26,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "mario_raceway_data.h" #include "collision.h" @@ -266,10 +266,10 @@ void MarioRaceway::WhatDoesThisDoAI(Player* player, int8_t playerId) { void MarioRaceway::SetStaffGhost() { u32 temp_v0 = func_800B4E24(0) & 0xfffff; if (temp_v0 <= 9000) { - D_80162DD6 = 0; + bCourseGhostDisabled = 0; D_80162DF4 = 0; } else { - D_80162DD6 = 1; + bCourseGhostDisabled = 1; D_80162DF4 = 1; } D_80162DC4 = d_mario_raceway_staff_ghost; diff --git a/src/engine/courses/MooMooFarm.cpp b/src/engine/courses/MooMooFarm.cpp index 7ebab2723..f864caf2a 100644 --- a/src/engine/courses/MooMooFarm.cpp +++ b/src/engine/courses/MooMooFarm.cpp @@ -27,7 +27,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/PodiumCeremony.cpp b/src/engine/courses/PodiumCeremony.cpp index 203e3416f..eecce4997 100644 --- a/src/engine/courses/PodiumCeremony.cpp +++ b/src/engine/courses/PodiumCeremony.cpp @@ -30,7 +30,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/RainbowRoad.cpp b/src/engine/courses/RainbowRoad.cpp index f3893d28a..36d2bebcf 100644 --- a/src/engine/courses/RainbowRoad.cpp +++ b/src/engine/courses/RainbowRoad.cpp @@ -26,7 +26,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/RoyalRaceway.cpp b/src/engine/courses/RoyalRaceway.cpp index b5b448e0e..681af2f78 100644 --- a/src/engine/courses/RoyalRaceway.cpp +++ b/src/engine/courses/RoyalRaceway.cpp @@ -26,7 +26,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" @@ -247,10 +247,10 @@ void RoyalRaceway::WhatDoesThisDoAI(Player* player, int8_t playerId) { void RoyalRaceway::SetStaffGhost() { u32 temp_v0 = func_800B4E24(0) & 0xfffff; if (temp_v0 <= 16000) { - D_80162DD6 = 0; + bCourseGhostDisabled = 0; D_80162DF4 = 0; } else { - D_80162DD6 = 1; + bCourseGhostDisabled = 1; D_80162DF4 = 1; } D_80162DC4 = d_royal_raceway_staff_ghost; diff --git a/src/engine/courses/SherbetLand.cpp b/src/engine/courses/SherbetLand.cpp index 6bcf06aa6..f48b5341c 100644 --- a/src/engine/courses/SherbetLand.cpp +++ b/src/engine/courses/SherbetLand.cpp @@ -26,7 +26,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/Skyscraper.cpp b/src/engine/courses/Skyscraper.cpp index 637f5c521..184110a2e 100644 --- a/src/engine/courses/Skyscraper.cpp +++ b/src/engine/courses/Skyscraper.cpp @@ -24,7 +24,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/TestCourse.cpp b/src/engine/courses/TestCourse.cpp index 1984fb143..f9af1f776 100644 --- a/src/engine/courses/TestCourse.cpp +++ b/src/engine/courses/TestCourse.cpp @@ -46,7 +46,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/ToadsTurnpike.cpp b/src/engine/courses/ToadsTurnpike.cpp index 387e39d33..0d79cd942 100644 --- a/src/engine/courses/ToadsTurnpike.cpp +++ b/src/engine/courses/ToadsTurnpike.cpp @@ -31,7 +31,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/engine/courses/WarioStadium.cpp b/src/engine/courses/WarioStadium.cpp index 9ab3b7915..d692c725a 100644 --- a/src/engine/courses/WarioStadium.cpp +++ b/src/engine/courses/WarioStadium.cpp @@ -26,7 +26,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" -#include "staff_ghosts.h" +#include "replays.h" #include "actors.h" #include "collision.h" #include "code_8003DC40.h" diff --git a/src/engine/courses/YoshiValley.cpp b/src/engine/courses/YoshiValley.cpp index 5a24644f7..f3769cb7a 100644 --- a/src/engine/courses/YoshiValley.cpp +++ b/src/engine/courses/YoshiValley.cpp @@ -29,7 +29,7 @@ extern "C" { #include "render_objects.h" #include "assets/common_data.h" #include "save.h" - #include "staff_ghosts.h" + #include "replays.h" #include "actors.h" #include "collision.h" #include "memory.h" diff --git a/src/main.c b/src/main.c index 7c5f15e91..4031da633 100644 --- a/src/main.c +++ b/src/main.c @@ -35,7 +35,7 @@ #include "render_player.h" #include "render_courses.h" #include "actors.h" -#include "staff_ghosts.h" +#include "replays.h" #include #include "crash_screen.h" #include "buffers/gfx_output_buffer.h" @@ -826,7 +826,7 @@ void race_logic_loop(void) { func_802A4EF4(); if (gModeSelection == TIME_TRIALS) { - staff_ghosts_loop(); + replays_loop(); } // Wait for all racers to load diff --git a/src/menu_items.c b/src/menu_items.c index f1039c5f3..f2510ad19 100644 --- a/src/menu_items.c +++ b/src/menu_items.c @@ -22,7 +22,7 @@ #include "memory.h" #include "audio/external.h" #include "render_objects.h" -#include "staff_ghosts.h" +#include "replays.h" #include #include "textures.h" #include "math_util.h" @@ -805,10 +805,7 @@ MenuTexture* D_800E7DC4[] = { // trophy textures MkAnimation* D_800E7E14[] = { - D_020020BC, - D_020020CC, - D_020020DC, - D_020020DC, D_020020EC, D_020020FC, D_0200210C, D_0200210C, + D_020020BC, D_020020CC, D_020020DC, D_020020DC, D_020020EC, D_020020FC, D_0200210C, D_0200210C, }; MkAnimation* D_800E7E34[] = { @@ -2306,8 +2303,8 @@ void print_text2_wide(s32 column, s32 row, char* text, s32 tracking, f32 scaleX, glyphTexture = (MenuTexture*) segmented_to_virtual_dupe((const void*) gGlyphTextureLUT[glyphIndex]); load_menu_img(glyphTexture); gDisplayListHead = - print_letter_wide_right(gDisplayListHead, glyphTexture, column - (gGlyphDisplayWidth[glyphIndex] / 2), row, - arg6, scaleX, scaleY); + print_letter_wide_right(gDisplayListHead, glyphTexture, + column - (gGlyphDisplayWidth[glyphIndex] / 2), row, arg6, scaleX, scaleY); if ((glyphIndex >= 0xD5) && (glyphIndex < 0xE0)) { characterWidth = 0x20; } else { @@ -3029,8 +3026,9 @@ Gfx* func_80095BD0(Gfx* displayListHead, u8* arg1, f32 arg2, f32 arg3, u32 arg4, displayListHead = AddTextMatrix(displayListHead, mf); // gSPMatrix(displayListHead++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gDPLoadTextureTile_4b(displayListHead++, arg1, G_IM_FMT_I, arg4, 0, 0, 0, arg4, arg5+2, 0, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPLoadTextureTile_4b(displayListHead++, arg1, G_IM_FMT_I, arg4, 0, 0, 0, arg4, arg5 + 2, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); switch (arg4) { default: var_a1 = D_02007CD8; @@ -3071,8 +3069,9 @@ Gfx* func_80095BD0_wide_right(Gfx* displayListHead, u8* arg1, f32 arg2, f32 arg3 displayListHead = AddTextMatrix(displayListHead, mf); // gSPMatrix(displayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxEffect[gMatrixEffectCount++]), // G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gDPLoadTextureTile_4b(displayListHead++, arg1, G_IM_FMT_I, arg4, 0, 0, 0, arg4-1, arg5-1, 0, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPLoadTextureTile_4b(displayListHead++, arg1, G_IM_FMT_I, arg4, 0, 0, 0, arg4 - 1, arg5 - 1, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); switch (arg4) { default: var_a1 = D_02007CD8; @@ -3109,8 +3108,8 @@ Gfx* func_800963F0(Gfx* displayListHead, s8 textureFormat, s32 texScaleS, s32 te s32 srcX, s32 srcY, s32 srcHeight, s32 srcWidth, s32 screenX, s32 screenY, u8* textureData, u32 texWidth, u32 texHeight) { gDPLoadTextureTile(displayListHead++, textureData, textureFormat, G_IM_SIZ_16b, texWidth, texHeight, srcX, srcY, - srcX + texWidth-1, srcY + texHeight-1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 0, 0, - G_TX_NOLOD, G_TX_NOLOD); + srcX + texWidth - 1, srcY + texHeight - 1, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, 0, 0, G_TX_NOLOD, G_TX_NOLOD); f32 percentScaleX = 1.0f / ((f32) texScaleS / 1024.0f); f32 percentScaleY = 1.0f / ((f32) texScaleT / 1024.0f); gSPWideTextureRectangle(displayListHead++, screenX << 2, screenY << 2, @@ -3305,8 +3304,8 @@ Gfx* func_80097A14(Gfx* displayListHead, s8 arg1, s32 arg2, s32 arg3, s32 arg4, } Gfx* func_80097AE4(Gfx* displayListHead, s8 textureFormat, s32 destX, s32 destY, u8* textureData, s32 sourceWidth) { - gDPLoadTextureTile(displayListHead++, textureData, textureFormat, G_IM_SIZ_16b, 64, 64, 0, 0, sourceWidth - 1, 32-1, 0, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); + gDPLoadTextureTile(displayListHead++, textureData, textureFormat, G_IM_SIZ_16b, 64, 64, 0, 0, sourceWidth - 1, + 32 - 1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); gSPWideTextureRectangle(displayListHead++, destX << 2, destY << 2, (destX + sourceWidth) << 2, (destY + 64) << 2, 0, 0, 0, 1024, 1024); return displayListHead; @@ -3320,8 +3319,8 @@ Gfx* func_80097E58(Gfx* displayListHead, s8 textureFormat, u32 uls, u32 ult, u32 } f32 percent = (f32) (32 - width) / 32.0f; gDPLoadTextureTile(displayListHead++, textureData, textureFormat, G_IM_SIZ_16b, textureWidth, textureHeight, uls, - ult, textureWidth - 1, textureHeight - 1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, - G_TX_NOLOD); + ult, textureWidth - 1, textureHeight - 1, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); screenX += (s32) ((f32) (textureWidth / 2) * (1.0f - percent)); gSPWideTextureRectangle(displayListHead++, (screenX) << 2, screenY << 2, (screenX + (s32) ((f32) textureWidth * percent)) << 2, (screenY + textureHeight) << 2, 0, 0, @@ -3339,10 +3338,10 @@ Gfx* func_80098558(Gfx* displayListHead, u32 arg1, u32 arg2, u32 arg3, u32 arg4, for (var_v0 = arg2; var_v0 < arg4; var_v0 += 0x20) { for (var_a3 = arg1; var_a3 < arg3; var_a3 += 0x20) { gDPLoadTextureTile(displayListHead++, sMenuTextureList, G_IM_FMT_RGBA, G_IM_SIZ_16b, arg8, 0, var_a3, - var_v0, var_a3 + 32-1, var_v0 + 32-1, 0, G_TX_NOMIRROR | G_TX_WRAP, + var_v0, var_a3 + 32 - 1, var_v0 + 32 - 1, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 5, 5, G_TX_NOLOD, G_TX_NOLOD); - gSPTextureRectangle(displayListHead++, arg5 << 2, arg6 << 2, (arg5 + 32) << 2, (arg6 + 32) << 2, 0, 0, - 0, 1024, 1024); + gSPTextureRectangle(displayListHead++, arg5 << 2, arg6 << 2, (arg5 + 32) << 2, (arg6 + 32) << 2, 0, 0, 0, + 1024, 1024); arg5 += 0x20; } arg5 = arg5Copy; @@ -4025,7 +4024,7 @@ void func_80099EC4(void) { #ifdef TARGET_N64 osInvalDCache((void*) gMenuCompressedBuffer, var_s0); osPiStartDma(&sp68, 0, 0, (u32) _textures_0aSegmentRomStart + SEGMENT_OFFSET(temp_s2->textureData), - gMenuCompressedBuffer, var_s0, &gDmaMesgQueue); + gMenuCompressedBuffer, var_s0, &gDmaMesgQueue); #endif if ((size && size) && size) {} osRecvMesg(&gDmaMesgQueue, &sp64, 1); @@ -4672,13 +4671,13 @@ Gfx* print_letter(Gfx* arg0, MenuTexture* glyphTexture, f32 arg2, f32 arg3, s32 switch (mode) { case 1: gSPDisplayList(arg0++, D_020077F8); - arg0 = func_80095BD0(arg0, var_s0->textureData, var_s0->dX + arg2, var_s0->dY + arg3, var_s0->width, - var_s0->height, scaleX, scaleY); + arg0 = func_80095BD0(arg0, var_s0->textureData, var_s0->dX + arg2, var_s0->dY + arg3, + var_s0->width, var_s0->height, scaleX, scaleY); break; case 2: gSPDisplayList(arg0++, D_02007818); - arg0 = func_80095BD0(arg0, var_s0->textureData, var_s0->dX + arg2, var_s0->dY + arg3, var_s0->width, - var_s0->height, scaleX, scaleY); + arg0 = func_80095BD0(arg0, var_s0->textureData, var_s0->dX + arg2, var_s0->dY + arg3, + var_s0->width, var_s0->height, scaleX, scaleY); break; } } @@ -4868,10 +4867,8 @@ Gfx* func_8009C708(Gfx* arg0, struct_8018DEE0_entry* arg1, s32 arg2, s32 arg3, s break; } if (arg5 >= 0) { - arg0 = - func_80097E58(arg0, var_t0, 0, 0U, var_s1->width, var_s1->height, var_s1->dX + arg2, var_s1->dY + arg3, - var_s1->textureData, - var_s1->width, var_s1->height, (u32) arg5); + arg0 = func_80097E58(arg0, var_t0, 0, 0U, var_s1->width, var_s1->height, var_s1->dX + arg2, + var_s1->dY + arg3, var_s1->textureData, var_s1->width, var_s1->height, (u32) arg5); } var_s1++; } @@ -6032,9 +6029,8 @@ void add_menu_item(s32 type, s32 column, s32 row, s8 priority) { case MENU_ITEM_TYPE_05A: case MENU_ITEM_TYPE_05B: case COURSE_SELECT_BATTLE_NAMES: - load_menu_img_comp_type( - gMenuTexturesTrackSelection[type - COURSE_SELECT_MAP_SELECT], - LOAD_MENU_IMG_TKMK00_ONCE); + load_menu_img_comp_type(gMenuTexturesTrackSelection[type - COURSE_SELECT_MAP_SELECT], + LOAD_MENU_IMG_TKMK00_ONCE); break; case MENU_ITEM_TYPE_05F: case MENU_ITEM_TYPE_060: @@ -6077,7 +6073,8 @@ void add_menu_item(s32 type, s32 column, s32 row, s8 priority) { case MENU_ITEM_TYPE_079: case MENU_ITEM_TYPE_07A: case MENU_ITEM_TYPE_07B: - load_menu_img_comp_type(segmented_to_virtual_dupe(D_800E82F4[type - MENU_ITEM_TYPE_078]), LOAD_MENU_IMG_TKMK00_ONCE); + load_menu_img_comp_type(segmented_to_virtual_dupe(D_800E82F4[type - MENU_ITEM_TYPE_078]), + LOAD_MENU_IMG_TKMK00_ONCE); break; case MENU_ITEM_TYPE_08C: load_menu_img_comp_type(segmented_to_virtual_dupe(seg2_data_texture), LOAD_MENU_IMG_TKMK00_ONCE); @@ -6150,9 +6147,9 @@ void add_menu_item(s32 type, s32 column, s32 row, s8 priority) { case MENU_ITEM_TYPE_0BB: var_ra->param1 = func_800B5020(playerHUD[0].someTimer, gCharacterSelections[0]); var_ra->param2 = func_800B5218(); - if (D_80162DD4 != 1) { + if (bPlayerGhostDisabled != 1) { if (func_800051C4() >= 0x3C01) { - D_80162DD4 = 1; + bPlayerGhostDisabled = 1; } } if ((var_ra->param1 == 0) || (var_ra->param2 != 0)) { @@ -7080,14 +7077,12 @@ void func_800A143C(MenuItem* arg0, s32 arg1) { case 2: case 3: gDisplayListHead = - render_menu_textures(gDisplayListHead, gMenuTexturesTrackSelection[arg1 + 1], - arg0->column, arg0->row); + render_menu_textures(gDisplayListHead, gMenuTexturesTrackSelection[arg1 + 1], arg0->column, arg0->row); break; case 1: case 4: - gDisplayListHead = - func_8009BC9C(gDisplayListHead, gMenuTexturesTrackSelection[arg1 + 1], - arg0->column, arg0->row, 2, arg0->param1); + gDisplayListHead = func_8009BC9C(gDisplayListHead, gMenuTexturesTrackSelection[arg1 + 1], arg0->column, + arg0->row, 2, arg0->param1); break; } } @@ -7872,12 +7867,12 @@ void func_800A3E60(MenuItem* arg0) { text_rainbow_effect(arg0->state - 5, var_s1, 1); switch (var_s1) { case 4: - if (D_80162DF8 == 1) { + if (gPostTimeTrialReplayCannotSave == 1) { var_v1 = 1; } break; case 5: - if (D_80162DD4 != 0) { + if (bPlayerGhostDisabled != 0) { var_v1 = 2; } break; @@ -7918,8 +7913,12 @@ void func_800A3E60(MenuItem* arg0) { if (D_8018EE10[var_s1].ghostDataSaved == 0) { print_text_mode_1(0xBB - arg0->column, 0xAA + (0x1E * var_s1), D_800E7A44, 0, 0.45f, 0.45f); } else { - print_text_mode_1(0xBB - arg0->column, 0xAA + (0x1E * var_s1), CM_GetProps()->Name, 0, 0.45f, - 0.45f); + print_text_mode_1( + 0xBB - arg0->column, 0xAA + (0x1E * var_s1), + CM_GetPropsCourseId( + gCupCourseOrder[D_8018EE10[var_s1].courseIndex / 4][D_8018EE10[var_s1].courseIndex % 4]) + ->Name, + 0, 0.45f, 0.45f); } } break; @@ -8204,16 +8203,14 @@ void render_pause_menu_versus(MenuItem* arg0) { break; case SCREEN_MODE_3P_4P_SPLITSCREEN: // Left side players - if ((temp_v0->player == gPlayerOne) || - (temp_v0->player == gPlayerThree)) { + if ((temp_v0->player == gPlayerOne) || (temp_v0->player == gPlayerThree)) { leftEdge = OTRGetDimensionFromLeftEdge(0); gDisplayListHead = draw_box_wide_pause_background(gDisplayListHead, leftEdge - temp_t3, temp_t0 - temp_t4, temp_v1 + temp_t3, temp_t0 + temp_t4, 0, 0, 0, 140); // Right side players - } else if ((temp_v0->player == gPlayerTwo) || - (temp_v0->player == gPlayerFour)) { + } else if ((temp_v0->player == gPlayerTwo) || (temp_v0->player == gPlayerFour)) { rightEdge = OTRGetDimensionFromRightEdge(SCREEN_WIDTH); gDisplayListHead = draw_box_wide_pause_background(gDisplayListHead, temp_v1 - temp_t3, temp_t0 - temp_t4, @@ -8493,8 +8490,12 @@ void render_menu_item_end_course_option(MenuItem* arg0) { if (D_8018EE10[var_s1].ghostDataSaved == 0) { print_text_mode_1(0x69 - arg0->column, (0x96 + (0x14 * var_s1)), D_800E7A44, 0, 0.75f, 0.75f); } else { - print_text_mode_1(0x69 - arg0->column, (0x96 + (0x14 * var_s1)), CM_GetProps()->Name, 0, 0.75f, - 0.75f); + print_text_mode_1( + 0x69 - arg0->column, (0x96 + (0x14 * var_s1)), + CM_GetPropsCourseId( + gCupCourseOrder[D_8018EE10[var_s1].courseIndex / 4][D_8018EE10[var_s1].courseIndex % 4]) + ->Name, + 0, 0.75f, 0.75f); } } break; @@ -10446,8 +10447,7 @@ void func_800AA69C(MenuItem* arg0) { case 2: if ((gCharacterGridIsSelected[temp_v0] == 0) && (var_a0 != 0)) { arg0->subState = 3; - func_8009A594(arg0->D_8018DEE0_index, 0, - gCharacterDeselectAnimation[temp_a0]); + func_8009A594(arg0->D_8018DEE0_index, 0, gCharacterDeselectAnimation[temp_a0]); } break; case 3: @@ -11735,7 +11735,7 @@ void func_800AD2E8(MenuItem* arg0) { arg0->param2 = 0; arg0->column = 0; arg0->state = gTimeTrialsResultCursorSelection; - if ((arg0->state == 9) && (D_80162DF8 == 1)) { + if ((arg0->state == 9) && (gPostTimeTrialReplayCannotSave == 1)) { arg0->state--; } D_800DC5EC->screenStartX = 0x00F0; @@ -11752,7 +11752,7 @@ void func_800AD2E8(MenuItem* arg0) { if ((gControllerOne->buttonPressed | gControllerOne->stickPressed) & 0x800) { if (arg0->state >= 6) { arg0->state--; - if ((D_80162DF8 == 1) && (arg0->state == 9)) { + if ((gPostTimeTrialReplayCannotSave == 1) && (arg0->state == 9)) { arg0->state--; } play_sound2(SOUND_MENU_CURSOR_MOVE); @@ -11765,10 +11765,10 @@ void func_800AD2E8(MenuItem* arg0) { if ((gControllerOne->buttonPressed | gControllerOne->stickPressed) & 0x400) { if (arg0->state < 0xA) { arg0->state++; - if ((D_80162DF8 == 1) && (arg0->state == 9)) { + if ((gPostTimeTrialReplayCannotSave == 1) && (arg0->state == 9)) { arg0->state++; } - if ((arg0->state == 0x0000000A) && (D_80162DD4 != 0)) { + if ((arg0->state == 0x0000000A) && (bPlayerGhostDisabled != 0)) { arg0->state -= 2; } else { play_sound2(SOUND_MENU_CURSOR_MOVE); @@ -12494,7 +12494,7 @@ void func_800AEF14(MenuItem* arg0) { void func_800AEF74(MenuItem* arg0) { switch (arg0->state) { case 0: - if (D_80162DF8 == 1) { + if (gPostTimeTrialReplayCannotSave == 1) { arg0->state = 1; arg0->param1 = 0; } else if (playerHUD[PLAYER_ONE].raceCompleteBool == (s8) 1) { diff --git a/src/menus.c b/src/menus.c index 85a14677f..78bdadcfc 100644 --- a/src/menus.c +++ b/src/menus.c @@ -15,7 +15,7 @@ #include "menu_items.h" #include "code_800AF9B0.h" #include "save.h" -#include "staff_ghosts.h" +#include "replays.h" #include "save_data.h" #include #include "spawn_players.h" @@ -1864,7 +1864,7 @@ void load_menu_states(s32 menuSelection) { gDebugGotoScene = DEBUG_GOTO_RACING; gGhostPlayerInit = 0; D_8016556E = 0; - D_80162DD4 = 1; + bPlayerGhostDisabled = 1; D_80162DD8 = 1; D_80162E00 = 0; D_80162DC8 = 1; diff --git a/src/racing/actors.c b/src/racing/actors.c index 87c6e8231..05a56d68b 100644 --- a/src/racing/actors.c +++ b/src/racing/actors.c @@ -1632,7 +1632,7 @@ bool collision_yoshi_egg(Player* player, struct YoshiValleyEgg* egg) { } else { apply_hit_sound_effect(player, player - gPlayerOne); if ((gModeSelection == TIME_TRIALS) && ((player->type & PLAYER_CPU) == 0)) { - D_80162DF8 = 1; + gPostTimeTrialReplayCannotSave = 1; } } } else { @@ -2174,7 +2174,7 @@ void evaluate_collision_between_player_actor(Player* player, struct Actor* actor if (query_collision_player_vs_actor_item(player, actor) == COLLISION) { func_800C98B8(actor->pos, actor->velocity, SOUND_ACTION_EXPLOSION); if ((gModeSelection == TIME_TRIALS) && !(player->type & PLAYER_CPU)) { - D_80162DF8 = 1; + gPostTimeTrialReplayCannotSave = 1; } if (player->effects & STAR_EFFECT) { actor->velocity[1] = 10.0f; diff --git a/src/racing/actors.h b/src/racing/actors.h index 4f71c9b97..8fa5741da 100644 --- a/src/racing/actors.h +++ b/src/racing/actors.h @@ -130,7 +130,7 @@ extern s16 gCurrentCourseId; extern u16 isCrossingTriggeredByIndex[]; extern Lights1 D_800DC610[]; -extern s32 D_80162DF8; +extern s32 gPostTimeTrialReplayCannotSave; extern s8 D_800DC628[]; extern s8 D_800DC630[]; diff --git a/src/racing/race_logic.c b/src/racing/race_logic.c index 243cba428..cd99ab400 100644 --- a/src/racing/race_logic.c +++ b/src/racing/race_logic.c @@ -7,7 +7,7 @@ #include #include "camera.h" #include "waypoints.h" -#include "staff_ghosts.h" +#include "replays.h" #include "main.h" #include "code_800029B0.h" #include "code_80057C60.h" @@ -775,7 +775,7 @@ void func_8028F970(void) { gIsGamePaused = (controller - gControllerOne) + 1; controller->buttonPressed = 0; func_800C9F90(1); - D_80162DF0 = 1; + gPauseTriggered = 1; if (gModeSelection == TIME_TRIALS) { if (gPlayerOne->type & (PLAYER_EXISTS | PLAYER_INVISIBLE_OR_BOMB)) { func_80005AE8(gPlayerOne); @@ -907,7 +907,7 @@ void func_8028FCBC(void) { D_800DC5B0 = 0; D_800DC5B8 = 1; CM_SpawnStarterLakitu(); // func_80078F64(); - if ((gModeSelection == TIME_TRIALS) && (D_80162DD6 == 0)) { + if ((gModeSelection == TIME_TRIALS) && (bCourseGhostDisabled == 0)) { phi_v0_4 = 0x1; //! @warning this used to be < gCurrentCourseId // Hopefully this is equivallent. diff --git a/src/racing/race_logic.h b/src/racing/race_logic.h index d2c3d7936..e63094a30 100644 --- a/src/racing/race_logic.h +++ b/src/racing/race_logic.h @@ -39,6 +39,6 @@ void func_80290B14(void); extern f32 gLapCompletionPercentByPlayerId[]; extern s32 gGPCurrentRaceRankByPlayerId[]; // D_801643B8 (position for each player) -extern u16 D_80162DD6; +extern u16 bCourseGhostDisabled; #endif diff --git a/src/replays.c b/src/replays.c new file mode 100644 index 000000000..ddd50faa1 --- /dev/null +++ b/src/replays.c @@ -0,0 +1,575 @@ +#include +#include +#include +#include +#include +#include +#include +#include "main.h" +#include "code_800029B0.h" +#include "buffers.h" +#include "save.h" +#include "replays.h" +#include "code_8006E9C0.h" +#include "menu_items.h" +#include "code_80057C60.h" +#include "kart_dma.h" +#include "port/Game.h" +#include "courses/staff_ghost_data.h" + +u8* sReplayGhostBuffer; +size_t sReplayGhostBufferSize; +s16 D_80162D86; + +static u16 sPlayerGhostButtonsPrev; +static u32 sPlayerGhostFramesRemaining; +static s16 sPlayerGhostReplayIdx; +u32* sPlayerGhostReplay; + +static u16 sButtonsPrevCourseGhost; +static u32 sCourseGhostFramesRemaining; +static s16 sCourseGhostReplayIdx; +static u32* sCourseGhostReplay; + +static u16 sPostTTButtonsPrev; +static s32 sPostTTFramesRemaining; +static s16 sPostTTReplayIdx; +static u32* sPostTTReplay; + +static s16 sPlayerInputIdx; +static u32* sPlayerInputs; + +uintptr_t staff_ghost_track_ptr; +StaffGhost* D_80162DC4; +s32 D_80162DC8; +s32 D_80162DCC; +s32 D_80162DD0; +u16 bPlayerGhostDisabled; +u16 bCourseGhostDisabled; +u16 D_80162DD8; +s32 D_80162DDC; +s32 D_80162DE0; // ghost kart id? +s32 D_80162DE4; +s32 D_80162DE8; +s32 sUnusedReplayCounter; +s32 gPauseTriggered; +s32 D_80162DF4; +s32 gPostTimeTrialReplayCannotSave; +s32 D_80162DFC; + +s32 D_80162E00; + +u32* sReplayGhostEncoded = (u32*) &D_802BFB80.arraySize8[0][2][3]; +u32* gReplayGhostCompressed = (u32*) &D_802BFB80.arraySize8[1][1][3]; + +extern s32 gLapCountByPlayerId[]; + +void load_course_ghost(void) { + sCourseGhostReplay = (u32*) &D_802BFB80.arraySize8[0][2][3]; + u8* dest = (u8*) sCourseGhostReplay; + osInvalDCache(&sCourseGhostReplay[0], 0x4000); + + u8* ghost = (u8*) D_80162DC4; + + size_t size = 0; + if (ghost == d_luigi_raceway_staff_ghost) { + size = 1046 * sizeof(StaffGhost); + } else if (ghost == d_mario_raceway_staff_ghost) { + size = 935 * sizeof(StaffGhost); + } else if (ghost == d_royal_raceway_staff_ghost) { + size = 1907 * sizeof(StaffGhost); + } + + // Manual memcpy required for byte swap + for (size_t i = 0; i < size; i += sizeof(StaffGhost)) { + dest[i] = ghost[i + 3]; + dest[i + 1] = ghost[i + 2]; + dest[i + 2] = ghost[i + 1]; + dest[i + 3] = ghost[i]; + } + // memcpy(dest, ghost, size); + + osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK); + sCourseGhostFramesRemaining = (*sCourseGhostReplay & REPLAY_FRAME_COUNTER); + sCourseGhostReplayIdx = 0; +} + +void load_post_time_trial_replay(void) { + sPostTTReplay = (u32*) &D_802BFB80.arraySize8[0][D_80162DD0][3]; + sPostTTFramesRemaining = *sPostTTReplay & REPLAY_FRAME_COUNTER; + sPostTTReplayIdx = 0; +} + +void load_player_ghost(void) { + sPlayerGhostReplay = (u32*) &D_802BFB80.arraySize8[0][D_80162DC8][3]; + sPlayerGhostFramesRemaining = (s32) *sPlayerGhostReplay & REPLAY_FRAME_COUNTER; + sPlayerGhostReplayIdx = 0; +} +/** + * Activates staff ghost if time trial lap time is low enough + * + */ +#ifdef VERSION_EU +#define GHOST_UNLOCK_MARIO 10700 +#define GHOST_UNLOCK_ROYAL 19300 +#define GHOST_UNLOCK_LUIGI 13300 +#else +#define GHOST_UNLOCK_MARIO 9000 +#define GHOST_UNLOCK_ROYAL 16000 +#define GHOST_UNLOCK_LUIGI 11200 + +#endif + +void set_staff_ghost(void) { + CM_SetStaffGhost(); +} + +// Always returns true because mio0encode is stubbed. +s32 func_800051C4(void) { + s32 phi_v0; + + if (sReplayGhostBufferSize != 0) { + // func_80040174 in mio0_decode.s + func_80040174((void*) sReplayGhostBuffer, (sReplayGhostBufferSize * 4) + 0x20, (s32) sReplayGhostEncoded); + phi_v0 = + mio0encode((s32) sReplayGhostEncoded, (sReplayGhostBufferSize * 4) + 0x20, (s32) gReplayGhostCompressed); + return phi_v0 + 0x1e; + } +} + +void func_8000522C(void) { + sPlayerGhostReplay = (u32*) &D_802BFB80.arraySize8[0][D_80162DC8][3]; + mio0decode((u8*) gReplayGhostCompressed, (u8*) sPlayerGhostReplay); + sPlayerGhostFramesRemaining = (s32) (*sPlayerGhostReplay & REPLAY_FRAME_COUNTER); + sPlayerGhostReplayIdx = 0; + D_80162E00 = 1; +} + +void func_800052A4(void) { + s16 temp_v0; + + if (D_80162DC8 == 1) { + D_80162DC8 = 0; + D_80162DCC = 1; + } else { + D_80162DC8 = 1; + D_80162DCC = 0; + } + temp_v0 = sPlayerInputIdx; + sReplayGhostBuffer = (void*) &D_802BFB80.arraySize8[0][D_80162DC8][3]; + sReplayGhostBufferSize = temp_v0; + D_80162D86 = temp_v0; +} + +void func_80005310(void) { + + if (gModeSelection == TIME_TRIALS) { + + set_staff_ghost(); + + if (staff_ghost_track_ptr != (uintptr_t) GetCourse()) { + bPlayerGhostDisabled = 1; + } + + staff_ghost_track_ptr = (uintptr_t) GetCourse(); + gPauseTriggered = 0; + sUnusedReplayCounter = 0; + gPostTimeTrialReplayCannotSave = 0; + + if (gModeSelection == TIME_TRIALS && gActiveScreenMode == SCREEN_MODE_1P) { + + if (D_8015F890 == 1) { + load_post_time_trial_replay(); + if (D_80162DD8 == 0) { + load_player_ghost(); + } + if (bCourseGhostDisabled == 0) { + load_course_ghost(); + } + } else { + + D_80162DD8 = 1U; + sPlayerInputs = (u32*) &D_802BFB80.arraySize8[0][D_80162DCC][3]; + sPlayerInputs[0] = -1; + sPlayerInputIdx = 0; + D_80162DDC = 0; + func_80091EE4(); + if (bPlayerGhostDisabled == 0) { + load_player_ghost(); + } + if (bCourseGhostDisabled == 0) { + load_course_ghost(); + } + } + } + } +} + +/* Special handling for buttons saved in replays. The listing of L_TRIG here is odd + * because it is not saved in the replay data structure. Possibly, L was initially deleted + * here to make way for the frame counter, but then the format changed when the stick + * coordinates were added */ +#define REPLAY_MASK (ALL_BUTTONS ^ (A_BUTTON | B_BUTTON | Z_TRIG | R_TRIG | L_TRIG)) + +/* Inputs for replays (including player and course ghosts) are saved in a s32[] where + each entry is a combination of the inputs and how long those inputs were held for. + In essence it's "These buttons were pressed and the joystick was in this position. + This was the case for X frames". + + bits 1-8: Stick X + bits 9-16: Stick Y + bits 17-24: Frame counter + bits 25-28: Unused + bit 29: R + bit 30: Z + bit 31: B + bit 32: A +*/ +void process_post_time_trial_replay(void) { + u32 inputs; + u32 stickBytes; + UNUSED u16 unk; + u16 buttons_temp; + s16 stickVal; + s16 buttons = 0; + + if (sPostTTReplayIdx >= 0x1000) { + gPlayerOne->type = PLAYER_CINEMATIC_MODE | PLAYER_START_SEQUENCE | PLAYER_CPU; + return; + } + + inputs = sPostTTReplay[sPostTTReplayIdx]; + stickBytes = inputs & REPLAY_STICK_X; + + // twos complement trick, converting singned 8-bit value to signed 16 bit + if (stickBytes < 0x80U) { + stickVal = (s16) (stickBytes & 0xFF); + } else { + stickVal = (s16) (stickBytes | (~0xFF)); + } + + stickBytes = (u32) (inputs & REPLAY_STICK_Y) >> 8; + gControllerEight->rawStickX = stickVal; + + if (stickBytes < 0x80U) { + stickVal = (s16) (stickBytes & 0xFF); + } else { + stickVal = (s16) (stickBytes | (~0xFF)); + } + gControllerEight->rawStickY = stickVal; + if (inputs & REPLAY_A_BUTTON) { + buttons |= A_BUTTON; + } + if (inputs & REPLAY_B_BUTTON) { + buttons |= B_BUTTON; + } + if (inputs & REPLAY_Z_TRIG) { + buttons |= Z_TRIG; + } + if (inputs & REPLAY_R_TRIG) { + buttons |= R_TRIG; + } + buttons_temp = gControllerEight->buttonPressed & REPLAY_MASK; + gControllerEight->buttonPressed = (buttons & (buttons ^ sPostTTButtonsPrev)) | buttons_temp; + buttons_temp = gControllerEight->buttonDepressed & REPLAY_MASK; + gControllerEight->buttonDepressed = (sPostTTButtonsPrev & (buttons ^ sPostTTButtonsPrev)) | buttons_temp; + sPostTTButtonsPrev = buttons; + gControllerEight->button = buttons; + + if (sPostTTFramesRemaining == 0) { + sPostTTReplayIdx++; + sPostTTFramesRemaining = (s32) (sPostTTReplay[sPostTTReplayIdx] & REPLAY_FRAME_COUNTER); + } else { + sPostTTFramesRemaining -= REPLAY_FRAME_INCREMENT; + } +} + +// See process_post_time_trial_replay comment +void process_course_ghost_replay(void) { + u32 inputs; + u32 stickBytes; + UNUSED u16 unk; + u16 buttonsTemp; + s16 stickVal; + s16 buttons = 0; + + if (sCourseGhostReplayIdx >= 0x1000) { + func_80005AE8(gPlayerThree); + return; + } + inputs = sCourseGhostReplay[sCourseGhostReplayIdx]; + stickBytes = inputs & REPLAY_STICK_X; + // converting signed 8-bit values to signed 16-bit values + if (stickBytes < 0x80U) { + stickVal = (s16) (stickBytes & 0xFF); + } else { + stickVal = (s16) (stickBytes | (~0xFF)); + } + + stickBytes = (u32) (inputs & REPLAY_STICK_Y) >> 8; + gControllerSeven->rawStickX = stickVal; + + if (stickBytes < 0x80U) { + stickVal = (s16) (stickBytes & 0xFF); + } else { + stickVal = (s16) (stickBytes | (~0xFF)); + } + gControllerSeven->rawStickY = stickVal; + + if (inputs & REPLAY_A_BUTTON) { + buttons = A_BUTTON; + } + if (inputs & REPLAY_B_BUTTON) { + buttons |= B_BUTTON; + } + if (inputs & REPLAY_Z_TRIG) { + buttons |= Z_TRIG; + } + if (inputs & REPLAY_R_TRIG) { + buttons |= R_TRIG; + } + + // Blanks the A, B, Z, R and L buttons + buttonsTemp = gControllerSeven->buttonPressed & REPLAY_MASK; + gControllerSeven->buttonPressed = (buttons & (buttons ^ sButtonsPrevCourseGhost)) | buttonsTemp; + buttonsTemp = gControllerSeven->buttonDepressed & REPLAY_MASK; + gControllerSeven->buttonDepressed = (sButtonsPrevCourseGhost & (buttons ^ sButtonsPrevCourseGhost)) | buttonsTemp; + sButtonsPrevCourseGhost = buttons; + gControllerSeven->button = buttons; + if (sCourseGhostFramesRemaining == 0) { + sCourseGhostReplayIdx++; + sCourseGhostFramesRemaining = (s32) (sCourseGhostReplay[sCourseGhostReplayIdx] & REPLAY_FRAME_COUNTER); + } else { + sCourseGhostFramesRemaining -= (s32) REPLAY_FRAME_INCREMENT; + } +} + +// See process_post_time_trial_replay comment +void process_player_ghost_replay(void) { + u32 inputs; + u32 stickBytes; + UNUSED u16 unk; + u16 buttons_temp; + s16 stickVal; + s16 buttons = 0; + + if (sPlayerGhostReplayIdx >= 0x1000) { + func_80005AE8(gPlayerTwo); + return; + } + inputs = sPlayerGhostReplay[sPlayerGhostReplayIdx]; + stickBytes = inputs & REPLAY_STICK_X; + if (stickBytes < 0x80U) { + stickVal = (s16) (stickBytes & 0xFF); + } else { + stickVal = (s16) (stickBytes | ~0xFF); + } + + stickBytes = (u32) (inputs & REPLAY_STICK_Y) >> 8; + + gControllerSix->rawStickX = stickVal; + + if (stickBytes < 0x80U) { + stickVal = (s16) (stickBytes & 0xFF); + } else { + stickVal = (s16) (stickBytes | (~0xFF)); + } + + gControllerSix->rawStickY = stickVal; + + if (inputs & REPLAY_A_BUTTON) { + buttons = A_BUTTON; + } + if (inputs & REPLAY_B_BUTTON) { + buttons |= B_BUTTON; + } + if (inputs & REPLAY_Z_TRIG) { + buttons |= Z_TRIG; + } + if (inputs & REPLAY_R_TRIG) { + buttons |= R_TRIG; + } + buttons_temp = gControllerSix->buttonPressed & REPLAY_MASK; + gControllerSix->buttonPressed = (buttons & (buttons ^ sPlayerGhostButtonsPrev)) | buttons_temp; + + buttons_temp = gControllerSix->buttonDepressed & REPLAY_MASK; + gControllerSix->buttonDepressed = (sPlayerGhostButtonsPrev & (buttons ^ sPlayerGhostButtonsPrev)) | buttons_temp; + sPlayerGhostButtonsPrev = buttons; + gControllerSix->button = buttons; + + if (sPlayerGhostFramesRemaining == 0) { + sPlayerGhostReplayIdx++; + sPlayerGhostFramesRemaining = (s32) (sPlayerGhostReplay[sPlayerGhostReplayIdx] & REPLAY_FRAME_COUNTER); + } else { + sPlayerGhostFramesRemaining -= (s32) REPLAY_FRAME_INCREMENT; + } +} + +// See process_post_time_trial_replay comment +void save_player_replay(void) { + s16 buttons; + u32 inputs; + u32 stickX; + u32 stickY; + u32 inputCounter; + u32 prevInputsWCounter; + u32 prevInputs; + /* Input file is too long or picked up by lakitu or Out of bounds + Not sure if there is any way to be considered out of bounds without lakitu getting called */ + + if (((sPlayerInputIdx >= 0x1000) || ((gPlayerOne->unk_0CA & 2) != 0)) || ((gPlayerOne->unk_0CA & 8) != 0)) { + gPostTimeTrialReplayCannotSave = 1; + return; + } + + stickX = gControllerOne->rawStickX; + stickX &= 0xFF; + stickY = gControllerOne->rawStickY; + stickY = (stickY & 0xFF) << 8; + buttons = gControllerOne->button; + inputs = 0; + if (buttons & A_BUTTON) { + inputs |= REPLAY_A_BUTTON; + } + if (buttons & B_BUTTON) { + inputs |= REPLAY_B_BUTTON; + } + if (buttons & Z_TRIG) { + inputs |= REPLAY_Z_TRIG; + } + if (buttons & R_TRIG) { + inputs |= REPLAY_R_TRIG; + } + inputs |= stickX; + inputs |= stickY; + prevInputsWCounter = sPlayerInputs[sPlayerInputIdx]; + /* The 5th and 6th bytes from the right are counters. Instead of saving the same inputs over and over, + it says "these inputs were played for __ frames" */ + prevInputs = prevInputsWCounter & REPLAY_CLEAR_FRAME_COUNTER; + // first frame of inputs + if ((*sPlayerInputs) == -1) { + + sPlayerInputs[sPlayerInputIdx] = inputs; + + } else if (prevInputs == inputs) { + + inputCounter = prevInputsWCounter & REPLAY_FRAME_COUNTER; + + if (inputCounter == REPLAY_FRAME_COUNTER) { + + sPlayerInputIdx++; + sPlayerInputs[sPlayerInputIdx] = inputs; + + } else { + // increment counter by 1 + prevInputsWCounter += REPLAY_FRAME_INCREMENT; + sPlayerInputs[sPlayerInputIdx] = prevInputsWCounter; + } + } else { + sPlayerInputIdx++; + sPlayerInputs[sPlayerInputIdx] = inputs; + } +} + +// sets player to AI? (unconfirmed) +void func_80005AE8(Player* ply) { + if (((ply->type & PLAYER_INVISIBLE_OR_BOMB) != 0) && (ply != gPlayerOne)) { + ply->type = PLAYER_CINEMATIC_MODE | PLAYER_START_SEQUENCE | PLAYER_CPU; + } +} + +void func_80005B18(void) { + if (gModeSelection == TIME_TRIALS) { + if ((gLapCountByPlayerId[0] == 3) && (D_80162DDC == 0) && (gPostTimeTrialReplayCannotSave != 1)) { + if (bPlayerGhostDisabled == 1) { + D_80162DD0 = D_80162DCC; + func_800052A4(); + bPlayerGhostDisabled = 0; + D_80162DDC = 1; + D_80162DE0 = gPlayerOne->characterId; + D_80162DE8 = gPlayerOne->characterId; + D_80162E00 = 0; + D_80162DFC = playerHUD[PLAYER_ONE].someTimer; + func_80005AE8(gPlayerTwo); + func_80005AE8(gPlayerThree); + } else if (gLapCountByPlayerId[1] != 3) { + D_80162DD0 = D_80162DCC; + func_800052A4(); + D_80162DDC = 1; + D_80162DE0 = gPlayerOne->characterId; + D_80162DFC = playerHUD[PLAYER_ONE].someTimer; + D_80162E00 = 0; + D_80162DE8 = gPlayerOne->characterId; + func_80005AE8(gPlayerTwo); + func_80005AE8(gPlayerThree); + } else { + sReplayGhostBuffer = D_802BFB80.arraySize8[0][D_80162DC8][3].pixel_index_array; + sReplayGhostBufferSize = D_80162D86; + D_80162DD0 = D_80162DCC; + D_80162DE8 = gPlayerOne->characterId; + D_80162DD8 = 0; + bPlayerGhostDisabled = 0; + D_80162DDC = 1; + func_80005AE8(gPlayerTwo); + func_80005AE8(gPlayerThree); + } + } else { + if ((gLapCountByPlayerId[0] == 3) && (D_80162DDC == 0) && (gPostTimeTrialReplayCannotSave == 1)) { + sReplayGhostBuffer = D_802BFB80.arraySize8[0][D_80162DC8][3].pixel_index_array; + sReplayGhostBufferSize = D_80162D86; + D_80162DDC = 1; + } + if ((gPlayerOne->type & 0x800) == 0x800) { + func_80005AE8(gPlayerTwo); + func_80005AE8(gPlayerThree); + } else { + sUnusedReplayCounter += 1; + if (sUnusedReplayCounter > 100) { + sUnusedReplayCounter = 100; + } + if ((gModeSelection == TIME_TRIALS) && (gActiveScreenMode == SCREEN_MODE_1P)) { + if ((bPlayerGhostDisabled == 0) && (gLapCountByPlayerId[1] != 3)) { + process_player_ghost_replay(); + } + if ((bCourseGhostDisabled == 0) && (gLapCountByPlayerId[2] != 3)) { + process_course_ghost_replay(); + } + if (!(gPlayerOne->type & PLAYER_CINEMATIC_MODE)) { + save_player_replay(); + } + } + } + } + } +} + +void func_80005E6C(void) { + if ((gModeSelection == TIME_TRIALS) && (gModeSelection == TIME_TRIALS) && (gActiveScreenMode == SCREEN_MODE_1P)) { + if ((D_80162DD8 == 0) && (gLapCountByPlayerId[1] != 3)) { + process_player_ghost_replay(); // 3 + } + if ((bCourseGhostDisabled == 0) && (gLapCountByPlayerId[2] != 3)) { + process_course_ghost_replay(); // 2 + } + if ((gPlayerOne->type & PLAYER_CINEMATIC_MODE) != PLAYER_CINEMATIC_MODE) { + process_post_time_trial_replay(); // 1 + return; + } + func_80005AE8(gPlayerTwo); + func_80005AE8(gPlayerThree); + } +} + +void replays_loop(void) { + if (D_8015F890 == 1) { + func_80005E6C(); + return; + } + if (!gPauseTriggered) { + func_80005B18(); + return; + } + /* This only gets triggered when the previous if-statements are not met + Seems like just for pausing */ + gPostTimeTrialReplayCannotSave = 1; +} diff --git a/src/staff_ghosts.h b/src/replays.h similarity index 54% rename from src/staff_ghosts.h rename to src/replays.h index 73723b974..1a632932f 100644 --- a/src/staff_ghosts.h +++ b/src/replays.h @@ -1,25 +1,25 @@ -#ifndef STAFF_GHOSTS_H -#define STAFF_GHOSTS_H +#ifndef REPLAYS_H +#define REPLAYS_H #include #include void func_80005B18(void); -void func_80004EF0(void); -void func_80004FB0(void); -void func_80004FF8(void); +void load_course_ghost(void); +void load_post_time_trial_replay(void); +void load_player_ghost(void); void set_staff_ghost(void); s32 func_800051C4(void); void func_8000522C(void); void func_800052A4(void); void func_80005310(void); -void func_8000546C(void); -void func_8000561C(void); -void func_800057DC(void); -void func_8000599C(void); +void process_post_time_trial_replay(void); +void process_course_ghost_replay(void); +void process_player_ghost_replay(void); +void save_player_replay(void); void func_80005AE8(Player*); void func_80005E6C(void); -void staff_ghosts_loop(void); +void replays_loop(void); // mi0decode @@ -28,19 +28,19 @@ extern s32 mio0encode(s32 input, s32, s32); extern StaffGhost* D_80162DC4; extern s32 D_80162DC8; extern s32 D_80162DCC; -extern u16 D_80162DD4; -extern u16 D_80162DD6; +extern u16 bPlayerGhostDisabled; +extern u16 bCourseGhostDisabled; extern u16 D_80162DD8; extern s32 D_80162E00; extern s32 D_80162DE0; extern s32 D_80162DE4; extern s32 D_80162DE8; -extern s32 D_80162DF0; +extern s32 gPauseTriggered; extern s32 D_80162DF4; -extern s32 D_80162DF8; +extern s32 gPostTimeTrialReplayCannotSave; extern u8* sReplayGhostBuffer; extern size_t sReplayGhostBufferSize; -extern u32* sReplayGhostDecompressed; +extern u32* sPlayerGhostReplay; -#endif /* STAFF_GHOSTS_H */ +#endif /* REPLAYS_H */ diff --git a/src/save.c b/src/save.c index ddb88aeb0..abba01a42 100644 --- a/src/save.c +++ b/src/save.c @@ -8,7 +8,7 @@ #include "menu_items.h" #include "menus.h" #include "save_data.h" -#include "staff_ghosts.h" +#include "replays.h" #include "code_80057C60.h" #include "port/Game.h" #include "buffers.h" @@ -249,8 +249,8 @@ u32 func_800B4DF4(u8* arr) { // Get a time trial record, infer course index s32 func_800B4E24(s32 recordIndex) { - return func_800B4DF4(gSaveData.allCourseTimeTrialRecords.cupRecords[(((GetCupIndex() * 4) + gCourseIndexInCup) / 4)] - .courseRecords[(((GetCupIndex() * 4) + gCourseIndexInCup) % 4)] + return func_800B4DF4(gSaveData.allCourseTimeTrialRecords.cupRecords[GetCupIndex()] + .courseRecords[GetCupCursorPosition()] .records[recordIndex]); } @@ -263,8 +263,8 @@ u32 func_800B4EB4(s32 recordIndex, s32 courseIndex) { // Get Best Lap record of the inferred course index s32 func_800B4F2C(void) { - return func_800B4DF4(gSaveData.allCourseTimeTrialRecords.cupRecords[(((GetCupIndex() * 4) + gCourseIndexInCup) / 4)] - .courseRecords[(((GetCupIndex() * 4) + gCourseIndexInCup) % 4)] + return func_800B4DF4(gSaveData.allCourseTimeTrialRecords.cupRecords[GetCupIndex()] + .courseRecords[GetCupCursorPosition()] .records[TIME_TRIAL_1LAP_RECORD]); } @@ -282,7 +282,7 @@ s32 func_800B5020(u32 time, s32 charId) { s32 j; CourseTimeTrialRecords* tt; - course = GetCupIndex() * 4 + gCourseIndexInCup; + course = GetCupIndex() * 4 + GetCupCursorPosition(); tt = &gSaveData.allCourseTimeTrialRecords.cupRecords[course / 4].courseRecords[course % 4]; i = 0; @@ -329,7 +329,7 @@ s32 func_800B5218(void) { s32 checkLapIndex; s32 character; s32 lapBitmask; - recordIndex = (GetCupIndex() * 4) + gCourseIndexInCup; + recordIndex = (GetCupIndex() * 4) + GetCupCursorPosition(); recordPointer = &gSaveData.allCourseTimeTrialRecords.cupRecords[recordIndex / 4].courseRecords[recordIndex % 4].records[0][0]; lapBitmask = 1; @@ -782,7 +782,7 @@ s32 func_800B6178(s32 arg0) { if (var_v0 == 0) { temp_s3->ghostDataSaved = 1; if (gGamestate == 4) { - temp_s3->courseIndex = (GetCupIndex() * 4) + gCourseIndexInCup; + temp_s3->courseIndex = (GetCupIndex() * 4) + GetCupCursorPosition(); } temp_s3->unk_00 = D_80162DFC; temp_s3->characterId = (u8) D_80162DE0; @@ -827,11 +827,11 @@ s32 func_800B63F0(s32 arg0) { s32 phi_s3; func_800051C4(); - D_80162DD6 = 1; + bCourseGhostDisabled = 1; func_80005AE8(gPlayerThree); phi_s3 = 0; - if (((GetCupIndex() * 4) + gCourseIndexInCup) != D_8018EE10[arg0].courseIndex) { + if (((GetCupIndex() * 4) + GetCupCursorPosition()) != D_8018EE10[arg0].courseIndex) { phi_s3 = 2; } else if (D_80162DFC != D_8018EE10[arg0].unk_00) { phi_s3 = 3; @@ -866,16 +866,16 @@ s32 func_800B64EC(s32 arg0) { return -1; } - sReplayGhostDecompressed = (u32*) &D_802BFB80.arraySize8[0][D_80162DC8][3]; + sPlayerGhostReplay = (u32*) &D_802BFB80.arraySize8[0][D_80162DC8][3]; temp_v0 = osPfsReadWriteFile(&gControllerPak1FileHandle, gControllerPak1FileNote, PFS_READ, - (arg0 * (sizeof(u8) * 0x1000)) + 0x100, sizeof(u8) * 0x1000, (u8*) sReplayGhostDecompressed); + (arg0 * (sizeof(u8) * 0x1000)) + 0x100, sizeof(u8) * 0x1000, (u8*) sPlayerGhostReplay); if (temp_v0 == 0) { // clang-format off phi_s1 = (u8 *) &D_8018EE10[arg0]; temp_s0 = 0; while (1) { // clang-format on - if (phi_s1[7] != func_800B60E8(temp_s0, (u8*) sReplayGhostDecompressed)) { + if (phi_s1[7] != func_800B60E8(temp_s0, (u8*) sPlayerGhostReplay)) { D_8018EE10[arg0].ghostDataSaved = 0; return -2; } @@ -883,7 +883,7 @@ s32 func_800B64EC(s32 arg0) { ++phi_s1; if ((++temp_s0) == 0x3C) { func_8000522C(); - D_80162DD4 = 0; + bPlayerGhostDisabled = 0; D_80162DE0 = (s32) D_8018EE10[arg0].characterId; D_80162DFC = D_8018EE10[arg0].unk_00; break; diff --git a/src/save.h b/src/save.h index 3c399329d..3e91a6abe 100644 --- a/src/save.h +++ b/src/save.h @@ -98,7 +98,7 @@ extern s8 sControllerPak2State; // Current state of the Controller Pak 2 extern const u8 D_800F2E60[]; extern const u8 gGameName[]; extern const u8 gExtCode[]; -extern u16 D_80162DD6; +extern u16 bCourseGhostDisabled; extern s32 D_80162DE0; extern s32 D_80162DFC; extern OSPfs gControllerPak1FileHandle; diff --git a/src/spawn_players.c b/src/spawn_players.c index 30b14e99b..46be8d509 100644 --- a/src/spawn_players.c +++ b/src/spawn_players.c @@ -16,7 +16,7 @@ #include "code_80057C60.h" #include "collision.h" #include "render_courses.h" -#include "staff_ghosts.h" +#include "replays.h" #include "code_80005FD0.h" #include "render_player.h" #include "podium_ceremony_actors.h" @@ -596,14 +596,14 @@ void spawn_players_versus_one_player(f32* arg0, f32* arg1, f32 arg2) { } else if (D_8015F890 != 1) { spawn_player(gPlayerOne, 0, arg0[0], arg1[0], arg2, 32768.0f, gCharacterSelections[0], PLAYER_EXISTS | PLAYER_START_SEQUENCE | PLAYER_HUMAN); - if (D_80162DD4 == 0) { + if (bPlayerGhostDisabled == 0) { spawn_player(gPlayerTwo, 1, arg0[0], arg1[0], arg2, 32768.0f, D_80162DE0, PLAYER_EXISTS | PLAYER_HUMAN | PLAYER_START_SEQUENCE | PLAYER_INVISIBLE_OR_BOMB); } else { spawn_player(gPlayerTwo, 1, arg0[0], arg1[0], arg2, 32768.0f, gCharacterSelections[0], PLAYER_START_SEQUENCE | PLAYER_CPU); } - if (D_80162DD6 == 0) { + if (bCourseGhostDisabled == 0) { spawn_player(gPlayerThree, 2, arg0[0], arg1[0], arg2, 32768.0f, D_80162DE4, PLAYER_EXISTS | PLAYER_HUMAN | PLAYER_START_SEQUENCE | PLAYER_INVISIBLE_OR_BOMB); } else { @@ -620,7 +620,7 @@ void spawn_players_versus_one_player(f32* arg0, f32* arg1, f32 arg2) { spawn_player(gPlayerTwo, 1, arg0[0], arg1[0], arg2, 32768.0f, gCharacterSelections[0], PLAYER_START_SEQUENCE | PLAYER_CPU); } - if (D_80162DD6 == 0) { + if (bCourseGhostDisabled == 0) { spawn_player(gPlayerThree, 2, arg0[0], arg1[0], arg2, 32768.0f, D_80162DE4, PLAYER_EXISTS | PLAYER_HUMAN | PLAYER_START_SEQUENCE | PLAYER_INVISIBLE_OR_BOMB); } else { diff --git a/src/staff_ghosts.c b/src/staff_ghosts.c deleted file mode 100644 index 16620e0d1..000000000 --- a/src/staff_ghosts.c +++ /dev/null @@ -1,542 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "main.h" -#include "code_800029B0.h" -#include "buffers.h" -#include "save.h" -#include "staff_ghosts.h" -#include "code_8006E9C0.h" -#include "menu_items.h" -#include "code_80057C60.h" -#include "kart_dma.h" -#include "port/Game.h" -#include "courses/staff_ghost_data.h" - -u8* sReplayGhostBuffer; -size_t sReplayGhostBufferSize; -s16 D_80162D86; -u16 D_80162D88; - -u32 D_80162D8C; -s16 D_80162D90; -u32* sReplayGhostDecompressed; - -u16 D_80162D98; -u32 D_80162D9C; -s16 D_80162DA0; -u32* D_80162DA4; - -u16 D_80162DA8; -s32 D_80162DAC; -s16 D_80162DB0; -u32* D_80162DB4; - -s16 D_80162DB8; -u32* D_80162DBC; - -uintptr_t staff_ghost_track_ptr; -StaffGhost* D_80162DC4; -s32 D_80162DC8; -s32 D_80162DCC; -s32 D_80162DD0; -u16 D_80162DD4; -u16 D_80162DD6; -u16 D_80162DD8; -s32 D_80162DDC; -s32 D_80162DE0; // ghost kart id? -s32 D_80162DE4; -s32 D_80162DE8; -s32 D_80162DEC; -s32 D_80162DF0; -s32 D_80162DF4; -s32 D_80162DF8; -s32 D_80162DFC; - -s32 D_80162E00; - -u32* sReplayGhostEncoded = (u32*) &D_802BFB80.arraySize8[0][2][3]; -u32* gReplayGhostCompressed = (u32*) &D_802BFB80.arraySize8[1][1][3]; - -extern s32 gLapCountByPlayerId[]; - -void func_80004EF0(void) { - D_80162DA4 = (u32*) &D_802BFB80.arraySize8[0][2][3]; - u8* dest = (u8*) D_80162DA4; - osInvalDCache(&D_80162DA4[0], 0x4000); - - u8* ghost = (u8*) D_80162DC4; - - size_t size = 0; - if (ghost == d_luigi_raceway_staff_ghost) { - size = 187 * sizeof(StaffGhost); - } else if (ghost == d_mario_raceway_staff_ghost) { - size = 208 * sizeof(StaffGhost); - } else if (ghost == d_royal_raceway_staff_ghost) { - size = 377 * sizeof(StaffGhost); - } - - // Manual memcpy required for byte swap - for (size_t i = 0; i < size; i += 4) { - dest[i] = ghost[i + 3]; - dest[i + 1] = ghost[i + 2]; - dest[i + 2] = ghost[i + 1]; - dest[i + 3] = ghost[i]; - } - - osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK); - D_80162D9C = (*D_80162DA4 & 0xFF0000); - D_80162DA0 = 0; -} - -void func_80004FB0(void) { - D_80162DB4 = (u32*) &D_802BFB80.arraySize8[0][D_80162DD0][3]; - D_80162DAC = *D_80162DB4 & 0xFF0000; - D_80162DB0 = 0; -} - -void func_80004FF8(void) { - sReplayGhostDecompressed = (u32*) &D_802BFB80.arraySize8[0][D_80162DC8][3]; - D_80162D8C = (s32) *sReplayGhostDecompressed & 0xFF0000; - D_80162D90 = 0; -} -/** - * Activates staff ghost if time trial lap time is lower enough - * - */ -#ifdef VERSION_EU -#define BLAH 10700 -#define BLAH2 19300 -#define BLAH3 13300 -#else -#define BLAH 9000 -#define BLAH2 16000 -#define BLAH3 11200 - -#endif - -void set_staff_ghost(void) { - CM_SetStaffGhost(); -} - -// Always returns true because mio0encode is stubbed. -s32 func_800051C4(void) { - s32 phi_v0; - - if (sReplayGhostBufferSize != 0) { - // func_80040174 in mio0_decode.s - func_80040174((void*) sReplayGhostBuffer, (sReplayGhostBufferSize * 4) + 0x20, (s32) sReplayGhostEncoded); - phi_v0 = - mio0encode((s32) sReplayGhostEncoded, (sReplayGhostBufferSize * 4) + 0x20, (s32) gReplayGhostCompressed); - return phi_v0 + 0x1e; - } -} - -void func_8000522C(void) { - sReplayGhostDecompressed = (u32*) &D_802BFB80.arraySize8[0][D_80162DC8][3]; - mio0decode((u8*) gReplayGhostCompressed, (u8*) sReplayGhostDecompressed); - D_80162D8C = (s32) (*sReplayGhostDecompressed & 0xFF0000); - D_80162D90 = 0; - D_80162E00 = 1; -} - -void func_800052A4(void) { - s16 temp_v0; - - if (D_80162DC8 == 1) { - D_80162DC8 = 0; - D_80162DCC = 1; - } else { - D_80162DC8 = 1; - D_80162DCC = 0; - } - temp_v0 = D_80162DB8; - sReplayGhostBuffer = (void*) &D_802BFB80.arraySize8[0][D_80162DC8][3]; - sReplayGhostBufferSize = temp_v0; - D_80162D86 = temp_v0; -} - -void func_80005310(void) { - - if (gModeSelection == TIME_TRIALS) { - - set_staff_ghost(); - - if (staff_ghost_track_ptr != (uintptr_t)GetCourse()) { - D_80162DD4 = 1; - } - - staff_ghost_track_ptr = (uintptr_t)GetCourse(); - D_80162DF0 = 0; - D_80162DEC = 0; - D_80162DF8 = 0; - - if (gModeSelection == TIME_TRIALS && gActiveScreenMode == SCREEN_MODE_1P) { - - if (D_8015F890 == 1) { - func_80004FB0(); - if (D_80162DD8 == 0) { - func_80004FF8(); - } - if (D_80162DD6 == 0) { - func_80004EF0(); - } - } else { - - D_80162DD8 = 1U; - D_80162DBC = (u32*) &D_802BFB80.arraySize8[0][D_80162DCC][3]; - D_80162DBC[0] = -1; - D_80162DB8 = 0; - D_80162DDC = 0; - func_80091EE4(); - if (D_80162DD4 == 0) { - func_80004FF8(); - } - if (D_80162DD6 == 0) { - func_80004EF0(); - } - } - } - } -} - -void func_8000546C(void) { - u32 temp_a0; - u32 temp_a1; - UNUSED u16 unk; - u16 temp_v1; - s16 phi_v1; - s16 phi_v0 = 0; - - if (D_80162DB0 >= 0x1000) { - gPlayerOne->type = PLAYER_CINEMATIC_MODE | PLAYER_START_SEQUENCE | PLAYER_CPU; - return; - } - - temp_a0 = D_80162DB4[D_80162DB0]; - temp_a1 = temp_a0 & 0xFF; - - if (temp_a1 < 0x80U) { - phi_v1 = (s16) (temp_a1 & 0xFF); - } else { - phi_v1 = (s16) (temp_a1 | (~0xFF)); - } - - temp_a1 = (u32) (temp_a0 & 0xFF00) >> 8; - gControllerEight->rawStickX = phi_v1; - - if (temp_a1 < 0x80U) { - phi_v1 = (s16) (temp_a1 & 0xFF); - } else { - phi_v1 = (s16) (temp_a1 | (~0xFF)); - } - gControllerEight->rawStickY = phi_v1; - if (temp_a0 & 0x80000000) { - phi_v0 |= A_BUTTON; - } - if (temp_a0 & 0x40000000) { - phi_v0 |= B_BUTTON; - } - if (temp_a0 & 0x20000000) { - phi_v0 |= Z_TRIG; - } - if (temp_a0 & 0x10000000) { - phi_v0 |= R_TRIG; - } - temp_v1 = gControllerEight->buttonPressed & 0x1F0F; - gControllerEight->buttonPressed = (phi_v0 & (phi_v0 ^ D_80162DA8)) | temp_v1; - temp_v1 = gControllerEight->buttonDepressed & 0x1F0F; - gControllerEight->buttonDepressed = (D_80162DA8 & (phi_v0 ^ D_80162DA8)) | temp_v1; - D_80162DA8 = phi_v0; - gControllerEight->button = phi_v0; - - if (D_80162DAC == 0) { - D_80162DB0++; - D_80162DAC = (s32) (D_80162DB4[D_80162DB0] & 0xFF0000); - } else { - D_80162DAC += 0xFFFF0000; - } -} - -void func_8000561C(void) { - u32 temp_a0; - u32 temp_v0; - UNUSED u16 unk; - u16 temp_v1; - s16 phi_v1; - s16 phi_a2 = 0; - - if (D_80162DA0 >= 0x1000) { - func_80005AE8(gPlayerThree); - return; - } - temp_a0 = D_80162DA4[D_80162DA0]; - temp_v0 = temp_a0 & 0xFF; - if (temp_v0 < 0x80U) { - phi_v1 = (s16) (temp_v0 & 0xFF); - } else { - phi_v1 = (s16) (temp_v0 | (~0xFF)); - } - - temp_v0 = (u32) (temp_a0 & 0xFF00) >> 8; - gControllerSeven->rawStickX = phi_v1; - - if (temp_v0 < 0x80U) { - phi_v1 = (s16) (temp_v0 & 0xFF); - } else { - phi_v1 = (s16) (temp_v0 | (~0xFF)); - } - gControllerSeven->rawStickY = phi_v1; - - if (temp_a0 & 0x80000000) { - phi_a2 = A_BUTTON; - } - if (temp_a0 & 0x40000000) { - phi_a2 |= B_BUTTON; - } - if (temp_a0 & 0x20000000) { - phi_a2 |= Z_TRIG; - } - if (temp_a0 & 0x10000000) { - phi_a2 |= R_TRIG; - } - - temp_v1 = gControllerSeven->buttonPressed & 0x1F0F; - gControllerSeven->buttonPressed = (phi_a2 & (phi_a2 ^ D_80162D98)) | temp_v1; - temp_v1 = gControllerSeven->buttonDepressed & 0x1F0F; - gControllerSeven->buttonDepressed = (D_80162D98 & (phi_a2 ^ D_80162D98)) | temp_v1; - D_80162D98 = phi_a2; - gControllerSeven->button = phi_a2; - if (D_80162D9C == 0) { - D_80162DA0++; - D_80162D9C = (s32) (D_80162DA4[D_80162DA0] & 0xFF0000); - } else { - D_80162D9C += (s32) 0xFFFF0000; - } -} - -void func_800057DC(void) { - u32 temp_a0; - u32 temp_v0; - UNUSED u16 unk; - u16 temp_v1; - s16 phi_v1; - s16 phi_a2 = 0; - - if (D_80162D90 >= 0x1000) { - func_80005AE8(gPlayerTwo); - return; - } - temp_a0 = sReplayGhostDecompressed[D_80162D90]; - temp_v0 = temp_a0 & 0xFF; - if (temp_v0 < 0x80U) { - phi_v1 = (s16) (temp_v0 & 0xFF); - } else { - phi_v1 = (s16) (temp_v0 | ~0xFF); - } - - temp_v0 = (u32) (temp_a0 & 0xFF00) >> 8; - - gControllerSix->rawStickX = phi_v1; - - if (temp_v0 < 0x80U) { - phi_v1 = (s16) (temp_v0 & 0xFF); - } else { - phi_v1 = (s16) (temp_v0 | (~0xFF)); - } - - gControllerSix->rawStickY = phi_v1; - - if (temp_a0 & 0x80000000) { - phi_a2 |= A_BUTTON; - } - if (temp_a0 & 0x40000000) { - phi_a2 |= B_BUTTON; - } - if (temp_a0 & 0x20000000) { - phi_a2 |= Z_TRIG; - } - if (temp_a0 & 0x10000000) { - phi_a2 |= R_TRIG; - } - temp_v1 = gControllerSix->buttonPressed & 0x1F0F; - gControllerSix->buttonPressed = (phi_a2 & (phi_a2 ^ D_80162D88)) | temp_v1; - - temp_v1 = gControllerSix->buttonDepressed & 0x1F0F; - gControllerSix->buttonDepressed = (D_80162D88 & (phi_a2 ^ D_80162D88)) | temp_v1; - D_80162D88 = phi_a2; - gControllerSix->button = phi_a2; - - if (D_80162D8C == 0) { - D_80162D90++; - D_80162D8C = (s32) (sReplayGhostDecompressed[D_80162D90] & 0xFF0000); - } else { - D_80162D8C += (s32) 0xFFFF0000; - } -} - -void func_8000599C(void) { - s16 temp_a2; - u32 phi_a3; - u32 temp_v1; - u32 temp_v2; - u32 temp_v0; - u32 temp_t0; - u32 temp_a0_2; - - if (((D_80162DB8 >= 0x1000) || ((gPlayerOne->unk_0CA & 2) != 0)) || ((gPlayerOne->unk_0CA & 8) != 0)) { - D_80162DF8 = 1; - return; - } - - temp_v1 = gControllerOne->rawStickX; - temp_v1 &= 0xFF; - temp_v2 = gControllerOne->rawStickY; - temp_v2 = (temp_v2 & 0xFF) << 8; - temp_a2 = gControllerOne->button; - phi_a3 = 0; - if (temp_a2 & 0x8000) { - phi_a3 |= 0x80000000; - } - if (temp_a2 & 0x4000) { - phi_a3 |= 0x40000000; - } - if (temp_a2 & 0x2000) { - phi_a3 |= 0x20000000; - } - if (temp_a2 & 0x0010) { - phi_a3 |= 0x10000000; - } - phi_a3 |= temp_v1; - phi_a3 |= temp_v2; - temp_t0 = D_80162DBC[D_80162DB8]; - temp_a0_2 = temp_t0 & 0xFF00FFFF; - - if ((*D_80162DBC) == 0xFFFFFFFF) { - - D_80162DBC[D_80162DB8] = phi_a3; - - } else if (temp_a0_2 == phi_a3) { - - temp_v0 = temp_t0 & 0xFF0000; - - if (temp_v0 == 0xFF0000) { - - D_80162DB8++; - D_80162DBC[D_80162DB8] = phi_a3; - - } else { - - temp_t0 += 0x10000; - D_80162DBC[D_80162DB8] = temp_t0; - } - } else { - D_80162DB8++; - D_80162DBC[D_80162DB8] = phi_a3; - } -} - -// sets player to AI? (unconfirmed) -void func_80005AE8(Player* ply) { - if (((ply->type & PLAYER_INVISIBLE_OR_BOMB) != 0) && (ply != gPlayerOne)) { - ply->type = PLAYER_CINEMATIC_MODE | PLAYER_START_SEQUENCE | PLAYER_CPU; - } -} - -void func_80005B18(void) { - if (gModeSelection == TIME_TRIALS) { - if ((gLapCountByPlayerId[0] == 3) && (D_80162DDC == 0) && (D_80162DF8 != 1)) { - if (D_80162DD4 == 1) { - D_80162DD0 = D_80162DCC; - func_800052A4(); - D_80162DD4 = 0; - D_80162DDC = 1; - D_80162DE0 = gPlayerOne->characterId; - D_80162DE8 = gPlayerOne->characterId; - D_80162E00 = 0; - D_80162DFC = playerHUD[PLAYER_ONE].someTimer; - func_80005AE8(gPlayerTwo); - func_80005AE8(gPlayerThree); - } else if (gLapCountByPlayerId[1] != 3) { - D_80162DD0 = D_80162DCC; - func_800052A4(); - D_80162DDC = 1; - D_80162DE0 = gPlayerOne->characterId; - D_80162DFC = playerHUD[PLAYER_ONE].someTimer; - D_80162E00 = 0; - D_80162DE8 = gPlayerOne->characterId; - func_80005AE8(gPlayerTwo); - func_80005AE8(gPlayerThree); - } else { - sReplayGhostBuffer = D_802BFB80.arraySize8[0][D_80162DC8][3].pixel_index_array; - sReplayGhostBufferSize = D_80162D86; - D_80162DD0 = D_80162DCC; - D_80162DE8 = gPlayerOne->characterId; - D_80162DD8 = 0; - D_80162DD4 = 0; - D_80162DDC = 1; - func_80005AE8(gPlayerTwo); - func_80005AE8(gPlayerThree); - } - } else { - if ((gLapCountByPlayerId[0] == 3) && (D_80162DDC == 0) && (D_80162DF8 == 1)) { - sReplayGhostBuffer = D_802BFB80.arraySize8[0][D_80162DC8][3].pixel_index_array; - sReplayGhostBufferSize = D_80162D86; - D_80162DDC = 1; - } - if ((gPlayerOne->type & 0x800) == 0x800) { - func_80005AE8(gPlayerTwo); - func_80005AE8(gPlayerThree); - } else { - D_80162DEC += 1; - if (D_80162DEC >= 0x65) { - D_80162DEC = 0x00000064; - } - if ((gModeSelection == TIME_TRIALS) && (gActiveScreenMode == SCREEN_MODE_1P)) { - if ((D_80162DD4 == 0) && (gLapCountByPlayerId[1] != 3)) { - func_800057DC(); - } - if ((D_80162DD6 == 0) && (gLapCountByPlayerId[2] != 3)) { - func_8000561C(); - } - if (!(gPlayerOne->type & 0x800)) { - func_8000599C(); - } - } - } - } - } -} - -void func_80005E6C(void) { - if ((gModeSelection == TIME_TRIALS) && (gModeSelection == TIME_TRIALS) && (gActiveScreenMode == SCREEN_MODE_1P)) { - if ((D_80162DD8 == 0) && (gLapCountByPlayerId[1] != 3)) { - func_800057DC(); // 3 - } - if ((D_80162DD6 == 0) && (gLapCountByPlayerId[2] != 3)) { - func_8000561C(); // 2 - } - if ((gPlayerOne->type & PLAYER_CINEMATIC_MODE) != PLAYER_CINEMATIC_MODE) { - func_8000546C(); // 1 - return; - } - func_80005AE8(gPlayerTwo); - func_80005AE8(gPlayerThree); - } -} - -void staff_ghosts_loop(void) { - if (D_8015F890 == 1) { - func_80005E6C(); - return; - } - if (!D_80162DF0) { - func_80005B18(); - return; - } - D_80162DF8 = 1; -} diff --git a/src/update_objects.c b/src/update_objects.c index 990646a74..fe823d602 100644 --- a/src/update_objects.c +++ b/src/update_objects.c @@ -205,7 +205,7 @@ void func_80072180(void) { if (gModeSelection == TIME_TRIALS) { if (((gPlayerOne->type & PLAYER_EXISTS) != 0) && ((gPlayerOne->type & (PLAYER_INVISIBLE_OR_BOMB | PLAYER_CPU)) == 0)) { - D_80162DF8 = 1; + gPostTimeTrialReplayCannotSave = 1; } } } diff --git a/src/update_objects.h b/src/update_objects.h index a26d04a99..66cd2ea6e 100644 --- a/src/update_objects.h +++ b/src/update_objects.h @@ -363,7 +363,7 @@ extern u16* gHudLapTextures[]; extern u16* gPortraitTLUTs[]; extern u8* gPortraitTextures[]; -extern s32 D_80162DF8; +extern s32 gPostTimeTrialReplayCannotSave; extern s16 D_8016347C; extern s32 D_80165594; extern s32 D_80165598;